他のAWSアカウントのEC2とCodeCommitのリポジトリを共有する

やりたいこと

  • 自分の所属するAWSアカウント(アカウントAと呼ぶ)にあるCodeCommitのリポジトリを他のAWSアカウント(アカウントBと呼ぶ)の下にあるEC2からアクセスできるようにする
  • IAMのアクセスキーやCodeCommit用のIDとパスワードの受け渡しはせずに、アクセス認可を与えたい

f:id:translucens:20200326013422p:plain
リポジトリ共有の全体像

CodeCommitを持っているAWSアカウントAでの作業

IAMポリシーの作成

CodeCommitへのアクセスを許可するIAMポリシーを作成します(図の1)。 ResourceAWSアカウントID部分とリポジトリ名は適宜変更してください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "codecommit:BatchGet*",
                "codecommit:DescribePullRequestEvents",
                "codecommit:Get*",
                "codecommit:GitPull",
                "codecommit:List*"
                ],
            "Resource": "arn:aws:codecommit::123456789012:REPOSITORY-NAME"
        }
    ]
}

IAMロールの作成

共有先AWSアカウントを信頼するアカウントとするIAMロールを作成します(図の2)。

f:id:translucens:20200326013546p:plain
IAMロールの作成

先に作成したIAMポリシーをロールにアタッチします。作成したIAMロールのARN arn:aws:iam::123456789012:role/CodeCommitReadonly をアカウントBに伝えてください。

アカウントB(リポジトリを共有される側)での作業

アカウントAからのIAMロールを引き受けられるようにするIAMロールの作成

作業1、2によりアカウントAはアカウントBを信頼しているのですが、アカウントBのEC2はアカウントAのロールを引き受けられない状態になっています。これは意図しないロールを勝手に引き受けないようにして、権限を最小にするためです。

アカウントAから提供されたロールを引き受ける(sts:AssumeRole)ためのIAMポリシーとIAMロールを作成します(図の3)。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::123456789012:role/CodeCommitReadonly"
        }
    ]
}

IAMロールのEC2へのアタッチ

EC2インスタンスにアカウントBで作成した作成したロールを設定します(図の4)。ロールの指定はEC2インスタンス作成時または、インスタンス生成後の設定のいずれでも可能です。

AWS CLIへのIAMロールの登録

AWS CLIはプロファイルを切り替えることで、複数のロールを切り替えることができます。 ~/.aws/configにCodeCommitアクセス用のプロファイル(ここではCrossAccountAccessProfile)を作成し、アカウントAから提供されたロールを登録します(図の5)。external_id=の行はアカウントAのIAM Roleロールで外部IDを必要とする場合のみ記載してください。

[profile CrossAccountAccessProfile]
region=ap-northeast-1
role_arn=arn:aws:iam::123456789012:role/CodeCommitReadonly
external_id=EXTERNAL-ID
credential_source=Ec2InstanceMetadata

Gitの認証情報をAWS CLIから取得させる設定

下記コマンドを実行すれば、Gitの認証情報をAWS CLIから取得するようにできます(図の6)

git config --global credential.helper '!aws --profile CrossAccountAccessProfile codecommit credential-helper $@'
git config --global credential.UseHttpPath true

リポジトリへのアクセス

ここまで来れば、アカウントBのEC2からアカウントAのCodeCommitリポジトリへアクセスすることが可能です。 認証情報は自動的に取得されます(図の7)。認証情報を要求された場合、設定に誤りがある可能性があります。

git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/REPOSITORY-NAME

アカウントBでの作業を自動化するCloudFormationテンプレート

アカウントBでの作業が煩雑なので、自動化するテンプレートを作成しました。 IAMポリシーとロールの作成、EC2インスタンスの作成やGitとAWS CLIとの連携等全て自動で行えます。

AWSTemplateFormatVersion: 2010-09-09
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
    - Label:
        default: Role for cross account access
      Parameters:
        - AssumeRoleARN
        - AssumeRoleExternalID
    - Label:
        default: EC2 server config
      Parameters:
        - Server1AMI
        - Server1InstanceType
        - Server1SubnetID
        - Server1UserName
        - Server1KeyName
    ParameterLabels:
      AssumeRoleARN:
        default: ARN of external IAM role
      AssumeRoleExternalID:
        default: External ID of external IAM role
      Server1AMI:
        default: AMI ID of Server1
      Server1InstanceType:
        default: Instance type of server 1
      Server1SubnetID:
        default: Subnet of server 1
      Server1UserName:
        default: Username of server 1
      Server1KeyName:
        default: Secret key name of server 1
Parameters:
  AssumeRoleARN:
    Description: ARN of IAM role which allows to access CodeCommit repository in external AWS account.
    Type: String
    Default: arn:aws:iam::123456789012:role/CodeCommitReadonly
  AssumeRoleExternalID:
    Type: String
  Server1InstanceType:
    Type: String
    Default: t2.medium
  Server1SubnetID:
    Type: AWS::EC2::Subnet::Id
    Description: e.g. subnet-0123456789abcdef
  Server1UserName:
    Type: String
    Default: ec2-user
  Server1KeyName:
    Type: AWS::EC2::KeyPair::KeyName
  LatestAmiId:
    Type : 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: /aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2
Resources:
  EC2Server1:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref LatestAmiId
      IamInstanceProfile: !Ref InstanceProfileAllowCodeCommit
      InstanceType: !Ref Server1InstanceType
      KeyName: !Ref Server1KeyName
      Tags:
        -
          Key: Name
          Value: Server 1
      BlockDeviceMappings:
        -
          DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 30
            VolumeType: gp2
      UserData:
        Fn::Base64:
          !Sub |
            #! /bin/bash
            yum update -y
            yum install -y git
            sudo -u ${Server1UserName} git config --global credential.helper '!aws --profile CrossAccountAccessProfile codecommit credential-helper $@'
            sudo -u ${Server1UserName} git config --global credential.UseHttpPath true
            mkdir -p ~${Server1UserName}/.aws
            touch ~${Server1UserName}/.aws/config
            chown ${Server1UserName}: ~${Server1UserName}/.aws
            chown ${Server1UserName}: ~${Server1UserName}/.aws/config
            echo "[profile CrossAccountAccessProfile]" >> ~${Server1UserName}/.aws/config
            echo "region=ap-northeast-1" >> ~${Server1UserName}/.aws/config
            echo "role_arn=${AssumeRoleARN}" >> ~${Server1UserName}/.aws/config
            echo "external_id=${AssumeRoleExternalID}" >> ~${Server1UserName}/.aws/config
            echo "credential_source=Ec2InstanceMetadata" >> ~${Server1UserName}/.aws/config
  InstanceProfileAllowCodeCommit:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref IAMRoleAccessToExternalCodeCommit
  IAMRoleAccessToExternalCodeCommit:
    Type: AWS::IAM::Role
    Properties:
      RoleName: RoleAllowAccessToExternalCodeCommit
      AssumeRolePolicyDocument: 
        Version: "2012-10-17"
        Statement: 
          - 
            Effect: "Allow"
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action:
              - "sts:AssumeRole"
      Path: "/"
  IAMPolicyAccessToExternalCodeCommit:
    Type: AWS::IAM::Policy
    Properties:
      PolicyName : PolicyAllowAccessToExternalCodeCommit
      PolicyDocument:
        Version: 2012-10-17
        Statement: 
          -
            Effect: Allow
            Action: sts:AssumeRole
            Resource: !Ref AssumeRoleARN
      Roles : 
        - !Ref IAMRoleAccessToExternalCodeCommit