移植性を最大限にするにはARNのパーティションをハードコーディングしてはいけない(中国リージョンの話)

ARNをコードで構築する際 arn:aws: の部分をハードコーディングすると思わぬ罠にはまるかもしれない。
2023.07.24

こんにちは。サービス開発室の武田です。

みなさんARN(Amazon Resource Name)はおそらくご存じでしょう。こういうやつです。

arn:aws:iam::123456789012:role/my-role

さてCloudFormationやプログラムの中でARNを組み立てる場合、どういうコードを書いていますか?

たとえばCloudFormationの場合。

!Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'

たとえばPythonの場合。

role_arn = f"arn:aws:iam::{account_id}:role/{role_name}",

これらのコードはおそらく、ほとんどの場合において問題なく動きます。しかし、それは通常のAWS商用リージョンに限った話です。

AWSのパーティション

AWSにはパーティションという概念があり、リージョンはいずれかのパーティションに属します。パーティションが異なると、IAMのクロスアカウントアクセスなどもできません。そしてパーティションが異なるとARNも異なります。

たとえばみなさんよくお世話になるポリシーとしてAdministratorAccessがあります。通常このポリシーのARNは次のようになっています。

arn:aws:iam::aws:policy/AdministratorAccess

しかしこれが中国リージョンの属するパーティションだと、次のように変わります。

arn:aws-cn:iam::aws:policy/AdministratorAccess

ARNの2セクション目がaws-cnになっていますね。そう、実はここはaws以外になりうるのです。

ちなみにBoto3で有効なパーティション一覧が取得できます。

>>> boto3.__version__
'1.26.161'

>>> session = boto3.session.Session()
>>> session.get_available_partitions()
['aws', 'aws-cn', 'aws-us-gov', 'aws-iso', 'aws-iso-b', 'aws-iso-e', 'aws-iso-f']

というわけで、普段awsしか見ていないパーティションですが、実はこれだけ定義されています(なお、isoが何かはよく知りません)。

パーティションを変数で置換する

AWS商用リージョン以外でも動作するようにするためには、ARNを構築する際にパーティションをハードコーディングしてはいけません。先ほどの例を書き直してみましょう。

たとえばCloudFormationの場合。

!Sub 'arn:${AWS::Partition}:ec2:${AWS::Region}:${AWS::AccountId}:vpc/${vpc}'

たとえばPythonの場合。

partition = session.get_partition_for_region(region_name=session.region_name)
role_arn = f"arn:{partition}:iam::{account_id}:role/{role_name}",

get_partition_for_region()関数は、指定したリージョンが属するパーティションを返す関数です。

>>> session.get_partition_for_region(region_name="ap-northeast-1")
'aws'

>>> session.get_partition_for_region(region_name="cn-north-1")
'aws-cn'

そのため、処理対象のリージョンを引数に渡すことで、パーティションを得られます。これでパーティションが変わっても動作可能な、移植性の高いコードになりました。

まとめ

なんとなくARNの先頭部分、arn:aws:までは固定だと思いがちですが、そうではないというお話でした。AWS商用リージョン以外を触る機会が出てきそうな方は、ぜひ覚えておいてください。