この IAM ユーザーが過去30日間にアクセスした AWS サービスを一覧化してください と言われたら

マネジメントコンソールに頼らずコマンドでやりくりして結果を求めてみましょう。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンバンハ、千葉(幸)です。

タイトルの通りですが、特定の IAM ユーザーが過去一定期間でアクセスした AWS サービスを一覧で見たい、と言われたら皆さんはどのようなアプローチをとりますか?

IAM ユーザーに限らず、グループロールポリシーに置き換えてもよいです。

実は、以下の AWS CLI コマンドを使えば簡単にそのような要件に対応できます。

これらのコマンドはまったく目新しい機能ではないですが、たまたま流れてきたツイートで存在を知りました。試したところ面白そうだったのでご紹介します。

ツイートの内容をそのままなぞるのも工夫がないので、ちょっとだけアレンジを加えています。

目次

要はアクセスアドバイザーなんです。

今回やりたいことは、マネジメントコンソールからであればアクセスアドバイザーの項目を参照することで満たせます。

アクセスアドバイザーは、ユーザー、ロール、グループ、ポリシーそれぞれの切り口で、以下を表示してくれる機能です。

  • アクセス可能な AWS サービス
  • AWS サービスへの最終アクセス時刻

例えば ロールの画面からアクセスアドバイザーを参照しているイメージは以下となります。

グループやポリシーの切り口で参照するときは若干表示が異なりますが、基本的な考え方は同じです。

アクセスアドバイザー自体は、 2015 年から存在している古株の機能です。

2020 年には、S3 限定ですが、アクションレベルでもアクセス履歴が参照できるようになりました。

こういった履歴は最大で過去 400 日間まで遡って確認できるそうです。

最近のアクティビティは通常、4 時間以内に IAM コンソールに表示されます。サービス情報の追跡期間は、過去 400 日間です。
最終アクセス時間情報を使用したアクセス許可の調整 - AWS Identity and Access Management

マネジメントコンソールから参照できるこれらの履歴を AWS CLI でも見てしまおう、というのが今回の趣旨です。ドキュメントでは以下に記載があります。

やってみた

今回は、結果を参照しやすくするために jq がインストールされていることを前提としています。

$ jq --version
jq-1.6

また、AWS CLI は以下のバージョンで試しています。

$ aws --version
aws-cli/2.0.42 Python/3.7.4 Darwin/19.6.0 exe/x86_64

加工なしでの表示

大まかな流れとしては以下です。

  • aws iam generate-service-last-accessed-details(generate)の実行
    • JobIdが返却される
  • aws iam get-service-last-accessed-details(get)の実行
    • 先ほどのJobIdを引数として指定する

今回は以下のロールに対して実行します。

  • cm-chiba.yukihiro
    • AWS 管理ポリシーAdministratorAccessがアタッチされている

まずはaws iam generate-service-last-accessed-detailsの実行です。JobIdが生成されます。

aws iam generate-service-last-accessed-details \
  --arn arn:aws:iam::000000000000:role/cm-chiba.yukihiro
{
    "JobId": "72bxxxa9-0939-fb81-1a23-exxxxx3460c5"
}

上記のJobIdを引数として指定して、aws iam get-service-last-accessed-detailsを実行します。

各種サービスの過去のアクセス履歴が一覧で表示されます。

aws iam get-service-last-accessed-details \
  --job-id 72bxxxa9-0939-fb81-1a23-exxxxx3460c5
{
    "JobStatus": "COMPLETED",
    "JobType": "SERVICE_LEVEL",
    "JobCreationDate": "2020-08-25T01:53:35.347000+00:00",
    "ServicesLastAccessed": [
        {
            "ServiceName": "Alexa for Business",
            "ServiceNamespace": "a4b",
            "TotalAuthenticatedEntities": 0
        },
        {
            "ServiceName": "IAM Access Analyzer",
            "LastAuthenticated": "2020-08-19T09:10:08+00:00",
            "ServiceNamespace": "access-analyzer",
            "LastAuthenticatedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
            "LastAuthenticatedRegion": "ap-northeast-1",
            "TotalAuthenticatedEntities": 1
        },
        {
            "ServiceName": "AWS Accounts",
            "ServiceNamespace": "account",
            "TotalAuthenticatedEntities": 0
        },
        {
            "ServiceName": "AWS Certificate Manager",
            "LastAuthenticated": "2020-08-20T08:38:00+00:00",
            "ServiceNamespace": "acm",
            "LastAuthenticatedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
            "LastAuthenticatedRegion": "us-east-1",
            "TotalAuthenticatedEntities": 1
        },
        {
            "ServiceName": "AWS Certificate Manager Private Certificate Authority",
            "LastAuthenticated": "2020-02-21T10:34:00+00:00",
            "ServiceNamespace": "acm-pca",
            "LastAuthenticatedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
            "LastAuthenticatedRegion": "ap-northeast-1",
            "TotalAuthenticatedEntities": 1
        },
        {
            "ServiceName": "AWS Amplify",
            "ServiceNamespace": "amplify",
            "TotalAuthenticatedEntities": 0
        },
ーーー 以下略 ーーー

ここで結果に表れる AWS サービスは、確認対象の IAM リソースが「アクセス権を持つ」もののみです。今回試しているロールはAdministratorAccessがアタッチされているため、200程度の大量のサービスに関する結果が返ってきます。

また、ここで「アクセス権を持つ」という評価の対象となるのは、 IAM permissions ポリシーのみです。以下のようなポリシーは評価対象外となっているため、仮にこれらで Deny が定義されていた場合、実際の評価論理においては「アクセス権を持たない」状態である可能性があります。その点はご留意ください。

  • リソースベースポリシー
  • アクセスコントロールリスト
  • Organizations ポリシー
  • IAM permissions バウンダリー
  • セッションポリシー

加工しての表示

上記の戻り値のままだと見づらいので、jqを利用して見やすく加工します。以下のように指定すれば、アクセス実績のあるサービス名のみが一覧で確認できます。

$ aws iam get-service-last-accessed-details --job-id 72bxxxa9-0939-fb81-1a23-exxxxx3460c5 \
 | jq '.ServicesLastAccessed[] | select( .TotalAuthenticatedEntities > 0) | .ServiceName'
"IAM Access Analyzer"
"AWS Certificate Manager"
"AWS Certificate Manager Private Certificate Authority"
"Manage - Amazon API Gateway"
"AWS AppConfig"
"Application Auto Scaling"
"CloudWatch Application Insights"
"Amazon Athena"
"Amazon EC2 Auto Scaling"
"AWS Auto Scaling"
"AWS Marketplace"
"AWS Marketplace Management Portal"
"AWS Billing"
"AWS Backup"
"AWS Backup storage"
"AWS Budget Service"
"AWS CloudFormation"
"Amazon CloudFront"
"AWS CloudHSM"
"AWS CloudTrail"
"Amazon CloudWatch"
"AWS CodeDeploy"
"Amazon Cognito User Pools"
"Compute Optimizer"
"AWS Config"
ーーー 以下略 ーーー

アクセス実績があればTotalAuthenticatedEntities1となるので、その情報を基にフィルタリングを行っています。

ここまでが冒頭のツイートで触れられている内容です。

さらにアレンジして表示

以下のアレンジを加えてみます。

  • 最終アクセス時刻でフィルタリング
  • サービス名と最終アクセス時刻を並列表示

結果、このような形となります。

aws iam get-service-last-accessed-details --job-id 72bxxxa9-0939-fb81-1a23-exxxxx3460c5 \
 | jq -c '.ServicesLastAccessed[] | select( .LastAuthenticated > "2020-08-23T10:38:32+00:00") | [.ServiceName, .LastAuthenticated]'
["Application Auto Scaling","2020-08-24T03:59:52+00:00"]
["CloudWatch Application Insights","2020-08-24T03:59:52+00:00"]
["Amazon EC2 Auto Scaling","2020-08-24T04:00:02+00:00"]
["AWS CloudFormation","2020-08-24T08:37:52+00:00"]
["AWS CloudTrail","2020-08-24T04:00:03+00:00"]
["Amazon CloudWatch","2020-08-24T04:07:03+00:00"]
["AWS CodeDeploy","2020-08-24T04:00:02+00:00"]
["Amazon EC2","2020-08-24T08:40:01+00:00"]
["Amazon Elastic Container Service","2020-08-24T04:00:03+00:00"]
["Amazon EventBridge","2020-08-24T04:00:01+00:00"]
["Amazon Kinesis Firehose","2020-08-24T04:00:03+00:00"]
["AWS Health APIs and Notifications","2020-08-24T09:05:17+00:00"]
["AWS Identity and Access Management","2020-08-24T04:00:04+00:00"]
["Amazon Kinesis","2020-08-24T04:00:02+00:00"]
["AWS Key Management Service","2020-08-24T04:00:02+00:00"]
["AWS Lambda","2020-08-24T04:00:02+00:00"]
["Amazon CloudWatch Logs","2020-08-24T04:04:55+00:00"]
["AWS Resource Access Manager","2020-08-24T08:40:00+00:00"]
["AWS Resource Groups","2020-08-24T03:59:53+00:00"]
["Amazon SNS","2020-08-24T04:00:03+00:00"]

.LastAuthenticated > "2020-08-23T10:38:32+00:00"の部分を適宜変更すれば、タイトルの通り「過去 30 日間」という期間の結果を得ることができます。

jqのオプションの指定の仕方は、以下を参考にしています。

アクションレベルの出力

ここまで見てきたのは、すべてサービスレベルでの出力です。

アクセスアドバイザーで確認した通り、S3 だけはアクションレベルでアクセス履歴が確認できます。確認する手法をさらっておきます。

手順の違いとしては、JobIdを生成する際に--granularity ACTION_LEVELを付与する、という点だけです。

$ aws iam generate-service-last-accessed-details \
  --granularity ACTION_LEVEL \
  --arn arn:aws:iam::000000000000:role/cm-chiba.yukihiro
{
    "JobId": "xxxx11b4-07e6-13xx-b845-5a9f01xxxxxf"
}

上記のJobIdを用いて参照すると、S3 に関する部分のみTrackedActionsLastAccessedというフィールドが増えて、個々のアクションに関する記述が追加されます。(従来のサービスレベルの結果に加えて、アクションレベルの結果も表示される、というイメージです。)

$ aws iam get-service-last-accessed-details --job-id xxxx11b4-07e6-13xx-b845-5a9f01xxxxxf

ーーー 略 ーーー
        {
            "ServiceName": "Amazon S3",
            "LastAuthenticated": "2020-08-20T16:31:54+00:00",
            "ServiceNamespace": "s3",
            "LastAuthenticatedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
            "LastAuthenticatedRegion": "ap-northeast-1",
            "TotalAuthenticatedEntities": 1,
            "TrackedActionsLastAccessed": [
                {
                    "ActionName": "CreateAccessPoint"
                },
                {
                    "ActionName": "CreateBucket",
                    "LastAccessedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
                    "LastAccessedTime": "2020-08-19T05:19:00+00:00",
                    "LastAccessedRegion": "ap-northeast-1"
                },
                {
                    "ActionName": "CreateJob"
                },
                {
                    "ActionName": "DeleteAccessPoint"
                },
                {
                    "ActionName": "DeleteAccessPointPolicy"
                },
                {
                    "ActionName": "DeleteBucket",
                    "LastAccessedEntity": "arn:aws:iam::000000000000:role/cm-chiba.yukihiro",
                    "LastAccessedTime": "2020-08-07T10:18:35+00:00",
                    "LastAccessedRegion": "ap-northeast-1"
                },
ーーー 以下略 ーーー

過去に実行したことのあるアクションをアクセス時刻と共にリスト化」というのをやってみました。

$ aws iam get-service-last-accessed-details --job-id xxxx11b4-07e6-13xx-b845-5a9f01xxxxxf \
 | jq -c '.ServicesLastAccessed[] | select( .TrackedActionsLastAccessed !=null) | .TrackedActionsLastAccessed[] | select(.LastAccessedEntity !=null ) | [.ActionName, .LastAccessedTime]'
["CreateBucket","2020-08-19T05:19:00+00:00"]
["DeleteBucket","2020-08-07T10:18:35+00:00"]
["DeleteBucketPolicy","2020-08-07T10:17:49+00:00"]
["GetAccountPublicAccessBlock","2020-08-07T10:18:42+00:00"]
["GetBucketAcl","2020-08-07T10:18:42+00:00"]
["GetBucketCORS","2020-08-07T10:18:42+00:00"]
["GetBucketLocation","2020-08-19T05:18:59+00:00"]
["GetBucketLogging","2020-08-07T10:18:40+00:00"]
["GetBucketNotification","2020-08-07T10:18:40+00:00"]
["GetBucketObjectLockConfiguration","2020-08-07T10:18:40+00:00"]
["GetBucketPolicy","2020-08-07T10:18:42+00:00"]
["GetBucketPolicyStatus","2020-08-07T10:18:42+00:00"]
["GetBucketPublicAccessBlock","2020-08-07T10:18:42+00:00"]
["GetBucketRequestPayment","2020-08-07T10:18:40+00:00"]
["GetBucketTagging","2020-08-07T10:18:40+00:00"]
["GetBucketVersioning","2020-08-07T10:18:38+00:00"]
["GetBucketWebsite","2020-08-07T10:18:40+00:00"]
["GetEncryptionConfiguration","2020-08-07T10:18:42+00:00"]
["GetLifecycleConfiguration","2020-08-07T10:18:23+00:00"]
["GetReplicationConfiguration","2020-08-07T10:18:23+00:00"]
["ListAccessPoints","2020-08-07T10:18:25+00:00"]
["ListAllMyBuckets","2020-08-20T16:31:54+00:00"]
["PutBucketAcl","2020-07-14T08:52:15+00:00"]
["PutBucketPolicy","2020-07-21T10:36:48+00:00"]
["PutBucketPublicAccessBlock","2020-08-04T10:38:11+00:00"]
["PutBucketTagging","2020-07-21T10:36:23+00:00"]
["PutEncryptionConfiguration","2020-07-21T11:24:48+00:00"]

jqは今日初めて触ったので、もっとスマートな書き方があるかもしれません。条件を変えて書けば、いろいろな要件に対応できそうですね。

おまけ

今回学んだことを活用して「コマンド一発で AWS サービスの一覧を出力する」ということができないか試してみました。

結果から言うと、できませんでした

AdministratorAccessがアタッチされていれば全てのサービスにアクセスできるはずなので、フィルタリングをしないでそのまま出力すればすべての AWS サービスを出力できるのでは?という目論見でした。

出力結果が 200 程度しかなかったので、取り込めていないサービスがまだまだあります。

折り畳み
$ aws iam get-service-last-accessed-details --job-id 72bxxxa9-0939-fb81-1a23-exxxxx3460c5 \
 | jq '.ServicesLastAccessed[] | .ServiceName'
"Alexa for Business"
"IAM Access Analyzer"
"AWS Accounts"
"AWS Certificate Manager"
"AWS Certificate Manager Private Certificate Authority"
"AWS Amplify"
"Manage - Amazon API Gateway"
"AWS AppConfig"
"Amazon AppFlow"
"Application Auto Scaling"
"CloudWatch Application Insights"
"AWS App Mesh"
"AWS App Mesh Preview"
"Amazon AppStream 2.0"
"AWS AppSync"
"Application Discovery Arsenal"
"AWS Artifact"
"Amazon Athena"
"Amazon EC2 Auto Scaling"
"AWS Auto Scaling"
"AWS Marketplace"
"AWS Marketplace Management Portal"
"AWS Billing"
"AWS Connector Service"
"AWS Backup"
"AWS Backup storage"
"AWS Batch"
"Amazon Braket"
"AWS Budget Service"
"Amazon Keyspaces (for Apache Cassandra)"
"AWS Cost Explorer Service"
"AWS Chatbot"
"Amazon Chime"
"AWS Cloud9"
"Amazon Cloud Directory"
"AWS CloudFormation"
"Amazon CloudFront"
"AWS CloudHSM"
"Amazon CloudSearch"
"AWS CloudTrail"
"Amazon CloudWatch"
"AWS CodeArtifact"
"AWS CodeBuild"
"AWS CodeCommit"
"AWS CodeDeploy"
"Amazon CodeGuru"
"Amazon CodeGuru Profiler"
"Amazon CodeGuru Reviewer"
"AWS CodePipeline"
"AWS CodeStar"
"AWS CodeStar Connections"
"AWS CodeStar Notifications"
"Amazon Cognito Identity"
"Amazon Cognito User Pools"
"Amazon Cognito Sync"
"Amazon Comprehend"
"Comprehend Medical"
"Compute Optimizer"
"AWS Config"
"Amazon Connect"
"AWS Cost and Usage Report"
"AWS Data Exchange"
"Data Pipeline"
"DataSync"
"Amazon DynamoDB Accelerator (DAX)"
"Database Query Metadata Service"
"AWS DeepComposer"
"AWS DeepLens"
"AWS DeepRacer"
"Amazon Detective"
"AWS Device Farm"
"AWS Direct Connect"
"AWS Application Discovery Service"
"Amazon Data Lifecycle Manager"
"AWS Database Migration Service"
"AWS Directory Service"
"Amazon DynamoDB"
"Amazon Elastic Block Store"
"Amazon EC2"
"Amazon EC2 Instance Connect"
"Amazon Message Delivery Service"
"Amazon Elastic Container Registry"
"Amazon Elastic Container Service"
"Amazon Elastic Container Service for Kubernetes"
"Amazon Elastic Inference"
"Amazon ElastiCache"
"AWS Elastic Beanstalk"
"Amazon Elastic File System"
"Elastic Load Balancing"
"Amazon Elastic MapReduce"
"Amazon Elastic Transcoder"
"Elemental Activations"
"AWS Elemental Appliances and Software"
"Amazon Elasticsearch Service"
"Amazon EventBridge"
"Amazon API Gateway"
"Amazon Kinesis Firehose"
"AWS Firewall Manager"
"Amazon Forecast"
"Amazon Fraud Detector"
"Amazon FreeRTOS"
"Amazon FSx"
"Amazon GameLift"
"Amazon Glacier"
"AWS Global Accelerator"
"AWS Glue"
"AWS IoT Greengrass"
"AWS Ground Station"
"Amazon GroundTruth Labeling"
"Amazon GuardDuty"
"AWS Health APIs and Notifications"
"Amazon Honeycode"
"AWS Identity and Access Management"
"AWS Identity Store"
"Amazon EC2 Image Builder"
"AWS Import Export"
"Amazon Inspector"
"AWS IoT"
"AWS IoT Device Tester"
"AWS IoT 1-Click"
"AWS IoT Analytics"
"AWS IoT Events"
"AWS IoT SiteWise"
"AWS IoT Things Graph"
"AWS IQ"
"AWS IQ Permissions"
"Amazon Interactive Video Service"
"Amazon Managed Streaming for Apache Kafka"
"Amazon Kendra"
"Amazon Kinesis"
"Amazon Kinesis Analytics"
"Amazon Kinesis Video Streams"
"AWS Key Management Service"
"AWS Lake Formation"
"AWS Lambda"
"Launch Wizard"
"Amazon Lex"
"AWS License Manager"
"Amazon Lightsail"
"Amazon CloudWatch Logs"
"Amazon Machine Learning"
"Amazon Macie Classic"
"Amazon Macie"
"Amazon Managed Blockchain"
"Amazon Mechanical Turk"
"AWS Elemental MediaConnect"
"AWS Elemental MediaConvert"
"AWS Elemental MediaLive"
"AWS Elemental MediaPackage"
"AWS Elemental MediaPackage VOD"
"AWS Elemental MediaStore"
"AWS Elemental MediaTailor"
"AWS Migration Hub"
"Amazon Mobile Analytics"
"AWS Mobile Hub"
"Amazon Pinpoint"
"Amazon MQ"
"Amazon Neptune"
"Network Manager"
"AWS OpsWorks"
"AWS OpsWorks Configuration Management"
"AWS Organizations"
"AWS Outposts"
"Amazon Personalize"
"AWS Performance Insights"
"Amazon Polly"
"AWS Price List"
"AWS Purchase Orders Console"
"Amazon QLDB"
"Amazon QuickSight"
"AWS Resource Access Manager"
"Amazon RDS"
"Amazon RDS Data API"
"Amazon RDS IAM Authentication"
"Amazon Redshift"
"Amazon Rekognition"
"AWS Tag Editor"
"AWS Resource Groups"
"AWS RoboMaker"
"Amazon Route 53"
"Amazon Route53 Domains"
"Amazon Route 53 Resolver"
"Amazon S3"
"Amazon SageMaker"
"AWS Savings Plans"
"Amazon EventBridge Schemas"
"Amazon SimpleDB"
"AWS Secrets Manager"
"AWS Security Hub"
"AWS Serverless Application Repository"
"AWS Service Catalog"
"AWS Cloud Map"
"Service Quotas"
"Amazon SES"
"AWS Shield"
"AWS Code Signing for Amazon FreeRTOS"
"AWS Server Migration Service"
"Amazon Pinpoint SMS and Voice Service"
"AWS Snowball"
"Amazon SNS"

少なくとも以下ページに羅列されているものよりは数十個少ない数です。「コマンド一発で AWS サービスの一覧を出力する」、何かいい方法があるといいのですが……。

AWS のサービスのアクション、リソース、および条件キー - AWS Identity and Access Management

以下、2020/10/05追記

これは 明示的に--max-itemsを指定していないことによるものでした。デフォルトでは 200 までしか出力されないようなので、途中で結果が打ち切られています。

get-service-last-accessed-details — AWS CLI 2.0.54 Command Reference

( リファレンスでは 100 と書かれているのが少し気になるところです。)

If you do not include this parameter, the number of items defaults to 100.

こちらの内容を踏まえて別エントリに記載しましたので、併せてご参照ください。

終わりに

AWS CLI を用いたアクセス履歴の参照方法について確認しました。マネジメントコンソールでも同じようなことは確認できるのですが、コマンドを叩いて結果が得られるというのはまた違った趣があっていいですね。

何かしら参考になれば幸いです。

以上、千葉(幸)がお送りしました。