はじめに
Amazon GuardDutyにIPリストを設定する際、
S3バケット上のIPリストにアクセスするための権限ってどうすればいいのでしょうか?
まとめ
S3バケット上のIPリストにアクセスする際に使用する権限は、
GuardDutyのサービスロール(AWSServiceRoleForAmazonGuardDuty
)です。
ただし、このサービスロールに権限を追加するために、設定が必要です。
具体的には、IPリストを設定(guardduty:CreateThreatIntelSet
)するユーザの権限に、iam:PutRolePolicy
が必要です。
したがって、IPリストを新規設定するユーザの、最小権限は下記になります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"guardduty:*ThreatIntelSet*"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PutRolePolicy"
],
"Resource": "arn:aws:iam::*:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty"
}
]
}
※上記の権限は、IPリストを新規設定する際の、超最小権限です。実際は、参照・更新・削除の権限も入れておきましょう。詳しくは、「さいごに」を参照してください。
前提
GuardDuty・S3について復習しましょう。
前提1:GuardDutyって?IPリストって?
Amazon GuardDutyは、CloudTrail、VPCフローログ、DNSログ、S3データアクセスイベントから、不審な操作を検出するサービスです。
GuardDutyの設定として、ユーザ指定のIPリストに基づいて、アラートを発生させたり、抑制させたりできます。
大まかな動作は次のエントリで理解できます。
脅威リストを使ったGuardDutyの検出テスト | DevelopersIO
このIPリストですが、S3上に置く必要があります。
前提2:S3の権限って?
Amazon S3はオブジェクトストレージサービスです。
S3にアクセスするためには、適切なアクセス権限の付与が必要です。
権限付与の方法はいくつかあり、次のエントリがわかりやすいです。
S3のアクセスコントロールが多すぎて訳が解らないので整理してみる | DevelopersIO
今回は、GuardDutyがS3に置いたIPリストにアクセスするために、どのような権限が必要か検証します。
検証
次の流れで検証します。途中、別シェルで環境を分けます。
- 準備
- S3バケットを作成して、IPリストをアップロード
- GuardDutyの有効化
- IAMロールを最小権限で作成
- 検証
- IAMロールでIPリスト設定(別シェルで実行)
- 失敗したら、CloudTrailで失敗したAPIを確認
- IAMロールに失敗したAPIの許可を追加
- 再度、IAMロールでIPリスト設定(別シェルで実行)
- 新たに許可されたAPIの実行内容を確認
なお、今回使用するIPリストは、脅威とみなすIPアドレスのリストとなります。
信頼するIPアドレスについても、恐らく同様の結果になるはずです。(試してない)
検証環境
- 作業するIAMユーザには
AdministratorAccess
ポリシーをアタッチしてください。 - 次のすべてのツールを使います。
- AWS-CLI
- jq
- AWS-CLIの操作については、POSIXシェル上で実施してください。
1. 準備
1-1. S3バケットを作成して、IPリストをアップロード
脅威とみなすIPアドレスのリストとして、ThreatIntelSet.txt
を作成します。
XXX.XXX.XXX.XXX
バケットを作成して、IPリストをアップロードします。
$ BUCKETNAME=guard-duty-iplist-test-$(date '+%Y%m%d-%H%M%S')
$ aws s3 mb s3://$BUCKETNAME
make_bucket: guard-duty-iplist-test-20211120-141946
$ aws s3 cp ThreatIntelSet.txt s3://$BUCKETNAME/
upload: ./ThreatIntelSet.txt to s3://guard-duty-iplist-test-20211120-141946/ThreatIntelSet.txt
別シェルでの作業で、バケット名を使うため、バケット名をファイルに出力します。
$ echo $BUCKETNAME > BucketName.txt
確認はしませんが、この時点でS3へのアクセス権限は何も設定されていません。
作業中のIAMユーザがこのS3バケットにアクセスできるのは、AdministratorAccess
をアタッチしているからです。
1-2. GuardDutyの有効化
GuardDutyを有効にします。
ちなみに、GuardDutyはアカウント・リージョンで高々一つしか有効にできません。すでに有効になっている場合には失敗します。もし失敗したら、delete-detector
で削除できます。
$ aws guardduty create-detector --enable \
--finding-publishing-frequency FIFTEEN_MINUTES \
--query 'DetectorId' --output text > DetectorId.txt
別シェルでの作業で、GuardDutyのIDを使うため、ファイルに出力します。
1-3. IAMロールを最小権限で作成
GuardDutyにIPリストを設定するためのIAMロールを、最小権限で作成します。
ここでは2つのファイルを使用します。
-
assume-role-policy.json
: IAMロールの信頼ポリシー ※要編集 -
policy-guardduty-ip-list.json
: IAMロールのインラインポリシーに定義するIAMポリシー
assume-role-policy.json
を編集して、your-account-id
を、ご自身のアカウントIDに置き換え、保存してください。
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Principal": {
"AWS": "your-account-id"
},
"Action": "sts:AssumeRole"
}
}
policy-guardduty-ip-list.json
で許可されているAPIはGuardDutyに関するものだけですね。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"guardduty:*ThreatIntelSet*"
],
"Resource": "*"
}
]
}
IAMロールを作成して、上記のポリシーを付与します。
$ aws iam create-role --role-name role-guard-duty \
--assume-role-policy-document file://assume-role-policy.json > /dev/null
$ aws iam put-role-policy --role-name role-guard-duty \
--policy-name policy-guardduty-ip-list \
--policy-document file://policy-guardduty-ip-list.json
さらに、一時的な認証情報を取得し、別シェルでの作業するためにファイルに出力します。
この認証情報の有効期限は1時間なので、もし有効期限が切れたら、もう一度assume-role
して認証情報を取得しなおしてください。
$ aws sts assume-role \
--role-session-name role-session-guardduty-test \
--role-arn $( \
aws iam get-role --role-name role-guard-duty \
--query 'Role.Arn' --output text \
) > assume.txt
2. 検証
2-1. IAMロールでIPリスト設定(別シェルで実行)
今まで、AdministratorAccess
がアタッチされたユーザで作業してきましたが、
暫くの間、最小権限のIAMロールで作業するために、別のシェルで作業していきます。
今までのAdministratorAccess
のシェルはまた後で使うので閉じずに置いておいてください。
別のシェルで、一時的な認証情報を環境変数に設定します。
これで最小権限のIAMロールで作業可能になります。(aws sts get-caller-identity
で確認してみてください)
$ assume=$(cat assume.txt)
$ export \
AWS_ACCESS_KEY_ID=$(echo $assume | jq -r '.Credentials.AccessKeyId') \
AWS_SECRET_ACCESS_KEY=$(echo $assume | jq -r '.Credentials.SecretAccessKey') \
AWS_SESSION_TOKEN=$(echo $assume | jq -r '.Credentials.SessionToken')
さて!それでは、最小権限のIAMロールでIPリストの設定を試みましょう。
ここで使うのは、guardduty:CreateThreatIntelSet
APIです。
$ BUCKETNAME=$(cat BucketName.txt)
$ DetectorId=$(cat DetectorId.txt)
$ aws guardduty create-threat-intel-set --detector-id $DetectorId \
--name ThreatIntelSet --activate --format TXT \
--location s3://$BUCKETNAME/ThreatIntelSet.txt
An error occurred (BadRequestException) when calling the CreateThreatIntelSet operation: The request was rejected because you do not have the required iam:PutRolePolicy permission.
*失敗!*親切なことに、エラーメッセージに足りない権限が書いてありますね。
iam:PutRolePolicy
APIの権限が不足しているみたいです。
2-2. CloudTrailで失敗したAPIを確認
一度、AdministratorAccess
のシェルに戻って、失敗の原因を詳しく調査します。
一時的な認証情報のシェルは、あとでまた使うので閉じずに置いておいてください。
AdministratorAccess
のシェルで、CloudTrailのイベントを出力します。
$ aws cloudtrail lookup-events --lookup-attributes \
AttributeKey=Username,AttributeValue=role-session-guardduty-test \
> cloudtrail-events.json
cloudtrail-events.txtを開いて、実行時間付近のイベントを探しましょう……。
次のような、iam:PutRolePolicy
APIのイベントがありました。
{
"EventId": "81f77b0d-0e9f-4ad7-ad4a-9b8d5ced458a",
"EventName": "PutRolePolicy",
"ReadOnly": "false",
"AccessKeyId": "XXXXXXXXXXXXXXXX",
"EventTime": "2021-11-20T22:34:33+09:00",
"EventSource": "iam.amazonaws.com",
"Username": "role-session-guardduty-test",
"Resources": [],
"CloudTrailEvent": "<省略:イベント内容>"
}
CloudTrailEvent
アイテムに詳しいイベントの内容が書いてあります。
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "XXXXXXXXXXXX:role-session-guardduty-test",
"arn": "arn:aws:sts::XXXXXXXXXXXX:assumed-role/role-guard-duty/role-session-guardduty-test",
"accountId": "XXXXXXXXXXXX",
"accessKeyId": "XXXXXXXXXXXX",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "XXXXXXXXXXXX",
"arn": "arn:aws:iam::XXXXXXXXXXXX:role/role-guard-duty",
"accountId": "XXXXXXXXXXXX",
"userName": "role-guard-duty"
},
"webIdFederationData": {},
"attributes": {
"creationDate": "2021-11-20T13:27:19Z",
"mfaAuthenticated": "false"
}
},
"invokedBy": "guardduty.amazonaws.com"
},
"eventTime": "2021-11-20T13:34:33Z",
"eventSource": "iam.amazonaws.com",
"eventName": "PutRolePolicy",
"awsRegion": "us-east-1",
"sourceIPAddress": "guardduty.amazonaws.com",
"userAgent": "guardduty.amazonaws.com",
"errorCode": "AccessDenied",
"errorMessage": "User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/role-guard-duty/role-session-guardduty-test is not authorized to perform: iam:PutRolePolicy on resource: role AWSServiceRoleForAmazonGuardDuty",
"requestParameters": null,
"responseElements": null,
"requestID": "XXXXXXXXXXXX",
"eventID": "XXXXXXXXXXXX",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "XXXXXXXXXXXX",
"eventCategory": "Management"
}
ここから、検証のポイントになります。
APIを発行した者は、userIdentity.invokedBy
/sourceIPAddress
/userAgent
から、GuardDutyと推測できます。
GuardDutyが引き受けている権限はarn:aws:sts::XXXXXXXXXXXX:assumed-role/role-guard-duty/role-session-guardduty-test
ですが、これは先ほど作成したIAMロールの一時的な認証情報ですね。
一つ目のポイントは、このように、GuardDutyはguardduty:CreateThreatIntelSet
APIを発行したユーザの権限を引き受けて、別のAPI(iam:PutRolePolicy
)を発行するということです。
なので、guardduty:CreateThreatIntelSet
APIを発行するユーザには、GuardDutyが発行したいAPIの権限も付与しなければいけないのです。
さらに、errorMessage
がAWS-CLIの出力したものと異なり、AWSServiceRoleForAmazonGuardDuty
と書いてあります。
2つ目のポイントは、GuardDutyが、iam:PutRolePolicy
APIで、何かしらの権限を付与したかった対象は、AWSServiceRoleForAmazonGuardDuty
というロールということです。
さて、AWSServiceRoleForAmazonGuardDuty
とは、何なのか?
答えは、GuardDutyのサービスロールですね。
サービスロールとは、AWSサービスが引き受けるIAMロールのことです。
GuardDutyは固定でAWSServiceRoleForAmazonGuardDuty
を使います。
AdministratorAccess
のシェルで、GuardDutyの詳細を取得すると、
サービスロールがAWSServiceRoleForAmazonGuardDuty
となっていることを確認できます。
$ DetectorId=$(cat DetectorId.txt)
$ aws guardduty get-detector --detector-id $DetectorId
{
"CreatedAt": "2021-11-20T14:45:09.083Z",
"FindingPublishingFrequency": "FIFTEEN_MINUTES",
"ServiceRole": "arn:aws:iam::XXXXXXXXXXXX:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty",
"Status": "ENABLED",
"UpdatedAt": "2021-11-20T14:45:09.083Z",
"DataSources": {
"CloudTrail": {
"Status": "ENABLED"
},
"DNSLogs": {
"Status": "ENABLED"
},
"FlowLogs": {
"Status": "ENABLED"
},
"S3Logs": {
"Status": "ENABLED"
}
},
"Tags": {}
}
2-3. IAMロールに失敗したAPIの許可を追加
IAMロールにiam:PutRolePolicy
APIの許可を追加します。
AdministratorAccess
のシェルで、policy-guardduty-ip-list.json
を編集して、policy-guardduty-ip-list-v2.json
を作成します。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"guardduty:*ThreatIntelSet*"
],
"Resource": "*"
+ },
+ {
+ "Effect": "Allow",
+ "Action": [
+ "iam:PutRolePolicy"
+ ],
+ "Resource": "arn:aws:iam::*:role/aws-service-role/guardduty.amazonaws.com/AWSServiceRoleForAmazonGuardDuty"
}
]
}
IAMロールに編集したポリシーを付与します。
$ aws iam put-role-policy --role-name role-guard-duty \
--policy-name policy-guardduty-ip-list \
--policy-document file://policy-guardduty-ip-list-v2.json
2-4. 再度、IAMロールでIPリスト設定(別シェルで実行)
一時的な認証情報のシェルに移って、もう一度、IAMロールでIPリストの設定を試みます。
AdministratorAccess
のシェルはまた後で使うので閉じずに置いておいてください。
レッツ・リトライ!
$ aws guardduty create-threat-intel-set --detector-id $DetectorId \
--name ThreatIntelSet --activate --format TXT \
--location s3://$BUCKETNAME/ThreatIntelSet.txt
{
"ThreatIntelSetId": "XXXXXXXXXXXXXXXXXXXX"
}
正常にIPリストを設定できました!
2-5. 新たに許可されたAPIの実行内容を確認
AdministratorAccess
のシェルに戻って、新たに許可したiam:PutRolePolicy
APIで、どんな内容のIAMポリシーを付与しているのか確認します。
AdministratorAccess
のシェルで、CloudTrailのイベントを出力します。
$ aws cloudtrail lookup-events --lookup-attributes \
AttributeKey=Username,AttributeValue=role-session-guardduty-test \
| jq '.Events[] | select(.EventName == "PutRolePolicy")' \
> cloudtrail-events-v2.json
新しいイベントが増えています。
{
"EventId": "c62d89db-46f3-4538-b345-a13c71a44893",
"EventName": "PutRolePolicy",
"ReadOnly": "false",
"AccessKeyId": "XXXXXXXXXXXXXXXX",
"EventTime": "2021-11-20T22:37:15+09:00",
"EventSource": "iam.amazonaws.com",
"Username": "role-session-guardduty-test",
"Resources": [
{
"ResourceType": "AWS::IAM::Policy",
"ResourceName": "d4be9ec85d6cd89f8b08bb31a23570c8"
},
{
"ResourceType": "AWS::IAM::Role",
"ResourceName": "AWSServiceRoleForAmazonGuardDuty"
}
],
"CloudTrailEvent": "<省略:イベント内容>"
}
{
"eventVersion": "1.08",
"userIdentity": {
"type": "AssumedRole",
"principalId": "AROAYTUJN4U3EHCPQK73U:role-session-guardduty-test",
"arn": "arn:aws:sts::XXXXXXXXXXXXXXXX:assumed-role/role-guard-duty/role-session-guardduty-test",
"accountId": "XXXXXXXXXXXXXXXX",
"accessKeyId": "XXXXXXXXXXXXXXXX",
"sessionContext": {
"sessionIssuer": {
"type": "Role",
"principalId": "AROAYTUJN4U3EHCPQK73U",
"arn": "arn:aws:iam::XXXXXXXXXXXXXXXX:role/role-guard-duty",
"accountId": "XXXXXXXXXXXXXXXX",
"userName": "role-guard-duty"
},
"webIdFederationData": {},
"attributes": {
"creationDate": "2021-11-20T10:39:14Z",
"mfaAuthenticated": "false"
}
},
"invokedBy": "guardduty.amazonaws.com"
},
"eventTime": "2021-11-20T11:07:33Z",
"eventSource": "iam.amazonaws.com",
"eventName": "PutRolePolicy",
"awsRegion": "us-east-1",
"sourceIPAddress": "guardduty.amazonaws.com",
"userAgent": "guardduty.amazonaws.com",
"requestParameters": {
"roleName": "AWSServiceRoleForAmazonGuardDuty",
"policyName": "XXXXXXXXXXXXXXXXXXXX",
"policyDocument": "{"Version":"2012-10-17","Statement":[{"Sid":"1","Effect":"Allow","Action":["s3:GetObject"],"Resource":["arn:aws:s3: : :guard-duty-iplist-test-20211120-141946/ThreatIntelSet.txt"]}]}"
},
"responseElements": null,
"requestID": "36291f18-4a00-4a1b-9b15-06cc736fac3f",
"eventID": "cc0b380b-2bdf-48b4-9974-020774ea92e9",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "XXXXXXXXXXXXXXXX",
"eventCategory": "Management"
}
requestParametersにAPIのパラメータが記録されています。
さらにその中の、policyDocumentの内容を展開します。(json入れ子ひどい……)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3: : :guard-duty-iplist-test-20211120-141946/ThreatIntelSet.txt"
]
}
]
}
s3:GetObject
APIを許可しています。しかも、Getする対象はThreatIntelSet.txt
ですね。
このポリシーをGuardDutyのサービスロール(AWSServiceRoleForAmazonGuardDuty
)に付与することで、S3上のIPリストへのアクセスを実現しているんですね。
以上で、IPリスト設定のために、IPリストを保持するS3バケットへのアクセス権限の設定方法がわかりましたね。
余談
ちなみに、サービスロール(AWSServiceRoleForAmazonGuardDuty
)にs3:GetObject
APIの許可があれば、別にIAMロールにiam:PutRolePolicy
APIは必要ないんじゃ……と思い試しましたが、ダメでした。
サービスロール(AWSServiceRoleForAmazonGuardDuty
)は直接編集不可能なので、
上記手順をすべて実施した後に、もう一度、手順1-3と手順2-1だけを実施して、試せます。
結果は、同じでiam:PutRolePolicy
APIが許可されていないと怒られますね。
iam:PutRolePolicy
はもう必要ない手順なんですけどね。
これだと、S3のバケットポリシーに、サービスロール(AWSServiceRoleForAmazonGuardDuty
)を指定してもダメでしょうね。(試していない)
さいごに
実のところ、公式ドキュメントに必要な権限が書かれています。
iam:DeleteRolePolicy
APIも許可すると、しっかり追加したポリシーを掃除してくれるみたいです。