[アップデート] タグ好き必見!リソースグループタグ付け API で ARN リストに基づいたタグ取得ができるようになりました

タグを愛する、すべての人類へ。

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

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

  • Resource Groups Tagging APIの、
  • GetResourcesオペレーションで、
  • ResourceARNListパラメータを使用できるようになりました!

なんのこっちゃ!

リソースグループタグ付け API とは

簡単に言うと、リソース種別を横断してタグ操作できる API の集まり です。

当初はAWS Resource Tagging APIとして発表されました。いつの間にか AWS Resource Groups Tagging API に成長していました。

マネジメントコンソールではタグエディターとして操作できる部分が、関わりが深いです。

2021年1月現在のマネジメントコンソールでは、AWS Resource Groups の画面から操作できます。

サービスの名前空間はtagで、使用できるアクションの一覧は以下の通りです。

GetResources オペレーションとは

GetResources オペレーションはリソースグループタグ付け API のアクションの一つで、tag:GetResourcesと表されます。

リソースおよびそこに付与されているタグの一覧を取得できるものであり、いくつかの条件でフィルタリングすることもできます。

簡易的なリソースの棚卸しに

GetResources オペレーションに対応する AWS CLI コマンドはaws resourcegroupstaggingapi get-resourcesです。

実行すると以下のような結果が返ってきます。

{
    "ResourceTagMappingList": [
        {
            "ResourceARN": " arn:aws:inspector:us-west-2:123456789012:target/0-nvgVhaxX/template/0-7sbz2Kz0",
            "Tags": [
                {
                    "Key": "Environment",
                    "Value": "Production"
                }
            ]
        },
        {
            "ResourceARN": " arn:aws:inspector:us-west-2:123456789012:target/0-nvgVhaxX/template/0-7sbz2sss",
            "Tags": [
                {
                    "Key": "Environment",
                    "Value": "Production"
                },
                {
                    "Key": "Name",
                    "Value": "Sample"
                },               
            ]
        }
    ]
}

jqなどを利用してリソース ARN のみを表示するようすれば、簡易的な棚卸しが実現できます。

試しに私の検証環境で、東京リージョンのリソースを出力してみた結果が以下です。「そう言えばこんなの作ってたなー」と思ったりします。

% aws resourcegroupstaggingapi get-resources\
  | jq '.ResourceTagMappingList[].ResourceARN'
"arn:aws:backup:ap-northeast-1:012345678901:backup-plan:c4bcbb21-509a-4bdf-840b-bf74d101a465"
"arn:aws:backup:ap-northeast-1:012345678901:backup-plan:ef14acec-ce65-4211-9220-8c0b6ff9546c"
"arn:aws:backup:ap-northeast-1:012345678901:backup-vault:test"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-ssmagent"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:database-test-alarm-CPUUtilization"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:database-test-alarm-FreeableMemory"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-mem_used_percent"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-disk_used_percent"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-StatusCheckFailed"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-syslog"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:test-psalarm"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-clamscan"
"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-CPUUtilization"
"arn:aws:datasync:ap-northeast-1:012345678901:agent/agent-0ede018a4e6886383"
"arn:aws:datasync:ap-northeast-1:012345678901:agent/agent-0506e01837463d221"
"arn:aws:datasync:ap-northeast-1:012345678901:location/loc-0ee59fec463fff39a"
"arn:aws:datasync:ap-northeast-1:012345678901:location/loc-0039b57523d4cee2b"
"arn:aws:datasync:ap-northeast-1:012345678901:location/loc-05bcd26b8b52a51a0"
"arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-0ba622cab3a9dc60d"
"arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-05e3cd01fe10ad9ee"
"arn:aws:ec2:ap-northeast-1:012345678901:customer-gateway/cgw-04ec5a11e94ffd212"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0f3a638ff4bc2d66a"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0167977651e1d11be"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0a7e610df58f1a480"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0d7254ef551f228ed"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-02b0f120a941e83da"
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-091abda999bef592f"
"arn:aws:ec2:ap-northeast-1:012345678901:instance/i-0938992d87f175f68"
"arn:aws:ec2:ap-northeast-1:012345678901:instance/i-0feca7f781ffbdca2"
"arn:aws:ec2:ap-northeast-1:012345678901:instance/i-00b9d2f1094c08616"
"arn:aws:ec2:ap-northeast-1:012345678901:instance/i-0a8de93080327ef29"
"arn:aws:ec2:ap-northeast-1:012345678901:internet-gateway/igw-08e5fdb8617062dab"
"arn:aws:ec2:ap-northeast-1:012345678901:internet-gateway/igw-07557d6c440e93867"
"arn:aws:ec2:ap-northeast-1:012345678901:internet-gateway/igw-0b54c2be78ae23937"
"arn:aws:ec2:ap-northeast-1:012345678901:internet-gateway/igw-0f24eb03ccd4f36f5"
"arn:aws:ec2:ap-northeast-1:012345678901:network-acl/acl-0a6e723c779cdd2f1"
"arn:aws:ec2:ap-northeast-1:012345678901:network-acl/acl-0b1930c8cbfa31f60"
"arn:aws:ec2:ap-northeast-1:012345678901:network-acl/acl-045bc1944cb16829b"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0fd53a6f69fe5dc5e"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0c4ca04bb0e6a2de3"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0cfe92a2ee1cc4e41"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0bde8f360f611141d"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0ae0e1b12a958b4f4"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0da1325e1240ae677"
"arn:aws:ec2:ap-northeast-1:012345678901:route-table/rtb-0eabe456478a5e171"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-0bed12184b6fcc57f"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-074c66a9ced2409f3"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-0a597e5b2a9a1d86d"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-0e6d27407927da2f4"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-0e397fe90b00bc997"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-02d9d038b65bf387a"
"arn:aws:ec2:ap-northeast-1:012345678901:security-group/sg-04b167c5ccef42abc"
"arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-0a1787be9c396d104"
"arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-05766d092e24a3a11"
"arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-0b3056ee125473c81"
"arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-049995a50dba61710"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-0ea5568426090a4c6"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-09b107b0d68026bb8"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-07f30be336c9c53be"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-00dacbc375b6cf11d"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-03a0136bc55f733fd"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-078b384654af475ad"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-069f98d58b2129eea"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-07995f977fbed6be0"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-0caa45223899b4b73"
"arn:aws:ec2:ap-northeast-1:012345678901:subnet/subnet-0a29365dfe098b218"
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0efeb265e2d8c1b59"
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0df5bba432c583dcd"
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0e3624f5d552711d3"
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-097a1d73bdf4e0e86"
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0f1cc5008fddb546f"
"arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-09beb440a1e665383"
"arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-0e4acafc38414468c"
"arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-0b0a7562a61588939"
"arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-0f4af0dd9672f6eb1"
"arn:aws:elasticfilesystem:ap-northeast-1:012345678901:file-system/fs-fbb9a9da"
"arn:aws:elasticfilesystem:ap-northeast-1:012345678901:file-system/fs-da6e8cfa"
"arn:aws:elasticfilesystem:ap-northeast-1:012345678901:file-system/fs-ea3a25cb"
"arn:aws:events:ap-northeast-1:012345678901:rule/AlertGuardDutyFindings"
"arn:aws:events:ap-northeast-1:012345678901:rule/test"
"arn:aws:events:ap-northeast-1:012345678901:rule/config-revaluate"
"arn:aws:events:ap-northeast-1:012345678901:rule/CWLogsPutRetentionPolicyEvent"
"arn:aws:events:ap-northeast-1:012345678901:rule/AutoScalingManagedRule"
"arn:aws:events:ap-northeast-1:012345678901:rule/AWSBigDataBlog-GlueDynamoExportTableExport-Trigger-1CX0PNI843MPY"
"arn:aws:events:ap-northeast-1:012345678901:rule/config"
"arn:aws:lambda:ap-northeast-1:012345678901:function:AWSBigDataBlog-GlueDynamoExportT-CreateCurrentView-K1KBFSLTS6G1"
"arn:aws:lambda:ap-northeast-1:012345678901:function:transcribe-function"
"arn:aws:lambda:ap-northeast-1:012345678901:function:LogGroupPutRetentionPolicy"
"arn:aws:lambda:ap-northeast-1:012345678901:function:AWSBigDataBlog-GlueDynamoExpo-GetCurrentViewStatus-SOWZAONHY5MJ"
"arn:aws:lambda:ap-northeast-1:012345678901:function:AWSBigDataBlog-GlueDynamoExportTa-StartGlueCrawler-LHEP9BGFS2NZ"
"arn:aws:lambda:ap-northeast-1:012345678901:function:translate-after-transcribe-function"
"arn:aws:lambda:ap-northeast-1:012345678901:function:test-dynamodb-to-s3-ddbToFirehose-1MELND04EJEIH"
"arn:aws:lambda:ap-northeast-1:012345678901:function:AWSBigDataBlog-GlueDynamoExpo-GetGlueCrawlerStatus-1D6OO6MQMQ4YJ"
"arn:aws:rds:ap-northeast-1:012345678901:es:test-cwalarm-rdseventsubscription-132tlwr3jme1i"
"arn:aws:rds:ap-northeast-1:012345678901:og:test-oracle-og-primarydboptiongroup-z8g9vatjrcnr"
"arn:aws:s3:::dynamodb-exports-012345678901-ap-northeast-1"
"arn:aws:s3:::chiba-prd-staticcontents-012345678901"
"arn:aws:s3:::test-dynamodb-to-s3-mys3bucket-1ounjvcs4v5ka"
"arn:aws:ssm:ap-northeast-1:012345678901:maintenancewindow/mw-02087f8c338da880c"
"arn:aws:ssm:ap-northeast-1:012345678901:patchbaseline/pb-0749392d7bb7a7ac0"
"arn:aws:ssm:ap-northeast-1:012345678901:session/cm-chiba.yukihiro-08200ef9f1029dcec"
"arn:aws:ssm:ap-northeast-1:012345678901:session/cm-chiba.yukihiro-05e65802da1da7f1f"
"arn:aws:ssm:ap-northeast-1:012345678901:session/cm-chiba.yukihiro-0d713c31051f17cba"
"arn:aws:states:ap-northeast-1:012345678901:stateMachine:DynamoDBExportAndAthenaLoad"
"arn:aws:workspaces:ap-northeast-1:012345678901:directory/d-95671b938e"

Name タグを併記させることもできます。

% aws resourcegroupstaggingapi get-resources \
  | jq -c '.ResourceTagMappingList[] | [.ResourceARN,(.Tags[] | select(.Key == "Name").Value)]'

---略---
["arn:aws:datasync:ap-northeast-1:012345678901:location/loc-0039b57523d4cee2b"]
["arn:aws:datasync:ap-northeast-1:012345678901:location/loc-05bcd26b8b52a51a0"]
["arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-0ba622cab3a9dc60d","test-vpn-client"]
["arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-05e3cd01fe10ad9ee","tokyo10-cvpn"]
["arn:aws:ec2:ap-northeast-1:012345678901:customer-gateway/cgw-04ec5a11e94ffd212","hogehogehoge"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0f3a638ff4bc2d66a"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0167977651e1d11be"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0a7e610df58f1a480","tokyo192a"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0d7254ef551f228ed","image-20201208"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-02b0f120a941e83da","image-20201208-2"]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-091abda999bef592f","ManagedInstance"]
["arn:aws:ec2:ap-northeast-1:012345678901:instance/i-0938992d87f175f68","ManagedInstance"]
["arn:aws:ec2:ap-northeast-1:012345678901:instance/i-0feca7f781ffbdca2","AWS CLI"]
---略---

同様の話は以下のエントリでも取り上げられています。

対象となるリソースは?

上記のコマンドで確認できる対象として、すべての AWS サービスのリソースが含まれるわけではありません

リソースグループタグ付け API でサポートされている AWS サービスが以下の通りで、ここに含まれていないものは対象外です。 IAM リソースなどは取得できないですね。

また、GetResources の API リファレンスを確認すると、以下の記述があります。

Returns all the tagged or previously tagged resources that are located in the specified Region for the AWS account.

機械翻訳すると以下の通り。

AWSアカウントの指定されたリージョンにある、すべてのタグ付き または 以前にタグ付けされたリソースを返します。

確かに、先述の私の実行結果を確認すると「リソース種別としては対応しているが結果に含まれていない」リソースがいくつかあります。当該リソースにはタグ付けをしていません。

一方で、過去に一度もタグ付けしたことがない(記憶がない)リソースが結果に含まれている部分もあります。

この辺りの線引きが厳密には確認できなかったので、棚卸し目的で使用される際にはご留意ください。

ResourceARNList とは

今回新たに GetResources オペレーションに対応したパラメータです。

ふたたび AWS CLI を例にとって説明します。

これまでは、以下のフィルタリングが可能でした。

  • タグ キー(および値)
    • --tag-filters
  • リソース種別(EC2インスタンスのみ、VPCのみなど)
    • --resource-type-filters

今回のアップデートにより、以下の方式でもフィルタリングが可能となりました。

  • ARN リスト
    • --resource-arn-list

以下のような形式で指定することで、タグを確認したいリソースに限定して結果を返すことができます。

aws resourcegroupstaggingapi get-resources\
  --resource-arn-list "ARN 1" "ARN 2" "ARN 3" ...

管理対象としたいリソースが決まっている場合、それをリストとして渡すことによって、一度の API 呼び出しでタグづけ状況を確認できるようになりました。

やってみた

早速やってみます。

AWS CLI のバージョンを現時点の最新にして試しました。

% aws --version
aws-cli/2.1.21 Python/3.7.4 Darwin/19.6.0 exe/x86_64 prompt/off

リストをオプションで羅列するのはしんどいので、先に別ファイルを作っておきます。

今回は先ほどの簡易的な棚卸し結果からピックアップしてリストを作ります。(ダブルクォーテーションで囲まれていると後続の手順でうまくいかなかったため、jq で -r オプションを指定しています。)

% aws resourcegroupstaggingapi get-resources \
  | jq -r '.ResourceTagMappingList[].ResourceARN'
arn:aws:backup:ap-northeast-1:012345678901:backup-plan:c4bcbb21-509a-4bdf-840b-bf74d101a465
arn:aws:backup:ap-northeast-1:012345678901:backup-plan:ef14acec-ce65-4211-9220-8c0b6ff9546c
---略---

ファイル名をarn_list.txtとして、以下のリストを作成しました。

arn_list.txt

arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-clamscan
arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-0ba622cab3a9dc60d
arn:aws:ec2:ap-northeast-1:012345678901:customer-gateway/cgw-04ec5a11e94ffd212
arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0f3a638ff4bc2d66a
arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0e3624f5d552711d3
arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-09beb440a1e665383
arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-0b3056ee125473c81

オプションとして以下のような形でリストを渡し、タグを一覧化してみました。

% aws resourcegroupstaggingapi get-resources\
 --resource-arn-list `cat arn_list.txt`\
 | jq '.ResourceTagMappingList[] | .ResourceARN,.Tags[]'

"arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-clamscan"
"arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-0ba622cab3a9dc60d"
{
  "Key": "Name",
  "Value": "test-vpn-client"
}
"arn:aws:ec2:ap-northeast-1:012345678901:customer-gateway/cgw-04ec5a11e94ffd212"
{
  "Key": "Name",
  "Value": "hogehogehoge"
}
"arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0a7e610df58f1a480"
{
  "Key": "Name",
  "Value": "tokyo192a"
}
{
  "Key": "Patch Group",
  "Value": "Test"
}
{
  "Key": "aws:backup:source-resource",
  "Value": "i-0dbce6ea46c613c78:b0b8cf0e-6240-4c90-815f-cbab32b5793f"
}
"arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0e3624f5d552711d3"
{
  "Key": "Name",
  "Value": "Win"
}
"arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-09beb440a1e665383"
{
  "Key": "Name",
  "Value": "tokyo10"
}
"arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-0b3056ee125473c81"
{
  "Key": "aws:backup:source-resource",
  "Value": "i-0dbce6ea46c613c78:b0b8cf0e-6240-4c90-815f-cbab32b5793f"
}

1行にまとめたい場合は、以下のような指定をします。

% aws resourcegroupstaggingapi get-resources\
 --resource-arn-list `cat arn_list.txt`\
 | jq -c '.ResourceTagMappingList[] | [.ResourceARN,.Tags[]]'

["arn:aws:cloudwatch:ap-northeast-1:012345678901:alarm:ip-192-168-0-79.ap-northeast-1.compute.internal-alarm-clamscan"]
["arn:aws:ec2:ap-northeast-1:012345678901:client-vpn-endpoint/cvpn-endpoint-0ba622cab3a9dc60d",{"Key":"Name","Value":"test-vpn-client"}]
["arn:aws:ec2:ap-northeast-1:012345678901:customer-gateway/cgw-04ec5a11e94ffd212",{"Key":"Name","Value":"hogehogehoge"}]
["arn:aws:ec2:ap-northeast-1:012345678901:image/ami-0a7e610df58f1a480",{"Key":"Name","Value":"tokyo192a"},{"Key":"Patch Group","Value":"Test"},{"Key":"aws:backup:source-resource","Value":"i-0dbce6ea46c613c78:b0b8cf0e-6240-4c90-815f-cbab32b5793f"}]
["arn:aws:ec2:ap-northeast-1:012345678901:volume/vol-0e3624f5d552711d3",{"Key":"Name","Value":"Win"}]
["arn:aws:ec2:ap-northeast-1:012345678901:vpc/vpc-09beb440a1e665383",{"Key":"Name","Value":"tokyo10"}]
["arn:aws:ec2:ap-northeast-1:012345678901:snapshot/snap-0b3056ee125473c81",{"Key":"aws:backup:source-resource","Value":"i-0dbce6ea46c613c78:b0b8cf0e-6240-4c90-815f-cbab32b5793f"}]

リストをきちんと作っておけば、必要なタグ付けがきちんとなされているか?という確認を手軽に行えますね。

終わりに

よいタグライフをお過ごしください。

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