クロスアカウントVPCピアリング作成時の挙動

2023.02.16

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

VPCピアリングをCFnで生成する場合、
クロスアカウントのケースではIAMロールの指定が必須となります。
AWS::EC2::VPCPeeringConnection

マネコンから生成する場合ロールは特に利用しないため、
ふと気になりマネコンとCFnでどのような挙動の違いがあるかを実際に確認してみました。

結論

クロスアカウントのVPCピアリング作成の場合マネコンとCFnで承認の挙動がが異なります。

  • マネコンから作る場合承認はアクセプタ側のアカウントで作成時とは別に手動で行う
  • CFnから作成する場合はスタックの作成中に指定したロールを利用して承認を行う
    • 指定がない場合はCFnを実行している権限で承認を行おうとする
      (権限不足で結果的に失敗する)

現時点ではCFnで生成する場合の承認の制御を指定するパラメータはは見当たりませんでした。

実際の挙動を見てみる

マネコンから作る場合

実際にマネコンからピアリング接続を作成してみます。

設定時に別アカウントのVPCを指定しピアリング接続を生成します。
この場合CloudTrailの出力は以下のようになります。

作成アカウント(リクエスタ側)の変更操作は
CreateVpcPeeringConnectionsのみとなっていました。

対抗側(アクセプタ側)のアカウントに承認依頼が来ていますので
アクセプタ側のマネコンのVPCピアリングの画面より承認を行います。

CloudTrailを確認することでアクセプタ側で
AcceptVpcPeeringConnectionsが実行されていることが確認できました。

リクエスタ側のアカウントのCloudTrailを確認しましたが同時刻前後で関連しそうな出力はなく
承認は操作APIでベルではアクセプタ側のみで完結してることがわかります。

CFnから作成する場合

IAMロールを指定しない場合

まずはIAMロールがない状態でどのようになるのかを確認してみます。

以下のようなテンプレートで作成しました。

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Peering:
    Type: AWS::EC2::VPCPeeringConnection
    Properties: 
      PeerOwnerId: {アクセプタ側のアカウントID}
      PeerRegion: ap-northeast-1
      PeerVpcId: {アクセプタ側のVPCのID}
      VpcId: {リクエスタ側のVPCのID}

生成が失敗しロールバックが発生します。

CloudTrailには以下の出力がされました。

特筆すべきはAcceptVpcPeeringConnectionsの実行がスタックの作成を実行したユーザによって行われている点です。
この際のイベントは以下のようになり権限不足で失敗していることがわかります。

{
...
    "errorCode": "Client.OperationNotPermitted",
    "errorMessage": "User xxxxxx cannot accept peering pcx-xxxx",
    "requestParameters": {
        "vpcPeeringConnectionId": "pcx-xxxxxx"
    },
...
}

ピアリング接続のIDはリクエスタ側アクセプタ側で同じなのでこれだけみると悩みますが、
マネコン生成や後述のロール指定時の操作よりアクセプタ側で実行すべきAcceptVpcPeeringConnectionsがリクエスタ側のアカウントのユーザで実行されてることが原因と推定できます。

IAMロールを指定する場合

まず準備として以下のような権限を持つIAMロールをアクセプタ側で作成します。
peering-test-roleというロール名で作成しています。

Principal

{
    "Version": "2012-10-17"
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS" : "{リクエスタ側のアカウントのID}"
            }
        }
    ]
}

Policy
以下のページを見るとvpc-peering-connectionのみの許可で良さそうに見えますが、
これだけで実行すると権限不足で失敗します(しました)。 https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudformation-vpc-peering-error/

そのためResourceにvpcも追加してください。

{
    "Version": "2012-10-17"
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "ec2.AccpectVpcPeeringConnection",
            "Resource": [
                "arn:aws:ec2:*:{リクエスタ側のアカウトID}:vpc/*",
                "arn:aws:ec2:*:{リクエスタ側のアカウトID}:vpc-peering-connection/*"
        }
    ]
}

以下のテンプレートでスタックを作成することで
承認までセットで完了した状態でスタックの作成が完了します。

AWSTemplateFormatVersion: 2010-09-09
Resources:
  Peering:
    Type: AWS::EC2::VPCPeeringConnection
    Properties: 
      PeerOwnerId: {アクセプタ側のアカウントID}
      PeerRegion: ap-northeast-1
      PeerVpcId: {アクセプタ側のVPCのID}
      VpcId: {リクエスタ側のVPCのID}
      PeerRoleArn: {上記で生成したIAMロールのARN}

実行タイミングでリクエスタ側ではAsuumeRoleが実行されています。

詳細を確認してみると先ほど指定したロールに成り代わっていることが確認できます。

    "userAgent": "AWS Internal",
    "requestParameters": {
        "roleArn": "arn:aws:iam::xxxxxxx:role/peering-test-role",
        "roleSessionName": "pcx-xxxxxx",
        "durationSeconds": 900
    },

アクセプタ側を確認するとAccpectVpcPeeringConnectionが実行されています。

詳細を確認してみると指定したロールでAccpectVpcPeeringConnection実行されていることが確認できます。

    "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "xxxxxx",
                "arn": "arn:aws:iam::xxxxxx:role/peering-test-role",
                "accountId": "xxxxxx",
                "userName": "xxxxxx"
            },
            ....
    }

実際に実行してみて

今回マネコンとCFnの実行をそれぞれ行いCloudTrailでイベントを確認することによって、
生成時の具体的な挙動を確認することができました。

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-vpcpeeringconnection.html#cfn-ec2-vpcpeeringconnection-peerrolearn The Amazon Resource Name (ARN) of the VPC peer role for the peering connection in another AWS account. This is required when you are peering a VPC in a different AWS account.

またドキュメント上PeerRoleArnパラメータは別アカウントの場合は必須となっていますが、
今回の検証よりパラメータチェック的に必須ではなく実行の権限的に結果として必須になるということがわかります。

CloudFormationで管理しているのであれば可能であればその管理に収めたいですが、
クロスアカウントとなると管理管轄の違いですぐが難しい場合もあるかと思います。

手動作成とすると全くCloudFormation上での管理ができなくなるというものではなく、
既存リソースのインポートを使うことで後々スタックの管理配下に収めることは可能ですので、
状況に応じて生成方法を選択し構築を検討してみてください。