ECSタスクの環境変数をParameter Storeで管理する
Parameter Storeってなに?
パラメータを保存・管理してくれるAWSのマネージドサービスです。
以降は簡略化のためParameter Store
をパラメータストア
と表記します。
パラメータストアでECS環境変数を管理するメリット
- タスク定義に環境変数をベタ書きせずにすむ
- 接続先DBのパスワード等の機密情報をAWS側で安全に管理できます。
- 復号処理が不要
- コンテナ側で復号処理を行う必要がありません。
- 参照管理にIAMポリシーを使用出来る
- 機密情報の管理にIAMポリシーを使うことが出来ます。セキュリティレベルが上がりますね。
こんなことが実現出来ます
タスク定義で以下のようにパラメータストアのArnを入力すると
コンテナ内部から環境変数として参照することが出来ます。
root@ip-10-10-2-105:/# env | grep SecretEnv
SecretEnv=Today's date is June 10th, 2023.
考慮点
いくつか考慮することがあるので、この構成を試す場合はドキュメントを確認します。
- 稼働中のコンテナに環境変数は渡せないため、新しくデプロイする必要がある
- Fargateでパラメータストアを使用する場合、Fargateの1.3.0以上を使用する必要がある
- プライベートサブネットにECSタスクが存在する場合、VPCエンドポイント経由でSSMエンドポイントへアクセスする必要がある
今回の検証内容
- awscliでパラメータストアを設定
- TerraformのDataでパラメータストアを読み込み、コンテナ定義から環境変数として設定する
- タスクにECSEXECし、設定した環境変数を確認する
環境
- awscliとTerraform,セッションマネージャープラグイン(ECSExec用)を使用します。
$ aws --version
aws-cli/2.11.2 Python/3.11.2 Linux/5.4.0-150-generic exe/x86_64.ubuntu.20 prompt/off
$ terraform --version
Terraform v1.4.6
on linux_amd64
手順
パラメータストア設定
awscliで設定します。
パスワード等の機密情報を想定し、SecureString
とします。
設定
$ aws ssm put-parameter \
--name "/test/secret-string" \
--description "test securestring" \
--value "Today's date is June 10th, 2023." \
--type SecureString
確認
$ aws ssm get-parameters \
> --names "/test/secret-string" \
> --with-decryption \
> --query Parameters[].Value \
> --output text
Today's date is June 10th, 2023.
設定したパラメータストアをTerraformから参照する
data
を使って参照します。
with_decryption
でsecurestringを復号してくれるため使用、
デフォルトでtrueなのですが、plaintextと区別する上でも有益だと思うので明示しておきます。
data "aws_ssm_parameter" "securestring" {
name = "/test/secret-string"
with_decryption = "true"
}
詳しくはこちら
パラメータストアアクセス用IAMポリシー
ECSがパラメータストアにアクセスするためのIAMポリシーをタスク実行ロールにアタッチする必要があります。
タスクロールではないので注意しましょう。
data "aws_iam_policy_document" "GetParameterStore" {
statement {
effect = "Allow"
actions = [
"ssm:GetParameters",
]
resources = [
"${data.aws_ssm_parameter.securestring.arn}",
]
}
}
resource "aws_iam_policy" "GetParameterStore" {
name = "GetParameterStore"
path = "/"
policy = data.aws_iam_policy_document.GetParameterStore.json
}
resource "aws_iam_role" "task_execution_role" {
name = "${var.system_name}_${var.environment}_task_execution_role"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = { Service = "ecs-tasks.amazonaws.com" }
Action = "sts:AssumeRole"
}
]
})
managed_policy_arns = [
"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
"${aws_iam_policy.GetParameterStore.arn}"
]
}
パラメータストアのArnをコンテナ定義から使用する
わたしの環境ではコンテナ定義を外部ファイルcontainer_definitions.json
で外だししています。
Terraformのtemplatefile
でパラメータストアのArnを渡してあげます。
resource "aws_ecs_task_definition" "app" {
container_definitions = templatefile("../../modules/app/container_definitions.json",
{
securestring = data.aws_ssm_parameter.securestring.arn
}
)
パラメータストアの値を使う場合はsecrets
を使用します。
[
{
// 略
"secrets": [
{
"name": "SecretEnv",
"valueFrom": "${securestring}"
}
],
今回の場合、環境変数名をSecretEnv
、その値をパラメータストアsecurestring
としています。
ECSExecする準備
本題ではないため割愛しますが、環境変数の確認のためにECSExecが実行可能でなくてはいけません。
-
aws_ecs_service
でenable_execute_command = true
とする - ECSExec用のIAMポリシーを作成する
-
aws_ecs_task_definition
でECSExec用のタスクロールを指定する - タスクの再デプロイ
といったステップを踏む必要があるので、別途対応しましょう。
動作確認
ここまでできれば準備完了です。
terraform apply
、ECSExec
を行い、パラメータストアの値を参照できるか確認しましょう。
$ aws ecs execute-command --cluster <cluster> \
--task <task arn> \
--container nginx \
--interactive \
--command "/bin/bash"
The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.
Starting session with SessionId: ecs-execute-command-04b9bc781d0f1939a
root@ip-10-10-1-158:/#
root@ip-10-10-1-158:/# env | grep SecretEnv
SecretEnv=Today's date is June 10th, 2023.
無事できましたね。
ここまで読んでいただきありがとうございました。
参考
あとは公式ドキュメント群
Discussion