AWS Security Hub「EC2.2」対策 - 番外編:ECS タスクが一時的に使うセキュリティグループの調査方法

記事タイトルとURLをコピーする

この記事は約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

aaa
リソース名でセキュリティグループID等が確認できます。

以下、CreateNetworkInterface 詳細情報 例
AWSコンソール画面:「CloudTrail 」-「イベント履歴」-「対象のイベント名」
bbb
こちらでは、ECSから起動され、デフォルトのセキュリティグループを利用しているようでした。

以下、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 のデフォルトのセキュリティ グループ」が利用されているようでした。

docs.aws.amazon.com

セキュリティ グループを指定しない場合は、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 イベントをもとに、どのリソースがデフォルトのセキュリティグループを使っていたのかを特定する方法をご紹介しました。

今後、同様の構成で一時的に起動するサービスがある場合も、デフォルトのセキュリティグループの利用を明示的に避けるための確認手順として、本記事の内容が参考になれば幸いです。

近藤 諒都

(記事一覧)

カスタマーサクセス部CS5課

夜行性ではありません。朝活派です。

趣味:お酒、旅行、バスケ、掃除、家庭用パン作り(ピザも)など