シナリオ
新しいマイクロサービスやLambda関数をデプロイしたばかりだとしましょう。すべて順調に見えますが、ログを確認すると状況が一変します。アプリケーションデータが表示される代わりに、大量のAccessDeniedExceptionエラーが発生しています。アプリケーションはCloudWatchにデータをプッシュしようとしていますが、AWSによって拒否されている状態です。
An error occurred (AccessDeniedException) when calling the PutLogEvents operation: User: arn:aws:sts::123456789012:assumed-role/MyRole is not authorized to perform: logs:PutLogEvents on resource
このエラーは、十分な権限を付与したつもりでも発生することが多いため、非常に厄介です。たとえCloudWatchLogsFullAccessをアタッチしていたとしても、リソースレベルでの細かな制限やKMS権限の不足により、ロギングパイプラインが停止してしまうことがあります。
なぜこのエラーが発生するのか?
PutLogEventsアクションは、他の多くのAWS操作よりも制約が厳格です。主な原因は以下の通りです。
- ヘルパーアクションの不足: Python用のBoto3などの多くのSDKは、単に
PutLogEventsを呼び出すだけではありません。通常、まずDescribeLogStreamsを使用してストリームの存在を確認します。このアクションの権限が不足していると、プロセス全体が失敗します。 - 末尾のワイルドカード: よくある間違いは、IAMポリシーで
:*を付けずにロググループのARNを指定してしまうことです。このワイルドカードがないと、ポリシーはグループに対しては権限を付与しますが、その中の「ストリーム」に対しては権限を付与しません。 - KMS暗号化: カスタマー管理キー(CMK)を使用してログを暗号化している場合、IAMロールにはログの権限だけでなく、その特定のキーを使用するための権限も必要になります。
- 組織のガードレール: 多くの企業のAWSアカウントでは、サービスコントロールポリシー(SCP)がマスターオーバーライドとして機能します。SCPで
logs:*が拒否されている場合、ローカルのIAMポリシーの設定に関わらず拒否されます。
ステップバイステップの修正方法
1. 正確なリソースARNを特定する
問題が発生している特定のロググループを特定します。CloudWatchコンソールを開き、ロググループに移動します。ロググループの詳細タブからARNを取得します。形式は以下のようになります。
arn:aws:logs:us-east-1:123456789012:log-group:my-app-logs
2. IAMポリシーを洗練させる
エラーメッセージに記載されているIAMロールを開きます。広範な権限を使用する代わりに、以下のターゲットを絞ったポリシーを適用してください。これには、最新のSDKがスムーズに動作するために必要なDescribeおよびCreateアクションが含まれています。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:DescribeLogStreams",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-1:123456789012:log-group:my-app-logs:*"
]
}
]
}
プロのヒント: リソース文字列の末尾にある:*に注目してください。PutLogEventsにおいてこれは必須です。なぜなら、このアクションは技術的にはロググループの子要素であるログ「ストリーム」に対して実行されるからです。
3. KMSキーの権限を確認する
ログはカスタムキーで暗号化されていますか?その場合、IAMロールを「キーユーザー」にする必要があります。ロールのポリシーに以下のステートメントを追加して、ログデータを即座に暗号化できるようにします。
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:GenerateDataKey*"
],
"Resource": "arn:aws:kms:us-east-1:123456789012:key/your-key-id"
}
修正のテスト
IAMの変更は通常数秒で反映されますが、反映までに最大1分ほどかかる場合もあります。ローカルマシンのAWS CLIを使用して、接続をすぐにテストできます(同じ権限を持っていることが前提です)。
1. テストストリームを作成する:
aws logs create-log-stream --log-group-name my-app-logs --log-stream-name manual-test
2. ダミーイベントを送信する:
aws logs put-log-events \
--log-group-name my-app-logs \
--log-stream-name manual-test \
--log-events timestamp=$(date +%s000),message="Permission test success"
If the CLI returns a nextSequenceToken, you are back in business.
ベストプラクティスのまとめ
- 最小権限の原則:
Resource: "*"を使用しないでください。これはセキュリティリスクになります。アプリケーションが実際に使用する特定のロググループにのみアクセスを制限してください。 - Infrastructure as Code (IaC): これらの権限はTerraformやAWS CDKで定義しましょう。コンソールでの手動変更は追跡が難しく、ステージング環境から本番環境へ移行する際の再現も困難です。
- スロットリングの監視: 権限を修正してもログが表示されない場合は、
ThrottlingExceptionを確認してください。ストリームあたりのPutLogEventsの制限である、毎秒5トランザクション(TPS)に達している可能性があります。

