dockleでコンテナイメージのセキュリティを強化する

# Dockle: コンテナイメージのセキュリティを強化するツール

## 1. はじめに

Dockleは、コンテナイメージのセキュリティを強化するためのオープンソースのコンテナイメージライナーおよびセキュリティスキャナーです。Aqua Securityによって開発されたこのツールは、コンテナ化されたアプリケーションのセキュリティを向上させるための重要な役割を果たしています。

コンテナ技術の急速な普及に伴い、コンテナのセキュリティは開発者とセキュリティ専門家にとって重要な関心事となっています。Dockleは、コンテナイメージの脆弱性を特定し、ベストプラクティスに基づいたセキュリティ対策を提案することで、この課題に対処します。

## 2. Dockleの主な機能

Dockleは以下の主要な機能を提供しています：

1. コンテナイメージの静的解析：Dockleはイメージの内容を詳細に分析し、潜在的なセキュリティリスクを特定します。

2. セキュリティベストプラクティスの検証：業界標準のベストプラクティスに基づいて、イメージの構成をチェックします。

3. CIS Dockerベンチマークとの整合性チェック：Center for Internet Security（CIS）が定めるDockerセキュリティガイドラインへの準拠を確認します。

4. Dockerfileの問題点の特定：Dockerfileの記述に関する潜在的な問題や改善点を指摘します。

## 3. Dockleの使い方

### インストール方法

Dockleは、以下のコマンドで簡単にインストールできます：

```bash
brew install goodwithtech/r/dockle
```

または、GitHubのリリースページから直接バイナリをダウンロードすることもできます。

### 基本的なコマンド構文

Dockleの基本的な使用方法は以下の通りです：

```bash
dockle [オプション] イメージ名
```
### サンプルアプリケーションを用意

今回は、FastAPIのサンプルアプリケーションを用意します。

カレントディレクトリに`main.py`,`Dockerfile`,`requirements.txt`ファイルを作成します。

```python
# main.py
from typing import Union

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def read_root():
    return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}
```

```Dockerfile
# Dockerfile
# ベースイメージとして公式のPythonイメージを使用
FROM python:3.9-slim

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピー
COPY requirements.txt .

# 依存関係をインストール
RUN pip install --no-cache-dir -r requirements.txt

# アプリケーションのコードをコピー
COPY . .

# FastAPIアプリケーションを起動
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
```

```txt
# requirements.txt
fastapi
uvicorn[standard]
```
```
# ファイル構成
.
|-- Dockerfile
|-- main.py
`-- requirements.txt
```

FastAPIの詳しい説明については以下をご参照ください。

https://fastapi.tiangolo.com/deployment/docker/#create-the-fastapi-code


### 実行例と結果の解釈

例えば、次のようにコマンドを実行します：

```bash
docker build -t fastapi-sample .
dockle fastapi-sample
```

Dockleは、イメージを分析し、検出された問題を重要度別に表示します。結果には、問題の説明と修正のためのアドバイスが含まれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/7976a115-3b67-3c1a-6398-9faa9b80259b.png)

要約すると以下のことが指摘されました。
1. 非rootユーザーの作成（CIS-DI-0001）
2. latestタグの回避（DKL-DI-0006）
3. Dockerをビルドする際に、署名されたイメージのみを使用するように設定（CIS-DI-0005）
4. HEALTHCHECKの追加（CIS-DI-0006）
5. セキュリティを強化するために、必要のないsetuid/setgidファイルを削除する（CIS-DI-0008)
6. 不要なファイルの削除（DKL-LI-0003）

上記の結果を踏まえDockerfileを改善します。

```Dockerfile
# ベースイメージとして公式のPythonイメージを使用（バージョンを固定）
FROM python:3.9-slim-bullseye

# 作業ディレクトリを設定
WORKDIR /app

# 依存関係をコピー
COPY requirements.txt .

# 依存関係をインストール、非rootユーザーを作成、不要なsetuid/setgidファイルを削除
RUN pip install --no-cache-dir -r requirements.txt && \
    adduser --disabled-password --no-create-home appuser && \
    apt-get update && \
    apt-get install -y curl && \
    rm -rf /var/lib/apt/lists/* && \
    rm -f /usr/bin/chfn /usr/bin/chsh /usr/bin/chage /usr/bin/expiry /usr/bin/gpasswd /usr/bin/newgrp /usr/bin/passwd /bin/su /bin/umount /bin/mount

# アプリケーションのコードをコピー（Dockerfileは除外）
COPY main.py .

HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \
  CMD curl -f http://localhost:80/ || exit 1

# 非rootユーザーに切り替え
USER appuser

# FastAPIアプリケーションを起動
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
```
上記の内容にDockerfileを修正して、再度ビルドして、`dockle`コマンドを実行します。

```bash
# build前に署名されたイメージのみを使用するように設定（CIS-DI-0005）
export DOCKER_CONTENT_TRUST=1
# 再ビルド
docker build -t fastapi-sample .
# Dockleで再スキャン
dockle fastapi-sample2
```

![image-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/306043/04bbab29-3418-a128-7a69-380ba13ccd91.png)


なぜか、latestタグの回避（DKL-DI-0006）のWarningが未だ表示されていますが、Dockerfile上で、既に、`-slim-bullseye`というタグを使用しているため、無視してもよいと思います。
setuid/setgidファイルの一部は重要な機能を持っている必要なもののみ残しています。


## 4. Dockleの高度な使用方法

### カスタムルールの作成

カスタムルールは、組織固有のセキュリティ要件に合わせて定義することができます。
例えば、以下のようなルールをYAMLファイルで作成します。

```yaml
rules:
  - name: CHECK_CUSTOM_FILE
    code: CUSTOM_FILE_001
    level: WARN
    description: Check if custom file exists
    match:
      type: file
      path: /app/custom-file.txt
      expectedResult:
        - exists  
```

dockleコマンドのオプションで`--custom-rules`をつけて実行します。

```bash
dockle --custom-rules custom-rules.yaml <image_name>
```

このルールは、コンテナ内の /app/custom-file.txt ファイルの存在をチェックし、存在しない場合に警告を出します。


### CIパイプラインへの統合

Dockleは、CI/CDパイプラインに容易に統合できます。例えば、GitHub actionsでワークフローサンプル`.github/workflows/dockle.yml`は以下のようになります。

```yaml
name: Dockle

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  dockle:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Build Docker image
        run: docker build -t my-image:${{ github.sha }} .

      - name: Run Dockle
        uses: erzz/dockle-action@v1
        with:
          image: my-image:${{ github.sha }}
          failure-threshold: fatal
          exit-code: 1
```

### 他のツールとの連携

DockleはTrivyなどの他のセキュリティスキャンツールと組み合わせて使用することで、より包括的なセキュリティチェックが可能になります。

## 5. Dockleのメリットとデメリット

### メリット
- 高速なスキャン処理
- 使いやすいインターフェース
- 豊富なチェック項目
- オープンソースで無料

### デメリット
- 一部の高度な設定では誤検知の可能性がある
- 特定の環境では機能が制限される場合がある

## 6. ユースケース

Dockleは以下のようなシナリオで活用されています：

- 開発段階でのイメージのセキュリティチェック
- 本番環境へのデプロイ前の最終確認
- 定期的なセキュリティ監査の一環としての使用

## 7. Dockleの将来性

Dockleは活発に開発が続けられており、今後も機能の拡張が期待されます。コンテナ技術の進化に合わせて、新しいセキュリティチェック項目が追加されていくでしょう。

## 8. まとめ

Dockleは、コンテナイメージのセキュリティ強化してより安全なコンテナアプリケーションを構築することに取り入れてみてはいかがでしょうか？