この記事は約5分で読めます。
こんにちは、近藤(りょう)です!
AWS Security Hub で 「AWS 基礎セキュリティのベストプラクティス v1.0.0(AWS Foundational Security Best Practices v1.0.0、以降 FSBP」 を有効化し、運用している AWS アカウントにおいて、Security Hub の 「EC2.2」 を検知していて
是正対象となっていたデフォルトのセキュリティグループが、AWS Step Functions から一時的に実行される ECS タスクによって使用されているケースがありました。
常時起動しているリソースであればネットワークインターフェース(以降、ENI)から確認することができますが、本ケースのように一時的に利用されている場合は確認ができません。
本記事では、そのような稀なケースでデフォルトのセキュリティグループが使用されているかを調査する方法を紹介します。
ECS タスク以外の事象もあるかもしれないので参考にご覧いただければ幸いです。
CloudTrail から セキュリティグループの利用を確認
デフォルトのセキュリティグループが一時的に使用されている対象を確認するために CloudTrail の CreateNetworkInterface イベントを確認します。
このイベント内にデフォルトのセキュリティグループ ID が含まれていれば、該当の ENI(Elastic Network Interface)でデフォルトのセキュリティグループが使用されている可能性があります。
以下、画面情報 例
AWSコンソール画面:「CloudTrail 」-「イベント履歴」
検索条件:ルックアップ属性: イベント名、値: CreateNetworkInterface

以下、CreateNetworkInterface 詳細情報 例
AWSコンソール画面:「CloudTrail 」-「イベント履歴」-「対象のイベント名」

以下、CreateNetworkInterface 詳細情報の イベントレコード情報となります。
{"eventVersion": "1.10",~省略~"responseElements": {"requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx","networkInterface": {},~省略~"groupSet": {"items": [{"groupId": "sg-xxxxxxxxx", ★デフォルトのセキュリティグループID"groupName": "default" ★デフォルトのセキュリティグループ名}]},~省略~}
作業手順
前項のように CloudTrail の画面上で対象を確認するには、対象の量がとても多いため、CloudTrail のイベントを取得・加工して対象を抽出する方法で今回は調査を行いました。
調査前提
- 対象期間:一か月(月次処理を考慮)
- 対象セキュリティグループ:
sg-xxxxxxxx
- ※sg-xxxxxxxxは調査対象のセキュリティグループIDに読替えること。
- CreateNetworkInterface イベントを「CreateNetworkInterface_event_history.json」として保存していること。
- RunTask イベントを「RunTask_event_history.json」として保存していること。
- StartExecution イベントを「StartExecution_event_history.json」として保存していること。
Step 1:CreateNetworkInterface イベントからの確認
CreateNetworkInterface イベントからデフォルトのセキュリティグループを利用している ENI を確認します。
対象セキュリティグループの ENI 抽出
目的: 対象 SG が関連する ENI イベントの絞り込み
抽出概要: .Records[] を1行ずつ整形し sg-xxxxxxxx を含む行を抽出
$ cat CreateNetworkInterface_event_history.json | jq -c .Records[] | grep sg-xxxxxxxx > sg-xxxxxxxx.json
ENI に紐づくリソース情報の抽出
目的: リソース(例:attachment ARN)を把握
抽出概要: セキュリティグループ ID と ENI の description
$ cat sg-xxxxxxxx.json | jq -c -r '{sg: .responseElements.networkInterface.groupSet.items[].groupId,description: .requestParameters.description}' > sg-xxxxxxxx.r1.json
抽出例
{"sg":"sg-xxxxxxxx","description":"arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:attachment/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}
description を確認した結果、今回の調査では「ecs」のみ確認ができました。
今回の調査では「ecs」のみ確認できましたが、ほかのケースもありますので その場合は以降で実施する「RunTask」以外のイベントを確認する必要があります。
リソース ID のみを抽出(attachment ID)
目的: RunTask イベントと繋げるための IDの取得
抽出概要: description の末尾の ID 部分
$ cat sg-xxxxxxxx.r1.json | jq -r '.description | gsub("^.*attachment/"; "")' > sg-xxxxxxxx.r2.json
この出力結果は、RunTask イベントと突合に利用します。
Step 2:RunTask イベントからの確認
今回の調査では「ecs」のみが対象であるため、RunTask イベントを確認をします。
RunTask イベントの整形
目的: RunTask イベントを 1 行ずつ扱いやすい形に変換
抽出概要: .Records[] を1行ずつ整形し sg-xxxxxxxx を含む行を抽出
$ cat RunTask_event_history.json | jq -r -c .Records[] > ecr-task.json
デフォルトのセキュリティグループを利用している ECS タスクのみを抽出
目的: ENI 情報と紐づいた ECS タスクを特定
抽出概要: attachment ID を含む行の抽出
$ grep -f sg-xxxxxxxx.r2.json ecr-task.json > ecr-task.r1.json
必要な ECS 情報の抽出
目的: 実行元とタスク情報の記録
抽出概要: startedBy, taskDefinitionArn, taskArnの抽出
$ cat ecr-task.r1.json | jq -r -c '.responseElements.tasks[] | {startedBy: .startedBy,taskDefinitionArn: .taskDefinitionArn,taskArn: .taskArn}' > ecr-task.r2.json
抽出例
{"creationDate": "YYYY-MM-DDThh:mm:ssZ","startedBy": "AWS Step Functions","requestID": "xxxxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxxxx","taskDefinitionArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:task-definition/<ECSタスク名>-xxx:xx","taskArn": "arn:aws:ecs:ap-northeast-1:xxxxxxxxxxxx:task/<ECSクラスター名>/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
この結果から startedBy で実行元のリソースを確認して、今回の場合は、Step Functions であることが分かりました。
また、taskDefinitionArn, taskArn から実行された ECS クラスター と ECS タスク が確認できます。
Step 3:Step Functions の実行確認
RunTask 側から Step Functions を直接辿ることができなかったため、Step Functions から ECS タスクを実行している StartExecution イベントを確認します。
StartExecution イベントの調査
抽出対象項目: userAgent に AWS_ECS_EC2 を含むもの
目的: ECS を起動するステートマシンの絞り込み
$ cat StartExecution_event_history.json | jq -r -c .Records[] | grep AWS_ECS_EC2 > ECS.stepfunctions.json
対象ステートマシン情報の抽出
目的: ステートマシンの特定と、RunTask 時間との突合せ
抽出概要: creationDate, stateMachineArn, executionArn, を抽出
$ cat ECS.stepfunctions.json | jq -r -c '{creationDate: .userIdentity.sessionContext.attributes.creationDate,stateMachineArn: .requestParameters.stateMachineArn,executionArn: .responseElements.executionArn}' > ECS.stepfunctions.r1.json
抽出例
{"creationDate": "YYYY-MM-DDThh:mm:ssZ","stateMachineArn": "arn:aws:states:ap-northeast-1:xxxxxxxxxxxx:stateMachine:<ステートマシン名>","executionArn": "arn:aws:states:ap-northeast-1:xxxxxxxxxxxx:execution:xxxxxxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}
stateMachineArn から対象のステートマシン名が確認できます。
Step 4:Step Functions の定義を確認
AWS Step Functions から対象のステートマシン名の定義を確認します。
今回の調査では、SecurityGroups のプロパティがありませんでしたので「VPC のデフォルトのセキュリティ グループ」が利用されているようでした。
セキュリティ グループを指定しない場合は、VPC のデフォルトのセキュリティ グループが使用されます。
AWS Step Functions 定義 設定概要
{"States": {~省略~"NetworkConfiguration": {"AwsvpcConfiguration": {"AssignPublicIp": "ENABLED","Subnets": ["subnet-xxxxxxxxxx","subnet-xxxxxxxxxx"]}},~省略~
AWS Step Functions 定義 修正概要
{"States": {~省略~"NetworkConfiguration": {"AwsvpcConfiguration": {"AssignPublicIp": "ENABLED","Subnets": ["subnet-xxxxxxxxxx","subnet-xxxxxxxxxx"],"SecurityGroups": [ ★SecurityGroupsプロパティ 追加"sg-xxxxxxxxxxxxxxxxx" ★適切なセキュリティグループ 追加}},~省略~
まとめ
一時的に起動される ECS タスクが意図せず VPC のデフォルトのセキュリティグループを使用しているケースは見落としがち(というより想定していない)であると思います。
本記事では、CloudTrail の CreateNetworkInterface や RunTask イベントをもとに、どのリソースがデフォルトのセキュリティグループを使っていたのかを特定する方法をご紹介しました。
今後、同様の構成で一時的に起動するサービスがある場合も、デフォルトのセキュリティグループの利用を明示的に避けるための確認手順として、本記事の内容が参考になれば幸いです。