Management Consoleの権限不足エラーをデコードする

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。望月です。
今日はヒジョーに縁の下の力持ち的なサービス、STSについてです。

権限不足のエラーメッセージ

IAM userを利用して利用できる権限を制御している場合、Management Consoleで許可されていない操作を実行しようとした場合にエラーになることがあります。 *1たとえばReadOnlyのPermissionを与えられているユーザがEC2をTerminateしようとした時などですね。Management Consoleですと、こういったエラーが表示されます。

not_authorized

画面だとエラーメッセージが見づらいですが、なにかエンコードされた文字列が並んでいるのが確認できると思います。AWS CLIからだとこういった出力があります。

$ aws ec2 terminate-instances --profile no-permission-user --instance-id i-xxxxxxxx

A client error (UnauthorizedOperation) occurred when calling the TerminateInstances operation: You are not authorized to perform this operation. 
Encoded authorization failure message: tbPtNRmz55vw........(後略)

さて、このエンコードされた文字列ですが、どうやってデコードすればいいのでしょうか?答えはAWS STSにAPIが用意されていますので、それを利用しましょう。

DecodeAuthorizationMessage

STSのDecodeAuthorizationMessage APIを利用すると、上記のエラー文字列をデコードすることが出来ます。APIの仕様やデータ構造などについては公式ドキュメントを参照して下さい。試しにAWS CLIでデコードしてみましょう。
ちなみに、デコードの時に使うアクセスキーは、エラーメッセージを取得するアクションを行ったアクセスキーと同じでなければいけません。
さらに、sts:DecodeAuthorizationMessageが許可されていないと処理が実行できないため、権限が足りない場合は明示的に権限を与えてあげましょう。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "sts:DecodeAuthorizationMessage",
      "Resource": "*"
    }
  ]
}

実行結果は以下のようになります。エンコードされた文字列が長いので、今回は文字列をerror.txtに保存してfile://で呼び出しています。

$ aws sts decode-authorization-message --encoded-message file://error.txt --profile no-permission-user
{
    "DecodedMessage": "{\"allowed\":false,\"explicitDeny\":false,\"matchedStatements\":{\"items\":[]},\"failures\":{\"items\":[]},\"context\":{\"principal\":{\"id\":\"xxxxxxxxxxxxxxxxxxxxx\",\"name\":\"no-permission\",\"arn\":\"arn:aws:iam::019930502935:user/no-permission\"},\"action\":\"ec2:TerminateInstances\",\"resource\":\"arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxxx:instance/i-xxxxxxxx\",\"conditions\":{\"items\":[{\"key\":\"ec2:Tenancy\",\"values\":{\"items\":[{\"value\":\"default\"}]}},{\"key\":\"ec2:RootDeviceType\",\"values\":{\"items\":[{\"value\":\"ebs\"}]}},{\"key\":\"ec2:ebsOptimized\",\"values\":{\"items\":[{\"value\":\"false\"}]}},{\"key\":\"ec2:InstanceType\",\"values\":{\"items\":[{\"value\":\"t1.micro\"}]}},{\"key\":\"ec2:Region\",\"values\":{\"items\":[{\"value\":\"ap-northeast-1\"}]}},{\"key\":\"ec2:ResourceTag/Name\",\"values\":{\"items\":[{\"value\":\"\"}]}},{\"key\":\"ec2:AvailabilityZone\",\"values\":{\"items\":[{\"value\":\"ap-northeast-1c\"}]}}]}}}"
}

だいぶ見づらいですが、デコードされていることは確認できました。あとはjqに食べさせてあげましょう。
今回は試しにどのアクションを行った時のエラーなのかを取得してみます。

$ aws sts decode-authorization-message --encoded-message file://error.txt --profile no-permission-user \
  | jq -r '.DecodedMessage' \
  | jq -c '.context.action'
"ec2:TerminateInstances"

TerminateInstancesを行った際のエラーメッセージであることが取得できました。Actionの他にもユーザのARNなど、様々な情報が取得できるので、権限周りでのManagement Consoleでのエラーに対するデバッグ用途に使えそうですね。

脚注

  1. 手元で確認した限り、ここで紹介したエラー文字列を返すAPIと返さないAPIがあるようです。どういった理由でその違いがあるかはわかりませんでした。どなたか知っていたら教えて下さい。