はじめに
AWSのコンテナサービスであるAmazon ECS(Fargate)を利用する際、データベースのパスワードやAPIキーなどの機密情報をどのようにコンテナへ渡すかは、セキュリティ設計における重要なテーマです。コンテナイメージ内に直接機密情報を埋め込んだり、タスク定義の環境変数にプレーンテキストで記述したりすることは、情報漏洩のリスクを高めるため避けるべきです。
本記事では、AWSの推奨ベストプラクティスである「AWS Secrets Manager」と「ECSタスク定義」を連携させ、安全に環境変数をコンテナへ注入する設定手順をステップバイステップで解説します。
前提知識/必要な理由
ECSで機密情報を扱う場合、主に「AWS Systems Manager Parameter Store」または「AWS Secrets Manager」を利用します。Secrets Managerは、強力な暗号化(AWS KMS)に加え、シークレットの自動ローテーション機能やクロスアカウントでの共有など、エンタープライズ用途に適した高度なセキュリティ機能を備えています。
ECSとSecrets Managerを連携させる最大のメリットは、「アプリケーションコードを変更することなく、コンテナの起動時に自動的かつ安全に環境変数として機密情報が注入される」点にあります。これにより、コンテナイメージやタスク定義のメタデータに機密情報が残るのを防ぐことができます。
なお、本手順で紹介するECS標準の連携機能(タスク定義のsecrets属性)を使用する場合、アプリケーション内にAWS SDKや外部ライブラリを導入する必要はありません。コンテナ側からは通常の環境変数としてシークレット値を読み込むことができるため、非常にシンプルに実装可能です。
具体的な設定手順・設計方法
ステップ1:Secrets Managerでシークレットを作成する
まずは、安全に管理したい機密情報をSecrets Managerに登録します。
- AWS管理コンソールから「Secrets Manager」を開き、「新しいシークレットを保存する」をクリックします。
- シークレットのタイプで「その他のシークレットのタイプ」を選択します。
- キー/値のペアとして、以下のように設定します。
- キー:
DB_PASSWORD - 値:
SuperSecurePassword123!(任意の強力なパスワード)
- キー:
- シークレット名を入力します(例:
prod/myapp/database)。 - 他の設定はデフォルトのまま、シークレットを保存します。作成完了後に表示される「シークレットのARN」をメモしておきます。
ステップ2:ECSタスク実行ロールに権限を付与する
ECSエージェントがコンテナ起動時にSecrets Managerから値を読み取れるよう、ECSタスク実行ロール(Task Execution Role)に権限を追加します。(※注:タスクロールではなく、コンテナを起動する主体である「タスク実行ロール」への付与が必要です)
IAMコンソールを開き、使用しているECSタスク実行ロール(通常は ecsTaskExecutionRole)に以下のインラインポリシーを追加します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/database-XXXXXX"
]
}
]
}
※ResourceのARNは、ステップ1で作成したシークレットの実際のARNに置き換えてください。デフォルトの暗号化キー(aws/secretsmanager)ではなく、独自に作成したカスタマー管理のKMSキーを使用している場合は、追加でkms:Decrypt権限の許可も必要です。
ステップ3:ECSタスク定義でシークレットを参照する
ECSタスク定義のコンテナ定義内で、環境変数としてSecrets Managerの値を割り当てます。AWS CLIやTerraform、またはJSONエディタを使用して、タスク定義の containerDefinitions 内の secrets 属性を以下のように設定します。
{
"containerDefinitions": [
{
"name": "web-app",
"image": "nginx:latest",
"essential": true,
"portMappings": [
{
"containerPort": 80,
"hostPort": 80
}
],
"secrets": [
{
"name": "DATABASE_PASSWORD",
"valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:prod/myapp/database-XXXXXX:DB_PASSWORD::"
}
]
}
]
}
設定のポイント:
valueFrom の末尾に :DB_PASSWORD:: と記述することで、Secrets Managerに保存されたJSON形式のシークレットから、特定のキー(DB_PASSWORD)の値のみをピンポイントで取得し、コンテナ内の環境変数 DATABASE_PASSWORD として注入できます。
実務での注意点
- FargateのVPCネットワーク設計に注意:
FargateタスクをパブリックIPを持たないプライベートサブネットで起動する場合、Secrets Managerからシークレットを取得するには、インターネットゲートウェイ(NAT Gateway経由)へのルートがあるか、もしくはSecrets Manager用の「VPCエンドポイント(Interface VPC Endpoint)」がVPC内に配置されている必要があります。これがないと、タスク起動時に名前解決や接続ができず、タスクが「PENDING」状態のまま停止します。 - シークレットのキャッシュとローテーションの考慮:
この方式ではコンテナ起動時にのみシークレットが注入されるため、Secrets Manager側でシークレットをローテーション(更新)しても、実行中のコンテナには即座に反映されません。反映させるには、ECSサービスの更新(再デプロイ)を行い、タスクを再起動する必要があります。 - 必要最小限の権限原則(LPOP):
タスク実行ロールに付与するIAMポリシーのResourceには、ワイルドカード(*)を使用せず、必ず特定のシークレットARNをフルパスで指定し、権限を最小限に絞るように設計してください。
まとめ
AWS Secrets ManagerとECS(Fargate)を連携させることで、アプリケーション側に余計なライブラリや認証ロジックを実装することなく、最もセキュアな方法で機密情報を環境変数として扱うことができます。
インフラの構築や運用を行う際は、セキュリティ設計の初期段階からこの仕組みを組み込み、機密情報の漏洩リスクを最小限に抑えた堅牢なコンテナインフラを目指しましょう。