みなさん、こんにちは。
AWS CLI が好きなテクニカルサポート課の市野です。
いただいたお問い合わせで Excel ファイルや CSV ファイルとして管理している一覧表から複数のリソースへ一括でのタグ付けができないか、というご質問がありました。
残念ながら現時点において AWS ではファイルインポートによる一括のタグ付けができないため、CSV ファイルを繰り返し読み込みながら AWS CLI でリソースへのタグ付けを極力一度の実行で行える方法をいくつか検討してみました。
クリックで目次が表示されます。
前提
以下の説明では、AWS アカウント ID に相当する部分のみ伏字としていますが、極力イメージがしやすいように各種 AWS リソースの ID はそのまま使用しています。
当該のリソースはすでに削除済みですのでご心配なく。
また、処理の際に読み込んでいるテキストファイルはタブ区切りとなっているため、本来は TSV ファイルやタブ区切りテキストと記載した方が正確と思いますが、より一般的に伝わりやすいよう CSV ファイルとして呼称を統一させていただきました。
以降の説明箇所で、CSV レイアウトの説明のために1行目にタイトル行を含んでいますが、ループ処理の中では、タイトル行の削除や無視といった考慮をしていませんので、実際にお使いいただく際にはご注意ください。
考えられるアプローチ
AWS CLI を用いる手法として、大きく 2 パターンが考えられるかと思います。
- Resource Groups Tagging API を用いた汎用的なタグ付与
- タグ付けしたい対象の AWS サービスネイティブの API でのタグ付与
検討1. Resource Groups Tagging API の利用
概要
Resource Groups Tagging API を AWS CLI から扱うために、resourcegroupstaggingapi tag-resources
サブコマンドが用意されています。
サブコマンドの詳細は AWS CLI Command Reference を参照いただきたいですが、--resource-arn-list
オプションの引数に対象となるリソースの ARN、--tags
オプションの引数に付与したいタグ文字列を付与し実行することでタグ付けを行うことが可能です。
注意点
以下 AWS ドキュメントにも記載のある通り、Resource Groups Tagging API によるタグ付けに対応していない AWS サービスがあります。
そのような AWS サービスのリソースに対するタグ付けを行うには、上記の手法では対応ができず、後述のタグ付けしたい対象の AWS サービスネイティブ(固有)の API でのタグ付与をせざるを得ない点に注意が必要です。
また、Resource Groups Tagging API によるタグ付けに対応している AWS サービスの一覧も下記ドキュメントにありますので、必要に応じて適宜ご参照ください。
やってみる
パターン1:EC2 インスタンスごとに別々のタグを付与する
CSV ファイルの例
一つ目のフィールドにタグ付け対象となる ARN、二つ目のフィールドにタグ名、三つ目のフィールドにタグ値を記載した CSV ファイルを作成します。
cat << EOF > resource-list.csv ResourceARN TagKey TagValue arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-0919bdc9b3e0fccae Environment Production arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-048bf759268a00246 Environment Staging EOF
実行前確認
現時点でのタグの付与状況を確認します。
もともと Name タグのみ付与されている想定です。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" } ] ], [ "i-048bf759268a00246", [ { "Key": "Name", "Value": "test02" } ] ] ]
実行処理
while read RESOURCE_LIST; do RESOURCE_ARN=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $1}') TAG_KEY=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $2}') TAG_VALUE=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $3}') aws resourcegroupstaggingapi tag-resources \ --resource-arn-list ${RESOURCE_ARN} \ --tags ${TAG_KEY}=${TAG_VALUE} done < resource-list.csv
タグ付け結果の確認
CSV ファイルに記載した通り、
i-0919bdc9b3e0fccae
には"Key": "Environment", "Value": "Production"
が、i-048bf759268a00246
には"Key": "Environment", "Value": "Staging"
が付与されていることが確認できました。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" }, { "Key": "Environment", "Value": "Production" } ] ], [ "i-048bf759268a00246", [ { "Key": "Environment", "Value": "Staging" }, { "Key": "Name", "Value": "test02" } ] ] ]
パターン2:複数の EC2 インスタンスごとに同一のタグを付与する
CSV ファイルの例
一つ目のフィールドにタグ付けしたい対象の ARN を配列として記載、二つ目のフィールドに タグ名=タグ値
形式を付与したいタグ分だけカンマ区切りで繋げた文字列として記載した CSV ファイルを作成します。
cat << EOF > resource-list.csv ResourceArray TagList "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-0919bdc9b3e0fccae","arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:volume/vol-0309d641ee71bebfd","arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:db:database-1" Environment=Production,Cost=1234 EOF
--resource-arn-list
オプションの引数で指定できるリソースの個数について
本エントリでは正しく動作する事例をさらっと書いてしまっているため唐突に複数のリソースを配列で指定していますが、AWS API TagResources
アクションのリファレンスを確認すると最大 20 リソースまでの配列を引数に取ることができるとあります。
ResourceARNList
〜中略〜
Array Members: Minimum number of 1 item. Maximum number of 20 items.
実行前確認
EC2 インスタンスの確認
パターン1と同様に、Name タグのみ付与されている想定です。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" } ] ] ]
EBS ボリュームの確認
EBS ボリュームは作成時にタグをつけておらず、何も返却されていない状態としています。
aws ec2 describe-volumes \ --query 'Volumes[].[VolumeId,Tags]' [ [ "vol-0309d641ee71bebfd", null ] ]
RDS DB インスタンスの確認
RDS インスタンスは作成時にタグをつけておらず、何も返却されていない状態としています。
aws rds describe-db-instances \ --query 'DBInstances[].[DBInstanceArn,TagList]' [ [ "arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:db:database-1", [] ] ]
実行処理
while read RESOURCE_LIST; do RESOURCE_ARRAY=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $1}') TAG_LIST=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $2}') aws resourcegroupstaggingapi tag-resources \ --resource-arn-list '['${RESOURCE_ARRAY}']' \ --tags ${TAG_LIST} done < resource-list.csv
タグ付け結果の確認
EC2 インスタンスの確認
CSV ファイルで指定した通り "Key": "Environment","Value": "Production"
と "Key": "Cost","Value": "1234"
が追加されていることが確認できます。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" }, { "Key": "Environment", "Value": "Production" }, { "Key": "Cost", "Value": "1234" } ] ] ]
EBS ボリュームの確認
EBS ボリュームについても CSV ファイルで指定した通り "Key": "Environment","Value": "Production"
と "Key": "Cost","Value": "1234"
が追加されていることが確認できます。
aws ec2 describe-volumes \ --query 'Volumes[].[VolumeId,Tags]' [ [ "vol-0309d641ee71bebfd", [ { "Key": "Environment", "Value": "Production" }, { "Key": "Cost", "Value": "1234" } ] ] ]
RDS DB インスタンスの確認
RDS DB インスタンスについても CSV ファイルで指定した通り "Key": "Environment","Value": "Production"
と "Key": "Cost","Value": "1234"
が追加されていることが確認できます。
aws rds describe-db-instances \ --query 'DBInstances[].[DBInstanceArn,TagList]' [ [ "arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:db:database-1", [ { "Key": "Environment", "Value": "Production" }, { "Key": "Cost", "Value": "1234" } ] ] ]
パターン3:対応していないサービスやリソースを含んでいる場合の処理
私が調査できている範囲では Resource Groups Tagging API でのタグ付けはできないが、当該のサービス固有の API であればタグ付けできる という AWS サービスやリソースの事例を確認できておらず、便宜上、元来タグ付与に対応していない IAM グループを例に取っていますのでご注意ください。
CSV ファイルの例
ファイルのフォーマットはパターン2と同一ですが、現時点でタグ付けに対応していない IAM グループ の ARN を含めています。
cat << EOF > resource-list.csv ResourceArray TagList "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-0919bdc9b3e0fccae","arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:volume/vol-0309d641ee71bebfd","arn:aws:rds:ap-northeast-1:xxxxxxxxxxxx:db:database-1","arn:aws:iam::xxxxxxxxxxxx:group/AdministratorAccessTest" Environment=Production,Cost=1234 EOF
実行処理
while read RESOURCE_LIST; do RESOURCE_ARRAY=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $1}') TAG_LIST=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $2}') aws resourcegroupstaggingapi tag-resources \ --resource-arn-list '['${RESOURCE_ARRAY}']' \ --tags ${TAG_LIST} done < resource-list.csv
実行結果例(エラー発生例)
Unrecognized service or resource type for tagging(意訳:タグ付け用のサービスまたはリソース タイプが認識されません)
というエラーが返却されることを確認できました。
{ "FailedResourcesMap": { "arn:aws:iam::xxxxxxxxxxxx:group/AdministratorAccessTest": { "StatusCode": 400, "ErrorCode": "InvalidParameterException", "ErrorMessage": "Unrecognized service or resource type for tagging" } } }
検討2. AWS サービスネイティブの API でのタグ付け
EC2 リソースであれば ec2 create-tags
サブコマンド、RDS リソースであれば rds add-tags-to-resource
サブコマンドなど、AWS サービス固有の API として用意されています。
前述の Resource Groups Tagging API に対応していない AWS サービスであれば、当該の AWS サービスに固有で用意されている API をご利用いただく必要がありますが、AWS サービス固有の API の方が処理が簡単だったり、できることが多い側面はあるかもしれません。
やってみる
EC2 サービス内の複数リソースに対するタグ付け
CSV ファイルの例
以下のリソースに、タグキー Environment
、値に Production
を付与する想定としています。
- EC2 インスタンス:i-0919bdc9b3e0fccae,i-000efe6f10a871ae3
- EBS ボリューム:vol-0309d641ee71bebfd,vol-09aede73c0c8f9ed5
- AMI イメージ:ami-0088e04c53373e6a3
cat << EOF > resource-list.csv ResourceIDs TagKey TagValue i-0919bdc9b3e0fccae,i-000efe6f10a871ae3,vol-0309d641ee71bebfd,vol-09aede73c0c8f9ed5,ami-0088e04c53373e6a3 Environment Production EOF
実行前確認
EC2 インスタンスの確認
Name タグのみが付与された状態です。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" } ] ], [ "i-000efe6f10a871ae3", [ { "Key": "Name", "Value": "test02" } ] ] ]
EBS ボリュームの確認
EBS ボリュームにもタグが付与されていないことが確認できます。
aws ec2 describe-volumes \ --query 'Volumes[].[VolumeId,Tags]' [ [ "vol-0309d641ee71bebfd", null ], [ "vol-09aede73c0c8f9ed5", null ] ]
AMI イメージの確認
AMI イメージにもタグが付与されていないことが確認できます。
aws ec2 describe-images \ --image-ids ami-0088e04c53373e6a3 \ --query 'Images[].[ImageId, Tags]' [ [ "ami-0088e04c53373e6a3", null ] ]
実行処理
処理のポイントとしては、ec2 create-tags
の --resource
オプションの引数には、リソース ID を space で区切って指定する仕様のため、sed で、カンマを半角スペースに置き換える処理を加えています。
while read RESOURCE_LIST; do RESOURCE_IDS=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $1}') TAG_KEY=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $2}') TAG_VALUE=$(echo ${RESOURCE_LIST} | awk -F ' ' '{print $3}') aws ec2 create-tags \ --resource $(echo ${RESOURCE_IDS} | sed -e 's/,/ /g') \ --tags Key=${TAG_KEY},Value=${TAG_VALUE} done < resource-list.csv
Request Parameters
〜中略〜
ResourceId.N
The IDs of the resources, separated by spaces.Constraints: Up to 1000 resource IDs. We recommend breaking up this request into smaller batches.
タグ付け結果の確認
EC2 インスタンスの確認
CSV ファイルで指定した通り、"Key": "Environment", "Value": "Production"
が付与されていることが確認できます。
aws ec2 describe-instances \ --query 'Reservations[].Instances[].[InstanceId,Tags]' [ [ "i-0919bdc9b3e0fccae", [ { "Key": "Name", "Value": "test" }, { "Key": "Environment", "Value": "Production" } ] ], [ "i-000efe6f10a871ae3", [ { "Key": "Name", "Value": "test02" }, { "Key": "Environment", "Value": "Production" } ] ] ]
EBS ボリュームの確認
EBS ボリュームにも、CSV ファイルで指定した通り、"Key": "Environment", "Value": "Production"
が付与されていることが確認できます。
aws ec2 describe-volumes \ --query 'Volumes[].[VolumeId,Tags]' [ [ "vol-0309d641ee71bebfd", [ { "Key": "Environment", "Value": "Production" } ] ], [ "vol-09aede73c0c8f9ed5", [ { "Key": "Environment", "Value": "Production" } ] ] ]
AMI イメージの確認
AMI イメージに対しても、CSV ファイルで指定した通り、"Key": "Environment", "Value": "Production"
が付与されていることが確認できます。
aws ec2 describe-images \ --image-ids ami-0088e04c53373e6a3 \ --query 'Images[].[ImageId, Tags]' [ [ "ami-0088e04c53373e6a3", [ { "Key": "Environment", "Value": "Production" } ] ] ]
所感
Resource Groups Tagging API を用いる resourcegroupstaggingapi tag-resources
サブコマンドであれば、対象となるリソースが複数の AWS サービスに跨っていても単一のコマンドを流用できる点に優位性があるかと考えられます。
反面、resourcegroupstaggingapi tag-resources
サブコマンドの場合であれば、リソースを必ず ARN 形式である点があるため、ARN 文字列を取得しにくい EC2 サービスのリソースを対象とする場合に別途 ARN 文字列を組み立てる必要性がある点、また同一のタグを付与する複数のリソースがあった場合に、20個までのリソースに限られる点の制約があると感じています。
AWS サービスネイティブの API でのタグ付けの場合であれば、例えば EC2 リソースを例にとると、VPC や インスタンス、AMI や EBS ボリュームなど、リソースの種別が異なっていても EC2 サービスの範疇にあれば一括で指定できる点や、同一のタグを付与する場合であれば最大 1,000 個のリソースを対象として ID のみの列記で指定できる点(ARN 文字列を指定しなくても良い点)のメリットがあると感じています。
ただ、タグ付けしたい対象リソースがサービスをまたがる場合には、都度、対象となる AWS サービスネイティブの API を確認し、目的に応じた AWS CLI コマンドの組み立てが必要である点で汎用性に欠けるデメリットがあるかと考えられます。
本記事がどなたかのお役に立てば幸いです。
ではまた。
市野 和明 (記事一覧)
マネージドサービス部・テクニカルサポート課
お客様から寄せられたご質問や技術検証を通じて得られた気づきを投稿していきます。
情シスだった前職までの経験で、UI がコロコロ変わる AWS においては GUI で手順を残していると画面構成が変わってしまって後々まごつくことが多かった経験から、極力変わりにくい AWS CLI での記事が多めです。
X(Twitter):@kazzpapa3(AWS Community Builder)