【PR】この記事にはA8.netのアフィリエイト広告を含みます。
先に結論:Dockerの環境変数へAPIキーを入れると、今回のXServer VPSではdocker inspect、container内env、containerとhostのPID 1環境という4/4経路から値が見えました。読み取り専用secret fileでは同じ4経路すべてで値が見えず、必要なprocessがfileから読む形にできます。ただしDockerを操作できる管理者はfileを読めるため、判定は一部解決です。
Dockerの環境変数にAPIキーを入れると見える?
見えました。今回は本物のAPIキーを一切使わず、実行時に作った42文字の合成canaryをAPP_SECRETへ設定しました。結果JSONにもraw値は残さず、検出できたかのbooleanとSHA-256だけを保存しています。
Docker公式のCompose secrets解説でも、passwordやAPI keyをenvironment variableで渡すと意図しない露出のriskがあり、processから広く利用できたりdebug logへ出たりする可能性が説明されています。
どの経路からsecretを探した?
docker inspectの完全JSONdocker exec env- container内の
/proc/1/environ - host側の
/proc/<container-pid>/environ docker logsdocker top/run/secrets/app_secretのfile内容
containerはCPU 0.1、RAM 32MiB、networkなし、公開portなしです。外部serviceへcanaryを送らず、XServer VPS内だけで比較しました。
環境変数とsecret fileの実測結果は?
| 確認経路 | 環境変数 | secret file |
|---|---|---|
| docker inspect | 値が見えた | 値は見えない |
| docker exec env | 値が見えた | 値は見えない |
| container /proc/1/environ | 値が見えた | 値は見えない |
| host /proc/<pid>/environ | 値が見えた | 値は見えない |
| docker logs | 見えない | 見えない |
| docker top | 見えない | 見えない |
| mounted file | なし | 値が見えた |
環境変数はconfigurationとprocess environmentの4/4経路で検出されました。file方式では同じ4経路が0/4です。単に.envをGitへ入れなければ終わり、という問題ではありません。container作成後のruntime情報にも値が残ります。
secret fileはどのように渡した?
43文字の別canaryをhost上のmode 400 fileへ入れ、containerの/run/secrets/app_secretへread-only bind mountしました。これはLinuxでDocker Composeがsecret fileをcontainerへ届ける仕組みに相当します。
environment:
APP_SECRET_FILE: /run/secrets/app_secret
secrets:
- app_secret
secrets:
app_secret:
file: ./app_secret.txt
Docker公式では、Compose secretは/run/secrets/<secret_name>へfileとしてmountされ、serviceごとにaccessを許可すると説明されています。_FILEは一部のofficial imageが対応するconventionです。
secret fileの権限とmount状態は?
| 項目 | 実測値 |
|---|---|
| container path | /run/secrets/app_secret |
| mount | bind、read-only |
| mode | 400 |
| owner | UID 1000 / GID 1000 |
| size | 43 byte |
| 内容hash | 元canaryと一致 |
docker inspectにはmount先pathが表示されましたが、file内容のcanaryは含まれませんでした。applicationは環境変数の「値」ではなく、APP_SECRET_FILE=/run/secrets/app_secretというpathだけを受け取れます。
secret fileなら絶対に盗まれない?
いいえ。今回もcontainer内でcat /run/secrets/app_secretできる権限からは値を読めました。applicationが使える以上、そのapplicationと同じ権限、container root、Docker daemonを操作できるoperatorから完全に隠すことはできません。
file方式の利点は、値をinspect、全process向けenvironment、process listingへ不必要に複製しないことです。source fileの権限、backup対象、rotation、access auditは別途必要です。
docker logsへAPIキーは出た?
今回の2方式では出ませんでした。applicationが出力したのはexp24-readyだけです。ただし、これはDockerが自動でsecretをmaskした結果ではありません。applicationがenvironmentや設定objectをdebug出力すれば、環境変数方式でもfile方式でも漏れる可能性があります。
ログ対策では「secretをfileで渡す」と「secretの値をloggerへ渡さない」の両方が必要です。
Docker Compose secretとSwarm secretは同じ?
同じものとして扱いません。今回検証したのは、standalone Linux containerへread-only fileをbind mountするCompose相当の方式です。
Docker Swarm secretsはSwarm service向けで、transit・Raft log上でのencryptionやin-memory filesystemへのmountを含みます。今回のXServer VPSではSwarmを有効化せず、その暗号化機構は検証していません。
実験中に発生した問題は?
初回はsecret値の比較自体には成功し、2 containerとhost上のcanary fileも削除できました。しかしshell用途に流用したPostgreSQL imageがVOLUME /var/lib/postgresql/dataを宣言しており、匿名volumeがcontainerごとに残りました。
確認すると、今回の2個だけでなく直前のDockerログ実験で作られた6個も同じ理由でdanglingでした。作成時刻とanonymous labelが実験と一致する8個だけを削除し、cleanupをdocker rm -f -vへ変更しました。
再実行ではdangling volumeが前0件、後0件です。container一覧が空でも、後片付け完了とは限りません。imageのConfig.Volumesとdocker volume lsも確認する必要がありました。
公開中のVPSサービスに影響は出た?
公開readyは実験前、2 container稼働中、cleanup後のすべてでHTTP 200でした。status=ready、database=ok、artifact_storage=okを維持しています。
両containerはnetwork mode none、公開port 0です。container、host canary file、一時directory、匿名volumeは削除済み。root diskの前後差は16,384 byte、swap使用量は変化なしでした。
AIエージェントのAPIキーはどう保存する?
- applicationを
API_KEY_FILEのようなfile読込に対応させる。 - 必要なserviceだけへsecretをmountする。
- source fileはproject外に置き、modeとownerを制限する。
- secret値をrequest log、exception、debug画面へ出さない。
- 定期rotationと失効手順を用意する。
- backupへsecretを混ぜない。
- Docker操作権限を持つuserを最小化する。
将来のAndroid調査worker、LLM API、WordPress連携など、用途ごとに別keyを発行し、漏洩時の影響範囲を分ける構成が向いています。
初心者が迷いそうなポイントは?
.envをGitから除外しても、containerのenvironmentへ渡した値はinspectから見える。- secret fileのpathを環境変数へ入れる場合、値ではなくpathが入る。
- すべてのimageが
_FILE形式へ対応しているわけではない。 - Compose secretとSwarm secretの保存・暗号化方式を混同しない。
- mode 400でもownerまたはrootは読める。
docker rmだけでは匿名volumeが残る場合がある。
よくある質問
docker inspectで環境変数のAPIキーは見える?
今回の合成canaryは見えました。container内env、containerとhostのprocess environmentからも検出しました。
secret fileの値はdocker inspectに出る?
今回のread-only bind mountでは値は出ませんでした。mount先pathは表示されました。
secret fileならDocker管理者にも見えない?
見えます。Dockerを操作してcontainer内fileを読む権限があれば取得できます。
本物のAPIキーで試した?
試していません。毎回生成した合成canaryだけを使い、結果にはraw値を保存していません。
VPS外へcanaryを送った?
送っていません。containerはnetworkなし、公開portなしで実行しました。
Docker環境変数のAPIキー漏洩問題は解決した?
一部解決です。secret file方式では、APIキー相当の値をinspect・env・container/hostのprocess environmentへ載せずに渡せました。一方、fileを読めるapplication・container root・Docker operatorから隠す仕組みではありません。file化に加え、権限、ログmask、rotation、用途別key、外部secret managerを組み合わせる必要があります。

コメント