← AWSサービスの内部原理 コース
134. 秘密はどうアプリに届くか — Lambda環境変数の暗号化・ECSのsecrets・buildspecの参照を1つのカタログにする
Lambda・ECS・CodeBuild という3つの現場で「秘密がどう実行環境に届くか」を図で追い、そこに共通する『設定と秘密の分離』という1本の設計原則を抽出していきます。
① 出発点: Lambdaの環境変数は保存時に暗号化されるが、値へのアクセスは別問題
環境変数を設定key=DB_HOST, value=... をfunction設定に保存
保存時暗号化encryption at rest / 既定はLambda管理のKMSキー
実行時に復号プロセスの環境変数へ
コンソール/CLIで閲覧設定を見る権限があれば値にアクセス可能
process.envで生値取得アプリコードが読む
- 公式の言い回し: 「Lambda stores environment variables securely by encrypting them at rest.」——保存時暗号化は既定で有効。
- 既定の暗号化キーとは別に、update-function-configuration --kms-key-arn <ARN> で独自のKMSキーを指定できる(公式: 「To configure a function's encryption key, set the KMSKeyARN option」/「You can configure Lambda to use a different encryption key」)。
- 「保存時に暗号化されている」ことと「その値に誰がアクセスできるか」は別の軸である。設定を見る・編集する権限を持つIAMプリンシパルは、環境変数の値そのものを扱える。だからこそ次のセクションの推奨につながる。
環境変数は「ディスク上では暗号化」されている。しかし暗号化は転送経路・保存場所を守る仕組みであって、「設定を閲覧できる人からその値を隠す」ためのものではない。暗号化されていること=秘密として扱われること、ではない。
② 公式の推奨: 本当の秘密は環境変数ではなくSecrets Managerに置く
機微な値の置き場所を選ぶ
環境変数に直接置く設定を見る権限があれば誰でも値を扱える/ローテーション自前
Secrets Managerに置く実体は専用サービスに一元管理/取得権限はIAMロールで制御
公式推奨- 公式の推奨(原文): 「To increase security, we recommend that you use AWS Secrets Manager instead of environment variables to store database credentials and other sensitive information like API keys or authorization tokens.」
- 環境変数は「設定を見る権限を持つ人であれば扱える」ため、DB認証情報・APIキー・認可トークンのような本当に機微な値には向かない。実行時にSecrets Managerから取得する設計にする。
環境変数は「コードを変えずに挙動を切り替える設定」向き。データベース認証情報のような秘密は、専用サービスに置いて実行時に取りに行くのが公式の推奨。
③ ECS: 秘密を取りに行くのはコンテナの外— タスク実行ロールを使うエージェントが取得して注入する
タスク定義secrets: [{ name: DB_PASS, valueFrom: <Secret ARN> }]
実際にAPIを呼ぶ主体はコンテナの外のエージェント
タスク実行ロールエージェントに一時クレデンシャルとしてGetSecretValue/GetParametersの権限を渡す
ロール自体は「権限を付与する」役割生値を取得
Secrets Manager秘密の実体
SSM Parameter Store秘密の実体
コンテナ起動時に注入環境変数として
アプリはenvから受け取るだけ取得に使ったロールの認証情報には直接アクセス不可
- 公式: 「Secrets can be seamlessly injected into containers from AWS Secrets Manager and Amazon EC2 Systems Manager Parameter Store」「They're referenced as environment variables that use the secrets container definition parameter」。秘密は「injected into containers at runtime」——起動時に注入。
- タスク実行ロールについて公式: 「The task execution role grants the Amazon ECS container and Fargate agents permission to make AWS API calls on your behalf.」——ロールが直接秘密を取りに行くのではなく、コンテナ/Fargateエージェントにその権限を委任する。
- さらに公式は明記: 「These permissions are made available to the agent running on your instance by Amazon ECS periodically sending it the role's temporary credentials, but they aren't directly accessible by the containers in the task.」——ロールの一時クレデンシャル自体はコンテナからは直接アクセスできない。
- 具体的な権限は secretsmanager:GetSecretValue(Secrets Manager参照時)・ssm:GetParameters(Parameter Store参照時、Secrets Manager経由の場合は追加でsecretsmanager:GetSecretValueも必要)・カスタムKMSキー使用時はkms:Decrypt。
- コンテナ編で見た「タスク実行ロール=ECSエージェント側がイメージ取得やログ送信に使うロール」が、ここでは秘密取得にも使われている。
ECSでは「秘密を取得する権限」はタスク実行ロールを通じてコンテナ/Fargateエージェントに委任され、その一時クレデンシャル自体もコンテナからは直接アクセスできない。コンテナ内のアプリは復号済みの生値を環境変数として受け取るだけ。取得の責務とアプリの責務が分離している。
④ CodeBuild: ビルドプロセスも秘密をコードに書かず参照キーで取り込む
buildspec.ymlのenv
取得権限はCodeBuildサービスロール(ssm:GetParametersが必要)
parameter-storekey: パラメータ名
secrets-managerkey: secret-id:json-key:version-stage:version-id
SSM Parameter Store
Secrets Manager
ビルド中の環境変数として利用リポジトリには参照キーだけ/実体は書かれない
ログ上ではマスク
- 公式: env/parameter-store は「retrieve custom environment variables stored in Amazon EC2 Systems Manager Parameter Store」。取り込むには「add the ssm:GetParameters action to your CodeBuild service role」が必要。
- env/secrets-manager は Secrets Manager からの取得。参照は LOCAL_SECRET_VAR: "TestSecret:MY_SECRET_VAR" の形式(secret-id:json-key:version-stage:version-id、json-key以降は省略可能)。
- 公式は平文の env/variables について「We strongly discourage the storing of sensitive values in environment variables. Environment variables can be displayed in plain text using tools such as the CodeBuild console and the AWS CLI. For sensitive values, we recommend that you use parameter-store or secrets-manager mapping instead」と明言。
- Parameter Store / Secrets Manager から取り込んだ値はCodeBuildのログ上でマスクされる。ただし公式注記: 「Masking matches the exact value stored in … Parameter Store or AWS Secrets Manager. If a build command transforms a secret before it appears in the logs, the result is a different string that is not masked.」——Base64エンコードや大文字小文字変換など変形すると別文字列になりマスクされない。
ビルドプロセスでも構図は同じ。buildspecに書くのは「どの秘密を参照するか」だけで、秘密の実体はコードにもリポジトリにも現れない。
⑤ カタログの結論: 3つの現場に共通する『設定と秘密の分離』
Lambda
ECS
CodeBuild
実体を一元管理Secrets Manager / Parameter Store
取得権限だけ委任IAMロールで持つ/値はコード・リポジトリに書かない
起動時に注入アプリは復号済みの生値を受け取るだけ
既習の原則の再適用KMS「鍵を渡さず操作を頼む」/IAMロール「権限だけを渡す」/12-Factor「設定を環境に分離」
- 3原則は3サービスの公式仕様(Lambdaの推奨・ECSのsecrets/タスク実行ロール/コンテナエージェント・CodeBuildのparameter-store/secrets-manager)から共通して読み取れる設計。
- basicsLink接続: 「コードに秘密を書かない」は12-Factor Appの設定分離原則そのもの。KMS編の「鍵という機密そのものは渡さず、KMSに操作を頼む」・IAMロールの「認証情報ではなく権限だけを渡す」という既習の抽象が、ここでは「秘密という具体的なデータ」に対して同じ形で現れている。
秘密の実体は専用サービスに集約し、使う側はIAMロールで「取得する権限」だけを持ち、値は実行時に注入される——この一行「設定と秘密の分離」が、Lambda・ECS・CodeBuild を貫く共通原則。