CloudWatchをAIエージェント経由で使いたい。でも「Identity Center も IdP もない、長期アクセスキーは使いたくない、また費用もかけたくない」——こんな時のソリューションです。
構成図
TL;DR
- ローカル Mac で動く AI エージェント(Claude Code / Claude Desktop)から、awslabs の CloudWatch MCP Server を使って CloudWatch のログ・メトリクス・アラームを分析したい。
- 前提: IAM Identity Center なし / OIDC・SAML の IdP なし / 長期アクセスキーは使いたくない。
- 結論は IAM Roles Anywhere + 自己署名ルート CA。追加費用 $0 で、AWS 公式が推奨する「一時クレデンシャル」の原則に則ることができる。
- AI 専用の IAM ロールを人間用と分離する。MCP 経由のアクセスを CloudTrail で切り分けられ、権限も最小化できる。
背景 — Amazon CloudWatchをMCP経由で操作して楽をしたい
CloudWatch のログを Logs Insights で分析する、メトリクスをグラフ化する、発火中のアラームを一覧する。こういった運用の定型作業は、AI エージェントに MCP(Model Context Protocol)サーバー経由で操作できれば便利です。awslabs が公式に出している awslabs.cloudwatch-mcp-server を使えば、ログ検索・Logs Insights クエリ・メトリクス取得・アクティブアラーム取得といったツールがそのままエージェントの手足になります。
本記事はそのエージェントに対して AWS クレデンシャルをどう供給するかに焦点を当てています。
- IAM Identity Center(旧 AWS SSO)が未導入 — 組織判断が必要で、すぐには入れられない
- OIDC / SAML の IdP がない — フェデレーションのタネがない
- 長期アクセスキーは避けたい — AWS 公式が明確に非推奨としている
- 実行環境はローカル Mac — EC2/ECS のインスタンスロールが使えない
「ローカル Mac」「Identity Center なし」「IdP なし」は多くの個人開発者・小規模チームが直面する構成です。ここで長期アクセスキーを ~/.aws/credentials に置いてしまうのが最も安易ですが、それは避けたい。
なぜ IAM Roles Anywhere なのか
候補を並べて消去法で残ったのが IAM Roles Anywhere でした。
| 方式 | 判定 |
|---|---|
| IAM Identity Center | ✗ 未導入。導入は組織判断 |
| OIDC / SAML フェデレーション | ✗ 対応 IdP がない |
| 自前 OIDC Provider(Cognito 等) | △ Issuer の公開 HTTPS・トークン取得フロー自作など手数が多い |
| EC2 / ECS インスタンスロール | ✗ ローカル Mac 用途に不適 |
| 長期アクセスキー継続 | ✗ AWSが公式に非推奨 |
| IAM Roles Anywhere + 自己署名 CA | ✓ 採用 |
Roles Anywhere は、X.509 クライアント証明書を提示して STS の一時クレデンシャルを受け取る仕組みです。
- Identity Center / 外部 IdP がない環境で AWS が公式に推奨するルートの 1 つ
- 自己署名ルート CA が Trust Anchor の "External certificate bundle" として公式サポートされている(Private CA 不要)
- 費用 $0 — Roles Anywhere 本体・STS 発行・CloudTrail 管理イベントのいずれも無料
補足: macOS ローカル機では SSM Hybrid Activation は使えません(AWS 公式ドキュメントで Hybrid 対応 OS は Linux / Windows Server のみと明記、macOS は "Amazon EC2 instances only")。Parameter Store は「呼ぶのに先にクレデンシャルが要る」鶏と卵、DHMC は EC2 専用。非 EC2・非 Identity Center の macOS では、AWS 公式のクレデンシャル供給手段は実質 Roles Anywhere 一択です。
参考までに、2025 年 11 月発表の マネージド "AWS MCP Server" も選択肢ですが、us-east-1 限定 + マネージド提供のみのため、東京リージョン・ローカル PoC 用途では awslabs 版を使いました。
アーキテクチャ
冒頭の図の通り、信頼の起点は 自分で作った自己署名ルート CA です。この CA で署名したクライアント証明書だけが Trust Anchor を通過し、STS から MCP 専用ロールの一時クレデンシャルを受け取れます。
実装手順
0. 前提確認
uname -m # arm64 → Aarch64 バイナリ、x86_64 → X86_64 バイナリ
1. 自己署名ルート CA を作る
mkdir -p ~/.iam-roles-anywhere && cd ~/.iam-roles-anywhere
umask 077
# ルート CA 秘密鍵(4096 bit)
openssl genrsa -out rootCA.key 4096
# ルート CA 自己署名証明書(10 年、v3 拡張付き)
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \
-out rootCA.crt \
-subj "/C=JP/O=MyOrg/CN=MyOrg-Root-CA" \
-addext "basicConstraints=critical,CA:TRUE" \
-addext "keyUsage=critical,keyCertSign,cRLSign"
rootCA.keyは MCP 実行マシンに常駐させない。 パスワードマネージャー等に退避し、クライアント証明書を発行するときだけ取り出します。ルート CA 鍵が漏れれば、任意のクライアント証明書を偽造できてしまうためです。
2. クライアント証明書を作る
openssl genrsa -out client.key 2048
# CN は Trust Policy の Condition に使えるので、端末を識別できる名前に
openssl req -new -key client.key -out client.csr \
-subj "/C=JP/O=MyOrg/CN=my-macbook"
cat > client.ext <<EOF
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
EOF
# ルート CA で署名(1 年、年次ローテ想定)
openssl x509 -req -in client.csr -CA rootCA.crt -CAkey rootCA.key \
-CAcreateserial -out client.crt -days 365 -sha256 \
-extfile client.ext
chmod 600 client.key
3. AWS 側リソース(開発アカウント)
3-1. Trust Anchor — IAM Roles Anywhere コンソール → Create a trust anchor
- Certificate authority source: External certificate bundle
-
rootCA.crtの中身を貼り付け - 生成された ARN を控える:
arn:aws:rolesanywhere:ap-northeast-1:<ACCOUNT_ID>:trust-anchor/<TA_ID>
3-2. IAM Role(例: mcp-cloudwatch-readonly)
信頼ポリシー:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "rolesanywhere.amazonaws.com" },
"Action": ["sts:AssumeRole", "sts:TagSession", "sts:SetSourceIdentity"],
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:rolesanywhere:ap-northeast-1:<ACCOUNT_ID>:trust-anchor/<TA_ID>"
},
"StringEquals": {
"aws:PrincipalTag/x509Subject/CN": "my-macbook",
"aws:PrincipalTag/x509Issuer/CN": "MyOrg-Root-CA"
}
}
}]
}
切り分けのコツ: 最初は Condition を
ArnEquals(SourceArn)だけにして疎通を確認し、通ったら CN / Issuer 条件を足す。最初から 3 条件を全部盛ると、落ちたときに原因が特定しにくいです。
権限ポリシー(初期・最小):
CloudWatchReadOnlyAccessCloudWatchLogsReadOnlyAccess
権限昇格の明示 Deny(MCP 用ロール全般に推奨):
{
"Version": "2012-10-17",
"Statement": [{ "Effect": "Deny", "Action": "iam:*", "Resource": "*" }]
}
落とし穴: IAM ポリシーの Action は service 部分を
*にできません(*:Delete*は Validation エラー)。全サービスの破壊操作を横断禁止したい場合はサービスを列挙する必要があります。ただし Managed の*ReadOnly*ポリシーには Delete 系が含まれないので、実効的な追加防御は「IAM 経由の権限昇格禁止」で十分です。
3-3. Profile(例: mcp-profile)
- 紐付け Role: 上記の MCP 専用ロール
- セッションポリシー: 付けない(Role ポリシーがそのまま効く)
- セッション期間: 3600 秒(1 時間デフォルトを維持。延ばさない)
- 生成された ARN を控える:
arn:aws:rolesanywhere:ap-northeast-1:<ACCOUNT_ID>:profile/<PROFILE_ID>
4. aws_signing_helper を入れる
# Apple Silicon の例
curl -L -o ~/.iam-roles-anywhere/aws_signing_helper \
https://rolesanywhere.amazonaws.com/releases/1.8.2/Aarch64/MacOS/Sonoma/aws_signing_helper
chmod +x ~/.iam-roles-anywhere/aws_signing_helper
# 公式ハッシュと照合(改ざん検知)
shasum -a 256 ~/.iam-roles-anywhere/aws_signing_helper
5. ~/.aws/config
[profile ra-dev]
region = ap-northeast-1
credential_process = /Users/<you>/.iam-roles-anywhere/aws_signing_helper credential-process --certificate /Users/<you>/.iam-roles-anywhere/client.crt --private-key /Users/<you>/.iam-roles-anywhere/client.key --trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-1:<ACCOUNT_ID>:trust-anchor/<TA_ID> --profile-arn arn:aws:rolesanywhere:ap-northeast-1:<ACCOUNT_ID>:profile/<PROFILE_ID> --role-arn arn:aws:iam::<ACCOUNT_ID>:role/mcp-cloudwatch-readonly
6. 疎通確認
AWS_PROFILE=ra-dev aws sts get-caller-identity
# → assumed-role の ARN が返れば成功
AWS_PROFILE=ra-dev aws cloudwatch list-metrics --namespace AWS/EC2 --max-items 1
# → メトリクスが返れば read 権限も OK
AWS_PROFILE=ra-dev aws iam list-users
# → explicit deny で弾かれれば、権限昇格 Deny も効いている
7. CloudWatch MCP を登録
{
"mcpServers": {
"cloudwatch": {
"command": "uvx",
"args": ["awslabs.cloudwatch-mcp-server@latest"],
"env": { "AWS_PROFILE": "ra-dev", "AWS_REGION": "ap-northeast-1" }
}
}
}
実運用で効いた知見・ハマりどころ
MCP を実タスク(アラーム一覧・Logs Insights・メトリクスのグラフ化)で回して分かった実践的なコツです。
-
get_active_alarmsは 50 件を超えると context window を溢れさせる。 件数が多いアカウントでは、いったんファイルに落としてjqで集計する方が速くて安全。 -
Logs Insights の正規表現で
(?i)インラインフラグが効かない。 大文字小文字を無視したいときは[Ee][Rr][Rr][Oo][Rr]のように書き下すか、like /pattern/を併用する。 -
ロググループ検索は prefix 一致のみ。 部分一致がほしいときは
filterクエリ側で絞る。 -
グラフ生成は MCP の外で。 メトリクスは MCP で取得し、可視化は
uv run --scriptで matplotlib を ephemeral 実行して PNG 保存、という分業が扱いやすい。 -
権限不足で当初できなかったこと —
cloudtrail:LookupEvents(ユーザー行動ログ)、cloudwatch:PutDashboard(ダッシュボード作成)、EC2 の Name タグ参照。read-only を貫くなら、これらは意図的に落としたままにするか、必要になった時点で最小限だけ足す。
セキュリティ設計
AI経路を人間経路から分離する
MCP 用ロールは、人間が直接使うロールとは別に作る理由は 2 つ。
- CloudTrail の切り分け — 「この API 呼び出しは AI が投げたのか、人間が投げたのか」をロールで判別できる。
- 権限の最小化 — AI には read-only + 権限昇格 Deny を割り当て、人間ロールとはブラスト半径を分けられる。
補足:
aws:ViaAWSMCPService/aws:CalledViaAWSMCPというコンテキストキーは マネージドの AWS MCP Server 経由でのみ付与されます。awslabsをローカル起動する本構成ではロール分離で識別する設計で代替しています。
鍵保護ロードマップ
守るべきは証明書ではなく 秘密鍵 です。証明書(公開鍵)は Git に入れても Slack で送っても攻撃は成立しません。攻撃が成立するのは client.key が漏れたときだけ。段階的に固めていきます。
| 段階 | 方式 | 耐える脅威 |
|---|---|---|
| 初期 | ファイル + chmod 600 + FileVault |
カジュアルな窃取 |
| 次段 | macOS Keychain 化、--cert-selector 経由 |
ディスク上に平文 .key を残さない |
| 強固 | YubiKey / TPM に鍵格納、PKCS#11 経由 | ハードウェア MFA 相当(SAML + MFA と同等水準) |
Keychain 化の例:
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -name "ra-dev"
security create-keychain -p "PASSWORD" ra.keychain
security unlock-keychain -p "PASSWORD" ra.keychain
security import client.p12 -T ~/.iam-roles-anywhere/aws_signing_helper -P "P12_PASSWORD" -k ra.keychain
この場合 --private-key を外し、--cert-selector "Key=CN,Value=my-macbook" に切り替えます。
費用
| 項目 | 費用 |
|---|---|
| 自己署名 CA + OpenSSL | $0 |
| IAM Roles Anywhere(Trust Anchor / Profile / CreateSession) | $0 |
| STS 発行 | $0 |
| CloudTrail 管理イベント | $0(デフォルト) |
aws_signing_helper |
$0(AWS 配布) |
| 合計 | $0 |
対比として、AWS Private CA は general-purpose で約 $400 / 月 short-lived mode で $50 / 月
まとめ
- Identity Center も IdP もない環境でも、AI(MCP)に安全に AWS にアクセスする方法としてIAM Roles Anywhere + 自己署名ルート CAを利用でる、追加費用は $0。
- 長期アクセスキーを捨て、X.509 証明書 → STS 一時クレデンシャルに置き換えることで、AWS 公式のベストプラクティスに則ることができる。
- AI 専用ロールの分離(CloudTrail 切り分け + 最小権限 + 権限昇格 Deny)と、秘密鍵の段階的なハードウェア化。
- 同じ仕組みは CloudWatch に限らず、他の read-only な awslabs MCP サーバーにもそのまま横展開できる。