- AWS
AWSタグの付け方|AWS CLIでタグ付け・検索・一覧取得と命名ルール
AWS のタグは「キー」と「値」の組で、リソースに目印を付ける仕組みです。AWS CLI では aws ec2 create-tags --resources ID --tags Key=Env,Value=prod のように付けます。 ただし、タグを付けるコマンドの名前と引数の書き方はサービスごとに違います。EC2 は create-tags、S3 は put-bucket-tagging、Lambda や DynamoDB は tag-resource、RDS は add-tags-to-resource です。
この記事では、サービスごとのコマンドと引数の形を1枚の表にまとめ、付与・確認・削除を実行した出力つきで載せます。あわせて、タグでリソースを検索する2つの方法、タグが付いていないリソースを洗い出すワンライナー、S3 のバケットタグが全置換になる動き、命名ルールと上限、コスト配分タグ向けのキー設計、boto3 での一括付与コードを紹介します。
確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11、boto3 1.43.103、jq 1.7。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しました。掲載するコマンドは接続先の指定を外し、実際の AWS でそのまま使える形にしています。
AWS タグ付けコマンドの早見表(サービス別)
| サービス | 付ける | 確認する | 外す | リソースの指定 | --tags の形 |
|---|---|---|---|---|---|
| EC2(インスタンス・ボリュームなど) | ec2 create-tags |
ec2 describe-tags |
ec2 delete-tags |
--resources ID ... |
リスト形 |
| S3 バケット | s3api put-bucket-tagging |
s3api get-bucket-tagging |
s3api delete-bucket-tagging |
--bucket 名前 |
--tagging 'TagSet=[...]' |
| S3 オブジェクト | s3api put-object-tagging |
s3api get-object-tagging |
s3api delete-object-tagging |
--bucket 名前 --key キー |
--tagging 'TagSet=[...]' |
| Lambda | lambda tag-resource |
lambda list-tags |
lambda untag-resource |
--resource ARN |
マップ形 |
| DynamoDB | dynamodb tag-resource |
dynamodb list-tags-of-resource |
dynamodb untag-resource |
--resource-arn ARN |
リスト形 |
| RDS | rds add-tags-to-resource |
rds list-tags-for-resource |
rds remove-tags-from-resource |
--resource-name ARN |
リスト形 |
| IAM ロール | iam tag-role |
iam list-role-tags |
iam untag-role |
--role-name 名前 |
リスト形 |
| IAM ユーザー | iam tag-user |
iam list-user-tags |
iam untag-user |
--user-name 名前 |
リスト形 |
| SQS | sqs tag-queue |
sqs list-queue-tags |
sqs untag-queue |
--queue-url URL |
マップ形 |
| SNS | sns tag-resource |
sns list-tags-for-resource |
sns untag-resource |
--resource-arn ARN |
リスト形 |
| CloudWatch Logs | logs tag-resource |
logs list-tags-for-resource |
logs untag-resource |
--resource-arn ARN |
マップ形 |
| CloudWatch アラーム | cloudwatch tag-resource |
cloudwatch list-tags-for-resource |
cloudwatch untag-resource |
--resource-arn ARN |
リスト形 |
| SSM パラメータ | ssm add-tags-to-resource |
ssm list-tags-for-resource |
ssm remove-tags-from-resource |
--resource-type Parameter --resource-id 名前 |
リスト形 |
| Secrets Manager | secretsmanager tag-resource |
secretsmanager describe-secret |
secretsmanager untag-resource |
--secret-id 名前 |
リスト形 |
| サービス横断 | resourcegroupstaggingapi tag-resources |
resourcegroupstaggingapi get-resources |
resourcegroupstaggingapi untag-resources |
--resource-arn-list ARN ... |
マップ形 |
--tags の書き方は2種類あります。
| 形 | 書き方 | JSON で書くと |
|---|---|---|
| リスト形 | --tags Key=Env,Value=prod Key=Project,Value=shop |
[{"Key":"Env","Value":"prod"},{"Key":"Project","Value":"shop"}] |
| マップ形 | --tags Env=prod,Project=shop |
{"Env":"prod","Project":"shop"} |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWSタグの付け方|AWS CLIでタグ付け・検索・一覧取得と命名ルール」
タグの基本ルールと上限
公式ドキュメント(Tagging AWS resources のベストプラクティス)で確認した共通のルールです。
| 項目 | 上限・ルール |
|---|---|
| 1リソースあたりのタグ数 | ユーザーが付けるタグは50個まで(aws: で始まるタグは数に含めない) |
| キーの長さ | 1〜128文字(UTF-8 の Unicode 文字) |
| 値の長さ | 0〜256文字(空の値も可) |
| 使える文字 | 文字、数字、空白と、_ . : / = + - @(サービスによって違いがある) |
| 大文字と小文字 | 区別される。Env と env は別のキー |
| キーの重複 | 1リソースにつき同じキーは1つだけ。同じキーで付け直すと値が上書きされる |
aws: で始まるキー |
AWS が使う予約済みの接頭辞。編集も削除もできない |
| 書いてよい内容 | 個人を特定できる情報や機密情報は入れない |
大文字と小文字が区別されることは、手元でも確かめられます。
$ aws ec2 create-tags --resources i-e55ad0fe52e456b92 --tags Key=env,Value=prod Key=Env,Value=dev Key=Memo,Value=
$ aws ec2 describe-tags --filters Name=resource-id,Values=i-e55ad0fe52e456b92 --query 'Tags[].[Key,Value]' --output text
env prod
Env dev
Memo
env と Env が別々のタグとして登録され、Memo は値が空のタグになりました。表記がそろっていないと、検索やコスト集計で別のタグとして数えられます。 命名ルールを先に決めておくことが大切です(後述)。
EC2:タグを付ける・確認する・外す
付ける(create-tags)
--resources に ID を複数並べると、インスタンスとボリュームのように種類の違うリソースにも1回でまとめて付けられます。
$ aws ec2 create-tags --resources i-da0ee0aaf52d8284e vol-948f81833904581f5 \
--tags Key=Env,Value=prod Key=Project,Value=shop Key=Owner,Value=team-web
$ aws ec2 create-tags --resources i-a7050b2ba7e73da43 --tags Key=Env,Value=dev Key=Project,Value=shop
成功すると何も出力されません。値に空白を含むときは全体を引用符で囲み、カンマや等号を含むときは JSON で書きます。
$ aws ec2 create-tags --resources i-da0ee0aaf52d8284e --tags 'Key=Name,Value=web 01'
$ aws ec2 create-tags --resources i-da0ee0aaf52d8284e --tags '[{"Key":"Note","Value":"a,b=c"}]'
確認する(describe-tags)
$ aws ec2 describe-tags --filters Name=resource-id,Values=i-da0ee0aaf52d8284e --query 'Tags[].[Key,Value]' --output text
Env prod
Project shop
Owner team-web
Name web 01
Note a,b=c
--query を外すと、リソースの種類も含む JSON で返ります(一部を抜粋)。
$ aws ec2 describe-tags --filters Name=resource-id,Values=i-da0ee0aaf52d8284e
{
"Tags": [
{
"Key": "Env",
"ResourceId": "i-da0ee0aaf52d8284e",
"ResourceType": "instance",
"Value": "prod"
},
…(省略)…
]
}
値を変える
同じキーで create-tags を実行すると、値が上書きされます。ほかのタグはそのまま残ります。
$ aws ec2 create-tags --resources i-da0ee0aaf52d8284e --tags Key=Env,Value=stg
$ aws ec2 describe-tags --filters Name=resource-id,Values=i-da0ee0aaf52d8284e Name=key,Values=Env --query 'Tags[].Value' --output text
stg
外す(delete-tags)
$ aws ec2 delete-tags --resources i-da0ee0aaf52d8284e --tags Key=Note
$ aws ec2 delete-tags --resources i-da0ee0aaf52d8284e --tags Key=Owner,Value=someone-else
$ aws ec2 describe-tags --filters Name=resource-id,Values=i-da0ee0aaf52d8284e --query 'Tags[].[Key,Value]' --output text
Env prod
Project shop
Owner team-web
Name web 01
Key=Note はキーだけの指定なので削除されました。一方、Key=Owner,Value=someone-else は値が一致しなかったので削除されず、Owner が残っています。公式リファレンスでは次のように説明されています。
--tags の指定 |
動き |
|---|---|
Key=Note |
値に関係なく、そのキーのタグを削除する |
Key=Owner,Value=team-web |
キーと値の両方が一致したときだけ削除する |
Key=Memo,Value= |
値が空文字のタグだけを削除する |
--tags を省略 |
そのリソースのユーザー定義タグをすべて削除する(aws: で始まるタグは残る) |
--tags を省くと全部のタグが対象になるので、外すキーは必ず明示します。
作成と同時に付ける(--tag-specifications)
作ってから付けるより、作成時に付けるほうが、タグの付け漏れを防げます。
$ aws ec2 run-instances --image-id ami-03cf127a --instance-type t3.micro \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Env,Value=prod},{Key=Project,Value=blog}]' \
'ResourceType=volume,Tags=[{Key=Env,Value=prod}]' \
--query 'Instances[0].Tags'
[
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "blog"
}
]
ほかのサービスも、作成コマンドに --tags を付けられるものが多くあります。
| サービス | 作成時にタグを付ける例 |
|---|---|
| Lambda | aws lambda create-function ... --tags Env=prod,Project=shop |
| RDS | aws rds create-db-instance ... --tags Key=Env,Value=prod |
| SNS | aws sns create-topic --name 名前 --tags Key=Env,Value=prod |
| SSM パラメータ | aws ssm put-parameter --name 名前 --value 値 --type String --tags Key=Env,Value=prod |
| Secrets Manager | aws secretsmanager create-secret --name 名前 --secret-string 値 --tags Key=Env,Value=prod |
| CloudWatch アラーム | aws cloudwatch put-metric-alarm ... --tags Key=Env,Value=prod |
S3:put-bucket-tagging は既存のタグを全置換する
S3 のバケットタグは、ほかのサービスと動きが違います。put-bucket-tagging は「追加」ではなく「置き換え」です。
$ aws s3api get-bucket-tagging --bucket rjc-tag-demo
An error occurred (NoSuchTagSet) when calling the GetBucketTagging operation: The TagSet does not exist
$ aws s3api put-bucket-tagging --bucket rjc-tag-demo --tagging 'TagSet=[{Key=Env,Value=prod},{Key=Project,Value=shop}]'
$ aws s3api get-bucket-tagging --bucket rjc-tag-demo
{
"TagSet": [
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "shop"
}
]
}
タグが1つも無いバケットでは、get-bucket-tagging が NoSuchTagSet を返します。ここに Owner を足すつもりで、Owner だけを指定して実行します。
$ aws s3api put-bucket-tagging --bucket rjc-tag-demo --tagging 'TagSet=[{Key=Owner,Value=team-web}]'
$ aws s3api get-bucket-tagging --bucket rjc-tag-demo
{
"TagSet": [
{
"Key": "Owner",
"Value": "team-web"
}
]
}
Env と Project が消え、Owner だけになりました。 公式リファレンスにも「バケットにすでにあるタグを上書きする。既存のタグの一覧に追加する用途には使えない」と書かれています。
既存のタグを残して追加する書き方
いまのタグを読み、追加分と合成してから書き戻します。次のスクリプトは jq でキーごとにまとめ、同じキーがあれば追加分の値を優先します。
merge_bucket_tags.sh:
BUCKET=rjc-tag-demo
CURRENT=$(aws s3api get-bucket-tagging --bucket "$BUCKET" --query 'TagSet' --output json 2>/dev/null || echo '[]')
MERGED=$(jq -c --argjson add '[{"Key":"Env","Value":"prod"},{"Key":"Project","Value":"shop"}]' \
'{TagSet: ((. + $add) | group_by(.Key) | map(last))}' <<<"$CURRENT")
echo "$MERGED"
aws s3api put-bucket-tagging --bucket "$BUCKET" --tagging "$MERGED"
$ bash merge_bucket_tags.sh
{"TagSet":[{"Key":"Env","Value":"prod"},{"Key":"Owner","Value":"team-web"},{"Key":"Project","Value":"shop"}]}
$ aws s3api get-bucket-tagging --bucket rjc-tag-demo --query 'TagSet[].[Key,Value]' --output text
Env prod
Owner team-web
Project shop
Owner を残したまま Env と Project が加わりました。タグが無いバケットでは get-bucket-tagging がエラーを返すので、|| echo '[]' で空の配列に置き換えています。
オブジェクト単位のタグも同じ形で扱えます。
$ aws s3api put-object-tagging --bucket rjc-tag-demo --key a.txt --tagging 'TagSet=[{Key=Class,Value=public}]'
$ aws s3api get-object-tagging --bucket rjc-tag-demo --key a.txt --query 'TagSet[].[Key,Value]' --output text
Class public
Lambda・DynamoDB・RDS・IAM:コマンドと引数の違い
Lambda(マップ形・ARN 指定)
$ aws lambda tag-resource --resource arn:aws:lambda:ap-northeast-1:123456789012:function:resize \
--tags Owner=team-web,CostCenter=cc-1001
$ aws lambda list-tags --resource arn:aws:lambda:ap-northeast-1:123456789012:function:resize
{
"Tags": {
"Env": "prod",
"Project": "shop",
"Owner": "team-web",
"CostCenter": "cc-1001"
}
}
$ aws lambda untag-resource --resource arn:aws:lambda:ap-northeast-1:123456789012:function:resize --tag-keys CostCenter
Env と Project は、関数の作成時に --tags Env=prod,Project=shop で付けたものです。tag-resource は追加の動きなので、既存のタグは残ります。
DynamoDB(リスト形・ARN 指定)
$ aws dynamodb tag-resource --resource-arn arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders \
--tags Key=Env,Value=prod Key=Project,Value=shop
$ aws dynamodb list-tags-of-resource --resource-arn arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders
{
"Tags": [
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "shop"
}
]
}
$ aws dynamodb untag-resource --resource-arn arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders --tag-keys Project
RDS(リスト形・--resource-name に ARN)
$ aws rds add-tags-to-resource --resource-name arn:aws:rds:ap-northeast-1:123456789012:db:shop-db \
--tags Key=Project,Value=shop Key=Owner,Value=team-web
$ aws rds list-tags-for-resource --resource-name arn:aws:rds:ap-northeast-1:123456789012:db:shop-db
{
"TagList": [
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "shop"
},
{
"Key": "Owner",
"Value": "team-web"
}
]
}
$ aws rds remove-tags-from-resource --resource-name arn:aws:rds:ap-northeast-1:123456789012:db:shop-db --tag-keys Owner
RDS は、オプション名が --resource-name でも渡すのは ARN です。応答のキー名も Tags ではなく TagList になります。
IAM(リスト形・名前指定)
$ aws iam tag-role --role-name tag-role --tags Key=Env,Value=prod Key=Project,Value=shop
$ aws iam list-role-tags --role-name tag-role
{
"Tags": [
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "shop"
}
]
}
$ aws iam untag-role --role-name tag-role --tag-keys Project
$ aws iam list-role-tags --role-name tag-role --query 'Tags[].[Key,Value]' --output text
Env prod
IAM は ARN ではなく名前で指定し、ロールとユーザーでコマンドが分かれています(tag-role / tag-user)。
リスト形とマップ形を取り違えるとどうなるか
リスト形のサービスにマップ形で書くと、送信前の検査で止まります。
$ aws dynamodb tag-resource --resource-arn arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders --tags Env=prod
Parameter validation failed:
Missing required parameter in Tags[0]: "Key"
Missing required parameter in Tags[0]: "Value"
Unknown parameter in Tags[0]: "Env", must be one of: Key, Value
逆に、マップ形のサービスにリスト形で書くと、エラーにならずに意図と違うタグが付きます。
$ aws lambda tag-resource --resource arn:aws:lambda:ap-northeast-1:123456789012:function:resize --tags Key=Env,Value=prod
$ aws lambda list-tags --resource arn:aws:lambda:ap-northeast-1:123456789012:function:resize --query Tags
{
"Env": "prod",
"Project": "shop",
"Owner": "team-web",
"Key": "Env",
"Value": "prod"
}
Key というキーに Env、Value というキーに prod という2つのタグが付きました。Lambda・SQS・CloudWatch Logs・Resource Groups Tagging API はマップ形なので、キー=値,キー=値 で書きます。付けたあとは必ず確認コマンドで結果を見ておくと安心です。
タグでリソースを検索する
方法1:サービスのコマンドに --filters を付ける
EC2 の describe 系コマンドは、Name=tag:キー,Values=値 でタグによる絞り込みができます。
$ aws ec2 describe-instances --filters "Name=tag:Env,Values=prod" \
--query 'Reservations[].Instances[].InstanceId' --output text
i-da0ee0aaf52d8284e i-b006b2173fbe1f1aa
$ aws ec2 describe-instances --filters "Name=tag:Env,Values=prod,stg" "Name=tag:Project,Values=shop" \
--query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Env`]|[0].Value,Tags[?Key==`Project`]|[0].Value]' --output text
i-da0ee0aaf52d8284e prod shop
$ aws ec2 describe-volumes --filters Name=tag:Env,Values=prod --query 'Volumes[].VolumeId' --output text
vol-948f81833904581f5 vol-8f5c58c1238d67cd1
| フィルターの書き方 | 意味 |
|---|---|
Name=tag:Env,Values=prod |
Env が prod のもの |
Name=tag:Env,Values=prod,stg |
Env が prod または stg(同じフィルター内の値は OR) |
| フィルターを2つ並べる | 両方を満たすもの(フィルター同士は AND) |
Name=tag-key,Values=Owner |
Owner というキーが付いているもの(値は問わない) |
Name=tag:Project,Values=sh* |
値が sh で始まるもの(ワイルドカード) |
$ aws ec2 describe-instances --filters "Name=tag-key,Values=Owner" --query 'Reservations[].Instances[].InstanceId' --output text
i-da0ee0aaf52d8284e
$ aws ec2 describe-instances --filters "Name=tag:Project,Values=sh*" --query 'Reservations[].Instances[].InstanceId' --output text
i-da0ee0aaf52d8284e i-a7050b2ba7e73da43
あるキーが付いた EC2 リソースを種類をまたいで見たいときは、describe-tags が使えます。
$ aws ec2 describe-tags --filters Name=key,Values=Env --query 'Tags[].[ResourceType,ResourceId,Value]' --output text
instance i-da0ee0aaf52d8284e prod
volume vol-948f81833904581f5 prod
instance i-a7050b2ba7e73da43 dev
instance i-b006b2173fbe1f1aa prod
volume vol-8f5c58c1238d67cd1 prod
方法2:resourcegroupstaggingapi get-resources でサービスを横断する
Resource Groups Tagging API を使うと、サービスをまたいで、同じタグが付いたリソースの ARN を1回で取得できます。
$ aws resourcegroupstaggingapi get-resources --tag-filters Key=Env,Values=prod \
--query 'ResourceTagMappingList[].ResourceARN'
[
"arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders",
"arn:aws:sqs:ap-northeast-1:123456789012:tagq",
"arn:aws:logs:ap-northeast-1:123456789012:log-group:/app/tag",
"arn:aws:cloudwatch:ap-northeast-1:123456789012:alarm:tag-alarm",
"arn:aws:s3:::rjc-tag-demo",
"arn:aws:ssm:ap-northeast-1:123456789012:parameter/shop/key",
"arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:shop/key-lvIDxJ",
"arn:aws:sns:ap-northeast-1:123456789012:tagt",
"arn:aws:ec2:ap-northeast-1:123456789012:instance/i-da0ee0aaf52d8284e",
"arn:aws:ec2:ap-northeast-1:123456789012:instance/i-b006b2173fbe1f1aa",
"arn:aws:ec2:ap-northeast-1:123456789012:volume/vol-948f81833904581f5",
"arn:aws:ec2:ap-northeast-1:123456789012:volume/vol-8f5c58c1238d67cd1",
"arn:aws:lambda:ap-northeast-1:123456789012:function:resize",
"arn:aws:rds:ap-northeast-1:123456789012:db:shop-db"
]
リソースの種類で絞るときは --resource-type-filters を足します。応答には、そのリソースのタグがすべて含まれます(一部を抜粋)。
$ aws resourcegroupstaggingapi get-resources --tag-filters Key=Env,Values=prod,dev --resource-type-filters ec2:instance
{
"ResourceTagMappingList": [
{
"ResourceARN": "arn:aws:ec2:ap-northeast-1:123456789012:instance/i-da0ee0aaf52d8284e",
"Tags": [
{
"Key": "Env",
"Value": "prod"
},
{
"Key": "Project",
"Value": "shop"
},
…(省略)…
| オプション | 書き方 | 補足(公式リファレンスより) |
|---|---|---|
--tag-filters |
Key=Env,Values=prod,dev |
同じキーの値は OR、フィルター同士は AND。キーは50個まで、1キーの値は20個まで |
--tag-filters(キーのみ) |
Key=Project |
値を問わず、そのキーが付いたリソース |
--resource-type-filters |
ec2:instance s3 dynamodb |
サービス または サービス:リソース種別 |
--resources-per-page |
--resources-per-page 50 |
1ページの件数 |
get-resources が返すのは、指定したリージョンにある「タグが付いている、または以前付いていた」リソースです。別のリージョンを調べるときは --region を変えて実行します。
| 比べる点 | サービスの --filters |
get-resources |
|---|---|---|
| 対象 | そのサービスのリソース | 対応する複数のサービス |
| 返る内容 | リソースの詳細(状態、種類など) | ARN とタグ |
| 向いている使い方 | 状態と組み合わせた絞り込み、運用スクリプト | タグの棚卸し、横断の一覧 |
| 一度もタグを付けていないリソース | 取得できる | 対象外 |
タグなしリソースを洗い出すワンライナー
タグが付いていないリソースは --filters では探せないので、--query で「そのキーが無いもの」を選びます。
$ aws ec2 describe-instances \
--query 'Reservations[].Instances[?!not_null(Tags[?Key==`Env`].Value | [0])][].InstanceId' --output text
i-218af039af55059e1
not_null のかっこの中は Env タグの値を取り出す式で、タグが無ければ null になります。先頭の ! で反転させ、「値が無いもの」だけを残しています。タグが1つも付いていないインスタンスだけを探すなら、もっと短く書けます。
$ aws ec2 describe-instances --query 'Reservations[].Instances[?!Tags][].InstanceId' --output text
i-218af039af55059e1
必須にしたいタグを列に並べると、どこが欠けているかが一目で分かります。
$ aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Id:InstanceId,Env:Tags[?Key==`Env`]|[0].Value,Project:Tags[?Key==`Project`]|[0].Value,Owner:Tags[?Key==`Owner`]|[0].Value}' \
--output table
--------------------------------------------------------
| DescribeInstances |
+------+-----------------------+-----------+-----------+
| Env | Id | Owner | Project |
+------+-----------------------+-----------+-----------+
| prod| i-da0ee0aaf52d8284e | team-web | shop |
| dev | i-a7050b2ba7e73da43 | None | shop |
| None| i-218af039af55059e1 | None | None |
| prod| i-b006b2173fbe1f1aa | None | blog |
+------+-----------------------+-----------+-----------+
None と表示された欄が、タグが付いていない箇所です。
複数サービスにまとめて付ける(tag-resources)
Resource Groups Tagging API の tag-resources は、ARN を並べて同じタグを一度に付けられます。
$ aws resourcegroupstaggingapi tag-resources \
--resource-arn-list arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders \
arn:aws:lambda:ap-northeast-1:123456789012:function:resize \
--tags Release=2026-10
{
"FailedResourcesMap": {}
}
$ aws dynamodb list-tags-of-resource --resource-arn arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders \
--query 'Tags[].[Key,Value]' --output text
Env prod
Release 2026-10
FailedResourcesMap が空なら、すべてのリソースに付いています。 付けられなかったリソースがあると、ARN ごとにエラーコードとメッセージが入ります。公式リファレンスによる注意点は次のとおりです。
| 項目 | 内容 |
|---|---|
| 1回で指定できるリソース数 | 20個まで |
| 対象のリージョン | 指定したリージョンのリソースだけ |
| 必要な権限 | tag:TagResources に加えて、各サービスのタグ付け権限(EC2 なら ec2:CreateTags) |
| 対応サービス | すべてのリソースが対応しているわけではない |
外すときは untag-resources --resource-arn-list ARN ... --tag-keys Release です。
タグの命名ルールとキー設計
命名ルールの決め方
公式のベストプラクティスでは、次の点が挙げられています。
- 大文字・小文字の書き方を1つに決め、すべてのリソースで同じにする(
CostCenterとcostcenterを混ぜない)。 - 小文字とハイフンで区切る書き方や、
組織名:のような接頭辞を付けて自分たちのタグだと分かるようにする書き方(例:anycompany:cost-center)が紹介されている。 - 個人を特定できる情報や機密情報をタグに入れない。
- タグは少なすぎるより、多めに付けておく。
どの書き方を選んでも、決めたルールを全員が同じように使うことがいちばんの要点です。
| 決めること | 例A(パスカルケース) | 例B(小文字とハイフン+接頭辞) |
|---|---|---|
| キーの書き方 | CostCenter |
acme:cost-center |
| 値の書き方 | 小文字とハイフン(team-web) |
小文字とハイフン(team-web) |
| 環境の値 | prod / stg / dev の3つに固定 |
同じ |
| 日付の値 | 2026-10-05(ISO 8601) |
同じ |
| 値が無いとき | タグ自体を付けない | 同じ |
コスト配分タグ向けのキー設計例
「どの費用を、どの切り口で分けて見たいか」から逆算してキーを決めます。
| キー | 目的 | 値の例 | 必須 |
|---|---|---|---|
Project |
システムやサービスごとに費用を分ける | shop blog |
必須 |
Env |
本番と検証の費用を分ける | prod stg dev |
必須 |
Owner |
問い合わせ先のチームを示す | team-web |
必須 |
CostCenter |
費用を負担する部門のコードで分ける | cc-1001 |
必須 |
Service |
システム内の役割で分ける | api batch web |
任意 |
ManagedBy |
作成手段を示す | terraform cli console |
任意 |
Name |
コンソールでの表示名 | shop-prod-web-01 |
任意 |
値の種類が増え続けるもの(日時、ユーザー ID など)をコスト配分用のキーに使うと、集計の行が細かく分かれます。費用を分けたい切り口だけに絞るのがこつです。
コスト配分タグを有効にする
リソースにタグを付けただけでは、請求の集計には使われません。公式ドキュメントで確認した手順と注意点です。
| 項目 | 内容 |
|---|---|
| 有効化の場所 | Billing and Cost Management コンソールの「Cost allocation tags」で、キーを選んで Activate |
| 操作できるアカウント | 組織の管理アカウント、または組織に属さない単独のアカウント |
| キーが一覧に出るまで | タグをリソースに付けてから最大24時間 |
| 有効になるまで | Activate してから最大24時間 |
| さかのぼっての適用 | されない。タグを付ける前に作られたリソースには適用されない |
| レポートでの表示 | ユーザー定義のタグは user: の接頭辞が付く |
CLI で有効にする場合は、Cost Explorer の update-cost-allocation-tags-status を使います。公式リファレンスの書式は次のとおりで、1回に20個までまとめて指定できます。
aws ce update-cost-allocation-tags-status \
--cost-allocation-tags-status TagKey=CostCenter,Status=Active TagKey=Project,Status=Active
有効化はさかのぼって適用されないので、キーの設計とタグ付けは早い段階で済ませておくと、あとから集計できる期間が長くなります。
エラー文と直し方(実際の出力)
タグが50個を超えた
$ aws ec2 create-tags --resources i-218af039af55059e1 --tags Key=k0,Value=v Key=k1,Value=v …(51個)…
An error occurred (TagLimitExceeded) when calling the CreateTags operation: The maximum number of Tags for a resource has been reached.
IAM ロールでは、同じ内容が別のメッセージで返ります。
$ aws iam tag-role --role-name tag-role --tags Key=k0,Value=v Key=k1,Value=v …(51個)…
An error occurred (ValidationError) when calling the TagRole operation: 1 validation error detected: Value '[…(省略)…]' at 'tags' failed to satisfy constraint: Member must have length less than or equal to 50.
aws: で始まるキーを付けようとした
$ aws s3api put-bucket-tagging --bucket rjc-tag-demo --tagging 'TagSet=[{Key=aws:test,Value=x}]'
An error occurred (InvalidTag) when calling the PutBucketTagging operation: System tags cannot be added/updated by requester
エラーの早見表
| メッセージ | 原因 | 直し方 |
|---|---|---|
Unknown parameter in Tags[0]: "Env", must be one of: Key, Value |
リスト形のサービスにマップ形で書いた | Key=Env,Value=prod に直す |
TagLimitExceeded |
1リソース50個の上限を超えた | 使っていないタグを外す。キーを整理する |
ValidationError ... Member must have length less than or equal to 50 |
同上(IAM) | 同上 |
InvalidTag ... System tags cannot be added/updated by requester |
aws: で始まるキーを指定した |
別の接頭辞にする |
NoSuchTagSet ... The TagSet does not exist |
バケットにタグが1つも無い | 異常ではない。空として扱う |
エラーは出ないが Key Value というタグが付いた |
マップ形のサービスにリスト形で書いた | Env=prod の形に直し、余分なタグを外す |
boto3 で複数サービスに一括付与する
共通タグを EC2・S3・DynamoDB にまとめて付け、最後にタグで横断検索して確かめるスクリプトです。S3 は全置換なので、既存のタグを読んで合成してから書き戻しています。
tag_bulk.py:
"""共通タグを複数サービスのリソースへまとめて付ける。
使い方: python3 tag_bulk.py
"""
import boto3
from botocore.exceptions import ClientError
REGION = "ap-northeast-1"
COMMON = {"Project": "shop", "Env": "prod", "Owner": "team-web", "CostCenter": "cc-1001"}
ec2 = boto3.client("ec2", region_name=REGION)
s3 = boto3.client("s3", region_name=REGION)
ddb = boto3.client("dynamodb", region_name=REGION)
tagging = boto3.client("resourcegroupstaggingapi", region_name=REGION)
as_list = [{"Key": k, "Value": v} for k, v in COMMON.items()]
# 1. EC2: Env タグが無いインスタンスを探して、1回の呼び出しでまとめて付ける
ids = [
i["InstanceId"]
for page in ec2.get_paginator("describe_instances").paginate()
for r in page["Reservations"]
for i in r["Instances"]
if "Env" not in {t["Key"] for t in i.get("Tags", [])}
]
if ids:
ec2.create_tags(Resources=ids, Tags=as_list)
print("ec2 tagged:", ids)
# 2. S3: 全置換なので、既存タグを読んでから合成して書き戻す
def merge_bucket_tags(bucket: str, new_tags: dict) -> dict:
try:
current = {t["Key"]: t["Value"] for t in s3.get_bucket_tagging(Bucket=bucket)["TagSet"]}
except ClientError as e:
if e.response["Error"]["Code"] != "NoSuchTagSet":
raise
current = {}
merged = {**current, **new_tags}
s3.put_bucket_tagging(
Bucket=bucket,
Tagging={"TagSet": [{"Key": k, "Value": v} for k, v in merged.items()]},
)
return merged
print("s3 merged:", merge_bucket_tags("rjc-tag-demo", COMMON))
# 3. DynamoDB: ARN を指定して追加(既存タグは残る)
arn = ddb.describe_table(TableName="Orders")["Table"]["TableArn"]
ddb.tag_resource(ResourceArn=arn, Tags=as_list)
print("dynamodb tagged:", arn)
# 4. 結果をタグで横断検索して確かめる
found = []
for page in tagging.get_paginator("get_resources").paginate(
TagFilters=[{"Key": "Project", "Values": ["shop"]}, {"Key": "Env", "Values": ["prod"]}]
):
found += [m["ResourceARN"] for m in page["ResourceTagMappingList"]]
print(f"found {len(found)} resources")
for arn in sorted(found):
print(" ", arn)
$ python3 tag_bulk.py
ec2 tagged: ['i-218af039af55059e1']
s3 merged: {'Env': 'prod', 'Owner': 'team-web', 'Project': 'shop', 'CostCenter': 'cc-1001'}
dynamodb tagged: arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders
found 9 resources
arn:aws:dynamodb:ap-northeast-1:123456789012:table/Orders
arn:aws:ec2:ap-northeast-1:123456789012:instance/i-218af039af55059e1
arn:aws:ec2:ap-northeast-1:123456789012:instance/i-da0ee0aaf52d8284e
arn:aws:ec2:ap-northeast-1:123456789012:volume/vol-948f81833904581f5
arn:aws:lambda:ap-northeast-1:123456789012:function:resize
arn:aws:rds:ap-northeast-1:123456789012:db:shop-db
arn:aws:s3:::rjc-tag-demo
arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:shop/key-lvIDxJ
arn:aws:ssm:ap-northeast-1:123456789012:parameter/shop/key
タグが付いていなかったインスタンス(i-218af039af55059e1)に共通タグが付き、S3 は既存の Owner を残したまま4つのタグがそろいました。boto3 でも、EC2 と DynamoDB はリスト形、S3 は TagSet で包む形と、CLI と同じ違いがあります。
タグ運用のチェックリスト
| 確認すること | 方法 |
|---|---|
| キーの書き方(大文字・小文字、区切り)を決めた | 命名ルールの表を1枚作る |
| 必須のキーを決めた | Project Env Owner CostCenter など |
| 作成時にタグを付けている | --tag-specifications や作成コマンドの --tags |
| タグなしのリソースを定期的に洗い出している | --query のワンライナー、または boto3 のスクリプト |
| S3 バケットは読んでから合成して書いている | get-bucket-tagging → 合成 → put-bucket-tagging |
| 付けたあとに確認コマンドで結果を見ている | サービス別の「確認する」コマンド |
| コスト配分タグを有効にした | Billing and Cost Management コンソール、または aws ce update-cost-allocation-tags-status |
よくある質問
Q. すでにあるタグの値を変えるには?
A. 同じキーでもう一度付けます。EC2 の create-tags や Lambda の tag-resource で試すと、同じキーの値が上書きされ、ほかのタグは残りました。S3 の put-bucket-tagging だけは全体を置き換えるので、既存のタグも一緒に指定します。
Q. タグが付いていないリソースを探すには?
A. --filters は「付いているもの」を探すオプションなので、--query を使います。EC2 なら Reservations[].Instances[?!Tags][].InstanceId でタグが1つも無いインスタンス、!not_null(...) を使った式で特定のキーが無いインスタンスを取り出せます。
Q. create-tags と tag-resource のどちらを使えばよいですか?
A. サービスによって決まっています。EC2 は create-tags、Lambda・DynamoDB・SNS などは tag-resource、RDS と SSM は add-tags-to-resource、S3 は put-bucket-tagging です。冒頭の早見表で、サービスの行を確認してください。
Q. タグを付けたのに、コストの画面に出てきません。 A. コスト配分タグとして有効にする操作が別に必要です。公式ドキュメントによると、キーが一覧に現れるまで最大24時間、有効にしてから反映されるまでさらに最大24時間かかります。有効にする前の期間にはさかのぼって適用されません。
まとめ
- タグ付けコマンドはサービスごとに違う。EC2 は
create-tags、S3 はput-bucket-tagging、Lambda・DynamoDB はtag-resource、RDS はadd-tags-to-resource、IAM はtag-role。 --tagsにはリスト形(Key=Env,Value=prod)とマップ形(Env=prod)がある。取り違えると、エラーになるか、意図と違うタグが付く。- S3 の
put-bucket-taggingは全置換。既存のタグを読んで合成してから書き戻す。 - 検索は2通り。サービス内は
--filters "Name=tag:Env,Values=prod"、サービス横断はresourcegroupstaggingapi get-resources。 - タグなしのリソースは
--queryで洗い出す。?!Tagsや!not_null(...)を使う。 - キーは大文字・小文字まで区別される。命名ルールを先に決め、全員で同じ書き方にする。
- コスト配分タグは有効化が必要で、さかのぼって適用されない。早めに設計して付けておく。
参考・出典
- AWS Resource Groups とタグ:Best practices and strategies
- AWS CLI コマンドリファレンス:ec2 delete-tags
- AWS CLI コマンドリファレンス:s3api put-bucket-tagging
- AWS CLI コマンドリファレンス:resourcegroupstaggingapi get-resources
- AWS CLI コマンドリファレンス:resourcegroupstaggingapi tag-resources
- AWS Billing ユーザーガイド:Using user-defined cost allocation tags
- AWS Billing ユーザーガイド:Activating user-defined cost allocation tags
- AWS CLI コマンドリファレンス:ce update-cost-allocation-tags-status
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「AWSタグの付け方|AWS CLIでタグ付け・検索・一覧取得と命名ルール」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。