CloudFormation下のFargateでECS Exec

6 min read読了の目安(約5700字

CloudFormationで管理してたFargateでExecuteCommandを使ってみた際のメモ
間違いなどあれば、ご指摘お願いします!

FargateにExecuteCommandの設定を追加

AWS CLIの更新

自分の場合はv2がインストールされていたので、以下の2点を行いました

タスクロールにSession Managerの権限を追加する

ECS ExecはSSMの機能を使って実現しているので、ECSの実行ロールにIAM権限を追加することが必要です。

タスク実行ロールではないので注意です。

以下のJSONのポリシーを作成してタスクロールにアタッチします。
Fargateの場合はResourceの箇所になにを指定して権限を絞ればいいのでしょうか。いまいち分からなかったです

{
    "Effect": "Allow",
    "Action": [
        "ssmmessages:CreateControlChannel",
        "ssmmessages:CreateDataChannel",
        "ssmmessages:OpenControlChannel",
        "ssmmessages:OpenDataChannel"
    ],
    "Resource": "*"
},
  EcsExecRolePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: Ecs-exec-role
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - "ssmmessages:CreateControlChannel"
              - "ssmmessages:CreateDataChannel",
              - "ssmmessages:OpenControlChannel",
              - "ssmmessages:OpenDataChannel"
            Resource: "*"
      Roles:
        - # タスクロールを指定する

Service定義でExecCommandのを許可する

ここで行うことは EnableExecuteCommandをtrueにすることです。
これをtrueにすることで、実行コマンドが使用可能になります。
適当ですがサンプルコードです。

  Service:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref Cluster
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: !Ref DesiredCount # 読み替えてください
      EnableExecuteCommand: true # ここを追加する
      LaunchType: FARGATE
      LoadBalancers:
        - ContainerName: app
          ContainerPort: 80
          TargetGroupArn: arn # 読み替えてください
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - arn # 読み替えてください
          Subnets: 
            - arn # 読み替えてください
            - arn # 読み替えてください
      ServiceName: SampleFargate
      TaskDefinition: !Ref TaskDefinition # 読み替えてください

あとはCLIなどからexecute-commandを叩けばコンテナに入れるはずです。

ロギングの設定を追加してみる

ExecuteCommandのログはCloudTrail, S3, CloudWatchLogsに出力できます
他サービスと同じくCloudTrailにはAPIコールのみが記録されます。
なのでbin/bashbin/shなどでコンテナに入ったあとのコマンドは記録されません。
その記録にはS3とCloudWatchLogsを使い、S3とCloudWatchLogsの両方を指定可能のようです。
この記事ではKMSを暗号化は行っていません。

S3とCloudWatchに送るにはコンテナにcatscript (util-linux)がインストールされている必要があります。
これに気づかずはまりました、

タスクロールにS3とCloudWatchLogsの権限を追加する

以下のActionの追加が必要です

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:DescribeLogGroups"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": "*" // Arnで絞る
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "*" // Arnで絞る
        },
    ]
}
  EcsExecLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /ecs-exec/logs

  EcsExecLogBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: ecs-exec-log-bucket
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  EcsExecLoggingRolePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName: Ecs-exec-role
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - "logs:DescribeLogGroups"
            Resource: "*"
          - Effect: Allow
            Action:
              - "logs:CreateLogStream"
              - "logs:DescribeLogStreams"
              - "logs:PutLogEvents"
            Resource: "*" # 必要に応じて絞る
          - Effect: Allow
            Action:
              - "s3:PutObject"
            Resource: "*" # 必要に応じて絞る
      Roles:
        - # タスクロールを指定する

Clusterの設定を追加する

ここで設定するのはLogConfigurationLoggingの2つです
LoggingDEFAULTに指定すると、タスク定義に設定したawslogsの設定を使用します。
OVERRIDEを指定するとその設定を上書きして、別のs3バケットなどに出力出来ます。
コンテナの標準出力とECS-execのログを一緒に記録することは無さそうなので、OVERRIDEを指定します。

  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Ref ProjectName
       # 以下を追加する
      Configuration:
        ExecuteCommandConfiguration:
          KmsKeyId: # KMSを使用する場合
          LogConfiguration: 
            CloudWatchLogGroupName: # 作成したもの
            S3BucketName: # 上で作成したもの
            S3KeyPrefix: # オプション
          Logging: OVERRIDE

ログが送信出来ていない場合などは以下のコマンドでAgentログの確認が可能です
SSM Agentのデフォルトのロギング場所は/var/log/amazon/ssm/amazon-ssm-agent.logなので以下のコマンドになります

$ cat /var/log/amazon/ssm/amazon-ssm-agent.log

# エラーのみを表示する場合
$ awk '$3 ~ /ERROR/ { print }' /var/log/amazon/ssm/amazon-ssm-agent.log

コンテナからExitした時点で送信されるっぽいので注意です

これでS3とCLoudWatchLogsに記録されるはずです

参考

https://aws.amazon.com/jp/blogs/news/new-using-amazon-ecs-exec-access-your-containers-fargate-ec2/
https://zenn.dev/kappaz/articles/ada003ac97d8c4#8.-ecs-execによるfargateコンテナへのアクセス(※)
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-cluster-executecommandconfiguration.html