管理ポリシーの差分を出力する AWS CLI エイリアス aws diff を作ってみた

AWS管理ポリシーの変更により何が変わったの?をコマンド一発で確認するために。

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

コンバンハ、千葉(幸)です。

管理ポリシー、特に AWS 管理ポリシーの変更差分を確認したい機会がたまにあります。

マネジメントコンソール上で差分表示するような機能があれば便利なのですが、現時点では実装されていません。

Policy_Version

ないなら AWS CLI でやってみるか、ということでエイリアスを組んでみました。

管理ポリシーの差分を表示するエイリアス

以下のエイリアスを設定しました。

~/.aws/cli/alias

[toplevel]
diff = !f() {
    VERSION=$(aws iam get-policy --policy-arn $1 --query 'Policy.DefaultVersionId' --output text | tr -d "v")
    BEFORE_VERSION=$((VERSION-1))

    BEFORE_RESULT=$(aws iam get-policy-version --policy-arn $1 --version-id v$BEFORE_VERSION)
    AFTER_RESULT=$(aws iam get-policy-version --policy-arn $1 --version-id v$VERSION)

    echo $BEFORE_RESULT | jq .PolicyVersion.Document >> /tmp/policy_before
    echo $AFTER_RESULT | jq .PolicyVersion.Document >> /tmp/policy_after

    BEFORE_DATE=$(echo $BEFORE_RESULT | jq .PolicyVersion.CreateDate)
    AFTER_DATE=$(echo $AFTER_RESULT | jq .PolicyVersion.CreateDate)

    diff -C 0 --label "Version$BEFORE_VERSION:$BEFORE_DATE" --label "Version$VERSION:$AFTER_DATE" /tmp/policy_before /tmp/policy_after
    rm /tmp/policy_*
  }; f

このエイリアスに管理ポリシーの ARN を引数として渡してあげれば、直前のバージョンとの差分が表示されます。

$ aws diff arn:aws:iam::aws:policy/ReadOnlyAccess
*** Version82:"2021-10-26T20:14:30+00:00"
--- Version83:"2022-02-16T20:46:04+00:00"
***************
*** 333 ****
--- 334,335 ----
+         "ec2:ListSnapshotsInRecycleBin",
+         "ec2:SearchLocalGatewayRoutes",
***************
*** 372 ****
--- 375,381 ----
+         "emr-containers:DescribeJobRun",
+         "emr-containers:DescribeManagedEndpoint",
+         "emr-containers:DescribeVirtualCluster",
+         "emr-containers:ListJobRuns",
+         "emr-containers:ListManagedEndpoints",
+         "emr-containers:ListVirtualClusters",
+         "emr-containers:ListTagsForResource",
***************
*** 561 ****
--- 571,588 ----
+         "iotroborunner:GetAction",
+         "iotroborunner:GetActionTemplate",
+         "iotroborunner:GetActivity",
+         "iotroborunner:GetDestination",
+         "iotroborunner:GetDestinationRelationship",
----------以下略----------

以下の前提を満たす環境であれば使用できるかと思います。AWS CloudShell では実行できました。

  • AWS CLI エイリアスが使用できる
  • jq が使用できる
  • diff が使用できる
  • 以下を実行可能な権限を持っている
    • aws iam get-policy
    • aws iam get-policy-version

管理ポリシーの差分を表示するエイリアスの流れ

上記のエイリアスによって大まかに以下が実行されます。

  • 引数として指定したポリシーのデフォルトバージョンを取得
  • デフォルトバージョン、その直前のバージョンのポリシーの内訳を取得
    • ポリシードキュメントをtmpファイルに出力
    • ポリシーバージョンの作成日時を取得
  • tmpファイルを対象に diff を実施
  • tmpファイルを削除

aws iam get-policy

デフォルトバージョンを取得するために実行します。

{
    "Policy": {
        "PolicyName": "MySamplePolicy",
        "CreateDate": "2015-06-17T19:23;32Z",
        "AttachmentCount": 0,
        "IsAttachable": true,
                "PolicyId": "Z27SI6FQMGNQ2EXAMPLE1",
        "DefaultVersionId": "v1",
                "Path": "/",
                "Arn": "arn:aws:iam::123456789012:policy/MySamplePolicy",
                "UpdateDate": "2015-06-17T19:23:32Z"
    }
}

今回は「デフォルトバージョン=最新バージョン」であろうという想定のもとエイリアスを組んでいます。AWS 管理ポリシーはその原則で考えて問題ないと思いますが、カスタマー管理ポリシーの場合は注意してください。

aws iam get-policy-version

ポリシードキュメント、バージョンの作成日時を取得するために実行します。

{
    "PolicyVersion": {
        "CreateDate": "2015-06-17T19:23;32Z",
        "VersionId": "v2",
        "Document": {
                      "Version": "2012-10-17",
                      "Statement": [
                              {
                                      "Action": "iam:*",
                                      "Resource": "*",
                                      "Effect": "Allow"
                              }
                      ]
                }
        "IsDefaultVersion": "false"
    }
}

新旧の内容を取得するため、異なるバージョンを指定して2回実行しています。

diff を実行する

以下の条件で diff を実行します。

  • context形式で差分の前後の行の出力はなし(-C 0
  • ラベルとしてポリシーバージョンとバージョンの作成日時を表示
  • 一つ前のバージョン、デフォルトバージョンの順で比較

diff -C 0 --label "Version$BEFORE_VERSION:$BEFORE_DATE" --label "Version$VERSION:$AFTER_DATE" /tmp/policy_before /tmp/policy_after

ラベルを指定している箇所がちょっとしたお気に入りです。

diff の内容をカスタマイズしたい場合は以下を参考にどうぞ。

やりたかったけど実現できなかったこと

もう少し違う形にしたかったけど断念した集です。回避策を思いついた方は教えていただけると嬉しいです。

ポリシー ARN でなくポリシー名で指定する

当初はエイリアス側で--policy-arn arn:aws:iam::aws:policy/$1のような形式で指定していました。エイリアスコマンドの引数としてポリシー ARN すべてを打ち込むよりは、ポリシー名だけの方が楽だと思ったためです。

その場合、パス(/service-role//job-function/など)を持つポリシーに対応できないことに気づきました。回避方法も思いつかなかったので、大人しく ARN すべてを渡す方式にしました。

マネジメントコンソールからポリシー ARN をコピーできますので、こちらをご活用ください。

Policy_arn_copy

tmpファイルを作成しない

今回は一度ポリシードキュメントを tmp ファイルを作成してから最後にそれを削除しています。ファイルの作成をせず、環境変数の中身を比較する方式を取れればそれが理想でした。

最初期は以下のようなエイリアスを書いていました。

~/.aws/cli/alias

[toplevel]
diff = !f() {
    VERSION=$(aws iam get-policy --policy-arn $1 --query 'Policy.DefaultVersionId' --output text | tr -d "v")
    BEFORE_VERSION=$((VERSION-1))
    BEFORE=$(aws iam get-policy-version --policy-arn $1 --version-id v$BEFORE_VERSION --query PolicyVersion.Document)
    AFTER=$(aws iam get-policy-version --policy-arn $1 --version-id v$VERSION --query PolicyVersion.Document)
    diff <(echo $BEFORE) <(echo $AFTER)
  }; f

この状態でエイリアスを実行すると以下のようなエラーが出ます。

$ aws diff arn:aws:iam::aws:policy/ReadOnlyAccess
/bin/sh: -c: line 5: syntax error near unexpected token `('
/bin/sh: -c: line 5: `diff <(echo $BEFORE) <(echo $AFTER)'

こちらの記事にあるような事象だろうというところまで理解しましたが、解決策まで思いつかなかったので諦めました。

バージョンが一つしかないポリシーでのハンドリング

デフォルトバージョンが v1 のポリシーを引数として渡すと、「ひとつ前のバージョン」に対するaws iam get-policy-versionの段階でエラーが出ます。

$ aws diff arn:aws:iam::aws:policy/AdministratorAccess

An error occurred (ValidationError) when calling the GetPolicyVersion operation: 1 validation error detected: Value 'v0' at 'versionId' failed to satisfy constraint: Member must satisfy regular expression pattern: v[1-9][0-9]*(\.[A-Za-z0-9-]*)?
*** Version0:
--- Version1:"2015-02-06T18:39:46+00:00"
***************
*** 0 ****
--- 1,10 ----
+ {
+   "Version": "2012-10-17",
+   "Statement": [
+     {
+       "Effect": "Allow",
+       "Action": "*",
+       "Resource": "*"
+     }
+   ]
+ }

if 文などで回避してあげればスマートなのですが、まぁいいか……という感じでそのままにしています。

終わりに

管理ポリシーの差分を確認する AWS CLI エイリアスを作ってみました。

  • 一つ前のバージョンのポリシードキュメントを VS Code にペーストする
  • デフォルトバージョンのポリシードキュメントをコピーする
  • VS Code のコマンドパレットからFile: Compare Active File with Clipboardを行う

……という手順を頑張っておこなっていたのですが、耐えきれなくなったので楽をしてみました。いつかマネジメントコンソールで差分比較の機能が実装されることを夢見ながら、しばらくはこれで耐え凌ごうと思います。

同じような悩みを抱えている方の参考になれば幸いです。

以上、 チバユキ (@batchicchi) がお送りしました。

参考