はじめに
AWSのコンテナオーケストレーションサービスであるAmazon ECS(Fargate)を利用する際、データベースの接続パスワードやAPIキーなどの「機密情報(シークレット)」をどのように管理していますか?
タスク定義の環境変数にこれらを直接ハードコードすることは、重大なセキュリティリスクとなります。本記事では、AWS Systems Manager(SSM)Parameter Storeを利用して、ECSタスク定義から安全かつスマートに機密情報をロードする設定手順を分かりやすく解説します。
前提知識/必要な理由
なぜタスク定義に機密情報を直接書いてはいけないのか?
タスク定義にパスワードなどをプレーンテキストで記述してしまうと、AWSマネジメントコンソールやAWS CLIの権限を持つすべての開発者が機密情報を閲覧できてしまいます。また、タスク定義の履歴(リビジョン)に値が残るため、漏洩のリスクが非常に高くなります。
SSM Parameter Store(SecureString)を利用するメリット
- データの暗号化: KMS(Key Management Service)を使用して機密情報を暗号化して保存できます。
- ECSとのシームレスな連携: ECSコンテナの起動時に、ECSエージェントがParameter Storeから値を自動的に取得し、コンテナ内の環境変数として注入します。アプリケーションコードを変更する必要はありません。
- 低コスト: AWS Secrets Managerと比較して、Parameter Storeの標準パラメータ(SecureString含む)は追加料金なしで利用可能です。
具体的な設定手順・設計方法
ここからは、実際にSSM Parameter Storeに機密情報を保存し、ECS Fargateタスクから安全に呼び出すための3つのステップを解説します。
ステップ1: Parameter Storeへの機密情報の登録
まずは、AWS Systems ManagerのParameter Storeに機密情報を「SecureString」として登録します。AWS CLIを使用する場合は以下のコマンドを実行します。
aws ssm put-parameter \
--name "/production/app/DB_PASSWORD" \
--value "SuperSecretPassword123!" \
--type "SecureString" \
--key-id "alias/aws/ssm"
※独自の暗号化キーを使用する場合は、--key-idにカスタムKMSキーのARNを指定してください。デフォルトではAWS管理のKMSキー(alias/aws/ssm)が使用されます。
ステップ2: ECSタスク実行ロール(IAM)のポリシー設定
ECSが起動時にParameter Storeから暗号化された値を取得して復号するためには、タスク実行ロール(Task Execution Role)に適切なIAMポリシーを付与する必要があります(コンテナ内からAWS APIを叩くための「タスクロール」とは異なります)。
以下のIAMポリシーを定義し、ECSのタスク実行ロールにアタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters"
],
"Resource": [
"arn:aws:ssm:ap-northeast-1:123456789012:parameter/production/app/*"
]
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": [
"arn:aws:kms:ap-northeast-1:123456789012:key/YOUR-KMS-KEY-UUID"
]
}
]
}
※123456789012はご自身のAWSアカウントIDに、KMSキーは使用しているキーのARNまたはUUIDに置き換えてください。
ステップ3: ECSタスク定義での環境変数設定
ECSのタスク定義(JSON形式)を編集し、環境変数の取得元としてParameter StoreのARNを指定します。コンテナ定義のsecretsセクションを使用します。
{
"containerDefinitions": [
{
"name": "web-app",
"image": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-app:latest",
"essential": true,
"secrets": [
{
"name": "DATABASE_PASSWORD",
"valueFrom": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/production/app/DB_PASSWORD"
}
],
"portMappings": [
{
"containerPort": 80,
"hostPort": 80
}
]
}
],
"executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"family": "my-app-task"
}
この設定により、コンテナ内部のアプリケーションは、OSの標準環境変数として DATABASE_PASSWORD をそのまま読み取ることが可能になります。
実務での注意点
- 値更新時のサービス再デプロイ: Parameter Storeの値を更新しても、すでに稼働しているECSタスクには反映されません。新しい値を反映させるには、ECSサービスに対して「新しいデプロイの強制」を実行し、タスクを再起動させる必要があります。
- KMS復号エラーによるタスク起動失敗: ECSタスクの起動が
ResourceInitializationErrorで失敗する場合、タスク実行ロールにkms:Decrypt権限が不足している、またはKMSキーのキーポリシーで権限が制限されていることが主な原因です。CloudWatch Logsのイベント履歴を必ず確認しましょう。 - 環境変数ログ出力の制限: アプリケーションのデバッグログや、起動スクリプト内で
envコマンドの結果を丸ごとログ出力する設計になっていると、せっかく隠蔽した機密情報がログ監視ツールに平文で流れてしまいます。機密情報を扱う環境でのログ出力設計には十分に注意してください。
まとめ
本記事では、AWS Systems Manager Parameter Storeを活用して、ECS Fargate環境へ安全に機密情報をロードする手順を解説しました。
アプリケーション側に余計なライブラリやコードを導入することなく、セキュリティのベストプラクティスを実現できるのがこの手法の最大の強みです。実務でECSを構築する際は、必ず本構成を採用するようにしましょう。