![[アップデート] VPC Flow LogsでECSに関する情報を記録できるようになりました](https://devio2023-media.developers.io/wp-content/uploads/2023/08/amazon-vpc.png)
[アップデート] VPC Flow LogsでECSに関する情報を記録できるようになりました
どのECSタスクからの通信なのかログから判断したい
こんにちは、のんピ(@non____97)です。
皆さんはどのECSタスクからの通信なのかログから判断したいなと思ったことはありますか? 私はあります。
ECS上で複数のコンテナを動かしている場合、VPC Flow Logsに記録されているIPアドレスのみでどのECSタスクからの通信なのかを判断するのは非常に骨が折れます。加えて、タスクが入れ替わるとIPアドレスも入れ替わるので、ログ出力時点でどのタスクがどのIPアドレスを使用しているのか把握しておく必要があります。
今回、アップデートにより、VPC Flow LogsでECSに関する情報を記録できるようになりました。
AWS Blogsにも投稿されていますね。
実際に試してみたので紹介します。
いきなりまとめ
- 送信元のECSクラスターやECSサービス、ECSタスク、コンテナIDなどの情報をVPC Flow Logsに記録できるようになった
- VPC Flow Logs設定時点でECSクラスターがVPC内に存在している必要がある
- 検証をした限り、VPC Flow Logsで記録されるコンテナIDは、実際の送信元のコンテナIDではない可能性がある
取得できるようになった情報
取得できるようになった情報は以下のとおりです。
フィールド名 | 説明 |
---|---|
ecs-cluster-arn | トラフィックの発信元ECS タスクのECS クラスターARN サブスクリプションに含めるには、ecs:ListClusters の権限が必要 |
ecs-cluster-name | トラフィックの発信元ECS タスクのECS クラスター名 サブスクリプションに含めるには、ecs:ListClusters の権限が必要 |
ecs-container-instance-arn | トラフィックの発信元ECS タスクのECSコンテナインスタンスARN Fargate の場合、このフィールドは「-」になる サブスクリプションに含めるには、ecs:ListClusters および ecs:ListContainerInstances を呼び出す権限が必要 |
ecs-container-instance-id | トラフィックの発信元ECS タスクのECS コンテナインスタンスID Fargate の場合、このフィールドは「-」になる サブスクリプションに含めるには、ecs:ListClusters および ecs:ListContainerInstances を呼び出す権限が必要 |
ecs-container-id | トラフィックの発信元ECS タスク上のコンテナのDocker ランタイム ID ECS タスクに 1 つ以上のコンテナがある場合に最初のコンテナの Docker runtie IDを示す サブスクリプションに含めるには、ecs:ListClusters を呼び出す権限が必要 |
ecs-second-container-id | トラフィックの発信元ECS タスク上のコンテナのDocker ランタイム ID ECS タスクに 1 つ以上のコンテナがある場合に2つ目ののコンテナの Docker runtie IDを示す サブスクリプションに含めるには、ecs:ListClusters を呼び出す権限が必要 |
ecs-service-name | トラフィックの発信元ECS タスクのECS サービス名 ECS タスクが ECS サービスによって実行されたものではない場合、このフィールドは「-」になる サブスクリプションに含めるには、ecs:ListClusters および ecs:ListServices を呼び出す権限が必要 |
ecs-task-definition-arn | トラフィックの発信元ECS タスクのECS タスク定義の ARN サブスクリプションに含めるには、ecs:ListClusters および ecs:ListTaskDefinitions を呼び出す権限が必要 |
ecs-task-arn | トラフィックの発信元ECS タスクのARN サブスクリプションに含めるには、ecs:ListClusters および ecs:ListTasks を呼び出す権限が必要 |
ecs-task-id | トラフィックの発信元ECS タスクのID サブスクリプションに含めるには、ecs:ListClusters および ecs:ListTasks を呼び出す権限が必要 |
いずれもParquetのデータタイプはSTRING
です。
ecs-cluster-arn
とecs-cluster-name
、ecs-container-instance-arn
とecs-container-instance-id
など情報が部分的に重複するものもあるので、どのフィールドを記録するかはお好みで良いでしょう。
2024/5/27追記 ここから
AWS公式ドキュメントにもECS関連のログについて追記ありました。
ECS関連のログについての制限は以下のとおりです。
- ECSフィールドをを含むVPC Flow Logsの設定をするには、アカウントに少なくとも1つのECS クラスターが含まれている必要がある
- 記録されるECSタスクがVPC Flow Logsのサブスクリプションの所有者でない場合、ECSフィールドは記録されない
- VPC/SubnetのリソースレベルでECSフィールドを持つVPC Flow Logsサブスクリプションを作成する場合、ECS以外のENIで生成されたトラフィックも配信される
- ECSフィールドの値は、ECS以外のIPトラフィックに対して
-
になる
- ECSフィールドの値は、ECS以外のIPトラフィックに対して
ecs-container-id
とecs-second-container-id
はVPC Flow LogsサービスがECSイベントストリームから受信した順に並べられる- ECSのコンソールやDescribeTask API 呼び出しで表示される順序と同じであることは保証されない
- タスクの実行中にコンテナが
STOPPED
ステータスになった場合、ログに表示され続ける可能性がある
- ECSメタデータとIPトラフィックログは2つの異なるソースから計算する
- 上流の依存関係から必要な情報をすべて取得すると、すぐにECSトラフィックの計算を開始する
- 新しいタスクを開始すると、以下1と2の条件に当てはまるタイミングでECSフィールドの計算を開始します。
- 基礎となるネットワークインターフェースのIPトラフィックを受信したとき
- タスクが実行中であることを示すECSタスクのメタデータを含むECSイベントを受信したときに
- タスクを停止した後、以下1と2の条件に当てはまるタイミングでECSフィールドの計算を開始する
- 基礎となるネットワークインターフェースのIPトラフィックを受信しなくなったとき、または1日以上遅延したIPトラフィックを受信したとき
- タスクが実行中でなくなったことを示すECSタスクのメタデータを含むECSイベントを受信したとき
- awsvpcのECSタスクのみ記録される
通常のIPトラフィックログとECS関連の情報は異なるソースから計算すると言うのはポイントですね。
そのため、VPC Flow Logsで出力されるECS関連のフィールドの値は、実際のコンテナの通信内容に依存せずENI単位で固定の値が出力されることになります。
2024/5/27追記 ここまで
やってみた
検証環境
実際に試してみます。
検証環境は以下のとおりです。
以下の通信をチェックします。
- ECSクラスター間の通信
- ECS on FargateのECSクラスターからインターネットへの通信
ECSクラスター間の通信をするためにService Connectを使って名前解決をするようにしています。
検証環境はAWS CDKでデプロイしました。使用したコードは以下リポジトリに保存しています。
注意点はVPC Flow Logs設定時点でVPC内にECSクラスターが存在しない場合はCaller is not authorized to obtain ECS field(s). Failed with error: {A minimum of 1 ECS Cluster is required to Create Flow Logs with ECS Fields}
とエラーになる点です。
無理矢理感ありますが、今回は以下のようにECSクラスターの作成が完了したら、VPC Flow Logsを作成するようにしています。
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { EcsProps } from "../parameter/index"; import { NetworkConstruct } from "./construct/network-construct"; import { EcsFargateConstruct } from "./construct/ecs-fargate-construct"; export interface EcsStackProps extends cdk.StackProps, EcsProps {} export class EcsStack extends cdk.Stack { constructor(scope: Construct, id: string, props: EcsStackProps) { super(scope, id, props); const networkConstruct = new NetworkConstruct(this, "NetworkConstruct", { ...props.network, }); const privateDnsNamespace = new cdk.aws_servicediscovery.PrivateDnsNamespace( this, "PrivateDnsNamespace", { name: "local", vpc: networkConstruct.vpc, } ); const ecsFargateConstruct = new EcsFargateConstruct( this, "EcsFargateConstruct", { networkConstruct, privateDnsNamespace, discoveryName: "ecs-fargate", } ); ecsFargateConstruct.node.addDependency(privateDnsNamespace); const ecsFargateConstruct2 = new EcsFargateConstruct( this, "EcsFargateConstruct2", { networkConstruct, privateDnsNamespace, discoveryName: "ecs-fargate2", } ); ecsFargateConstruct2.node.addDependency(privateDnsNamespace); ecsFargateConstruct2.node.addDependency(ecsFargateConstruct); networkConstruct.addFlowLog(ecsFargateConstruct2); } }
import * as cdk from "aws-cdk-lib"; import { Construct } from "constructs"; import { NetworkProperty, LifecycleRule } from "../../parameter/index"; import { LogBucketConstruct } from "./log-bucket-construct"; export interface NetworkConstructProps extends NetworkProperty {} export class NetworkConstruct extends Construct { readonly vpc: cdk.aws_ec2.IVpc; readonly flowLogsOptions?: cdk.aws_ec2.S3DestinationOptions; readonly flowLogsTrafficType?: cdk.aws_ec2.FlowLogTrafficType; readonly flowLogsLifecycleRules?: LifecycleRule[]; constructor(scope: Construct, id: string, props: NetworkConstructProps) { super(scope, id); // VPC const vpc = new cdk.aws_ec2.Vpc(this, "Default", { ipAddresses: cdk.aws_ec2.IpAddresses.cidr(props.vpcCidr), enableDnsHostnames: true, enableDnsSupport: true, natGateways: props.natGateways, maxAzs: props.maxAzs, subnetConfiguration: props.subnetConfigurations, gatewayEndpoints: { S3: { service: cdk.aws_ec2.GatewayVpcEndpointAwsService.S3, }, }, }); this.vpc = vpc; this.flowLogsOptions = props.vpcFlowLogs.options; this.flowLogsTrafficType = props.vpcFlowLogs.trafficType; this.flowLogsLifecycleRules = props.vpcFlowLogs.lifecycleRules; } // VPC Flow Logs addFlowLog = (dependencyConstruct?: Construct) => { const flowLogsBucketConstruct = new LogBucketConstruct( this, "FlowLogsBucket", { lifecycleRules: this.flowLogsLifecycleRules, } ); const flowLogs = this.vpc.addFlowLog("FlowLogsToS3", { destination: cdk.aws_ec2.FlowLogDestination.toS3( flowLogsBucketConstruct.bucket, undefined, this.flowLogsOptions ), trafficType: this.flowLogsTrafficType, maxAggregationInterval: cdk.aws_ec2.FlowLogMaxAggregationInterval.TEN_MINUTES, logFormat: [ cdk.aws_ec2.LogFormat.VERSION, cdk.aws_ec2.LogFormat.ACCOUNT_ID, cdk.aws_ec2.LogFormat.INTERFACE_ID, cdk.aws_ec2.LogFormat.SRC_ADDR, cdk.aws_ec2.LogFormat.DST_ADDR, cdk.aws_ec2.LogFormat.SRC_PORT, cdk.aws_ec2.LogFormat.DST_PORT, cdk.aws_ec2.LogFormat.PROTOCOL, cdk.aws_ec2.LogFormat.PACKETS, cdk.aws_ec2.LogFormat.BYTES, cdk.aws_ec2.LogFormat.START_TIMESTAMP, cdk.aws_ec2.LogFormat.END_TIMESTAMP, cdk.aws_ec2.LogFormat.ACTION, cdk.aws_ec2.LogFormat.LOG_STATUS, cdk.aws_ec2.LogFormat.VPC_ID, cdk.aws_ec2.LogFormat.SUBNET_ID, cdk.aws_ec2.LogFormat.INSTANCE_ID, cdk.aws_ec2.LogFormat.TCP_FLAGS, cdk.aws_ec2.LogFormat.TRAFFIC_TYPE, cdk.aws_ec2.LogFormat.PKT_SRC_ADDR, cdk.aws_ec2.LogFormat.PKT_DST_ADDR, cdk.aws_ec2.LogFormat.REGION, cdk.aws_ec2.LogFormat.AZ_ID, cdk.aws_ec2.LogFormat.SUBLOCATION_TYPE, cdk.aws_ec2.LogFormat.SUBLOCATION_ID, cdk.aws_ec2.LogFormat.PKT_SRC_AWS_SERVICE, cdk.aws_ec2.LogFormat.PKT_DST_AWS_SERVICE, cdk.aws_ec2.LogFormat.FLOW_DIRECTION, cdk.aws_ec2.LogFormat.TRAFFIC_PATH, ], }); const cfnFlowLogs = flowLogs.node.defaultChild as cdk.aws_ec2.CfnFlowLog; cfnFlowLogs.logFormat += " \ ${ecs-cluster-name} \ ${ecs-cluster-arn} \ ${ecs-container-instance-id} \ ${ecs-container-instance-arn} \ ${ecs-service-name} \ ${ecs-task-definition-arn} \ ${ecs-task-id} \ ${ecs-task-arn} \ ${ecs-container-id} \ ${ecs-second-container-id}"; if (dependencyConstruct) { flowLogs.node.addDependency(dependencyConstruct); } }; }
動作確認
動作確認です。
ECSクラスター間の通信を試します。
2つ目のECSクラスターのNginxコンテナにECS Execをして、1つ目のECSクラスターで登録したecs-fargate.local
にcurlをします。
$ cluster_name="EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT" $ task_id=$( aws ecs list-tasks \ --cluster "${cluster_name}" \ --query 'taskArns[0]' \ --output text \ | sed 's/.*'"${cluster_name}"'\///' ) $ aws ecs execute-command \ --cluster "${cluster_name}" \ --task "${task_id}" \ --container NginxContainer \ --interactive \ --command "/bin/sh" $ cat /etc/hosts 127.0.0.1 localhost 10.10.0.17 ip-10-10-0-17.ec2.internal 127.255.0.1 ecs-fargate.local 2600:f0f0:0:0:0:0:0:1 ecs-fargate.local 127.255.0.2 ecs-fargate2.local 2600:f0f0:0:0:0:0:0:2 ecs-fargate2.local $ curl -v http://ecs-fargate.local * Trying 127.255.0.1:80... * Connected to ecs-fargate.local (127.255.0.1) port 80 (#0) > GET / HTTP/1.1 > Host: ecs-fargate.local > User-Agent: curl/7.88.1 > Accept: */* > < HTTP/1.1 200 OK < server: envoy < date: Sun, 19 May 2024 22:35:39 GMT < content-type: text/html < content-length: 615 < last-modified: Tue, 23 Apr 2024 14:04:32 GMT < etag: "6627bff0-267" < accept-ranges: bytes < x-envoy-upstream-service-time: 2 < <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> * Connection #0 to host ecs-fargate.local left intact
通信できましたね。
続いて、ECS on FargateのECSクラスターからインターネットへの通信です。
2つ目のECSクラスターのBusyBoxコンテナにECS Execをして、8.8.8.8
にpingをします。
$ cluster_name="EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT" $ task_id=$( aws ecs list-tasks \ --cluster "${cluster_name}" \ --query 'taskArns[0]' \ --output text \ | sed 's/.*'"${cluster_name}"'\///' ) $ aws ecs execute-command \ --cluster "${cluster_name}" \ --task "${task_id}" \ --container BusyboxContainer \ --interactive \ --command "/bin/sh" $ ping -c 4 8.8.8.8 PING 8.8.8.8 (8.8.8.8): 56 data bytes 64 bytes from 8.8.8.8: seq=0 ttl=116 time=1.500 ms 64 bytes from 8.8.8.8: seq=1 ttl=116 time=1.481 ms 64 bytes from 8.8.8.8: seq=2 ttl=116 time=1.461 ms 64 bytes from 8.8.8.8: seq=3 ttl=116 time=1.450 ms --- 8.8.8.8 ping statistics --- 4 packets transmitted, 4 packets received, 0% packet loss round-trip min/avg/max = 1.450/1.473/1.500 ms
こちらも問題なくできました。
AthenaでS3バケットに出力されたVPC Flow Logsに対してクエリを叩いてみましょう。
以下のDDLを実行してテーブルを作成します。
CREATE EXTERNAL TABLE `vpc_flow_logs_partition_projection` ( `version` int, `resource_type` string, `account_id` string, `srcaddr` string, `dstaddr` string, `srcport` int, `dstport` int, `protocol` bigint, `packets` bigint, `bytes` bigint, `start` bigint, `end` bigint, `action` string, `log_status` string, `vpc_id` string, `subnet_id` string, `instance_id` string, `tcp_flags` int, `type` string, `pkt_srcaddr` string, `pkt_dstaddr` string, `region` string, `az_id` string, `sublocation_type` string, `sublocation_id` string, `pkt_src_aws_service` string, `pkt_dst_aws_service` string, `flow_direction` string, `traffic_path` int, `ecs_cluster_name` string, `ecs_cluster_arn` string, `ecs_container_instance_id` string, `ecs_container_instance_arn` string, `ecs_service_name` string, `ecs_task_definition_arn` string, `ecs_task_id` string, `ecs_task_arn` string, `ecs_container_id` string, `ecs-second-container-id` string ) PARTITIONED BY ( `aws_account_id` string, `aws_region` string, `datehour` string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ' ' LOCATION 's3://ecsstack-networkconstructflowlogsbucketd21f5feb-eiw7koyoqmeb/AWSLogs/' TBLPROPERTIES ( 'projection.enabled'='true', 'has_encrypted_data'='true', "skip.header.line.count"="1", 'projection.aws_account_id.type'='enum', 'projection.aws_account_id.values'='<AWSアカウントID>', 'projection.aws_region.type'='enum', 'projection.aws_region.values'='us-east-1,ap-northeast-1', 'projection.datehour.type'='date', 'projection.datehour.interval'='1', 'projection.datehour.interval.unit'='HOURS', 'projection.datehour.range'='NOW-1YEARS,NOW', 'projection.datehour.format'='yyyy/MM/dd/HH', 'storage.location.template'='s3://ecsstack-networkconstructflowlogsbucketd21f5feb-eiw7koyoqmeb/AWSLogs/${aws_account_id}/vpcflowlogs/${aws_region}/${datehour}' )
テーブル作成完了後、各パターンの通信のログを確認します。
まず、ECSクラスター間の通信のログを確認するクエリを叩きます。
SELECT * FROM vpc_flow_logs_partition_projection WHERE aws_account_id='<AWSアカウントID>' and aws_region='us-east-1' and datehour='2024/05/19/22' and action='ACCEPT' and (dstport=80 or srcport=80) and start>1716158100
"version","resource_type","account_id","srcaddr","dstaddr","srcport","dstport","protocol","packets","bytes","start","end","action","log_status","vpc_id","subnet_id","instance_id","tcp_flags","type","pkt_srcaddr","pkt_dstaddr","region","az_id","sublocation_type","sublocation_id","pkt_src_aws_service","pkt_dst_aws_service","flow_direction","traffic_path","ecs_cluster_name","ecs_cluster_arn","ecs_container_instance_id","ecs_container_instance_arn","ecs_service_name","ecs_task_definition_arn","ecs_task_id","ecs_task_arn","ecs_container_id","ecs-second-container-id","aws_account_id","aws_region","datehour" "7","<AWSアカウントID>","eni-0783b0c994717f9a4","10.10.0.20","10.10.0.17","80","49512","6","3","1020","1716158123","1716158151","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","18","IPv4","10.10.0.20","10.10.0.17","us-east-1","use1-az6","-","-","-","-","ingress",,"EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-uVoQu1GEBKtI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:1","88316020871d4ec7a200c1ce6d25273d","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT/88316020871d4ec7a200c1ce6d25273d","88316020871d4ec7a200c1ce6d25273d-3472355196","-","<AWSアカウントID>","us-east-1","2024/05/19/22" "7","<AWSアカウントID>","eni-0783b0c994717f9a4","10.10.0.17","10.10.0.20","49512","80","6","4","413","1716158123","1716158151","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","2","IPv4","10.10.0.17","10.10.0.20","us-east-1","use1-az6","-","-","-","-","egress","1","EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-uVoQu1GEBKtI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:1","88316020871d4ec7a200c1ce6d25273d","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT/88316020871d4ec7a200c1ce6d25273d","88316020871d4ec7a200c1ce6d25273d-3472355196","-","<AWSアカウントID>","us-east-1","2024/05/19/22" "7","<AWSアカウントID>","eni-06d53ec12e8eb2e45","10.10.0.20","10.10.0.17","80","49512","6","3","1020","1716158149","1716158173","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","18","IPv4","10.10.0.20","10.10.0.17","us-east-1","use1-az6","-","-","-","-","egress","1","EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG","-","-","EcsStack-EcsFargateConstructService485E693B-zJq54DZ1cojO","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstructTaskDefinition9DD364BE:9","d077e9006cdb442dbaddcd059c7b9ba9","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG/d077e9006cdb442dbaddcd059c7b9ba9","d077e9006cdb442dbaddcd059c7b9ba9-3254704778","d077e9006cdb442dbaddcd059c7b9ba9-3472355196","<AWSアカウントID>","us-east-1","2024/05/19/22" "7","<AWSアカウントID>","eni-06d53ec12e8eb2e45","10.10.0.17","10.10.0.20","49512","80","6","4","413","1716158149","1716158173","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","2","IPv4","10.10.0.17","10.10.0.20","us-east-1","use1-az6","-","-","-","-","ingress",,"EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG","-","-","EcsStack-EcsFargateConstructService485E693B-zJq54DZ1cojO","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstructTaskDefinition9DD364BE:9","d077e9006cdb442dbaddcd059c7b9ba9","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG/d077e9006cdb442dbaddcd059c7b9ba9","d077e9006cdb442dbaddcd059c7b9ba9-3254704778","d077e9006cdb442dbaddcd059c7b9ba9-3472355196","<AWSアカウントID>","us-east-1","2024/05/19/22"
ECSクラスターやECSサービス、ECSタスク、コンテナIDが記録されていますね。
通信はEcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT
からEcsStack-EcsFargateConstructCluster1F80E083-QjhlCq9gvCwG
に対してリクエストをしました。各フィールドに記録されているのは通信の送信元の情報であることが分かります。
一点、リクエストのecs_container_id
が88316020871d4ec7a200c1ce6d25273d-3472355196
となっているのが気になります。こちらのIDはBusyBoxのコンテナのIDです。リクエストはNginxのコンテナから行っています。もしかすると、タスク内のどのコンテナからの通信なのかをログのみで正確に把握することは難しいかもしれません。
ecs-second-container-id
については、タスク内のどのコンテナからの通信なのかが明らかであるならば敢えて記録する必要もないのではと考えます。送信元の考えられる候補としてECSタスク内のコンテナIDを最大2つ返しているのでしょうか。その仮説が正しいのであれば、リクエストの際にecs-second-container-id
にNginxのコンテナIDが記録されないのが気になります。
ログが欠損しているのかと思い、時間を空けて2,3回試しましたが結果は変わりありませんでした。
スタックを再作成してリトライすると、ecs-container-id
の値は存在しないがecs-second-container-id
は存在するといったこともありました。ecs-second-container-id
に記録されているコンテナIDは確かにECS Exec先のNginxコンテナですが、挙動がちょっと怪しいですね。
"version","resource_type","account_id","srcaddr","dstaddr","srcport","dstport","protocol","packets","bytes","start","end","action","log_status","vpc_id","subnet_id","instance_id","tcp_flags","type","pkt_srcaddr","pkt_dstaddr","region","az_id","sublocation_type","sublocation_id","pkt_src_aws_service","pkt_dst_aws_service","flow_direction","traffic_path","ecs_cluster_name","ecs_cluster_arn","ecs_container_instance_id","ecs_container_instance_arn","ecs_service_name","ecs_task_definition_arn","ecs_task_id","ecs_task_arn","ecs_container_id","ecs-second-container-id","aws_account_id","aws_region","datehour" "7","<AWSアカウントID>","eni-0062fcb196a46928b","10.10.0.5","10.10.0.25","54760","80","6","4","413","1716179320","1716179348","ACCEPT","OK","vpc-0152760ee7636a7d9","subnet-02b4eee8c1bfa66f3","-","2","IPv4","10.10.0.5","10.10.0.25","us-east-1","use1-az6","-","-","-","-","egress","1","EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-SenET0heWI5p","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:2","25b9b1a127694afdbc9e0def558fab6c","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5/25b9b1a127694afdbc9e0def558fab6c","-","25b9b1a127694afdbc9e0def558fab6c-3254704778","<AWSアカウントID>","us-east-1","2024/05/20/04" "7","<AWSアカウントID>","eni-0062fcb196a46928b","10.10.0.25","10.10.0.5","80","54760","6","3","1020","1716179320","1716179348","ACCEPT","OK","vpc-0152760ee7636a7d9","subnet-02b4eee8c1bfa66f3","-","18","IPv4","10.10.0.25","10.10.0.5","us-east-1","use1-az6","-","-","-","-","ingress",,"EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-SenET0heWI5p","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:2","25b9b1a127694afdbc9e0def558fab6c","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YuTtwu0ZQtR5/25b9b1a127694afdbc9e0def558fab6c","-","25b9b1a127694afdbc9e0def558fab6c-3254704778","<AWSアカウントID>","us-east-1","2024/05/20/04" "7","<AWSアカウントID>","eni-0d78b1d149ced2e6a","10.10.0.25","10.10.0.5","80","54760","6","3","1020","1716179309","1716179319","ACCEPT","OK","vpc-0152760ee7636a7d9","subnet-02b4eee8c1bfa66f3","-","18","IPv4","10.10.0.25","10.10.0.5","us-east-1","use1-az6","-","-","-","-","egress","1","EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t","-","-","EcsStack-EcsFargateConstructService485E693B-foIQw9wUCkpI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstructTaskDefinition9DD364BE:10","e6d7d4244d6e4bc39566c31a027a6f61","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t/e6d7d4244d6e4bc39566c31a027a6f61","e6d7d4244d6e4bc39566c31a027a6f61-3472355196","e6d7d4244d6e4bc39566c31a027a6f61-3254704778","<AWSアカウントID>","us-east-1","2024/05/20/04" "7","<AWSアカウントID>","eni-0d78b1d149ced2e6a","10.10.0.5","10.10.0.25","54760","80","6","4","413","1716179309","1716179319","ACCEPT","OK","vpc-0152760ee7636a7d9","subnet-02b4eee8c1bfa66f3","-","2","IPv4","10.10.0.5","10.10.0.25","us-east-1","use1-az6","-","-","-","-","ingress",,"EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t","-","-","EcsStack-EcsFargateConstructService485E693B-foIQw9wUCkpI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstructTaskDefinition9DD364BE:10","e6d7d4244d6e4bc39566c31a027a6f61","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstructCluster1F80E083-Uewmoz48cw3t/e6d7d4244d6e4bc39566c31a027a6f61","e6d7d4244d6e4bc39566c31a027a6f61-3472355196","e6d7d4244d6e4bc39566c31a027a6f61-3254704778","<AWSアカウントID>","us-east-1","2024/05/20/04"
コンテナIDはあくまで参考程度に捉えておくと良さそうです。
次にECS on FargateのECSクラスターからインターネットへの通信のログを確認するクエリです。
SELECT * FROM vpc_flow_logs_partition_projection WHERE aws_account_id='<AWSアカウントID>' and aws_region='us-east-1' and datehour='2024/05/19/21' and action='ACCEPT' and (dstaddr='8.8.8.8' or srcaddr='8.8.8.8') LIMIT 10
"version","resource_type","account_id","srcaddr","dstaddr","srcport","dstport","protocol","packets","bytes","start","end","action","log_status","vpc_id","subnet_id","instance_id","tcp_flags","type","pkt_srcaddr","pkt_dstaddr","region","az_id","sublocation_type","sublocation_id","pkt_src_aws_service","pkt_dst_aws_service","flow_direction","traffic_path","ecs_cluster_name","ecs_cluster_arn","ecs_container_instance_id","ecs_container_instance_arn","ecs_service_name","ecs_task_definition_arn","ecs_task_id","ecs_task_arn","ecs_container_id","ecs-second-container-id","aws_account_id","aws_region","datehour" "7","<AWSアカウントID>","eni-0783b0c994717f9a4","10.10.0.17","8.8.8.8","0","0","1","4","336","1716154161","1716154185","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","0","IPv4","10.10.0.17","8.8.8.8","us-east-1","use1-az6","-","-","-","-","egress","8","EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-uVoQu1GEBKtI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:1","88316020871d4ec7a200c1ce6d25273d","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT/88316020871d4ec7a200c1ce6d25273d","88316020871d4ec7a200c1ce6d25273d-3472355196","-","<AWSアカウントID>","us-east-1","2024/05/19/21" "7","<AWSアカウントID>","eni-0783b0c994717f9a4","8.8.8.8","10.10.0.17","0","0","1","4","336","1716154161","1716154185","ACCEPT","OK","vpc-0926fc3c811765f21","subnet-043f08d86c8ca1516","-","0","IPv4","8.8.8.8","10.10.0.17","us-east-1","use1-az6","-","-","-","-","ingress",,"EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","arn:aws:ecs:us-east-1:<AWSアカウントID>:cluster/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT","-","-","EcsStack-EcsFargateConstruct2ServiceD9DCAB71-uVoQu1GEBKtI","arn:aws:ecs:us-east-1:<AWSアカウントID>:task-definition/EcsStackEcsFargateConstruct2TaskDefinition4E5DC27B:1","88316020871d4ec7a200c1ce6d25273d","arn:aws:ecs:us-east-1:<AWSアカウントID>:task/EcsStack-EcsFargateConstruct2Cluster15146226-YluNfbr7sUDT/88316020871d4ec7a200c1ce6d25273d","88316020871d4ec7a200c1ce6d25273d-3472355196","-","<AWSアカウントID>","us-east-1","2024/05/19/21"
ECS Exec先のBusyBoxコンテナのIDやECSタスクなどが記録されています。レスポンスについてはECS関連の情報は記録されないかと思いましたが、記録されていますね。
ECSサービス間の通信を把握する際に
VPC Flow LogsでECSに関する情報を記録できるようになったアップデートを紹介しました。
ECSサービス間の通信を把握する時に役立ちそうですね。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!