0

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?

craigcaulfield
  • 3,381
  • 10
  • 32
  • 40
  • Looking at the error message, AssumeFromCoreRole is being used to authenticate the route53:AssociateVPCWithHostedZone operation. You show a function that looks valid to create a client with the assumed credentials, but do you call that function? Do you use the client from it? – erik258 Jul 28 '23 at 01:13
  • I've updated the original question with how I'm using the assumed credentials. – craigcaulfield Jul 28 '23 at 01:44

1 Answers1

1

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.

Tofig Hasanov
  • 3,303
  • 10
  • 51
  • 81
  • Apologies, I didn't explain the dilemma adequately, and I've updated the question. The central account needs to perform a VPC association between a VPC in the workload account and a private hosted zone in the central account. And, the only way this can be done is as though from the workload account. – craigcaulfield Jul 28 '23 at 05:01