PR

Docker環境変数からAPIキーは見える?XServer VPSでsecret fileと7経路比較

【PR】この記事にはA8.netのアフィリエイト広告を含みます。

先に結論:Dockerの環境変数へAPIキーを入れると、今回のXServer VPSではdocker inspectcontainerenvcontainerhostPID 1環境という4/4経路から値が見えました。読み取り専用secret fileでは同じ4経路すべてで値が見えず、必要なprocessfileから読む形にできます。ただしDockerを操作できる管理者はfileを読めるため、判定は一部解決です。

Dockerの環境変数にAPIキーを入れると見える?

見えました。今回は本物のAPIキーを一切使わず、実行時に作った42文字の合成canaryAPP_SECRETへ設定しました。結果JSONにもraw値は残さず、検出できたかのbooleanSHA-256だけを保存しています。

Docker公式のCompose secrets解説でも、passwordAPI keyenvironment variableで渡すと意図しない露出のriskがあり、processから広く利用できたりdebug logへ出たりする可能性が説明されています。

どの経路からsecretを探した?

  1. docker inspectの完全JSON
  2. docker exec env
  3. container内の/proc/1/environ
  4. host側の/proc/<container-pid>/environ
  5. docker logs
  6. docker top
  7. /run/secrets/app_secretfile内容

containerCPU 0.1RAM 32MiBnetworkなし、公開portなしです。外部servicecanaryを送らず、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 なし 値が見えた

環境変数はconfigurationprocess environmentの4/4経路で検出されました。file方式では同じ4経路が0/4です。単に.envGitへ入れなければ終わり、という問題ではありません。container作成後のruntime情報にも値が残ります。

[PR]
VPSでいろいろ試すなら『XServer VPS』

secret fileはどのように渡した?

43文字の別canaryhost上のmode 400 fileへ入れ、container/run/secrets/app_secretread-only bind mountしました。これはLinuxDocker Composesecret filecontainerへ届ける仕組みに相当します。

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 bindread-only
mode 400
owner UID 1000 / GID 1000
size 43 byte
内容hash canaryと一致

docker inspectにはmountpathが表示されましたが、file内容のcanaryは含まれませんでした。applicationは環境変数の「値」ではなく、APP_SECRET_FILE=/run/secrets/app_secretというpathだけを受け取れます。

secret fileなら絶対に盗まれない?

いいえ。今回もcontainer内でcat /run/secrets/app_secretできる権限からは値を読めました。applicationが使える以上、そのapplicationと同じ権限、container rootDocker daemonを操作できるoperatorから完全に隠すことはできません。

file方式の利点は、値をinspect、全process向けenvironmentprocess listingへ不必要に複製しないことです。source fileの権限、backup対象、rotationaccess auditは別途必要です。

docker logsへAPIキーは出た?

今回の2方式では出ませんでした。applicationが出力したのはexp24-readyだけです。ただし、これはDockerが自動でsecretmaskした結果ではありません。applicationenvironmentや設定objectdebug出力すれば、環境変数方式でもfile方式でも漏れる可能性があります。

ログ対策では「secretfileで渡す」と「secretの値をloggerへ渡さない」の両方が必要です。

Docker Compose secretSwarm secretは同じ?

同じものとして扱いません。今回検証したのは、standalone Linux containerread-only filebind mountするCompose相当の方式です。

Docker Swarm secretsSwarm service向けで、transitRaft log上でのencryptionin-memory filesystemへのmountを含みます。今回のXServer VPSではSwarmを有効化せず、その暗号化機構は検証していません。

実験中に発生した問題は?

初回はsecret値の比較自体には成功し、2 containerhost上のcanary fileも削除できました。しかしshell用途に流用したPostgreSQL imageVOLUME /var/lib/postgresql/dataを宣言しており、匿名volumecontainerごとに残りました。

確認すると、今回の2個だけでなく直前のDockerログ実験で作られた6個も同じ理由でdanglingでした。作成時刻とanonymous labelが実験と一致する8個だけを削除し、cleanupdocker rm -f -vへ変更しました。

再実行ではdangling volumeが前0件、後0件です。container一覧が空でも、後片付け完了とは限りません。imageConfig.Volumesdocker volume lsも確認する必要がありました。

公開中のVPSサービスに影響は出た?

公開readyは実験前、2 container稼働中、cleanup後のすべてでHTTP 200でした。status=readydatabase=okartifact_storage=okを維持しています。

containernetwork mode none、公開port 0です。containerhost canary file、一時directory、匿名volumeは削除済み。root diskの前後差は16,384 byteswap使用量は変化なしでした。

AIエージェントのAPIキーはどう保存する?

将来のAndroid調査workerLLM APIWordPress連携など、用途ごとに別keyを発行し、漏洩時の影響範囲を分ける構成が向いています。

初心者が迷いそうなポイントは?

よくある質問

docker inspectで環境変数のAPIキーは見える?

今回の合成canaryは見えました。containerenvcontainerhostprocess environmentからも検出しました。

secret fileの値はdocker inspectに出る?

今回のread-only bind mountでは値は出ませんでした。mountpathは表示されました。

secret fileならDocker管理者にも見えない?

見えます。Dockerを操作してcontainerfileを読む権限があれば取得できます。

本物のAPIキーで試した?

試していません。毎回生成した合成canaryだけを使い、結果にはraw値を保存していません。

VPS外へcanaryを送った?

送っていません。containernetworkなし、公開portなしで実行しました。

[PR]
VPSでいろいろ試すなら『XServer VPS』

Docker環境変数のAPIキー漏洩問題は解決した?

一部解決です。secret file方式では、APIキー相当の値をinspectenvcontainer/hostprocess environmentへ載せずに渡せました。一方、fileを読めるapplicationcontainer rootDocker operatorから隠す仕組みではありません。file化に加え、権限、ログmaskrotation、用途別key、外部secret managerを組み合わせる必要があります。

コメント

タイトルとURLをコピーしました