【Security Hub対応(S3.8)】S3ブロックパブリックアクセスを有効化しても問題ないか確認する方法

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

こんにちは。AWS CLIが好きな福島です。

はじめに

早速ですが、Security Hubでは、以下のチェック項目がありチェックをクリアするためには、S3ブロックパブリックアクセスを有効化する必要があります。

S3.8 S3ブロックパブリックアクセス設定は、バケットレベルで有効にする必要があります

※余談ですが、アカウントレベルで有効化しているかチェックする項目(S3.1)もありますので、もし可能であればアカウントレベルで有効化することも検討いただくと良いかと存じます。

ただ、ブロックパブリックアクセスを有効化すると、名前の通りパブリックアクセスが無効化されるため、現在のS3の利用に影響が出る可能性があります。

ということで今回は、安全にS3ブロックパブリックアクセスを有効化できるよう、調査する方法をご紹介いたします。

結論

以下2点を確認いただければ、ブロックパブリックアクセスを有効化しても問題ないです。

  • ①Access Analyzer for S3にて検知されていないこと
  • ②オブジェクトのACLを設定変更し外部からアクセスできる状態にしていないこと

※1①で検知されていてもブロックパブリックアクセスを有効化できるケースもあります。

※2 オブジェクト数が多く②の確認ができない場合、代替案として③CloudTrailのデータイベント(S3)の確認があります。

①Access Analyzer for S3にて検知されていないこと

こちらの確認はすごく簡単です。

そもそも、IAM Access Analyzerとは

まずIAMには、IAM Access AnalyzerというAWSリソースに紐付いているポリシーを検査し、 他AWSアカウントや外部のインターネット等からのアクセスを可能とするような設定がされているか否か、 つまり管理者として"意図せぬ公開設定がされていないか"を検出および可視化してくれる機能があります。

詳細: https://blog.serverworks.co.jp/tech/2020/07/01/iam_access_analyzer-2/

そして、IAM Access AnalyzerでチェックできるサービスにはS3が含まれているため、 この機能を使うことで公開設定の有無を確認することができます。

またこの機能は無料で利用できるため、気軽に設定を有効化できます。 上記ブログに設定方法も記載されているため、有効化していない場合はぜひ有効化してください。

Access Analyzer for S3の確認方法

ここからAccess Analyzer for S3の確認方法を記載いたします。

IAM Access Analyzerへのアクセス

まず、IAM Access Analyzerにアクセスします。
https://ap-northeast-1.console.aws.amazon.com/access-analyzer/home?region=ap-northeast-1#/findings

リソースタイプの絞り込み

IAM Access Analyzerでチェックできるサービスは複数あるため、以下のようにリソースタイプをS3に絞ります。

検出結果例1 CloudFrontからのアクセスを許可している場合

CloudFrontからのアクセスを許可している場合、以下のような検出になります。
ここでポイントなのが、この検出結果だけ(②のオブジェクトACLの設定もしていないの)であれば、ブロックパブリックアクセスを有効化しても問題ありません。

検出結果例2 パブリックIPからのアクセスを許可している場合

パブリックIPからのアクセスを許可している場合、以下のような検出になります。
こちらは表示されているIPが意図したものかを確認し、意図したものであれば、ブロックパブリックアクセスは無効化のままにする必要があります。

検出結果例3 外部アカウントからのアクセスを許可している場合

外部アカウントからのアクセスを許可している場合、以下のような検出になります。
こちらは表示されているアカウントが意図したものかを確認し、意図したものであれば、ブロックパブリックアクセスは無効化のままにする必要があります。

検出結果例4 S3へのアクセスを厳格に制限している場合

S3へのアクセスを厳格に制限している場合、以下のようにエラーと表示されます。 これはおそらく、IAM Access Analyzerからアクセスできないことが原因かと存じます。

この場合、どういう設定が入っているか不明なため、内容を確認した上で対応する必要があります。

補足

検出結果の数が多くコンソールからの確認が大変な場合、以下のコマンドでCLIからも取得可能です。

echo "resourceType,resource,error,SourceIp,principal,action[0],action[1],action[2],action[3],action[4],action[5],action[6],analyzedAt" > /tmp/awscli.tmp ;\
aws accessanalyzer list-findings \
--analyzer-arn $(aws accessanalyzer list-analyzers --query "analyzers[].arn" --output text) \
--query 'findings[?resourceType==`AWS::S3::Bucket`].[resourceType,resource,error,condition.["aws:SourceIp"][
0],principal.AWS,action[0],action[1],action[2],action[3],action[4],action[5],action[6],analyzedAt]' --output text | tr "\t" "," >> /tmp/awscli.tmp ;\
column -s, -t /tmp/awscli.tmp ;\
rm -f /tmp/awscli.tmp
  • 実行結果例
resourceType    resource                      error          SourceIp          principal                                                                      action[0]                action[1]                     action[2]        action[3]                      action[4]              action[5]               action[6]               analyzedAt
AWS::S3::Bucket arn:aws:s3:::fk-test-xxx       ACCESS_DENIED   None    None    None    None    None    None    None    None    None    2022-07-15T20:49:36.020000+00:00
AWS::S3::Bucket arn:aws:s3:::fk-test-xxx     None    None    arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ENVEAZ2VQ06S9    s3:GetObject    None    None    None    None    None    None    2022-07-15T20:49:36.020000+00:00
AWS::S3::Bucket arn:aws:s3:::fk-test-xxx       None    None    *       s3:GetObject    None    None    None    None    None    None    2022-06-30T03:51:37.288000+00:00
AWS::S3::Bucket arn:aws:s3:::fk-test-xxx      None    xxx.xxx.xxx.xxx/32        *       s3:AbortMultipartUpload s3:BypassGovernanceRetention    s3:DeleteBucket s3:DeleteBucketWebsite  
AWS::S3::Bucket arn:aws:s3:::fk-test-xxx       None    None    123456789012    s3:DeleteObject s3:GetBucketAcl s3:ListBucket   s3:ListBucketMultipartUploads   s3:ListBucketVersions   s3:PutBucketAcl s3:PutObject    2022-07-15T23:51:29.228000+00:00

②オブジェクトのACLを設定変更し外部からアクセスできる状態にしていないこと

①の方法では、オブジェクトごとのACLの設定により外部公開していることはチェックできないため、 別途オブジェクトのACLの設定を1つずつ確認していく必要があります。

Security Hub(S3.8)でチェックされているS3バケットの一覧を取得

/tmp/check-s3-list.txtにSecurity Hub(S3.8)でチェックされているS3バケットの一覧をを出力します。

aws securityhub get-findings \
--filters "{\"GeneratorId\":[{\"Value\": \"aws-foundational-security-best-practices/v/1.0.0/S3.8\",\"Comparison\":\"PREFIX\"}],\"ComplianceStatus\": [{\"Value\":\"FAILED\",\"Comparison\":\"EQUALS\"}]}" \
--query 'Findings[].[Resources[0].Id]' --output text | sort | uniq | sed 's/arn:aws:s3::://g' > /tmp/check-s3-list.txt
  • 実行後のファイルの中身例
 # cat check-s3-list.txt
awslogs-elb-0123456789012
awslogs-cloudtrail-0123456789012
 # 

オブジェクト数の確認

オブジェクト数が多い場合、オブジェクトごとのACLの確認が困難なため、事前にオブジェクト数を確認します。

cat /tmp/check-s3-list.txt | while read line
do
   echo "$line $(aws s3api list-objects --bucket $line --query "Contents[].[Key]" --output text | wc -l)"
done
  • 実行例
awslogs-elb-0123456789012 3
awslogs-cloudtrail-0123456789012 5

※上記結果の2列目がオブジェクト数になりますが、オブジェクトの数が多い場合は、対象のS3バケットは除外(コメントアウト)し、③CloudTrailのデータイベント(S3)の確認を行った方が良いかと存じます。

check-s3-list.txtに記載のバケットのオブジェクトのACLの確認

/tmp/check-s3-list.txtの内容を基にオブジェクトACLを1つずつ確認します。 オブジェクトの外部公開設定されている場合、/tmp/s3-public-object.txtに結果を出力します。

> /tmp/s3-public-object.txt ;\
## バケット一覧からバケット名を1行ずつ読み込む(#が含まれている行は除外)
grep -v "#" /tmp/check-s3-list.txt | while read bucket
do
  echo "## $bucket"
  ## オブジェクト一覧を取得し、1行ずつ読み込む
  aws s3api list-objects --bucket $bucket --query "Contents[].[Key]" --output text | while read key
  do
    ## オブジェクトACLの設定を確認
    result=$(aws s3api get-object-acl --bucket $bucket --key "$key" --query "Grants[].Grantee.URI" --output text)
    ## 進捗状況が分かるようにオブジェクトパスを出力
    echo "s3://$bucket/$key"
    ## オブジェクトが外部公開されている場合、オブジェクトの設定内容および/tmp/s3-public-object.txtに結果を出力
    if [[ ! -z $result ]] ; then
       echo $result
       echo "$bucket,s3://$bucket/$key" >> /tmp/s3-public-object.txt
    fi
  done
done
  • 実行結果例
## awslogs-elb-0123456789012
s3://awslogs-elb-0123456789012/fk-test-001/AWSLogs/0123456789012/ELBAccessLogTestFile
s3://awslogs-elb-0123456789012/test.txt
http://acs.amazonaws.com/groups/global/AllUsers http://acs.amazonaws.com/groups/global/AuthenticatedUsers
#

以下のどちらかが出力されたオブジェクトは外部公開設定しているため、ブロックパブリックアクセスは無効化のままにする必要があります。

http://acs.amazonaws.com/groups/global/AllUsers
http://acs.amazonaws.com/groups/global/AuthenticatedUsers

上記の例で言うと、s3://awslogs-elb-0123456789012/test.txtが外部公開されていることになります。

また、/tmp/s3-public-object.txtのファイルに外部公開設定がされているバケットとフルパスを出力するようにしているため、 実行中の画面をずっと見ておく必要はないです。

  • イメージ
# cat /tmp/s3-public-object.txt
awslogs-elb-0123456789012,s3://awslogs-elb-0123456789012/test.txt
#

③CloudTrailのデータイベント(S3)の確認

基本的には、①、②を確認すれば良いのですが、オブジェクト数が多く②の確認ができない場合に本確認を行うと良いかと存じます。 これは実際に対象のS3へパブリックアクセスがあるかをログで確認し、ログがなければ問題ないと判断する方法です。

Athenaテーブル作成

CloudTrailの画面からAthenaテーブル作成を行います。

Athenaで分析(参考)

私は以下のクエリでパブリックアクセスの有無を分析いたしました。 ※【テーブル名】を適切な値に変更し実行します。

select eventtime,eventname,sourceipaddress,useragent,errorcode,errormessage,
  json_extract_scalar(requestParameters, '$.bucketName') as bucketName, 
  json_extract_scalar(requestParameters, '$.key') as object
from 【テーブル名】
where eventsource = 's3.amazonaws.com' and
sourceipaddress not like '%amazonaws.com' and 
sourceipaddress != 'AWS Internal' and
json_extract_scalar(requestParameters, '$.key') is not null
  • 実行結果

パブリックアクセスがある場合は、useragentが以下のようになっているケースが多いと思いますが、 出力された内容を精査し、ブロックパブリックアクセスを有効化するかご検討いただければと存じます。

[Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36]

クエリ補足(where句)

今回は、where句を以下の通り設定しましたが、環境に合わせて変更いただければと存じます。

where eventsource = 's3.amazonaws.com' and

⇒ データソースがS3のみに絞ります。

sourceipaddress not like '%amazonaws.com' and 
sourceipaddress != 'AWS Internal' and

⇒ ソースIPがAWSサービスまたはAWS Internalを除外します。

json_extract_scalar(requestParameters, '$.key') is not null

⇒ バケットへのパブリックアクセスの有無は①の手法で確認できるため、オブジェクトへのアクセスのみに限定しています。

終わりに

今回は、Security Hub対応の一環として、S3ブロックパブリックアクセスを有効化しても問題ないか確認する方法をご紹介いたしました。
どなかたのお役に立てれば幸いです。

福島 和弥 (記事一覧)

SRE3課

2019/10 入社

AWS CLIが好きです。