Azure Kubernetes ServiceでClamAVを使ってみた(後編: リアルタイム検知)


1. はじめに

記事は2部構成になっています。

  • Azure Kubernetes ServiceでClamAVを使ってみた(前編:ウィルススキャン)
  • Azure Kubernetes ServiceでClamAVを使ってみた(後編:リアルタイム検知)←本記事

結論から申し上げますと、本記事で試した方式では、Azure Kubernetes Serviceのワーカーノード全体のリアルタイム検知はうまくいきませんでした。これから検討する方の参考になれば幸いです。

なお、本記事ではClamAVやAzure Kubernetes Service(以降「AKS」と略します)の基本的な使い方についての説明は割愛します。

2. リアルタイムスキャンをするには

ClamAVでリアルタイムスキャンの機能が提供されています。公式ドキュメントの「On-Access Scanning」という機能が該当し、clamonaccコマンドを使用します。clamonaccはカーネルのfanotifyの機能でファイルシステムの変化を検知し、clamdデーモンにウィルススキャンを依頼する役割を果たします。

構成図

clamonaccコマンドをClamAVコンテナ内で起動して、ワーカーノード上のコンテナでリアルタイム検知ができるか試します。clamonaccはカーネルの機能を使用するので、ClamAVコンテナにSYS_ADMIN権限を設定しておきます。

3. ClamAVコンテナの準備

ClamAVコンテナの作成

今回は、Ubuntu LinuxのベースイメージにClamAVをインストールしたコンテナを作成しました。
次の通り、freshclamがデーモンとして起動するDockerfileを用意します。

Dockerfile
FROM ubuntu:20.04 AS builder

EXPOSE 3310

RUN apt update && apt install -y \
    clamav \
    clamav-daemon \
    clamav-freshclam \
    vim \
    wget

# テスト用ユーザーを追加
RUN groupadd -g 1000 user && useradd -m -s /bin/bash -u 1000 -g 1000 user

CMD ["/usr/bin/freshclam", "-d", "-F","-u","clamav"]

コンテナをビルドします。

$ docker image build -t <repository>:<tag>

このイメージをAzure Container Registryにプッシュします。

$ docker image tag <repository>:<tag> <registry-name>.azurecr.io/<repository>:<tag>
$ docker image push <registry-name>.azurecr.io/<repository>:<tag>

4. clamonaccの起動

clamonaccの起動準備

clamonaccコマンドは、カーネル「fanotify」を使用する1ため、コンテナ起動時にSYS_ADMIN権限を与える2必要があります。そこで、AKSにDaemonSetをデプロイする際のマニフェストファイルで指定します。

~~(略)~~
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      nodeSelector:
        "beta.kubernetes.io/os": linux
      containers:
      - name: clamav-scanner
        image: <registry-name>.azurecr.io/<repository>:<tag>
        securityContext:
          capabilities:
          add:
            - SYS_ADMIN
        volumeMounts:
~~(略)~~

fanotifyのinit処理でSYS_ADMIN権限が必要2となります。KubernetesのマニフェストにsecurityContextを定義して設定します。

DaemonSetのマニフェストファイルを使用してClamAVコンテナをAKSにデプロイします。

$ kubectl apply -f <manifest-file-name>

clamonaccを動かすにはClamAVのデーモン(clamd)を起動しておく必要があります。
ClamAVコンテナの中に入って、clamd.confファイルを編集します。

$ kubectl exec -it clamav-xxxxx /bin/bash
# vi /etc/clamav/clamd.conf

clamd.confの編集

clamd.confファイルの末尾にOn-Access Scanningの設定を追加します。
また、fanotifyを使用するので、clamdデーモンをroot権限で起動するようUser行も変更します。

clamd.conf
~~(略)~~

# TemporaryDirectory is not set to its default /tmp here to make overriding
# the default with environment variables TMPDIR/TMP/TEMP possible
- User clamav
+ User root 
ScanMail true

~~(略)~~

+ OnAccessPrevention yes
+ OnAccessMountPath /
+ OnAccessExcludeRootUID yes

clamonaccの起動

clamdデーモンを起動してから、clamonaccを起動します。

# clamd
# clamonacc --remove --config-file=/etc/clamav/clamd.conf --log=/var/log/clamav/clamonacc.log

psコマンドで確認すると、clamonaccが起動していることがわかります。

# ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
clamav       1     0  0 08:31 ?        00:00:00 /usr/bin/freshclam -d -F -u clamav
root        10     0  0 08:32 pts/0    00:00:00 /bin/bash
root        22     1  0 08:34 ?        00:00:00 clamd
root        25     1  0 08:34 ?        00:00:00 clamonacc --remove --config-file=/etc/clamav/clamd.conf --log=/var/log/clamav/clamonacc.log
root        32    10  0 08:34 pts/0    00:00:00 ps -ef

5. リアルタイム検知の実行

パターン1

まずは、ClamAVコンテナ内部でリアルタイム検知ができるか試してみます。
ClamAVコンテナに入ります。

$ kubectl exec -it clamav-xxxxx /bin/bash

テスト用ユーザーに切り替えます。

# su - user

テスト用ウィルスファイルを取得します。

$ wget https://www.eicar.org/download/eicar.com
--2022-03-10 08:36:20--  https://www.eicar.org/download/eicar.com
Resolving www.eicar.org (www.eicar.org)... 89.238.73.97, 2a00:1828:1000:2497::2
Connecting to www.eicar.org (www.eicar.org)|89.238.73.97|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 68
Saving to: 'eicar.com'

eicar.com                         100%[=============================================================>]      68  --.-KB/s    in 0s      

2022-03-10 08:36:22 (8.65 MB/s) - 'eicar.com' saved [68/68]

lsコマンドで確認すると、保存した「eicar.com」ファイルが存在していないことがわかります。

$ ls
$ 

ルートユーザーに戻り、clamonaccのログファイルを確認します。「eicar.com」ファイルを検知し、削除されたことがわかります。

$ exit
logout
# cat /var/log/clamav/clamonacc.log
/var/log/clamav/clamonacc.log
--------------------------------------
/home/user/eicar.com: Eicar-Signature FOUND
/home/user/eicar.com: Removed.
パターン2

別のターミナルでclamonaccが起動しているPodと同じノードにデプロイされているTomcatコンテナに入って試します。

$ kubectl exec -it ap-server-xxxxxxxxxx-xxxxx /bin/bash

Tomcatのコンテナで一般ユーザーを作成して、ユーザーを切り替えます。

# groupadd -g 1000 test
# useradd -m -s /bin/bash -u 1000 -g 1000 -G sudo test
# su - test

テスト用ウィルスファイルを取得します。

$ wget https://www.eicar.org/download/eicar.com
--2022-03-10 09:42:50--  https://www.eicar.org/download/eicar.com
Resolving www.eicar.org (www.eicar.org)... 89.238.73.97, 2a00:1828:1000:2497::2
Connecting to www.eicar.org (www.eicar.org)|89.238.73.97|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 68
Saving to: 'eicar.com'

eicar.com                         100%[=============================================================>]      68  --.-KB/s    in 0s      

2022-03-10 09:42:52 (64.8 MB/s) - 'eicar.com' saved [68/68]

lsコマンドで確認すると、保存した「eicar.com」ファイルが残っていることがわかります。

$ ls
eicar.com
$ 

ClamAVのコンテナに戻ってclamonaccのログファイルを確認します。

# cat /var/log/clamav/clamonacc.log

先ほどとログの内容が変わっておらず、Tomcatコンテナの/home/test配下のウィルスファイルが見つけられなかったことがわかります。

/var/log/clamav/clamonacc.log
--------------------------------------
/home/user/eicar.com: Eicar-Signature FOUND
/home/user/eicar.com: Removed.

Tomcatコンテナのウィルスファイルが検知できれば、ログファイルで以下のように出力されるはずですが、今回は記録されていませんでした。
/home/test/eicar.com: Eicar-Signature FOUND
/home/test/eicar.com: Removed.

6. まとめ

残念ながら、今回試した方式では、リアルタイム検知はClamAVのコンテナ内のみ可能で、他のコンテナも含むAKSのワーカーノード全体のリアルタイム検知はできませんでした。Linuxカーネルの権限を与えるなど、コンテナそのものの安全性を確保しにくくなるため、本番環境への適用は慎重に検討したほうが良いでしょう。


  • Microsoft Azure は,Microsoft Corporation の商標または登録商標です。
  • Dockerは、Docker Inc. の米国およびその他の国における登録商標もしくは商標です。
  • Kubernetesは、The Linux Foundation の米国およびその他の国における登録商標または商標です。
  • その他、本資料に記述してある会社名、製品名は、各社の登録商品または商標です。
  1. ClamAV Documentation 3.3.1. On-Access Scanning

  2. Ubuntu Manpage: capabilities - Linux のケーパビリティ (capability) の概要 2