Creating a cross-account role to perform VPC associations with Private Hosted Zones

208 Views Asked by At

I'm trying to create an IAM cross-account role following the example in https://repost.aws/knowledge-center/lambda-function-assume-iam-role. I want a central account (7935xxxxxxxxx) to be able to create a VPC association between a VPC in a workload account (6617xxxxxxxx) to a private hosted zone in the central account. The association can only be performed as though from the workload account. But I get this error:

"An error occurred (AccessDenied) when calling the AssociateVPCWithHostedZone operation: User: arn:aws:sts::6617xxxxxxxxx:assumed-role/AssumeFromCoreRole/cross_acct_lambda is not authorized to perform: route53:AssociateVPCWithHostedZone on resource: arn:aws:ec2:ap-southeast-2:6617xxxxxxxxx:vpc/vpc-0f37262673a5e9762 because no resource-based policy allows the route53:AssociateVPCWithHostedZone action"

I'm nor sure this error message is pointing me to the true problem as my understanding is that Route 53 doesn't have resource-based policies.

I've double-checked all my ducks are lined up:

  1. The workload account has a role that allows it to assume a role from the central account:
DNSACrossAccountRole:
Type: AWS::IAM::Role
Properties:
  AssumeRolePolicyDocument:
    Version: '2012-10-17'
    Statement:
      - Sid: AssumeRole
        Effect: Allow
        Principal:
          'AWS': !Sub 'arn:aws:iam::${CoreAccountID}:role/DNS-Automation-Factory-${Environment}'
        Action: 'sts:AssumeRole'
  RoleName: AssumeFromCoreRole
  1. The Lambda execution role in the central account allows the workload account to assume its role along with the necessary actions:
      DNSAutomationRole:
        Type: AWS::IAM::Role
        Properties:
          ManagedPolicyArns:
          - arn:aws:iam::aws:policy/AWSLambda_FullAccess
          - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
          AssumeRolePolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Sid: LambdaAssumeRole
              Effect: Allow
              Principal:
                Service: 'lambda.amazonaws.com'
              Action: 'sts:AssumeRole'
          RoleName: !Sub DNS-Automation-Factory-${Environment}
          Policies:
          - PolicyName: 'work-with-private-hosted-zone'
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
              - Effect: Allow
                Action:
                - route53:CreateVPCAssociationAuthorization
                - route53:CreateHostedZone
                - route53:AssociateVPCWithHostedZone
                - ec2:DescribeVpcs
                Resource: '*'
              - Sid: AllowCrossAccountAccess
                Effect: Allow
                Action:
                - 'sts:AssumeRole'
                Resource: arn:aws:iam::6617xxxxxxxxx:role/AssumeFromCoreRole
  1. The Python client code calls STS to assume the role to execute the API call:
def cross_account_client():
    sts_connection = boto3.client('sts')
    acct_b = sts_connection.assume_role(
        RoleArn="arn:aws:iam::6617xxxxxxxxx:role/AssumeFromCoreRole",
        RoleSessionName="cross_acct_lambda"
    )

    ACCESS_KEY = acct_b['Credentials']['AccessKeyId']
    SECRET_KEY = acct_b['Credentials']['SecretAccessKey']
    SESSION_TOKEN = acct_b['Credentials']['SessionToken']

    # create service client using the assumed role credentials, e.g. S3
    client = boto3.client(
        'route53',
        aws_access_key_id=ACCESS_KEY,
        aws_secret_access_key=SECRET_KEY,
        aws_session_token=SESSION_TOKEN,
    )
    return client

Then, I use it this way:

r53_cross_account_role_client = cross_account_client()
    try:
        logger.info('Calling associate_vpc_with_hosted_zone')
        r53_cross_account_role_client.associate_vpc_with_hosted_zone(
            HostedZoneId=phz_id,
            VPC={
                'VPCRegion': aws_region,
                'VPCId': workload_vpc_id
            }
        )

But I must be missing something obvious. Has anyone else come across the same?

1

There are 1 best solutions below

1
On

If I am reading this correctly, I think you have reverse relation between roles. Specifically, you mentioned that you want workload account to assume role in central account, but then your workload role is defined as:

DNSACrossAccountRole:
Type: AWS::IAM::Role
Properties:
  AssumeRolePolicyDocument:
    Version: '2012-10-17'
    Statement:
      - Sid: AssumeRole
        Effect: Allow
        Principal:
          'AWS': !Sub 'arn:aws:iam::${CoreAccountID}:role/DNS-Automation-Factory-${Environment}'
        Action: 'sts:AssumeRole'
  RoleName: AssumeFromCoreRole

Which does the opposite - it allows core account to assume it, not the other way around. If you want your workload role to be able to assume core account you need to use Policies, not AssumeRolePolicyDocument. As per documentation, AssumeRolePolicyDocument specified who can assume this role.