- AWS
IAMアクセスキーの作成・確認・ローテーション手順 CLI版
IAMアクセスキーのローテーションとは、「新しいキーを作る → アプリを新しいキーに切り替える → 以前のキーを無効化する → 使われていないことを確かめて削除する」という順で、キーを入れ替えることです。アクセスキーは、アクセスキー ID とシークレットアクセスキーの2つからなる、プログラム用の認証情報です。
この記事では、この入れ替えを AWS CLI だけで行う手順を、コマンドと JSON 出力つきで1本につなげて紹介します。後半では、全ユーザーのキーを作成日・状態・最終使用日つきで一覧にし、作成から 90 日を超えたものだけを抜き出すワンライナーと boto3 スクリプトも載せます。
確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11、boto3 1.43。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しました。掲載するコマンドは、接続先の指定を外して、AWS でそのまま使える形にしています。出力のシークレットアクセスキーは途中から省略しています。
アクセスキー操作の早見表
| やりたいこと | コマンド |
|---|---|
| キーを一覧する | aws iam list-access-keys --user-name app-batch |
| キーを作る | aws iam create-access-key --user-name app-batch |
| 最終使用日を見る | aws iam get-access-key-last-used --access-key-id AKIA... |
| 無効化する | aws iam update-access-key --user-name app-batch --access-key-id AKIA... --status Inactive |
| 有効に戻す | aws iam update-access-key --user-name app-batch --access-key-id AKIA... --status Active |
| 削除する | aws iam delete-access-key --user-name app-batch --access-key-id AKIA... |
| いま誰として接続しているか | aws sts get-caller-identity |
| 自分のキーを一覧する | aws iam list-access-keys(--user-name を省く) |
| 覚えておきたい決まり | 内容 |
|---|---|
| キーの本数 | 1ユーザーにつき2本まで(無効化したキーも数に入る) |
| シークレットアクセスキー | 見られるのは作成時の1回だけ。控えそこねたら、そのキーを削除して作り直す |
| 無効化と削除 | 無効化は Active に戻せる。削除したキーは一覧にも最終使用日の照会にも出なくなる |
| 入れ替えの目安 | AWS Security Hub のコントロール IAM.3 は 90 日以内の入れ替えを推奨 |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IAMアクセスキーの作成・確認・ローテーション手順 CLI版」
ローテーションの全体像
2本まで持てるという決まりを使い、新旧2本が並んで使える期間を作ってから切り替えるのがポイントです。こうすると、アプリを止めずに入れ替えられます。
flowchart LR
A[1. 一覧で現状確認<br>list-access-keys] --> B[2. 新しいキーを作成<br>create-access-key]
B --> C[3. アプリを切り替え<br>get-caller-identity で確認]
C --> D[4. 最終使用日を確認<br>get-access-key-last-used]
D --> E[5. 以前のキーを無効化<br>update-access-key]
E --> F[6. 削除<br>delete-access-key]
以降では、app-batch というユーザーのキーを入れ替えます。コマンドを打つのは、IAM を操作できる管理用のユーザーです。
手順1:いまのキーを確認する(list-access-keys)
aws iam list-access-keys --user-name app-batch
{
"AccessKeyMetadata": [
{
"UserName": "app-batch",
"AccessKeyId": "AKIARZPUZDIKATDFQ5FO",
"Status": "Active",
"CreateDate": "2026-03-19T06:12:47Z"
}
]
}
キーは1本で、作成日は 2026-03-19 です。一覧に出るのはアクセスキー ID・状態・作成日だけで、シークレットアクセスキーは出ません。
--user-name を省くと、コマンドを打っている本人のキーが返ります。
手順2:新しいキーを作る(create-access-key)
aws iam create-access-key --user-name app-batch
{
"AccessKey": {
"UserName": "app-batch",
"AccessKeyId": "AKIARZPUZDIKH2DHJWI4",
"Status": "Active",
"SecretAccessKey": "SzkK9QBawnDa…(省略)",
"CreateDate": "2026-10-05T06:12:52Z"
}
}
SecretAccessKey が表示されるのは、このときだけです。画面に流したままにせず、シークレットを保管するしくみ(AWS Secrets Manager、Systems Manager パラメータストア、CI のシークレット機能など)へすぐ登録します。
ファイルに受けてから取り出す形にしておくと、端末の履歴や画面に残りにくくなります。
aws iam create-access-key --user-name app-batch > newkey.json
NEW_ID=$(python3 -c "import json;print(json.load(open('newkey.json'))['AccessKey']['AccessKeyId'])")
NEW_SEC=$(python3 -c "import json;print(json.load(open('newkey.json'))['AccessKey']['SecretAccessKey'])")
登録が済んだら newkey.json は削除します。
手順3:アプリを新しいキーに切り替えて確かめる
切り替え先はアプリによって異なりますが、ここでは AWS CLI の profile に新しいキーを書き込み、そのキーで誰として接続できるかを確かめます。
aws configure set aws_access_key_id "$NEW_ID" --profile app-batch
aws configure set aws_secret_access_key "$NEW_SEC" --profile app-batch
aws sts get-caller-identity --profile app-batch
{
"UserId": "o3lc9r2j5h3ufxrl8tge",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/app-batch"
}
Arn が app-batch になっていれば、新しいキーで接続できています。get-caller-identity は権限を付けていなくても呼べるので、キーの確認に向いています。
手順4:最終使用日を確かめる(get-access-key-last-used)
新しいキーの最終使用日を見ます。
aws iam get-access-key-last-used --access-key-id AKIARZPUZDIKH2DHJWI4
{
"UserName": "app-batch",
"AccessKeyLastUsed": {
"LastUsedDate": "2026-10-05T06:12:54Z",
"ServiceName": "sts",
"Region": "ap-northeast-1"
}
}
手順3 の呼び出し(sts)が記録されました。続けて、以前のキーも見ます。
aws iam get-access-key-last-used --access-key-id AKIARZPUZDIKATDFQ5FO
{
"UserName": "app-batch",
"AccessKeyLastUsed": {
"LastUsedDate": "2026-10-02T03:12:47Z",
"ServiceName": "s3",
"Region": "ap-northeast-1"
}
}
以前のキーは、3日前に S3 で使われたのが最後です。切り替えのあと、以前のキーの LastUsedDate が進まなくなれば、すべての利用元が新しいキーへ移ったと判断できます。AWS のユーザーガイドでも、数日待ってから以前のキーの使用状況を確かめる方法が紹介されています。
ServiceName と Region が分かるので、日付が進んでしまったときは「どのサービスを、どのリージョンで呼んでいる処理が残っているか」を手がかりに、切り替え漏れを探せます。
一度も使われていないキーの表示
{
"UserName": "report-job",
"AccessKeyLastUsed": {
"ServiceName": "N/A",
"Region": "N/A"
}
}
| 項目 | 一度も使われていないとき |
|---|---|
| LastUsedDate | 項目そのものが出ない(--output text では None) |
| ServiceName | N/A |
| Region | N/A |
手順5:以前のキーを無効化する(update-access-key)
いきなり削除せず、まず無効化(Inactive)にします。無効化は元に戻せるので、切り替え漏れが見つかったときにすぐ対応できます。
aws iam update-access-key --user-name app-batch \
--access-key-id AKIARZPUZDIKATDFQ5FO --status Inactive
うまくいくと何も表示されません。一覧で状態を確かめます。
aws iam list-access-keys --user-name app-batch \
--query "AccessKeyMetadata[].[AccessKeyId,Status,CreateDate]" --output text
AKIARZPUZDIKATDFQ5FO Inactive 2026-03-19T06:12:47Z
AKIARZPUZDIKH2DHJWI4 Active 2026-10-05T06:12:52Z
切り替え漏れが見つかったら Active に戻す
aws iam update-access-key --user-name app-batch \
--access-key-id AKIARZPUZDIKATDFQ5FO --status Active
aws iam list-access-keys --user-name app-batch \
--query "AccessKeyMetadata[].[AccessKeyId,Status]" --output text
AKIARZPUZDIKATDFQ5FO Active
AKIARZPUZDIKH2DHJWI4 Active
残っていた利用元を新しいキーに切り替えたら、もう一度 Inactive にして様子を見ます。
手順6:以前のキーを削除する(delete-access-key)
無効化したまましばらく置き、アプリが新しいキーだけで動いていることを確かめてから削除します。
aws iam delete-access-key --user-name app-batch --access-key-id AKIARZPUZDIKATDFQ5FO
aws iam list-access-keys --user-name app-batch \
--query "AccessKeyMetadata[].[AccessKeyId,Status,CreateDate]" --output text
AKIARZPUZDIKH2DHJWI4 Active 2026-10-05T06:12:52Z
新しいキー1本だけになりました。削除したキーの最終使用日を照会すると、次のエラーになります。
aws iam get-access-key-last-used --access-key-id AKIARZPUZDIKATDFQ5FO
An error occurred (NoSuchEntity) when calling the GetAccessKeyLastUsed operation: The Access Key with id AKIARZPUZDIKATDFQ5FO cannot be found
最終使用日を記録に残したいときは、削除の前に控えておきます。
LimitExceeded:キーは2本までという上限
すでに2本のキーを持つユーザーに、3本目を作ろうとするとエラーになります。
aws iam list-access-keys --user-name report-job \
--query "AccessKeyMetadata[].[AccessKeyId,Status,CreateDate]" --output text
AKIARZPUZDIKLDUC7KGH Active 2026-06-07T06:12:47Z
AKIARZPUZDIKCOIYS2S4 Active 2026-09-25T06:12:47Z
aws iam create-access-key --user-name report-job
An error occurred (LimitExceeded) when calling the CreateAccessKey operation: Cannot exceed quota for AccessKeysPerUser: 2
無効化しただけのキーも1本として数えられます。手順5 のあと(Inactive が1本、Active が1本)の状態で create-access-key を打ったときも、同じエラーになりました。
| 状況 | 対処 |
|---|---|
| 2本とも使っている | どちらが以前のキーかを作成日で確かめ、利用元を1本に寄せてから、もう一方を無効化 → 削除 |
| 1本が Inactive のまま残っている | get-access-key-last-used で使われていないことを確かめて削除 |
| どちらも使われていない | 両方を無効化 → 削除し、必要になったときに作り直す |
ローテーションでは一時的に2本になるので、入れ替えが終わったら1本に戻しておくと、次の入れ替えのときに枠が空いています。
全ユーザーのキーを一覧にする(CLI)
list-access-keys はユーザーごと、get-access-key-last-used はキーごとの照会なので、ループで組み合わせます。次の内容を list_keys.sh として保存します。
for u in $(aws iam list-users --query "Users[].UserName" --output text); do
aws iam list-access-keys --user-name "$u" \
--query "AccessKeyMetadata[].[UserName,AccessKeyId,Status,CreateDate]" --output text |
while read -r name id status created; do
used=$(aws iam get-access-key-last-used --access-key-id "$id" \
--query "AccessKeyLastUsed.[LastUsedDate,ServiceName]" --output text)
printf '%s\t%s\t%s\t%s\t%s\n' "$name" "$id" "$status" "$created" "$used"
done
done
確認用に、作成日の異なるキーを持つユーザーを5人用意して実行しました。列は、ユーザー名・アクセスキー ID・状態・作成日・最終使用日・最後に使ったサービスです。
bash list_keys.sh
admin AKIARZPUZDIKJZGLDUQH Active 2026-09-15T06:12:47Z 2026-10-05T06:13:06Z iam
app-batch AKIARZPUZDIKH2DHJWI4 Active 2026-10-05T06:12:52Z 2026-10-05T06:12:54Z sts
report-job AKIARZPUZDIKLDUC7KGH Active 2026-06-07T06:12:47Z None N/A
report-job AKIARZPUZDIKCOIYS2S4 Active 2026-09-25T06:12:47Z 2026-10-04T03:12:47Z sqs
deploy-bot AKIARZPUZDIKHHKDI4KD Active 2026-09-05T06:12:47Z 2026-10-04T03:12:47Z cloudformation
legacy-tool AKIARZPUZDIKAT7H4YZE Inactive 2025-08-31T06:12:47Z 2025-09-20T03:12:47Z ec2
作成から 90 日を超えたキーだけを抜き出す
作成日は ISO 8601 形式なので、文字列としての大小がそのまま日付の前後になります。90 日前の日付を date コマンドで作り、4列目と比べます(GNU date の書き方です)。
bash list_keys.sh | awk -v d="$(date -u -d '90 days ago' +%Y-%m-%d)" '$4 < d'
report-job AKIARZPUZDIKLDUC7KGH Active 2026-06-07T06:12:47Z None N/A
legacy-tool AKIARZPUZDIKAT7H4YZE Inactive 2025-08-31T06:12:47Z 2025-09-20T03:12:47Z ec2
実行日は 2026-10-05 で、90 日前は 2026-07-07 です。それより前に作られた2本が残りました。report-job の1本は作成から一度も使われておらず、legacy-tool の1本は無効化されたまま残っていることも、同じ行から読み取れます。
1ユーザーだけを調べるなら、--query の中で日付を比べる形でも書けます。
D=$(date -u -d '90 days ago' +%Y-%m-%d)
aws iam list-access-keys --user-name legacy-tool --output text \
--query "AccessKeyMetadata[?CreateDate<='$D'].[UserName,AccessKeyId,CreateDate]"
legacy-tool AKIARZPUZDIKAT7H4YZE 2025-08-31T06:12:47Z
全ユーザーのキーを一覧にする(boto3)
定期的に調べるなら、Python のスクリプトにしておくと、日数の計算や通知への組み込みがしやすくなります。key_report.py として保存します。
"""全ユーザーのアクセスキーを一覧にし、作成から MAX_AGE_DAYS 日を超えたものを抜き出す"""
from datetime import datetime, timezone
import boto3
MAX_AGE_DAYS = 90
iam = boto3.client("iam")
now = datetime.now(timezone.utc)
rows = []
for page in iam.get_paginator("list_users").paginate():
for user in page["Users"]:
name = user["UserName"]
for kpage in iam.get_paginator("list_access_keys").paginate(UserName=name):
for key in kpage["AccessKeyMetadata"]:
used = iam.get_access_key_last_used(AccessKeyId=key["AccessKeyId"])["AccessKeyLastUsed"]
last = used.get("LastUsedDate") # 一度も使われていないキーには無い
rows.append({
"user": name,
"key": key["AccessKeyId"],
"status": key["Status"],
"age": (now - key["CreateDate"]).days,
"idle": (now - last).days if last else None,
"service": used["ServiceName"],
})
def show(title, items):
print(f"== {title}({len(items)} 件)")
print(f"{'user':<12} {'key':<21} {'status':<9} {'age':>4} {'idle':>5} service")
for r in items:
idle = "-" if r["idle"] is None else r["idle"]
print(f"{r['user']:<12} {r['key']:<21} {r['status']:<9} {r['age']:>4} {idle:>5} {r['service']}")
show("すべてのキー", rows)
show(f"作成から {MAX_AGE_DAYS} 日超", [r for r in rows if r["age"] > MAX_AGE_DAYS])
python3 key_report.py
== すべてのキー(6 件)
user key status age idle service
admin AKIARZPUZDIKJZGLDUQH Active 20 0 iam
app-batch AKIARZPUZDIKH2DHJWI4 Active 0 0 sts
report-job AKIARZPUZDIKLDUC7KGH Active 120 - N/A
report-job AKIARZPUZDIKCOIYS2S4 Active 10 1 sqs
deploy-bot AKIARZPUZDIKHHKDI4KD Active 30 1 cloudformation
legacy-tool AKIARZPUZDIKAT7H4YZE Inactive 400 380 ec2
== 作成から 90 日超(2 件)
user key status age idle service
report-job AKIARZPUZDIKLDUC7KGH Active 120 - N/A
legacy-tool AKIARZPUZDIKAT7H4YZE Inactive 400 380 ec2
age は作成からの日数、idle は最後に使われてからの日数です。スクリプトのポイントは3つあります。
| ポイント | 理由 |
|---|---|
| paginator を使う | ユーザーやキーが多いときも、続きのページまで取りこぼさない |
used.get("LastUsedDate") で受ける |
一度も使われていないキーには、この項目が無い |
datetime.now(timezone.utc) と比べる |
boto3 が返す日時はタイムゾーンつきなので、同じ形にそろえて引き算する |
一覧から読み取れること
| 見えた状態 | 次の一手 |
|---|---|
| age が 90 を超え、idle が小さい | いまも使われているキー。この記事の手順でローテーションする |
| age が大きく、idle が「-」 | 作られてから使われていない。持ち主に確かめて無効化 → 削除 |
| status が Inactive のまま日数がたっている | 削除の候補。枠を1本ふさいでいる |
| 1ユーザーに Active が2本 | 入れ替えの途中で止まっていないか確かめる |
AWS Security Hub のコントロールでは、IAM.3 が「アクセスキーは 90 日以内に入れ替える」、IAM.22 が「45 日以上使われていない認証情報は取り除く」ことを確かめる内容になっています。上のスクリプトの MAX_AGE_DAYS や、idle の値を判定に使えば、同じ観点で手元でも確認できます。
AKIA と ASIA:接頭辞で種類を見分ける
アクセスキー ID の先頭4文字は、種類を表します。
| 接頭辞 | 種類 | 一緒に必要なもの | 期限 |
|---|---|---|---|
| AKIA | IAM ユーザーなどの長期のアクセスキー | シークレットアクセスキー | 削除するまで有効(だからローテーションする) |
| ASIA | AWS STS が発行する一時的なアクセスキー | シークレットアクセスキーとセッショントークン | 期限つき |
この記事で作成したキーはすべて AKIA で始まっています。一方、ロールを引き受けたとき(sts assume-role)に返るキーは ASIA で始まり、セッショントークンが付いてきます。
aws sts assume-role --role-arn arn:aws:iam::123456789012:role/tmp-role \
--role-session-name check \
--query "Credentials.[AccessKeyId,SessionToken!=null]" --output text
ASIARZPUZDIKGC3GV2TT True
ASIA で始まるキーを使うときは、セッショントークン(環境変数なら AWS_SESSION_TOKEN)も一緒に設定します。ログや設定ファイルにキー ID を見つけたときも、先頭が AKIA か ASIA かで、長期のキーか一時的なキーかを切り分けられます。
IAM のユーザーガイドには、ほかの ID の接頭辞も載っています。
| 接頭辞 | 種類 |
|---|---|
| AIDA | IAM ユーザー(get-caller-identity の UserId など) |
| AROA | ロール |
| AGPA | ユーザーグループ |
| ANPA | 管理ポリシー |
| AIPA | EC2 インスタンスプロファイル |
ローテーションのチェックリスト
| 確認すること | コマンド・目安 |
|---|---|
| 入れ替え前に、キーが1本であること | list-access-keys(2本あるなら先に整理) |
| 新しいキーのシークレットを、その場で保管先へ登録したか | 表示は作成時の1回だけ |
| 新しいキーで接続できたか | sts get-caller-identity |
| 以前のキーの最終使用日が進んでいないか | get-access-key-last-used を数日おいて確認 |
| 削除の前に無効化を挟んだか | update-access-key --status Inactive |
| 入れ替え後に1本へ戻したか | delete-access-key |
| 作業用のファイル(newkey.json など)を消したか | シークレットを残さない |
よくある質問
Q. シークレットアクセスキーを控えそこねました。もう一度表示できますか? A. 表示できるのは作成時だけです。そのキーを削除し、新しいキーを作成します。
Q. 無効化と削除は、どう使い分けますか? A. 無効化は Active に戻せるので、切り替え漏れがないかを見る期間に使います。問題がないと分かったら削除します。無効化したキーも2本の枠に数えられるため、残したままにせず、最後は削除まで進めます。
Q. どのくらいの間隔で入れ替えればよいですか? A. AWS Security Hub のコントロール IAM.3 は、90 日以内の入れ替えを確かめる内容です。この記事のワンライナーやスクリプトで、90 日を超えたキーを定期的に洗い出すと管理しやすくなります。
Q. そもそもアクセスキーを使わない方法はありますか? A. あります。AWS のユーザーガイドは、EC2 などの AWS 上で動くアプリには IAM ロールを使い、一時的な認証情報を優先することを勧めています。一時的なキー(ASIA で始まるもの)は期限つきなので、手作業のローテーションが要りません。
まとめ
- ローテーションは 作成 → 切り替え → 無効化 → 最終使用日の確認 → 削除 の順で進める
- シークレットアクセスキーが見られるのは作成時だけ。その場で保管先へ登録する
- 切り替えの確認は sts get-caller-identity、使われていないことの確認は get-access-key-last-used
- いきなり削除せず、無効化を挟む。Active に戻せるので安心して進められる
- キーは 1ユーザー2本まで。無効化したキーも数に入り、3本目は LimitExceeded になる
- 全ユーザーの棚卸しは、list-users と list-access-keys のループか boto3 の paginator で行う
- AKIA は長期のキー、ASIA は一時的なキー。ASIA にはセッショントークンが必要
参考・出典
- AWS IAM ユーザーガイド「アクセスキーの更新(id-credentials-access-keys-update)」「IAM ユーザーのアクセスキーの管理(id_credentials_access-keys)」「アクセスキーを保護する(securing_access-keys)」「IAM 識別子(reference_identifiers)」
- AWS CLI Command Reference「iam get-access-key-last-used」
- AWS Security Hub ユーザーガイド「IAM のコントロール(IAM.3、IAM.22)」
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「IAMアクセスキーの作成・確認・ローテーション手順 CLI版」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。