From fe4bc1dccae89ace70f3dab81b7e7545173d5750 Mon Sep 17 00:00:00 2001 From: Nick Aiello Date: Thu, 28 Mar 2024 18:57:55 -0500 Subject: [PATCH] feat(route53): allow specifying an STS region when creating a cross-account zone delegation (#29466) ### Issue # (if applicable) n/a ### Reason for this change In certain circumstances, the default STS region resolution logic will not properly select a region due to the hardcoded mapping between region prefixes and STS regions. ### Description of changes This change allows callers to specify a region in which STS will be called. ### Description of how you validated changes Unit tests were added to aws-cdk-lib. Integ tests were updated and pass on my personal accounts, but I'm not sure how to check if they'll pass in CI. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../index.js | 1 - .../__entrypoint__.js | 0 .../index.js | 1 + ...-stack-with-assume-role-region.assets.json | 34 +++ ...tack-with-assume-role-region.template.json | 159 ++++++++++++++ .../child-opt-in-stack.assets.json | 10 +- .../child-opt-in-stack.template.json | 6 +- .../child-stack.assets.json | 10 +- .../child-stack.template.json | 2 +- .../integ.json | 3 +- .../manifest.json | 83 ++++++- .../tree.json | 202 +++++++++++++++++- .../integ.cross-account-zone-delegation.ts | 25 ++- .../index.js | 1 - .../__entrypoint__.js | 0 .../index.js | 1 + .../child-stack.assets.json | 10 +- .../child-stack.template.json | 2 +- .../manifest.json | 2 +- .../index.ts | 5 +- packages/aws-cdk-lib/aws-route53/README.md | 29 +++ .../aws-cdk-lib/aws-route53/lib/record-set.ts | 8 + .../aws-route53/test/record-set.test.ts | 54 +++++ 23 files changed, 615 insertions(+), 33 deletions(-) delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js rename packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/{asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a => asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458}/__entrypoint__.js (100%) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.template.json delete mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js rename packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/{asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a => asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458}/__entrypoint__.js (100%) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js deleted file mode 100644 index d69c0934f88d4..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var h=(o,e)=>{for(var s in e)a(o,s,{get:e[s],enumerable:!0})},P=(o,e,s,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Z(e))!N.call(o,n)&&n!==s&&a(o,n,{get:()=>e[n],enumerable:!(t=p(e,n))||t.enumerable});return o};var E=o=>P(a({},"__esModule",{value:!0}),o);var T={};h(T,{handler:()=>w});module.exports=E(T);var c=require("@aws-sdk/client-route-53"),u=require("@aws-sdk/credential-providers");async function w(o){let e=o.ResourceProperties;switch(o.RequestType){case"Create":return r(e,!1);case"Update":return D(e,o.OldResourceProperties);case"Delete":return r(e,!0)}}async function D(o,e){e&&o.DelegatedZoneName!==e.DelegatedZoneName&&await r(e,!0),await r(o,!1)}async function r(o,e){let{AssumeRoleArn:s,ParentZoneId:t,ParentZoneName:n,DelegatedZoneName:d,DelegatedZoneNameServers:m,TTL:g}=o;if(!t&&!n)throw Error("One of ParentZoneId or ParentZoneName must be specified");let l=new Date().getTime(),i=new c.Route53({credentials:(0,u.fromTemporaryCredentials)({clientConfig:{region:S(process.env.AWS_REGION??process.env.AWS_DEFAULT_REGION??"")},params:{RoleArn:s,RoleSessionName:`cross-account-zone-delegation-${l}`}})}),R=t??await A(n,i);await i.changeResourceRecordSets({HostedZoneId:R,ChangeBatch:{Changes:[{Action:e?"DELETE":"UPSERT",ResourceRecordSet:{Name:d,Type:"NS",TTL:g,ResourceRecords:m.map(f=>({Value:f}))}}]}})}async function A(o,e){let t=(await e.listHostedZonesByName({DNSName:o})).HostedZones?.filter(n=>n.Name===`${o}.`)??[];if(t&&t.length!==1)throw Error(`Expected one hosted zone to match the given name but found ${t.length}`);return t[0].Id}function S(o){let e={cn:"cn-northwest-1","us-gov":"us-gov-west-1","us-iso":"us-iso-east-1","us-isob":"us-isob-east-1","eu-isoe":"eu-isoe-west-1","us-isof":"us-isof-south-1"};for(let[s,t]of Object.entries(e))if(o.startsWith(`${s}-`))return t;return"us-east-1"}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/__entrypoint__.js similarity index 100% rename from packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/__entrypoint__.js rename to packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/__entrypoint__.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js new file mode 100644 index 0000000000000..3f0f1c7eede9c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js @@ -0,0 +1 @@ +"use strict";var a=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var P=(o,e)=>{for(var n in e)a(o,n,{get:e[n],enumerable:!0})},E=(o,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of N(e))!h.call(o,s)&&s!==n&&a(o,s,{get:()=>e[s],enumerable:!(t=Z(e,s))||t.enumerable});return o};var A=o=>E(a({},"__esModule",{value:!0}),o);var v={};P(v,{handler:()=>w});module.exports=A(v);var c=require("@aws-sdk/client-route-53"),u=require("@aws-sdk/credential-providers");async function w(o){let e=o.ResourceProperties;switch(o.RequestType){case"Create":return r(e,!1);case"Update":return D(e,o.OldResourceProperties);case"Delete":return r(e,!0)}}async function D(o,e){e&&o.DelegatedZoneName!==e.DelegatedZoneName&&await r(e,!0),await r(o,!1)}async function r(o,e){let{AssumeRoleArn:n,ParentZoneId:t,ParentZoneName:s,DelegatedZoneName:m,DelegatedZoneNameServers:d,TTL:g,AssumeRoleRegion:R}=o;if(!t&&!s)throw Error("One of ParentZoneId or ParentZoneName must be specified");let l=new Date().getTime(),i=new c.Route53({credentials:(0,u.fromTemporaryCredentials)({clientConfig:{region:R??T(process.env.AWS_REGION??process.env.AWS_DEFAULT_REGION??"")},params:{RoleArn:n,RoleSessionName:`cross-account-zone-delegation-${l}`}})}),f=t??await S(s,i);await i.changeResourceRecordSets({HostedZoneId:f,ChangeBatch:{Changes:[{Action:e?"DELETE":"UPSERT",ResourceRecordSet:{Name:m,Type:"NS",TTL:g,ResourceRecords:d.map(p=>({Value:p}))}}]}})}async function S(o,e){let t=(await e.listHostedZonesByName({DNSName:o})).HostedZones?.filter(s=>s.Name===`${o}.`)??[];if(t&&t.length!==1)throw Error(`Expected one hosted zone to match the given name but found ${t.length}`);return t[0].Id}function T(o){let e={cn:"cn-northwest-1","us-gov":"us-gov-west-1","us-iso":"us-iso-east-1","us-isob":"us-isob-east-1","eu-isoe":"eu-isoe-west-1","us-isof":"us-isof-south-1"};for(let[n,t]of Object.entries(e))if(o.startsWith(`${n}-`))return t;return"us-east-1"}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.assets.json new file mode 100644 index 0000000000000..fcf8c9d9a0b2c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.assets.json @@ -0,0 +1,34 @@ +{ + "version": "36.0.0", + "files": { + "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458": { + "source": { + "path": "asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458", + "packaging": "zip" + }, + "destinations": { + "234567890123-af-south-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", + "objectKey": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip", + "region": "af-south-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-af-south-1" + } + } + }, + "a78a3dc2d80e9c4da64e1535efeb43c779441835dfc427c092f0c61fed0c63c4": { + "source": { + "path": "child-opt-in-stack-with-assume-role-region.template.json", + "packaging": "file" + }, + "destinations": { + "234567890123-af-south-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", + "objectKey": "a78a3dc2d80e9c4da64e1535efeb43c779441835dfc427c092f0c61fed0c63c4.json", + "region": "af-south-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-af-south-1" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.template.json new file mode 100644 index 0000000000000..2355e36da150a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack-with-assume-role-region.template.json @@ -0,0 +1,159 @@ +{ + "Resources": { + "SubZoneF7955E1A": { + "Type": "AWS::Route53::HostedZone", + "Properties": { + "Name": "sub3.uniqueexample.com." + } + }, + "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1970772B0": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1", + "Roles": [ + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "/", + { + "Fn::Select": [ + 5, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", + "Arn" + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + }, + "delegateCrossAccountZoneDelegationCustomResource23BD590B": { + "Type": "Custom::CrossAccountZoneDelegation", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265", + "Arn" + ] + }, + "AssumeRoleArn": "arn:aws:iam::12345678:role/MyUniqueDelegationRole", + "ParentZoneName": "uniqueexample.com", + "DelegatedZoneName": "sub3.uniqueexample.com", + "DelegatedZoneNameServers": { + "Fn::GetAtt": [ + "SubZoneF7955E1A", + "NameServers" + ] + }, + "TTL": 172800, + "AssumeRoleRegion": "eu-west-1" + }, + "DependsOn": [ + "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1970772B0" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ] + } + }, + "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": "cdk-hnb659fds-assets-234567890123-af-south-1", + "S3Key": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", + "Arn" + ] + }, + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.assets.json index 71e2bce9c16b6..09f4ec5c6b1ca 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.assets.json @@ -1,21 +1,21 @@ { "version": "36.0.0", "files": { - "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a": { + "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458": { "source": { - "path": "asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a", + "path": "asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458", "packaging": "zip" }, "destinations": { "234567890123-af-south-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", - "objectKey": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip", + "objectKey": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip", "region": "af-south-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-af-south-1" } } }, - "34da3610276ae2d635b15c43c511f47cbd7b4f6e3b7de7b82b980f76956011b1": { + "c1eff1c52ef11d0e701efdf0a44fa41b7e08915b74b284a3d6dd71f1ff90a6cf": { "source": { "path": "child-opt-in-stack.template.json", "packaging": "file" @@ -23,7 +23,7 @@ "destinations": { "234567890123-af-south-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", - "objectKey": "34da3610276ae2d635b15c43c511f47cbd7b4f6e3b7de7b82b980f76956011b1.json", + "objectKey": "c1eff1c52ef11d0e701efdf0a44fa41b7e08915b74b284a3d6dd71f1ff90a6cf.json", "region": "af-south-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-af-south-1" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.template.json index fb9d627591fd9..bd87415d2baed 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.template.json @@ -3,7 +3,7 @@ "SubZoneF7955E1A": { "Type": "AWS::Route53::HostedZone", "Properties": { - "Name": "sub.uniqueexample.com." + "Name": "sub2.uniqueexample.com." } }, "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26DE28FC01D": { @@ -61,7 +61,7 @@ }, "AssumeRoleArn": "arn:aws:iam::12345678:role/MyUniqueDelegationRole", "ParentZoneName": "uniqueexample.com", - "DelegatedZoneName": "sub.uniqueexample.com", + "DelegatedZoneName": "sub2.uniqueexample.com", "DelegatedZoneNameServers": { "Fn::GetAtt": [ "SubZoneF7955E1A", @@ -103,7 +103,7 @@ "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-234567890123-af-south-1", - "S3Key": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip" + "S3Key": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip" }, "Timeout": 900, "MemorySize": 128, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.assets.json index 3e9342b96558d..735331fee4937 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.assets.json @@ -1,21 +1,21 @@ { "version": "36.0.0", "files": { - "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a": { + "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458": { "source": { - "path": "asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a", + "path": "asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458", "packaging": "zip" }, "destinations": { "234567890123-us-east-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", - "objectKey": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip", + "objectKey": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-1" } } }, - "3e4b4f51ab2cf9d297070625300465aeacdc41af65e442818c5ef6c17e800728": { + "842851077ae4d9217e979ac9b947e1aba7d8ee848ad1606c64fd070f2d09a426": { "source": { "path": "child-stack.template.json", "packaging": "file" @@ -23,7 +23,7 @@ "destinations": { "234567890123-us-east-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", - "objectKey": "3e4b4f51ab2cf9d297070625300465aeacdc41af65e442818c5ef6c17e800728.json", + "objectKey": "842851077ae4d9217e979ac9b947e1aba7d8ee848ad1606c64fd070f2d09a426.json", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-1" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.template.json index 0e056b8c4a286..55d04123d6a51 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.template.json @@ -103,7 +103,7 @@ "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-234567890123-us-east-1", - "S3Key": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip" + "S3Key": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip" }, "Timeout": 900, "MemorySize": 128, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/integ.json index a1405d643a470..7a1037b90cdd7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/integ.json @@ -4,7 +4,8 @@ "Route53CrossAccountInteg/DefaultTest": { "stacks": [ "child-stack", - "child-opt-in-stack" + "child-opt-in-stack", + "child-opt-in-stack-with-assume-role-region" ], "diffAssets": true, "assertionStack": "Route53CrossAccountInteg/DefaultTest/DeployAssert", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/manifest.json index e880c00afc438..d9097fab077c7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/manifest.json @@ -84,7 +84,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-deploy-role-234567890123-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-cfn-exec-role-234567890123-us-east-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-us-east-1/3e4b4f51ab2cf9d297070625300465aeacdc41af65e442818c5ef6c17e800728.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-us-east-1/842851077ae4d9217e979ac9b947e1aba7d8ee848ad1606c64fd070f2d09a426.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -163,7 +163,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-deploy-role-234567890123-af-south-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-cfn-exec-role-234567890123-af-south-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-af-south-1/34da3610276ae2d635b15c43c511f47cbd7b4f6e3b7de7b82b980f76956011b1.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-af-south-1/c1eff1c52ef11d0e701efdf0a44fa41b7e08915b74b284a3d6dd71f1ff90a6cf.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -225,6 +225,85 @@ }, "displayName": "child-opt-in-stack" }, + "child-opt-in-stack-with-assume-role-region.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "child-opt-in-stack-with-assume-role-region.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "child-opt-in-stack-with-assume-role-region": { + "type": "aws:cloudformation:stack", + "environment": "aws://234567890123/af-south-1", + "properties": { + "templateFile": "child-opt-in-stack-with-assume-role-region.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-deploy-role-234567890123-af-south-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-cfn-exec-role-234567890123-af-south-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-af-south-1/a78a3dc2d80e9c4da64e1535efeb43c779441835dfc427c092f0c61fed0c63c4.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "child-opt-in-stack-with-assume-role-region.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-lookup-role-234567890123-af-south-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "parent-stack", + "child-opt-in-stack-with-assume-role-region.assets" + ], + "metadata": { + "/child-opt-in-stack-with-assume-role-region/SubZone/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SubZoneF7955E1A" + } + ], + "/child-opt-in-stack-with-assume-role-region/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1970772B0" + } + ], + "/child-opt-in-stack-with-assume-role-region/delegate/CrossAccountZoneDelegationCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "delegateCrossAccountZoneDelegationCustomResource23BD590B" + } + ], + "/child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" + } + ], + "/child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265" + } + ], + "/child-opt-in-stack-with-assume-role-region/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/child-opt-in-stack-with-assume-role-region/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "child-opt-in-stack-with-assume-role-region" + }, "Route53CrossAccountIntegDefaultTestDeployAssertF1D808C9.assets": { "type": "cdk:asset-manifest", "properties": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/tree.json index af266b3859958..6ed5d16c08087 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/tree.json @@ -377,7 +377,7 @@ "attributes": { "aws:cdk:cloudformation:type": "AWS::Route53::HostedZone", "aws:cdk:cloudformation:props": { - "name": "sub.uniqueexample.com." + "name": "sub2.uniqueexample.com." } }, "constructInfo": { @@ -563,6 +563,206 @@ "version": "0.0.0" } }, + "child-opt-in-stack-with-assume-role-region": { + "id": "child-opt-in-stack-with-assume-role-region", + "path": "child-opt-in-stack-with-assume-role-region", + "children": { + "SubZone": { + "id": "SubZone", + "path": "child-opt-in-stack-with-assume-role-region/SubZone", + "children": { + "Resource": { + "id": "Resource", + "path": "child-opt-in-stack-with-assume-role-region/SubZone/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Route53::HostedZone", + "aws:cdk:cloudformation:props": { + "name": "sub3.uniqueexample.com." + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_route53.CfnHostedZone", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_route53.PublicHostedZone", + "version": "0.0.0" + } + }, + "MutableRoleDelegationRole": { + "id": "MutableRoleDelegationRole", + "path": "child-opt-in-stack-with-assume-role-region/MutableRoleDelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "DelegationRole": { + "id": "DelegationRole", + "path": "child-opt-in-stack-with-assume-role-region/DelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "delegate": { + "id": "delegate", + "path": "child-opt-in-stack-with-assume-role-region/delegate", + "children": { + "cross-account-zone-delegation-handler-role": { + "id": "cross-account-zone-delegation-handler-role", + "path": "child-opt-in-stack-with-assume-role-region/delegate/cross-account-zone-delegation-handler-role", + "children": { + "PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1": { + "id": "PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1", + "path": "child-opt-in-stack-with-assume-role-region/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1", + "children": { + "Resource": { + "id": "Resource", + "path": "child-opt-in-stack-with-assume-role-region/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" + } + ], + "Version": "2012-10-17" + }, + "policyName": "PolicychildoptinstackwithassumeroleregiondelegatecrossaccountzonedelegationhandlerroleA822DAE1", + "roles": [ + { + "Fn::Select": [ + 1, + { + "Fn::Split": [ + "/", + { + "Fn::Select": [ + 5, + { + "Fn::Split": [ + ":", + { + "Fn::GetAtt": [ + "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", + "Arn" + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "CrossAccountZoneDelegationCustomResource": { + "id": "CrossAccountZoneDelegationCustomResource", + "path": "child-opt-in-stack-with-assume-role-region/delegate/CrossAccountZoneDelegationCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "child-opt-in-stack-with-assume-role-region/delegate/CrossAccountZoneDelegationCustomResource/Default", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_route53.CrossAccountZoneDelegationRecord", + "version": "0.0.0" + } + }, + "Custom::CrossAccountZoneDelegationCustomResourceProvider": { + "id": "Custom::CrossAccountZoneDelegationCustomResourceProvider", + "path": "child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "child-opt-in-stack-with-assume-role-region/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.CustomResourceProviderBase", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "child-opt-in-stack-with-assume-role-region/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "child-opt-in-stack-with-assume-role-region/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, "Route53CrossAccountInteg": { "id": "Route53CrossAccountInteg", "path": "Route53CrossAccountInteg", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.ts index 54ac97f2df5ca..5ceb81c95f453 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.ts @@ -39,7 +39,6 @@ const crossAccount = process.env.CDK_INTEG_CROSS_ACCOUNT || '234567890123'; // t const delegationRoleName = 'MyUniqueDelegationRole'; const parentZoneName = 'uniqueexample.com'; -const subZoneName = 'sub.uniqueexample.com'; class ParentStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { @@ -56,12 +55,17 @@ class ParentStack extends cdk.Stack { } } +interface ChildStackProps extends cdk.StackProps { + readonly subZoneName: string; + readonly assumeRoleRegion?: string; +} + class ChildStack extends cdk.Stack { - constructor(scope: Construct, id: string, props?: cdk.StackProps) { + constructor(scope: Construct, id: string, props: ChildStackProps) { super(scope, id, props); const subZone = new route53.PublicHostedZone(this, 'SubZone', { - zoneName: subZoneName, + zoneName: props.subZoneName, }); const delegationRoleArn = cdk.Stack.of(this).formatArn({ @@ -77,6 +81,7 @@ class ChildStack extends cdk.Stack { delegatedZone: subZone, parentHostedZoneName: parentZoneName, delegationRole, + assumeRoleRegion: props.assumeRoleRegion, }); } } @@ -93,6 +98,7 @@ const childStack = new ChildStack(app, 'child-stack', { account: crossAccount, region: 'us-east-1', }, + subZoneName: 'sub.uniqueexample.com', }); const childOptInStack = new ChildStack(app, 'child-opt-in-stack', { @@ -100,12 +106,23 @@ const childOptInStack = new ChildStack(app, 'child-opt-in-stack', { account: crossAccount, region: 'af-south-1', }, + subZoneName: 'sub2.uniqueexample.com', +}); + +const childOptInStackWithAssumeRoleRegion = new ChildStack(app, 'child-opt-in-stack-with-assume-role-region', { + env: { + account: crossAccount, + region: 'af-south-1', + }, + assumeRoleRegion: 'eu-west-1', + subZoneName: 'sub3.uniqueexample.com', }); childStack.addDependency(parentStack); childOptInStack.addDependency(parentStack); +childOptInStackWithAssumeRoleRegion.addDependency(parentStack); new IntegTest(app, 'Route53CrossAccountInteg', { - testCases: [childStack, childOptInStack], + testCases: [childStack, childOptInStack, childOptInStackWithAssumeRoleRegion], diffAssets: true, }); \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js deleted file mode 100644 index d69c0934f88d4..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/index.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";var a=Object.defineProperty;var p=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var h=(o,e)=>{for(var s in e)a(o,s,{get:e[s],enumerable:!0})},P=(o,e,s,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of Z(e))!N.call(o,n)&&n!==s&&a(o,n,{get:()=>e[n],enumerable:!(t=p(e,n))||t.enumerable});return o};var E=o=>P(a({},"__esModule",{value:!0}),o);var T={};h(T,{handler:()=>w});module.exports=E(T);var c=require("@aws-sdk/client-route-53"),u=require("@aws-sdk/credential-providers");async function w(o){let e=o.ResourceProperties;switch(o.RequestType){case"Create":return r(e,!1);case"Update":return D(e,o.OldResourceProperties);case"Delete":return r(e,!0)}}async function D(o,e){e&&o.DelegatedZoneName!==e.DelegatedZoneName&&await r(e,!0),await r(o,!1)}async function r(o,e){let{AssumeRoleArn:s,ParentZoneId:t,ParentZoneName:n,DelegatedZoneName:d,DelegatedZoneNameServers:m,TTL:g}=o;if(!t&&!n)throw Error("One of ParentZoneId or ParentZoneName must be specified");let l=new Date().getTime(),i=new c.Route53({credentials:(0,u.fromTemporaryCredentials)({clientConfig:{region:S(process.env.AWS_REGION??process.env.AWS_DEFAULT_REGION??"")},params:{RoleArn:s,RoleSessionName:`cross-account-zone-delegation-${l}`}})}),R=t??await A(n,i);await i.changeResourceRecordSets({HostedZoneId:R,ChangeBatch:{Changes:[{Action:e?"DELETE":"UPSERT",ResourceRecordSet:{Name:d,Type:"NS",TTL:g,ResourceRecords:m.map(f=>({Value:f}))}}]}})}async function A(o,e){let t=(await e.listHostedZonesByName({DNSName:o})).HostedZones?.filter(n=>n.Name===`${o}.`)??[];if(t&&t.length!==1)throw Error(`Expected one hosted zone to match the given name but found ${t.length}`);return t[0].Id}function S(o){let e={cn:"cn-northwest-1","us-gov":"us-gov-west-1","us-iso":"us-iso-east-1","us-isob":"us-isob-east-1","eu-isoe":"eu-isoe-west-1","us-isof":"us-isof-south-1"};for(let[s,t]of Object.entries(e))if(o.startsWith(`${s}-`))return t;return"us-east-1"}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/__entrypoint__.js similarity index 100% rename from packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a/__entrypoint__.js rename to packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/__entrypoint__.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js new file mode 100644 index 0000000000000..3f0f1c7eede9c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458/index.js @@ -0,0 +1 @@ +"use strict";var a=Object.defineProperty;var Z=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var h=Object.prototype.hasOwnProperty;var P=(o,e)=>{for(var n in e)a(o,n,{get:e[n],enumerable:!0})},E=(o,e,n,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of N(e))!h.call(o,s)&&s!==n&&a(o,s,{get:()=>e[s],enumerable:!(t=Z(e,s))||t.enumerable});return o};var A=o=>E(a({},"__esModule",{value:!0}),o);var v={};P(v,{handler:()=>w});module.exports=A(v);var c=require("@aws-sdk/client-route-53"),u=require("@aws-sdk/credential-providers");async function w(o){let e=o.ResourceProperties;switch(o.RequestType){case"Create":return r(e,!1);case"Update":return D(e,o.OldResourceProperties);case"Delete":return r(e,!0)}}async function D(o,e){e&&o.DelegatedZoneName!==e.DelegatedZoneName&&await r(e,!0),await r(o,!1)}async function r(o,e){let{AssumeRoleArn:n,ParentZoneId:t,ParentZoneName:s,DelegatedZoneName:m,DelegatedZoneNameServers:d,TTL:g,AssumeRoleRegion:R}=o;if(!t&&!s)throw Error("One of ParentZoneId or ParentZoneName must be specified");let l=new Date().getTime(),i=new c.Route53({credentials:(0,u.fromTemporaryCredentials)({clientConfig:{region:R??T(process.env.AWS_REGION??process.env.AWS_DEFAULT_REGION??"")},params:{RoleArn:n,RoleSessionName:`cross-account-zone-delegation-${l}`}})}),f=t??await S(s,i);await i.changeResourceRecordSets({HostedZoneId:f,ChangeBatch:{Changes:[{Action:e?"DELETE":"UPSERT",ResourceRecordSet:{Name:m,Type:"NS",TTL:g,ResourceRecords:d.map(p=>({Value:p}))}}]}})}async function S(o,e){let t=(await e.listHostedZonesByName({DNSName:o})).HostedZones?.filter(s=>s.Name===`${o}.`)??[];if(t&&t.length!==1)throw Error(`Expected one hosted zone to match the given name but found ${t.length}`);return t[0].Id}function T(o){let e={cn:"cn-northwest-1","us-gov":"us-gov-west-1","us-iso":"us-iso-east-1","us-isob":"us-isob-east-1","eu-isoe":"eu-isoe-west-1","us-isof":"us-isof-south-1"};for(let[n,t]of Object.entries(e))if(o.startsWith(`${n}-`))return t;return"us-east-1"}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.assets.json index 9f17e5a71f2d7..098461f91e808 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.assets.json @@ -1,21 +1,21 @@ { "version": "36.0.0", "files": { - "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a": { + "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458": { "source": { - "path": "asset.aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a", + "path": "asset.f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458", "packaging": "zip" }, "destinations": { "234567890123-us-east-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", - "objectKey": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip", + "objectKey": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-1" } } }, - "29bfebfb05b102586faa0f38d585a3aea3433366ba19f4b7f213dbc46a9e7544": { + "14800d68ec4a699ef7ee95b17c76e0eba3badf933bf2e67a6880e082a148bfca": { "source": { "path": "child-stack.template.json", "packaging": "file" @@ -23,7 +23,7 @@ "destinations": { "234567890123-us-east-1": { "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", - "objectKey": "29bfebfb05b102586faa0f38d585a3aea3433366ba19f4b7f213dbc46a9e7544.json", + "objectKey": "14800d68ec4a699ef7ee95b17c76e0eba3badf933bf2e67a6880e082a148bfca.json", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-1" } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.template.json index b510dd3a2b69f..dadf35d9f1ecd 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/child-stack.template.json @@ -103,7 +103,7 @@ "Properties": { "Code": { "S3Bucket": "cdk-hnb659fds-assets-234567890123-us-east-1", - "S3Key": "aca4a134bf7ace6088b21213be7ab4357e3705f714362b690d76376b8f1df53a.zip" + "S3Key": "f43e5ef82b45e2e3ecb60cd54aa4a3599da7bb4c85d10cfe133dc43f54705458.zip" }, "Timeout": 900, "MemorySize": 128, diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/manifest.json index b5cc97c012268..fcb1f39df7be0 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.rename-cross-account-zone-delegation.js.snapshot/manifest.json @@ -84,7 +84,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-deploy-role-234567890123-us-east-1", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-cfn-exec-role-234567890123-us-east-1", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-us-east-1/29bfebfb05b102586faa0f38d585a3aea3433366ba19f4b7f213dbc46a9e7544.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-234567890123-us-east-1/14800d68ec4a699ef7ee95b17c76e0eba3badf933bf2e67a6880e082a148bfca.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ diff --git a/packages/@aws-cdk/custom-resource-handlers/lib/aws-route53/cross-account-zone-delegation-handler/index.ts b/packages/@aws-cdk/custom-resource-handlers/lib/aws-route53/cross-account-zone-delegation-handler/index.ts index 833ec0cb5d3b9..092b6aad9b27a 100644 --- a/packages/@aws-cdk/custom-resource-handlers/lib/aws-route53/cross-account-zone-delegation-handler/index.ts +++ b/packages/@aws-cdk/custom-resource-handlers/lib/aws-route53/cross-account-zone-delegation-handler/index.ts @@ -15,6 +15,7 @@ interface ResourceProperties { DelegatedZoneName: string, DelegatedZoneNameServers: string[], TTL: number, + AssumeRoleRegion?: string, } export async function handler(event: CrossAccountZoneDelegationEvent) { @@ -37,7 +38,7 @@ async function cfnUpdateEventHandler(props: ResourceProperties, oldProps: Resour } async function cfnEventHandler(props: ResourceProperties, isDeleteEvent: boolean) { - const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL } = props; + const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL, AssumeRoleRegion } = props; if (!ParentZoneId && !ParentZoneName) { throw Error('One of ParentZoneId or ParentZoneName must be specified'); @@ -47,7 +48,7 @@ async function cfnEventHandler(props: ResourceProperties, isDeleteEvent: boolean const route53 = new Route53({ credentials: fromTemporaryCredentials({ clientConfig: { - region: route53Region(process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? ''), + region: AssumeRoleRegion ?? route53Region(process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? ''), }, params: { RoleArn: AssumeRoleArn, diff --git a/packages/aws-cdk-lib/aws-route53/README.md b/packages/aws-cdk-lib/aws-route53/README.md index 2f7737d65a3b5..09298340c472d 100644 --- a/packages/aws-cdk-lib/aws-route53/README.md +++ b/packages/aws-cdk-lib/aws-route53/README.md @@ -305,6 +305,35 @@ new route53.CrossAccountZoneDelegationRecord(this, 'delegate', { }); ``` +Delegating the hosted zone requires assuming a role in the parent hosted zone's account. +In order for the assumed credentials to be valid, the resource must assume the role using +an STS endpoint in a region where both the subdomain's account and the parent's account +are opted-in. By default, this region is determined automatically, but if you need to +change the region used for the AssumeRole call, specify `assumeRoleRegion`: + +```ts +const subZone = new route53.PublicHostedZone(this, 'SubZone', { + zoneName: 'sub.someexample.com', +}); + +// import the delegation role by constructing the roleArn +const delegationRoleArn = Stack.of(this).formatArn({ + region: '', // IAM is global in each partition + service: 'iam', + account: 'parent-account-id', + resource: 'role', + resourceName: 'MyDelegationRole', +}); +const delegationRole = iam.Role.fromRoleArn(this, 'DelegationRole', delegationRoleArn); + +new route53.CrossAccountZoneDelegationRecord(this, 'delegate', { + delegatedZone: subZone, + parentHostedZoneName: 'someexample.com', // or you can use parentHostedZoneId + delegationRole, + assumeRoleRegion: "us-east-1", +}); +``` + ### Add Trailing Dot to Domain Names In order to continue managing existing domain names with trailing dots using CDK, you can set `addTrailingDot: false` to prevent the Construct from adding a dot at the end of the domain name. diff --git a/packages/aws-cdk-lib/aws-route53/lib/record-set.ts b/packages/aws-cdk-lib/aws-route53/lib/record-set.ts index 65e102e1e32a8..a0d2024e4a3d4 100644 --- a/packages/aws-cdk-lib/aws-route53/lib/record-set.ts +++ b/packages/aws-cdk-lib/aws-route53/lib/record-set.ts @@ -859,6 +859,13 @@ export interface CrossAccountZoneDelegationRecordProps { * @default RemovalPolicy.DESTROY */ readonly removalPolicy?: RemovalPolicy; + + /** + * Region from which to obtain temporary credentials. + * + * @default - the Route53 signing region in the current partition + */ + readonly assumeRoleRegion?: string; } /** @@ -897,6 +904,7 @@ export class CrossAccountZoneDelegationRecord extends Construct { DelegatedZoneName: props.delegatedZone.zoneName, DelegatedZoneNameServers: props.delegatedZone.hostedZoneNameServers!, TTL: (props.ttl || Duration.days(2)).toSeconds(), + AssumeRoleRegion: props.assumeRoleRegion, }, }); diff --git a/packages/aws-cdk-lib/aws-route53/test/record-set.test.ts b/packages/aws-cdk-lib/aws-route53/test/record-set.test.ts index a8f717e4b0242..292580cbd8eb4 100644 --- a/packages/aws-cdk-lib/aws-route53/test/record-set.test.ts +++ b/packages/aws-cdk-lib/aws-route53/test/record-set.test.ts @@ -811,6 +811,60 @@ describe('record set', () => { }); }); + test('Cross account zone delegation record with stsRegion', () => { + // GIVEN + const stack = new Stack(); + const parentZone = new route53.PublicHostedZone(stack, 'ParentHostedZone', { + zoneName: 'myzone.com', + crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal('123456789012'), + }); + + // WHEN + const childZone = new route53.PublicHostedZone(stack, 'ChildHostedZone', { + zoneName: 'sub.myzone.com', + }); + new route53.CrossAccountZoneDelegationRecord(stack, 'Delegation', { + delegatedZone: childZone, + parentHostedZoneId: parentZone.hostedZoneId, + delegationRole: parentZone.crossAccountZoneDelegationRole!, + ttl: Duration.seconds(60), + removalPolicy: RemovalPolicy.RETAIN, + assumeRoleRegion: 'fake-region-1', + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { + ServiceToken: { + 'Fn::GetAtt': [ + 'CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265', + 'Arn', + ], + }, + AssumeRoleArn: { + 'Fn::GetAtt': [ + 'ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E', + 'Arn', + ], + }, + ParentZoneId: { + Ref: 'ParentHostedZoneC2BD86E1', + }, + DelegatedZoneName: 'sub.myzone.com', + DelegatedZoneNameServers: { + 'Fn::GetAtt': [ + 'ChildHostedZone4B14AC71', + 'NameServers', + ], + }, + TTL: 60, + AssumeRoleRegion: 'fake-region-1', + }); + Template.fromStack(stack).hasResource('Custom::CrossAccountZoneDelegation', { + DeletionPolicy: 'Retain', + UpdateReplacePolicy: 'Retain', + }); + }); + testDeprecated('Cross account zone delegation record with parentHostedZoneName', () => { // GIVEN const stack = new Stack();