AIチャットボットのDocker Composeセキュリティ3層構造の解説図。非rootユーザー実行、localhostポート限定、entrypointによる自動硬化の3つのレイヤーと、クジラのアイコンで表現されたコンテナ群が描かれたイラスト。

OpenClawをDocker Compose上で運用する際、セキュリティをどこまで考慮すべきか悩んだことはありませんか?

私自身、Telegram/Discordの複数チャネルに対応し、外部AI API(GLM、Gemini、OpenAI)を利用するBotを構築した際に、認証情報の管理やネットワークの露出範囲について意外と考えることが多いと感じました。

この記事では、実際にDocker Compose環境でセキュリティを意識した構成を組んだ経験をもとに、非rootユーザー実行・localhostポート限定・entrypoint自動硬化の「3層セキュリティ」と、2段階の認証情報管理について紹介します。

こんな人におすすめ

  • Docker ComposeでBotやAPIサーバーを運用している方
  • コンテナのセキュリティ設定をどこまでやるべきか迷っている方
  • 複数のAI APIキー・トークンを安全に管理したい方
  • entrypoint.shを活用したセキュリティ自動化に興味がある方

目次

背景

OpenClawをDocker Compose上で運用するにあたり、セキュリティを考慮した環境構築を行いました。

Telegram/Discordの複数チャネルに対応し、外部AI API(GLM、Gemini、OpenAI)を利用する構成のため、認証情報の管理やネットワークの露出範囲を意識する必要がありました。

正直なところ、最初は「Dockerだからある程度安全だろう」と思っていましたが、実際に構築してみると考慮すべき点が予想以上に多かったです。

要件

  • 非rootユーザーでの実行
  • APIキー・トークンの安全な管理(.env ファイル分離)
  • ポートの公開範囲をlocalhostに限定
  • Gateway認証とDiscordチャンネルのアクセス制御
  • コンテナ起動時のセキュリティ設定自動適用

実装方針

今回採用したセキュリティ設計は、以下の3層構造です。

graph TD
    subgraph Layer1["Layer 1: Dockerコンテナ"]
        A[非rootユーザー実行<br/>UID 1001]
    end
    subgraph Layer2["Layer 2: ネットワーク"]
        B[ポート公開を<br/>127.0.0.1に限定]
    end
    subgraph Layer3["Layer 3: 起動時自動硬化"]
        C[entrypoint.shで<br/>セキュリティポリシー適用]
    end

    Layer1 --> Layer2 --> Layer3

    style Layer1 fill:#e8f5e9
    style Layer2 fill:#e3f2fd
    style Layer3 fill:#fff3e0

1. Docker構成のセキュリティ対策

非rootユーザー実行:

  • Dockerfile内でアプリ専用ユーザー(UID 1001)を作成しています
  • アプリケーション実行はすべて非rootです

ポート公開の限定:

ports:
  - "127.0.0.1:51121:51122"   # OAuth: localhost only
  - "127.0.0.1:18789:18790"   # Gateway: localhost only

外部からのアクセスを遮断し、localhostのみに制限しています。

認証情報の分離:

  • .env ファイルに機密情報を集約しています
  • .gitignore.env を除外しています
  • docker-compose.ymlenv_file で読み込みます

2. entrypoint.shによる自動セキュリティ硬化

コンテナ起動時に entrypoint.sh が以下を自動適用します:

  • 設定ディレクトリのパーミッション(700)
  • Discord groupPolicy を allowlist に強制
  • 信頼プロキシの設定
  • socat ブリッジによる内部ポートフォワード

3. アプリ固有の認証管理

このBotは独自の2層構造の認証管理を持っています:

flowchart LR
    A[".env<br/>環境変数"] --> B["bot-config.json<br/>auth.profiles"]
    B --> C["auth-profiles.json<br/>実際のAPIキー"]

    style A fill:#ffecb3
    style B fill:#bbdefb
    style C fill:#c8e6c9
  • bot-config.jsonauth.profiles がプロファイルを参照します
  • auth-profiles.json に実際のAPIキー・OAuthトークンが格納されています

環境変数だけでは不十分で、Bot内部のauthプロファイルにも登録が必要です。
ここは実際にハマったポイントで、.env に設定しただけでは動かず、原因の特定に時間がかかりました。

4. AIモデルの動的切り替え

  • BOT_AI_MODEL 環境変数は設定ファイルを自動で上書きしません
  • entrypoint.sh で起動時に bot models set を呼び出して適用します
  • Makefileに make model-glm / make model-gemini を用意し、再起動なしで即時切り替え可能です

良かった点

個人的に最も良かったのは、entrypoint.shによる自動硬化です。

設定ファイルが外部から書き換えられても、コンテナを再起動すればセキュリティポリシーが自動的に再適用されます。
「壊れても再起動すれば安全な状態に戻る」という安心感は、運用上とても大きいと感じています。

また、localhostバインドは設定が簡単なわりに効果が高く、Docker Composeの ports127.0.0.1: プレフィックスを付けるだけで外部公開を防止できます。

つまづいた点

実際に構築する中でいくつかハマったポイントがありました。

2層構造の認証管理: 環境変数(.env)に設定しただけでは不十分で、Bot固有の設定ファイルにも登録が必要でした。
この「環境変数 → アプリ設定のブリッジ処理」に気づくまでに、正直なところ2時間ほど費やしました。

セッションロック問題: コンテナ再起動後に .lock ファイルが残り、Botが起動できなくなる問題に遭遇しました。
entrypoint.shにロックファイル削除処理を追加することで解決しましたが、初回は原因がわからず困りました。

得られた効果

この3層セキュリティ + 2段階認証管理の構成を導入した結果:

  • セキュリティ設定の手動確認が不要に: entrypoint.shが起動時に自動チェックするため、人為的なミスを防止できます
  • 環境の再現性が向上: docker-compose up だけでセキュアな環境が再現できます
  • トラブルシューティングの効率化: ロックファイル対策やモデル切り替えをMakefileに集約し、運用ナレッジをコードに落とし込めました

まとめ

Docker ComposeでOpenClawを運用する際のセキュリティ設計として、以下の3点が効果的でした。

  • 非rootユーザー + localhostポート限定 + entrypoint自動硬化の3層構造
  • 複数のAPI認証情報を扱うため、.env + アプリ固有のauth管理の2段構えが必要です
  • 運用ナレッジ(モデル切り替え、トラブルシューティング)をMakefileやCLAUDE.mdに集約することで、次回のセッションで即座にコンテキストを復元できます

セキュリティ設計は「やりすぎかな」と思うくらいがちょうどよいと個人的には感じています。
特にAPIキーを複数扱うBotでは、最初にしっかり設計しておくことで、後々の運用が格段に楽になります。