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権限`を設定しておきます。

![img2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2369414/b9d08722-9c41-970a-6eb6-ed505b2bca11.png)

# 3. ClamAVコンテナの準備

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

```text: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をデプロイする際のマニフェストファイルで指定します。

[^1]: [ClamAV Documentation 3.3.1. On-Access Scanning](https://docs.clamav.net/manual/OnAccess.html)
[^2]: [Ubuntu Manpage: capabilities - Linux のケーパビリティ (capability) の概要](http://manpages.ubuntu.com/manpages/bionic/ja/man2/fanotify_init.2.html)

```yaml:
～～(略)～～
    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:
～～(略)～～
```
:::note
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行も変更します。

```diff_conf: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.
```
:::note info
Tomcatコンテナのウィルスファイルが検知できれば、ログファイルで以下のように出力されるはずですが、今回は記録されていませんでした。
/home/<font color="red">**test**</font>/eicar.com: Eicar-Signature FOUND
/home/<font color="red">**test**</font>/eicar.com: Removed.
:::

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

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