🐥

[AWS Secrets Manager] ECS デプロイ時に気をつけたい秘匿情報の扱いについて

2022/06/09に公開

はじめに

ECSタスクのコンテナからRDSなどの外部ストレージにアクセスする場合、AWS Secrets Manager のような秘匿情報を管理するマネージドサービスを使用して、セキュリティ面に配慮する必要があります。
チームの方針によってはプロダクション環境以外ではAWS Secrets Managerで管理することの優先度を下げる場合があるかと思いますが、基本的にはAWS Secrets Manager経由で秘匿情報を参照するのが望ましいと思います。

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/specifying-sensitive-data.html

ECSからAWS Secrets Managerにアクセスする

ECSからAWS Secrets Managerにアクセスする際に少し躓くポイントがあったので、ここで整理をしてみます。

VCPエンドポイントと紐付ける

あらかじめVPCエンドポイントを作成しておき、デプロイするECSのサービスを作成したVPC内に所属させる必要があります。

https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/vpc-endpoints.html

IAMポリシーを適切に付与する

秘匿情報が保管されているAWS Secrets Managerと、暗号化された秘匿情報を複合化するためのAWS Key Management Serviceにアクセスするための権限をECSタスク実行ロールに付与する必要があります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "kms:Decrypt"
      ],
      "Resource": [
        "arn:aws:secretsmanager:<region>:<aws_account_id>:secret:<secret_name>",
        "arn:aws:kms:<region>:<aws_account_id>:key/<key_id>"
      ]
    }
  ]
}

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/task_execution_IAM_role.html#task-execution-secrets

発生していたエラー

ECSのタスク実行ロールに上記の権限を付与できていないと、タスク実行時に以下のようなエラーが出てしまいECSクラスターにデプロイすることができません。

ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve secret from asm: service call has been retried 5 time(s): failed to fetch secret
arn:aws:secretsmanager:ap-northeast-1:xxxxxxxx:secret:prod/project/xxxxxxxxxx from secrets manager: RequestCanceled: request context canceled caused by: context deadline exceeded

(補足)AWS Key Management Service

データの暗号化、複合化に関するマネージドサービスです。

https://aws.amazon.com/jp/kms/

タスク定義について

task-definition.json
{
  "containerDefinitions": [
    {
      "name": "server",
      "image": "xxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/grpc-server",
      "cpu": 0,
      "memoryReservation": 300,
      "portMappings": [
        {
          "containerPort": 50051,
          "hostPort": 50051,
          "protocol": "tcp"
        }
      ],
      "essential": true,
      "secrets": [
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxxx:host::",
          "name": "DB_HOST"
        },
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxxx:dbClusterIdentifier::",
          "name": "DB_NAME"
        },
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxxx:password::",
          "name": "DB_PASS"
        },
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxxx:port::",
          "name": "DB_PORT"
        },
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxxx:username::",
          "name": "DB_USER"
        }
      ],
      "mountPoints": [],
      "volumesFrom": [],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/grpc-server-task",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      }
    }
  ],
  "family": "grpc-server-task",
  "taskRoleArn": "arn:aws:iam::xxxxxxxxxx:role/ecsTaskExecutionRole",
  "executionRoleArn": "arn:aws:iam::xxxxxxxxxx:role/ecsTaskExecutionRole",
  "networkMode": "awsvpc",
  "volumes": [],
  "placementConstraints": [],
  "runtimePlatform": {
    "operatingSystemFamily": "LINUX"
  },
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "tags": []
}

containerDefinitionssecretsフィールドを使用する

      "secrets": [
        {
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:xxxxxxxxxx:secret:prod/project/xxxxxxxx:host::",
          "name": "DB_HOST"
        },

AWS Secrets Managerに登録した秘匿情報を参照するためには、上記のようにsecretsフィールドに環境変数を定義する必要があります。
AWSコンソールからAWS Secrets Managerシークレットとアクセスし、「シークレットのarn」を取得しましょう。

シークレットの値を参照するための記法

シークレットに定義された各変数を参照するためには以下のように記載する必要があります。

シークレットのarn:キー名::

上記の記法でtask定義を行わないとシークレットの値を正しく参照できないので注意しましょう。

**RoleArnについて

  "taskRoleArn": "arn:aws:iam::xxxxxxxxxx:role/ecsTaskExecutionRole",
  "executionRoleArn": "arn:aws:iam::xxxxxxxxxx:role/ecsTaskExecutionRole",

AWS Secrets ManagerおよびAWS Key Management Serviceへのアクセス権限を付与したtaskRoleを使用するようにtask定義ファイルの中できちんと明示しましょう。

終わりに

今回の記事に書かれたポイントを押さえると、秘匿情報をAWS Secrets Managerから取得した上でコンテナを起動することができると思います。
ECSへのtask定義ファイルに秘匿情報をベタ書きして運用をするようなことがないように注意しましょう。

参考記事

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/specifying-sensitive-data-tutorial.html

https://dev.classmethod.jp/articles/tsnote-ecs-resourceinitializationerror/

Discussion