diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab/__entrypoint__.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563/__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.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab/__entrypoint__.js rename to packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563/__entrypoint__.js diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563/index.js new file mode 100644 index 0000000000000..f97f8b1e0dc62 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563/index.js @@ -0,0 +1,95 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +// eslint-disable-next-line import/no-extraneous-dependencies +const client_route_53_1 = require("@aws-sdk/client-route-53"); +// eslint-disable-next-line import/no-extraneous-dependencies +const credential_providers_1 = require("@aws-sdk/credential-providers"); +async function handler(event) { + const resourceProps = event.ResourceProperties; + switch (event.RequestType) { + case 'Create': + case 'Update': + return cfnEventHandler(resourceProps, false); + case 'Delete': + return cfnEventHandler(resourceProps, true); + } +} +exports.handler = handler; +async function cfnEventHandler(props, isDeleteEvent) { + const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL } = props; + if (!ParentZoneId && !ParentZoneName) { + throw Error('One of ParentZoneId or ParentZoneName must be specified'); + } + const timestamp = (new Date()).getTime(); + const route53 = new client_route_53_1.Route53({ + credentials: (0, credential_providers_1.fromTemporaryCredentials)({ + clientConfig: { + region: route53Region(process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? ''), + }, + params: { + RoleArn: AssumeRoleArn, + RoleSessionName: `cross-account-zone-delegation-${timestamp}`, + }, + }), + }); + const parentZoneId = ParentZoneId ?? await getHostedZoneIdByName(ParentZoneName, route53); + await route53.changeResourceRecordSets({ + HostedZoneId: parentZoneId, + ChangeBatch: { + Changes: [{ + Action: isDeleteEvent ? 'DELETE' : 'UPSERT', + ResourceRecordSet: { + Name: DelegatedZoneName, + Type: 'NS', + TTL, + ResourceRecords: DelegatedZoneNameServers.map(ns => ({ Value: ns })), + }, + }], + }, + }); +} +async function getHostedZoneIdByName(name, route53) { + const zones = await route53.listHostedZonesByName({ DNSName: name }); + const matchedZones = zones.HostedZones?.filter(zone => zone.Name === `${name}.`) ?? []; + if (matchedZones && matchedZones.length !== 1) { + throw Error(`Expected one hosted zone to match the given name but found ${matchedZones.length}`); + } + // will always be defined because we throw if length !==1 + return matchedZones[0].Id; +} +/** + * Return the region that hosts the Route53 endpoint + * + * Route53 is a partitional service: the control plane lives in one particular region, + * which is different for every partition. + * + * The SDK knows how to convert a "target region" to a "route53 endpoint", which + * equates to a (potentially different) region. However, when we use STS + * AssumeRole credentials, we must grab credentials that will work in that + * region. + * + * By default, STS AssumeRole will call the STS endpoint for the same region + * as the Lambda runs in. Normally, this is all good. However, when the AssumeRole + * is used to assume a role in a different account A, the AssumeRole will fail if the + * Lambda is executing in an an opt-in region R to which account A has not been opted in. + * + * To solve this, we will always AssumeRole in the same region as the Route53 call will + * resolve to. + */ +function route53Region(region) { + const partitions = { + 'cn': 'cn-northwest-1', + 'us-gov': 'us-gov-west-1', + 'us-iso': 'us-iso-east-1', + 'us-isob': 'us-isob-east-1', + }; + for (const [prefix, mainRegion] of Object.entries(partitions)) { + if (region.startsWith(`${prefix}-`)) { + return mainRegion; + } + } + // Default for commercial partition + return 'us-east-1'; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QsOERBQW1EO0FBQ25ELDZEQUE2RDtBQUM3RCx3RUFBeUU7QUFXbEUsS0FBSyxVQUFVLE9BQU8sQ0FBQyxLQUFrRDtJQUM5RSxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsa0JBQW1ELENBQUM7SUFFaEYsUUFBUSxLQUFLLENBQUMsV0FBVyxFQUFFO1FBQ3pCLEtBQUssUUFBUSxDQUFDO1FBQ2QsS0FBSyxRQUFRO1lBQ1gsT0FBTyxlQUFlLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQy9DLEtBQUssUUFBUTtZQUNYLE9BQU8sZUFBZSxDQUFDLGFBQWEsRUFBRSxJQUFJLENBQUMsQ0FBQztLQUMvQztBQUNILENBQUM7QUFWRCwwQkFVQztBQUVELEtBQUssVUFBVSxlQUFlLENBQUMsS0FBeUIsRUFBRSxhQUFzQjtJQUM5RSxNQUFNLEVBQUUsYUFBYSxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsaUJBQWlCLEVBQUUsd0JBQXdCLEVBQUUsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDO0lBRWhILElBQUksQ0FBQyxZQUFZLElBQUksQ0FBQyxjQUFjLEVBQUU7UUFDcEMsTUFBTSxLQUFLLENBQUMseURBQXlELENBQUMsQ0FBQztLQUN4RTtJQUVELE1BQU0sU0FBUyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3pDLE1BQU0sT0FBTyxHQUFHLElBQUkseUJBQU8sQ0FBQztRQUMxQixXQUFXLEVBQUUsSUFBQSwrQ0FBd0IsRUFBQztZQUNwQyxZQUFZLEVBQUU7Z0JBQ1osTUFBTSxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixJQUFJLEVBQUUsQ0FBQzthQUN0RjtZQUNELE1BQU0sRUFBRTtnQkFDTixPQUFPLEVBQUUsYUFBYTtnQkFDdEIsZUFBZSxFQUFFLGlDQUFpQyxTQUFTLEVBQUU7YUFDOUQ7U0FDRixDQUFDO0tBQ0gsQ0FBQyxDQUFDO0lBRUgsTUFBTSxZQUFZLEdBQUcsWUFBWSxJQUFJLE1BQU0scUJBQXFCLENBQUMsY0FBZSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBRTNGLE1BQU0sT0FBTyxDQUFDLHdCQUF3QixDQUFDO1FBQ3JDLFlBQVksRUFBRSxZQUFZO1FBQzFCLFdBQVcsRUFBRTtZQUNYLE9BQU8sRUFBRSxDQUFDO29CQUNSLE1BQU0sRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUTtvQkFDM0MsaUJBQWlCLEVBQUU7d0JBQ2pCLElBQUksRUFBRSxpQkFBaUI7d0JBQ3ZCLElBQUksRUFBRSxJQUFJO3dCQUNWLEdBQUc7d0JBQ0gsZUFBZSxFQUFFLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztxQkFDckU7aUJBQ0YsQ0FBQztTQUNIO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxJQUFZLEVBQUUsT0FBZ0I7SUFDakUsTUFBTSxLQUFLLEdBQUcsTUFBTSxPQUFPLENBQUMscUJBQXFCLENBQUMsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUNyRSxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUV2RixJQUFJLFlBQVksSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtRQUM3QyxNQUFNLEtBQUssQ0FBQyw4REFBOEQsWUFBWSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7S0FDbEc7SUFFRCx5REFBeUQ7SUFDekQsT0FBTyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRyxDQUFDO0FBQzdCLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBQ0gsU0FBUyxhQUFhLENBQUMsTUFBYztJQUNuQyxNQUFNLFVBQVUsR0FBRztRQUNqQixJQUFJLEVBQUUsZ0JBQWdCO1FBQ3RCLFFBQVEsRUFBRSxlQUFlO1FBQ3pCLFFBQVEsRUFBRSxlQUFlO1FBQ3pCLFNBQVMsRUFBRSxnQkFBZ0I7S0FDNUIsQ0FBQztJQUVGLEtBQUssTUFBTSxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQzdELElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDbkMsT0FBTyxVQUFVLENBQUM7U0FDbkI7S0FDRjtJQUVELG1DQUFtQztJQUNuQyxPQUFPLFdBQVcsQ0FBQztBQUNyQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgUm91dGU1MyB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1yb3V0ZS01Myc7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzXG5pbXBvcnQgeyBmcm9tVGVtcG9yYXJ5Q3JlZGVudGlhbHMgfSBmcm9tICdAYXdzLXNkay9jcmVkZW50aWFsLXByb3ZpZGVycyc7XG5cbmludGVyZmFjZSBSZXNvdXJjZVByb3BlcnRpZXMge1xuICBBc3N1bWVSb2xlQXJuOiBzdHJpbmcsXG4gIFBhcmVudFpvbmVOYW1lPzogc3RyaW5nLFxuICBQYXJlbnRab25lSWQ/OiBzdHJpbmcsXG4gIERlbGVnYXRlZFpvbmVOYW1lOiBzdHJpbmcsXG4gIERlbGVnYXRlZFpvbmVOYW1lU2VydmVyczogc3RyaW5nW10sXG4gIFRUTDogbnVtYmVyLFxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihldmVudDogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCkge1xuICBjb25zdCByZXNvdXJjZVByb3BzID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzIGFzIHVua25vd24gYXMgUmVzb3VyY2VQcm9wZXJ0aWVzO1xuXG4gIHN3aXRjaCAoZXZlbnQuUmVxdWVzdFR5cGUpIHtcbiAgICBjYXNlICdDcmVhdGUnOlxuICAgIGNhc2UgJ1VwZGF0ZSc6XG4gICAgICByZXR1cm4gY2ZuRXZlbnRIYW5kbGVyKHJlc291cmNlUHJvcHMsIGZhbHNlKTtcbiAgICBjYXNlICdEZWxldGUnOlxuICAgICAgcmV0dXJuIGNmbkV2ZW50SGFuZGxlcihyZXNvdXJjZVByb3BzLCB0cnVlKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBjZm5FdmVudEhhbmRsZXIocHJvcHM6IFJlc291cmNlUHJvcGVydGllcywgaXNEZWxldGVFdmVudDogYm9vbGVhbikge1xuICBjb25zdCB7IEFzc3VtZVJvbGVBcm4sIFBhcmVudFpvbmVJZCwgUGFyZW50Wm9uZU5hbWUsIERlbGVnYXRlZFpvbmVOYW1lLCBEZWxlZ2F0ZWRab25lTmFtZVNlcnZlcnMsIFRUTCB9ID0gcHJvcHM7XG5cbiAgaWYgKCFQYXJlbnRab25lSWQgJiYgIVBhcmVudFpvbmVOYW1lKSB7XG4gICAgdGhyb3cgRXJyb3IoJ09uZSBvZiBQYXJlbnRab25lSWQgb3IgUGFyZW50Wm9uZU5hbWUgbXVzdCBiZSBzcGVjaWZpZWQnKTtcbiAgfVxuXG4gIGNvbnN0IHRpbWVzdGFtcCA9IChuZXcgRGF0ZSgpKS5nZXRUaW1lKCk7XG4gIGNvbnN0IHJvdXRlNTMgPSBuZXcgUm91dGU1Myh7XG4gICAgY3JlZGVudGlhbHM6IGZyb21UZW1wb3JhcnlDcmVkZW50aWFscyh7XG4gICAgICBjbGllbnRDb25maWc6IHtcbiAgICAgICAgcmVnaW9uOiByb3V0ZTUzUmVnaW9uKHByb2Nlc3MuZW52LkFXU19SRUdJT04gPz8gcHJvY2Vzcy5lbnYuQVdTX0RFRkFVTFRfUkVHSU9OID8/ICcnKSxcbiAgICAgIH0sXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgUm9sZUFybjogQXNzdW1lUm9sZUFybixcbiAgICAgICAgUm9sZVNlc3Npb25OYW1lOiBgY3Jvc3MtYWNjb3VudC16b25lLWRlbGVnYXRpb24tJHt0aW1lc3RhbXB9YCxcbiAgICAgIH0sXG4gICAgfSksXG4gIH0pO1xuXG4gIGNvbnN0IHBhcmVudFpvbmVJZCA9IFBhcmVudFpvbmVJZCA/PyBhd2FpdCBnZXRIb3N0ZWRab25lSWRCeU5hbWUoUGFyZW50Wm9uZU5hbWUhLCByb3V0ZTUzKTtcblxuICBhd2FpdCByb3V0ZTUzLmNoYW5nZVJlc291cmNlUmVjb3JkU2V0cyh7XG4gICAgSG9zdGVkWm9uZUlkOiBwYXJlbnRab25lSWQsXG4gICAgQ2hhbmdlQmF0Y2g6IHtcbiAgICAgIENoYW5nZXM6IFt7XG4gICAgICAgIEFjdGlvbjogaXNEZWxldGVFdmVudCA/ICdERUxFVEUnIDogJ1VQU0VSVCcsXG4gICAgICAgIFJlc291cmNlUmVjb3JkU2V0OiB7XG4gICAgICAgICAgTmFtZTogRGVsZWdhdGVkWm9uZU5hbWUsXG4gICAgICAgICAgVHlwZTogJ05TJyxcbiAgICAgICAgICBUVEwsXG4gICAgICAgICAgUmVzb3VyY2VSZWNvcmRzOiBEZWxlZ2F0ZWRab25lTmFtZVNlcnZlcnMubWFwKG5zID0+ICh7IFZhbHVlOiBucyB9KSksXG4gICAgICAgIH0sXG4gICAgICB9XSxcbiAgICB9LFxuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0SG9zdGVkWm9uZUlkQnlOYW1lKG5hbWU6IHN0cmluZywgcm91dGU1MzogUm91dGU1Myk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHpvbmVzID0gYXdhaXQgcm91dGU1My5saXN0SG9zdGVkWm9uZXNCeU5hbWUoeyBETlNOYW1lOiBuYW1lIH0pO1xuICBjb25zdCBtYXRjaGVkWm9uZXMgPSB6b25lcy5Ib3N0ZWRab25lcz8uZmlsdGVyKHpvbmUgPT4gem9uZS5OYW1lID09PSBgJHtuYW1lfS5gKSA/PyBbXTtcblxuICBpZiAobWF0Y2hlZFpvbmVzICYmIG1hdGNoZWRab25lcy5sZW5ndGggIT09IDEpIHtcbiAgICB0aHJvdyBFcnJvcihgRXhwZWN0ZWQgb25lIGhvc3RlZCB6b25lIHRvIG1hdGNoIHRoZSBnaXZlbiBuYW1lIGJ1dCBmb3VuZCAke21hdGNoZWRab25lcy5sZW5ndGh9YCk7XG4gIH1cblxuICAvLyB3aWxsIGFsd2F5cyBiZSBkZWZpbmVkIGJlY2F1c2Ugd2UgdGhyb3cgaWYgbGVuZ3RoICE9PTFcbiAgcmV0dXJuIG1hdGNoZWRab25lc1swXS5JZCE7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSByZWdpb24gdGhhdCBob3N0cyB0aGUgUm91dGU1MyBlbmRwb2ludFxuICpcbiAqIFJvdXRlNTMgaXMgYSBwYXJ0aXRpb25hbCBzZXJ2aWNlOiB0aGUgY29udHJvbCBwbGFuZSBsaXZlcyBpbiBvbmUgcGFydGljdWxhciByZWdpb24sXG4gKiB3aGljaCBpcyBkaWZmZXJlbnQgZm9yIGV2ZXJ5IHBhcnRpdGlvbi5cbiAqXG4gKiBUaGUgU0RLIGtub3dzIGhvdyB0byBjb252ZXJ0IGEgXCJ0YXJnZXQgcmVnaW9uXCIgdG8gYSBcInJvdXRlNTMgZW5kcG9pbnRcIiwgd2hpY2hcbiAqIGVxdWF0ZXMgdG8gYSAocG90ZW50aWFsbHkgZGlmZmVyZW50KSByZWdpb24uIEhvd2V2ZXIsIHdoZW4gd2UgdXNlIFNUU1xuICogQXNzdW1lUm9sZSBjcmVkZW50aWFscywgd2UgbXVzdCBncmFiIGNyZWRlbnRpYWxzIHRoYXQgd2lsbCB3b3JrIGluIHRoYXRcbiAqIHJlZ2lvbi5cbiAqXG4gKiBCeSBkZWZhdWx0LCBTVFMgQXNzdW1lUm9sZSB3aWxsIGNhbGwgdGhlIFNUUyBlbmRwb2ludCBmb3IgdGhlIHNhbWUgcmVnaW9uXG4gKiBhcyB0aGUgTGFtYmRhIHJ1bnMgaW4uIE5vcm1hbGx5LCB0aGlzIGlzIGFsbCBnb29kLiBIb3dldmVyLCB3aGVuIHRoZSBBc3N1bWVSb2xlXG4gKiBpcyB1c2VkIHRvIGFzc3VtZSBhIHJvbGUgaW4gYSBkaWZmZXJlbnQgYWNjb3VudCBBLCB0aGUgQXNzdW1lUm9sZSB3aWxsIGZhaWwgaWYgdGhlXG4gKiBMYW1iZGEgaXMgZXhlY3V0aW5nIGluIGFuIGFuIG9wdC1pbiByZWdpb24gUiB0byB3aGljaCBhY2NvdW50IEEgaGFzIG5vdCBiZWVuIG9wdGVkIGluLlxuICpcbiAqIFRvIHNvbHZlIHRoaXMsIHdlIHdpbGwgYWx3YXlzIEFzc3VtZVJvbGUgaW4gdGhlIHNhbWUgcmVnaW9uIGFzIHRoZSBSb3V0ZTUzIGNhbGwgd2lsbFxuICogcmVzb2x2ZSB0by5cbiAqL1xuZnVuY3Rpb24gcm91dGU1M1JlZ2lvbihyZWdpb246IHN0cmluZykge1xuICBjb25zdCBwYXJ0aXRpb25zID0ge1xuICAgICdjbic6ICdjbi1ub3J0aHdlc3QtMScsXG4gICAgJ3VzLWdvdic6ICd1cy1nb3Ytd2VzdC0xJyxcbiAgICAndXMtaXNvJzogJ3VzLWlzby1lYXN0LTEnLFxuICAgICd1cy1pc29iJzogJ3VzLWlzb2ItZWFzdC0xJyxcbiAgfTtcblxuICBmb3IgKGNvbnN0IFtwcmVmaXgsIG1haW5SZWdpb25dIG9mIE9iamVjdC5lbnRyaWVzKHBhcnRpdGlvbnMpKSB7XG4gICAgaWYgKHJlZ2lvbi5zdGFydHNXaXRoKGAke3ByZWZpeH0tYCkpIHtcbiAgICAgIHJldHVybiBtYWluUmVnaW9uO1xuICAgIH1cbiAgfVxuXG4gIC8vIERlZmF1bHQgZm9yIGNvbW1lcmNpYWwgcGFydGl0aW9uXG4gIHJldHVybiAndXMtZWFzdC0xJztcbn0iXX0= \ 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/asset.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab/index.js b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab/index.js deleted file mode 100644 index 83c3f0eb66811..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/asset.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab/index.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -// eslint-disable-next-line import/no-extraneous-dependencies -const aws_sdk_1 = require("aws-sdk"); -async function handler(event) { - const resourceProps = event.ResourceProperties; - switch (event.RequestType) { - case 'Create': - case 'Update': - return cfnEventHandler(resourceProps, false); - case 'Delete': - return cfnEventHandler(resourceProps, true); - } -} -exports.handler = handler; -async function cfnEventHandler(props, isDeleteEvent) { - const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL, UseRegionalStsEndpoint } = props; - if (!ParentZoneId && !ParentZoneName) { - throw Error('One of ParentZoneId or ParentZoneName must be specified'); - } - const credentials = await getCrossAccountCredentials(AssumeRoleArn, !!UseRegionalStsEndpoint); - const route53 = new aws_sdk_1.Route53({ credentials }); - const parentZoneId = ParentZoneId ?? await getHostedZoneIdByName(ParentZoneName, route53); - await route53.changeResourceRecordSets({ - HostedZoneId: parentZoneId, - ChangeBatch: { - Changes: [{ - Action: isDeleteEvent ? 'DELETE' : 'UPSERT', - ResourceRecordSet: { - Name: DelegatedZoneName, - Type: 'NS', - TTL, - ResourceRecords: DelegatedZoneNameServers.map(ns => ({ Value: ns })), - }, - }], - }, - }).promise(); -} -async function getCrossAccountCredentials(roleArn, regionalEndpoint) { - const sts = new aws_sdk_1.STS(regionalEndpoint ? { stsRegionalEndpoints: 'regional' } : {}); - const timestamp = (new Date()).getTime(); - const { Credentials: assumedCredentials } = await sts - .assumeRole({ - RoleArn: roleArn, - RoleSessionName: `cross-account-zone-delegation-${timestamp}`, - }) - .promise(); - if (!assumedCredentials) { - throw Error('Error getting assume role credentials'); - } - return new aws_sdk_1.Credentials({ - accessKeyId: assumedCredentials.AccessKeyId, - secretAccessKey: assumedCredentials.SecretAccessKey, - sessionToken: assumedCredentials.SessionToken, - }); -} -async function getHostedZoneIdByName(name, route53) { - const zones = await route53.listHostedZonesByName({ DNSName: name }).promise(); - const matchedZones = zones.HostedZones.filter(zone => zone.Name === `${name}.`); - if (matchedZones.length !== 1) { - throw Error(`Expected one hosted zone to match the given name but found ${matchedZones.length}`); - } - return matchedZones[0].Id; -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QscUNBQW9EO0FBWTdDLEtBQUssVUFBVSxPQUFPLENBQUMsS0FBa0Q7SUFDOUUsTUFBTSxhQUFhLEdBQUcsS0FBSyxDQUFDLGtCQUFtRCxDQUFDO0lBRWhGLFFBQVEsS0FBSyxDQUFDLFdBQVcsRUFBRTtRQUN6QixLQUFLLFFBQVEsQ0FBQztRQUNkLEtBQUssUUFBUTtZQUNYLE9BQU8sZUFBZSxDQUFDLGFBQWEsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMvQyxLQUFLLFFBQVE7WUFDWCxPQUFPLGVBQWUsQ0FBQyxhQUFhLEVBQUUsSUFBSSxDQUFDLENBQUM7S0FDL0M7QUFDSCxDQUFDO0FBVkQsMEJBVUM7QUFFRCxLQUFLLFVBQVUsZUFBZSxDQUFDLEtBQXlCLEVBQUUsYUFBc0I7SUFDOUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxZQUFZLEVBQUUsY0FBYyxFQUFFLGlCQUFpQixFQUFFLHdCQUF3QixFQUFFLEdBQUcsRUFBRSxzQkFBc0IsRUFBRSxHQUFHLEtBQUssQ0FBQztJQUV4SSxJQUFJLENBQUMsWUFBWSxJQUFJLENBQUMsY0FBYyxFQUFFO1FBQ3BDLE1BQU0sS0FBSyxDQUFDLHlEQUF5RCxDQUFDLENBQUM7S0FDeEU7SUFFRCxNQUFNLFdBQVcsR0FBRyxNQUFNLDBCQUEwQixDQUFDLGFBQWEsRUFBRSxDQUFDLENBQUMsc0JBQXNCLENBQUMsQ0FBQztJQUM5RixNQUFNLE9BQU8sR0FBRyxJQUFJLGlCQUFPLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDO0lBRTdDLE1BQU0sWUFBWSxHQUFHLFlBQVksSUFBSSxNQUFNLHFCQUFxQixDQUFDLGNBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUUzRixNQUFNLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBQztRQUNyQyxZQUFZLEVBQUUsWUFBWTtRQUMxQixXQUFXLEVBQUU7WUFDWCxPQUFPLEVBQUUsQ0FBQztvQkFDUixNQUFNLEVBQUUsYUFBYSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLFFBQVE7b0JBQzNDLGlCQUFpQixFQUFFO3dCQUNqQixJQUFJLEVBQUUsaUJBQWlCO3dCQUN2QixJQUFJLEVBQUUsSUFBSTt3QkFDVixHQUFHO3dCQUNILGVBQWUsRUFBRSx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7cUJBQ3JFO2lCQUNGLENBQUM7U0FDSDtLQUNGLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUNmLENBQUM7QUFFRCxLQUFLLFVBQVUsMEJBQTBCLENBQUMsT0FBZSxFQUFFLGdCQUF5QjtJQUNsRixNQUFNLEdBQUcsR0FBRyxJQUFJLGFBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsRUFBRSxvQkFBb0IsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDbEYsTUFBTSxTQUFTLEdBQUcsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFFekMsTUFBTSxFQUFFLFdBQVcsRUFBRSxrQkFBa0IsRUFBRSxHQUFHLE1BQU0sR0FBRztTQUNsRCxVQUFVLENBQUM7UUFDVixPQUFPLEVBQUUsT0FBTztRQUNoQixlQUFlLEVBQUUsaUNBQWlDLFNBQVMsRUFBRTtLQUM5RCxDQUFDO1NBQ0QsT0FBTyxFQUFFLENBQUM7SUFFYixJQUFJLENBQUMsa0JBQWtCLEVBQUU7UUFDdkIsTUFBTSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQztLQUN0RDtJQUVELE9BQU8sSUFBSSxxQkFBVyxDQUFDO1FBQ3JCLFdBQVcsRUFBRSxrQkFBa0IsQ0FBQyxXQUFXO1FBQzNDLGVBQWUsRUFBRSxrQkFBa0IsQ0FBQyxlQUFlO1FBQ25ELFlBQVksRUFBRSxrQkFBa0IsQ0FBQyxZQUFZO0tBQzlDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxLQUFLLFVBQVUscUJBQXFCLENBQUMsSUFBWSxFQUFFLE9BQWdCO0lBQ2pFLE1BQU0sS0FBSyxHQUFHLE1BQU0sT0FBTyxDQUFDLHFCQUFxQixDQUFDLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDL0UsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQztJQUVoRixJQUFJLFlBQVksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQzdCLE1BQU0sS0FBSyxDQUFDLDhEQUE4RCxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNsRztJQUVELE9BQU8sWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUM1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHsgQ3JlZGVudGlhbHMsIFJvdXRlNTMsIFNUUyB9IGZyb20gJ2F3cy1zZGsnO1xuXG5pbnRlcmZhY2UgUmVzb3VyY2VQcm9wZXJ0aWVzIHtcbiAgQXNzdW1lUm9sZUFybjogc3RyaW5nLFxuICBQYXJlbnRab25lTmFtZT86IHN0cmluZyxcbiAgUGFyZW50Wm9uZUlkPzogc3RyaW5nLFxuICBEZWxlZ2F0ZWRab25lTmFtZTogc3RyaW5nLFxuICBEZWxlZ2F0ZWRab25lTmFtZVNlcnZlcnM6IHN0cmluZ1tdLFxuICBUVEw6IG51bWJlcixcbiAgVXNlUmVnaW9uYWxTdHNFbmRwb2ludD86IHN0cmluZyxcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcbiAgY29uc3QgcmVzb3VyY2VQcm9wcyA9IGV2ZW50LlJlc291cmNlUHJvcGVydGllcyBhcyB1bmtub3duIGFzIFJlc291cmNlUHJvcGVydGllcztcblxuICBzd2l0Y2ggKGV2ZW50LlJlcXVlc3RUeXBlKSB7XG4gICAgY2FzZSAnQ3JlYXRlJzpcbiAgICBjYXNlICdVcGRhdGUnOlxuICAgICAgcmV0dXJuIGNmbkV2ZW50SGFuZGxlcihyZXNvdXJjZVByb3BzLCBmYWxzZSk7XG4gICAgY2FzZSAnRGVsZXRlJzpcbiAgICAgIHJldHVybiBjZm5FdmVudEhhbmRsZXIocmVzb3VyY2VQcm9wcywgdHJ1ZSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gY2ZuRXZlbnRIYW5kbGVyKHByb3BzOiBSZXNvdXJjZVByb3BlcnRpZXMsIGlzRGVsZXRlRXZlbnQ6IGJvb2xlYW4pIHtcbiAgY29uc3QgeyBBc3N1bWVSb2xlQXJuLCBQYXJlbnRab25lSWQsIFBhcmVudFpvbmVOYW1lLCBEZWxlZ2F0ZWRab25lTmFtZSwgRGVsZWdhdGVkWm9uZU5hbWVTZXJ2ZXJzLCBUVEwsIFVzZVJlZ2lvbmFsU3RzRW5kcG9pbnQgfSA9IHByb3BzO1xuXG4gIGlmICghUGFyZW50Wm9uZUlkICYmICFQYXJlbnRab25lTmFtZSkge1xuICAgIHRocm93IEVycm9yKCdPbmUgb2YgUGFyZW50Wm9uZUlkIG9yIFBhcmVudFpvbmVOYW1lIG11c3QgYmUgc3BlY2lmaWVkJyk7XG4gIH1cblxuICBjb25zdCBjcmVkZW50aWFscyA9IGF3YWl0IGdldENyb3NzQWNjb3VudENyZWRlbnRpYWxzKEFzc3VtZVJvbGVBcm4sICEhVXNlUmVnaW9uYWxTdHNFbmRwb2ludCk7XG4gIGNvbnN0IHJvdXRlNTMgPSBuZXcgUm91dGU1Myh7IGNyZWRlbnRpYWxzIH0pO1xuXG4gIGNvbnN0IHBhcmVudFpvbmVJZCA9IFBhcmVudFpvbmVJZCA/PyBhd2FpdCBnZXRIb3N0ZWRab25lSWRCeU5hbWUoUGFyZW50Wm9uZU5hbWUhLCByb3V0ZTUzKTtcblxuICBhd2FpdCByb3V0ZTUzLmNoYW5nZVJlc291cmNlUmVjb3JkU2V0cyh7XG4gICAgSG9zdGVkWm9uZUlkOiBwYXJlbnRab25lSWQsXG4gICAgQ2hhbmdlQmF0Y2g6IHtcbiAgICAgIENoYW5nZXM6IFt7XG4gICAgICAgIEFjdGlvbjogaXNEZWxldGVFdmVudCA/ICdERUxFVEUnIDogJ1VQU0VSVCcsXG4gICAgICAgIFJlc291cmNlUmVjb3JkU2V0OiB7XG4gICAgICAgICAgTmFtZTogRGVsZWdhdGVkWm9uZU5hbWUsXG4gICAgICAgICAgVHlwZTogJ05TJyxcbiAgICAgICAgICBUVEwsXG4gICAgICAgICAgUmVzb3VyY2VSZWNvcmRzOiBEZWxlZ2F0ZWRab25lTmFtZVNlcnZlcnMubWFwKG5zID0+ICh7IFZhbHVlOiBucyB9KSksXG4gICAgICAgIH0sXG4gICAgICB9XSxcbiAgICB9LFxuICB9KS5wcm9taXNlKCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldENyb3NzQWNjb3VudENyZWRlbnRpYWxzKHJvbGVBcm46IHN0cmluZywgcmVnaW9uYWxFbmRwb2ludDogYm9vbGVhbik6IFByb21pc2U8Q3JlZGVudGlhbHM+IHtcbiAgY29uc3Qgc3RzID0gbmV3IFNUUyhyZWdpb25hbEVuZHBvaW50ID8geyBzdHNSZWdpb25hbEVuZHBvaW50czogJ3JlZ2lvbmFsJyB9IDoge30pO1xuICBjb25zdCB0aW1lc3RhbXAgPSAobmV3IERhdGUoKSkuZ2V0VGltZSgpO1xuXG4gIGNvbnN0IHsgQ3JlZGVudGlhbHM6IGFzc3VtZWRDcmVkZW50aWFscyB9ID0gYXdhaXQgc3RzXG4gICAgLmFzc3VtZVJvbGUoe1xuICAgICAgUm9sZUFybjogcm9sZUFybixcbiAgICAgIFJvbGVTZXNzaW9uTmFtZTogYGNyb3NzLWFjY291bnQtem9uZS1kZWxlZ2F0aW9uLSR7dGltZXN0YW1wfWAsXG4gICAgfSlcbiAgICAucHJvbWlzZSgpO1xuXG4gIGlmICghYXNzdW1lZENyZWRlbnRpYWxzKSB7XG4gICAgdGhyb3cgRXJyb3IoJ0Vycm9yIGdldHRpbmcgYXNzdW1lIHJvbGUgY3JlZGVudGlhbHMnKTtcbiAgfVxuXG4gIHJldHVybiBuZXcgQ3JlZGVudGlhbHMoe1xuICAgIGFjY2Vzc0tleUlkOiBhc3N1bWVkQ3JlZGVudGlhbHMuQWNjZXNzS2V5SWQsXG4gICAgc2VjcmV0QWNjZXNzS2V5OiBhc3N1bWVkQ3JlZGVudGlhbHMuU2VjcmV0QWNjZXNzS2V5LFxuICAgIHNlc3Npb25Ub2tlbjogYXNzdW1lZENyZWRlbnRpYWxzLlNlc3Npb25Ub2tlbixcbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEhvc3RlZFpvbmVJZEJ5TmFtZShuYW1lOiBzdHJpbmcsIHJvdXRlNTM6IFJvdXRlNTMpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB6b25lcyA9IGF3YWl0IHJvdXRlNTMubGlzdEhvc3RlZFpvbmVzQnlOYW1lKHsgRE5TTmFtZTogbmFtZSB9KS5wcm9taXNlKCk7XG4gIGNvbnN0IG1hdGNoZWRab25lcyA9IHpvbmVzLkhvc3RlZFpvbmVzLmZpbHRlcih6b25lID0+IHpvbmUuTmFtZSA9PT0gYCR7bmFtZX0uYCk7XG5cbiAgaWYgKG1hdGNoZWRab25lcy5sZW5ndGggIT09IDEpIHtcbiAgICB0aHJvdyBFcnJvcihgRXhwZWN0ZWQgb25lIGhvc3RlZCB6b25lIHRvIG1hdGNoIHRoZSBnaXZlbiBuYW1lIGJ1dCBmb3VuZCAke21hdGNoZWRab25lcy5sZW5ndGh9YCk7XG4gIH1cblxuICByZXR1cm4gbWF0Y2hlZFpvbmVzWzBdLklkO1xufVxuIl19 \ 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/aws-cdk-route53-cross-account-integ.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/aws-cdk-route53-cross-account-integ.assets.json deleted file mode 100644 index 3d0049a8e86ba..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/aws-cdk-route53-cross-account-integ.assets.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": "34.0.0", - "files": { - "ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab": { - "source": { - "path": "asset.ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab", - "packaging": "zip" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab.zip", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - }, - "acd818c0f9df9049fee65004b94b63e82b1dccf7da7b7c747b7b363c40ae4bdc": { - "source": { - "path": "aws-cdk-route53-cross-account-integ.template.json", - "packaging": "file" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "acd818c0f9df9049fee65004b94b63e82b1dccf7da7b7c747b7b363c40ae4bdc.json", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - } - }, - "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/aws-cdk-route53-cross-account-integ.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/aws-cdk-route53-cross-account-integ.template.json deleted file mode 100644 index e696fd4581aaa..0000000000000 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/aws-cdk-route53-cross-account-integ.template.json +++ /dev/null @@ -1,447 +0,0 @@ -{ - "Resources": { - "ParentHostedZoneC2BD86E1": { - "Type": "AWS::Route53::HostedZone", - "Properties": { - "Name": "myzone.com." - } - }, - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - } - } - ], - "Version": "2012-10-17" - }, - "Policies": [ - { - "PolicyDocument": { - "Statement": [ - { - "Action": "route53:ChangeResourceRecordSets", - "Condition": { - "ForAllValues:StringEquals": { - "route53:ChangeResourceRecordSetsRecordTypes": [ - "NS" - ], - "route53:ChangeResourceRecordSetsActions": [ - "UPSERT", - "DELETE" - ] - } - }, - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/", - { - "Ref": "ParentHostedZoneC2BD86E1" - } - ] - ] - } - }, - { - "Action": "route53:ListHostedZonesByName", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "delegation" - } - ] - } - }, - "ChildHostedZoneWithZoneId729259E6": { - "Type": "AWS::Route53::HostedZone", - "Properties": { - "Name": "sub.myzone.com." - } - }, - "DelegationWithZoneIdcrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C47314C14718": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473", - "Roles": [ - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "/", - { - "Fn::Select": [ - 5, - { - "Fn::Split": [ - ":", - { - "Fn::GetAtt": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", - "Arn" - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - }, - "DelegationWithZoneIdCrossAccountZoneDelegationCustomResourceFFD766E7": { - "Type": "Custom::CrossAccountZoneDelegation", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265", - "Arn" - ] - }, - "AssumeRoleArn": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - }, - "ParentZoneId": { - "Ref": "ParentHostedZoneC2BD86E1" - }, - "DelegatedZoneName": "sub.myzone.com", - "DelegatedZoneNameServers": { - "Fn::GetAtt": [ - "ChildHostedZoneWithZoneId729259E6", - "NameServers" - ] - }, - "TTL": 172800 - }, - "DependsOn": [ - "DelegationWithZoneIdcrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C47314C14718" - ], - "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": { - "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" - }, - "S3Key": "ab0afc2f801b8ac11473bad4d9f22578919d8959b5f1bcd21b05c4ac895dbcab.zip" - }, - "Timeout": 900, - "MemorySize": 128, - "Handler": "__entrypoint__.handler", - "Role": { - "Fn::GetAtt": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", - "Arn" - ] - }, - "Runtime": "nodejs16.x" - }, - "DependsOn": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" - ] - }, - "ChildHostedZoneWithZoneNameBC2C15F6": { - "Type": "AWS::Route53::HostedZone", - "Properties": { - "Name": "anothersub.myzone.com." - } - }, - "DelegationWithZoneNamecrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC28807823206B47A": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - } - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782", - "Roles": [ - { - "Fn::Select": [ - 1, - { - "Fn::Split": [ - "/", - { - "Fn::Select": [ - 5, - { - "Fn::Split": [ - ":", - { - "Fn::GetAtt": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B", - "Arn" - ] - } - ] - } - ] - } - ] - } - ] - } - ] - } - }, - "DelegationWithZoneNameCrossAccountZoneDelegationCustomResourceA1A1C94A": { - "Type": "Custom::CrossAccountZoneDelegation", - "Properties": { - "ServiceToken": { - "Fn::GetAtt": [ - "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265", - "Arn" - ] - }, - "AssumeRoleArn": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - }, - "ParentZoneName": "myzone.com", - "DelegatedZoneName": "anothersub.myzone.com", - "DelegatedZoneNameServers": { - "Fn::GetAtt": [ - "ChildHostedZoneWithZoneNameBC2C15F6", - "NameServers" - ] - }, - "TTL": 172800 - }, - "DependsOn": [ - "DelegationWithZoneNamecrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC28807823206B47A" - ], - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, - "Role1ABCC5F0": { - "Type": "AWS::IAM::Role", - "Properties": { - "AssumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - } - } - ], - "Version": "2012-10-17" - } - } - }, - "RoleDefaultPolicy5FFB7DAB": { - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyDocument": { - "Statement": [ - { - "Action": "route53:ChangeResourceRecordSets", - "Condition": { - "ForAllValues:StringEquals": { - "route53:ChangeResourceRecordSetsRecordTypes": [ - "NS" - ], - "route53:ChangeResourceRecordSetsActions": [ - "UPSERT", - "DELETE" - ] - } - }, - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-private-zone-id" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-public-zone-id" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-zone-id" - ] - ] - } - ] - }, - { - "Action": "route53:ListHostedZonesByName", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "PolicyName": "RoleDefaultPolicy5FFB7DAB", - "Roles": [ - { - "Ref": "Role1ABCC5F0" - } - ] - } - } - }, - "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 new file mode 100644 index 0000000000000..e7bc3748400a3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "34.0.0", + "files": { + "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563": { + "source": { + "path": "asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563", + "packaging": "zip" + }, + "destinations": { + "234567890123-af-south-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", + "objectKey": "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563.zip", + "region": "af-south-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-af-south-1" + } + } + }, + "b481c6b97f93808d848377e77bc7b690a451b4929eb5291f14d70c3233656bb2": { + "source": { + "path": "child-opt-in-stack.template.json", + "packaging": "file" + }, + "destinations": { + "234567890123-af-south-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-af-south-1", + "objectKey": "b481c6b97f93808d848377e77bc7b690a451b4929eb5291f14d70c3233656bb2.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.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 new file mode 100644 index 0000000000000..d3e20a410524a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-opt-in-stack.template.json @@ -0,0 +1,158 @@ +{ + "Resources": { + "SubZoneF7955E1A": { + "Type": "AWS::Route53::HostedZone", + "Properties": { + "Name": "sub.uniqueexample.com." + } + }, + "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26DE28FC01D": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D", + "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": "sub.uniqueexample.com", + "DelegatedZoneNameServers": { + "Fn::GetAtt": [ + "SubZoneF7955E1A", + "NameServers" + ] + }, + "TTL": 172800 + }, + "DependsOn": [ + "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26DE28FC01D" + ], + "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": "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563.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-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 new file mode 100644 index 0000000000000..119ad7a7f941c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.assets.json @@ -0,0 +1,34 @@ +{ + "version": "34.0.0", + "files": { + "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563": { + "source": { + "path": "asset.79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563", + "packaging": "zip" + }, + "destinations": { + "234567890123-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", + "objectKey": "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563.zip", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-1" + } + } + }, + "221e34158f82571532f29b46cc8472f8a339e3d8ab22c79339a98d5b6e0e0db1": { + "source": { + "path": "child-stack.template.json", + "packaging": "file" + }, + "destinations": { + "234567890123-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-234567890123-us-east-1", + "objectKey": "221e34158f82571532f29b46cc8472f8a339e3d8ab22c79339a98d5b6e0e0db1.json", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-file-publishing-role-234567890123-us-east-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-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 new file mode 100644 index 0000000000000..2474c2cd46142 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/child-stack.template.json @@ -0,0 +1,158 @@ +{ + "Resources": { + "SubZoneF7955E1A": { + "Type": "AWS::Route53::HostedZone", + "Properties": { + "Name": "sub.uniqueexample.com." + } + }, + "delegatecrossaccountzonedelegationhandlerrolePolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E86169197": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E", + "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": "sub.uniqueexample.com", + "DelegatedZoneNameServers": { + "Fn::GetAtt": [ + "SubZoneF7955E1A", + "NameServers" + ] + }, + "TTL": 172800 + }, + "DependsOn": [ + "delegatecrossaccountzonedelegationhandlerrolePolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E86169197" + ], + "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-us-east-1", + "S3Key": "79d89314ddbd33f89269ebfdd0cab9c219b5f5d59c210d4847fd849b9c341563.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/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/integ.json index ec3c63b72b7f2..0fa95973f0c53 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 @@ -3,7 +3,8 @@ "testCases": { "Route53CrossAccountInteg/DefaultTest": { "stacks": [ - "aws-cdk-route53-cross-account-integ" + "child-stack", + "child-opt-in-stack" ], "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 a95712985719b..9eea2eb30a440 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 @@ -1,124 +1,226 @@ { "version": "34.0.0", "artifacts": { - "aws-cdk-route53-cross-account-integ.assets": { + "parent-stack.assets": { "type": "cdk:asset-manifest", "properties": { - "file": "aws-cdk-route53-cross-account-integ.assets.json", + "file": "parent-stack.assets.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, - "aws-cdk-route53-cross-account-integ": { + "parent-stack": { "type": "aws:cloudformation:stack", - "environment": "aws://unknown-account/unknown-region", + "environment": "aws://12345678/us-east-1", "properties": { - "templateFile": "aws-cdk-route53-cross-account-integ.template.json", + "templateFile": "parent-stack.template.json", "validateOnSynth": false, - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", - "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/acd818c0f9df9049fee65004b94b63e82b1dccf7da7b7c747b7b363c40ae4bdc.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-deploy-role-12345678-us-east-1", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-cfn-exec-role-12345678-us-east-1", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-12345678-us-east-1/56fdc835ae6a670f2f958a73f56b508710e57cbe667bc0c562ed7a04dadd5cc4.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ - "aws-cdk-route53-cross-account-integ.assets" + "parent-stack.assets" ], "lookupRole": { - "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "arn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-lookup-role-12345678-us-east-1", "requiresBootstrapStackVersion": 8, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" } }, "dependencies": [ - "aws-cdk-route53-cross-account-integ.assets" + "parent-stack.assets" ], "metadata": { - "/aws-cdk-route53-cross-account-integ/ParentHostedZone/Resource": [ + "/parent-stack/HostedZone/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "HostedZoneDB99F866" + } + ], + "/parent-stack/CrossAccountRole/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ParentHostedZoneC2BD86E1" + "data": "CrossAccountRoleFACE29D1" } ], - "/aws-cdk-route53-cross-account-integ/ParentHostedZone/CrossAccountZoneDelegationRole/Resource": [ + "/parent-stack/CrossAccountRole/DefaultPolicy/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E" + "data": "CrossAccountRoleDefaultPolicy212A317F" } ], - "/aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneId/Resource": [ + "/parent-stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/parent-stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "parent-stack" + }, + "child-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "child-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "child-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://234567890123/us-east-1", + "properties": { + "templateFile": "child-stack.template.json", + "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/221e34158f82571532f29b46cc8472f8a339e3d8ab22c79339a98d5b6e0e0db1.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "child-stack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::234567890123:role/cdk-hnb659fds-lookup-role-234567890123-us-east-1", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "parent-stack", + "child-stack.assets" + ], + "metadata": { + "/child-stack/SubZone/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ChildHostedZoneWithZoneId729259E6" + "data": "SubZoneF7955E1A" } ], - "/aws-cdk-route53-cross-account-integ/DelegationWithZoneId/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473/Resource": [ + "/child-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DelegationWithZoneIdcrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C47314C14718" + "data": "delegatecrossaccountzonedelegationhandlerrolePolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E86169197" } ], - "/aws-cdk-route53-cross-account-integ/DelegationWithZoneId/CrossAccountZoneDelegationCustomResource/Default": [ + "/child-stack/delegate/CrossAccountZoneDelegationCustomResource/Default": [ { "type": "aws:cdk:logicalId", - "data": "DelegationWithZoneIdCrossAccountZoneDelegationCustomResourceFFD766E7" + "data": "delegateCrossAccountZoneDelegationCustomResource23BD590B" } ], - "/aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role": [ + "/child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role": [ { "type": "aws:cdk:logicalId", "data": "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" } ], - "/aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler": [ + "/child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler": [ { "type": "aws:cdk:logicalId", "data": "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265" } ], - "/aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneName/Resource": [ + "/child-stack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/child-stack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "child-stack" + }, + "child-opt-in-stack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "child-opt-in-stack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "child-opt-in-stack": { + "type": "aws:cloudformation:stack", + "environment": "aws://234567890123/af-south-1", + "properties": { + "templateFile": "child-opt-in-stack.template.json", + "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/b481c6b97f93808d848377e77bc7b690a451b4929eb5291f14d70c3233656bb2.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "child-opt-in-stack.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.assets" + ], + "metadata": { + "/child-opt-in-stack/SubZone/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ChildHostedZoneWithZoneNameBC2C15F6" + "data": "SubZoneF7955E1A" } ], - "/aws-cdk-route53-cross-account-integ/DelegationWithZoneName/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782/Resource": [ + "/child-opt-in-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DelegationWithZoneNamecrossaccountzonedelegationhandlerrolePolicyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC28807823206B47A" + "data": "delegatecrossaccountzonedelegationhandlerrolePolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26DE28FC01D" } ], - "/aws-cdk-route53-cross-account-integ/DelegationWithZoneName/CrossAccountZoneDelegationCustomResource/Default": [ + "/child-opt-in-stack/delegate/CrossAccountZoneDelegationCustomResource/Default": [ { "type": "aws:cdk:logicalId", - "data": "DelegationWithZoneNameCrossAccountZoneDelegationCustomResourceA1A1C94A" + "data": "delegateCrossAccountZoneDelegationCustomResource23BD590B" } ], - "/aws-cdk-route53-cross-account-integ/Role/Resource": [ + "/child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role": [ { "type": "aws:cdk:logicalId", - "data": "Role1ABCC5F0" + "data": "CustomCrossAccountZoneDelegationCustomResourceProviderRoleED64687B" } ], - "/aws-cdk-route53-cross-account-integ/Role/DefaultPolicy/Resource": [ + "/child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler": [ { "type": "aws:cdk:logicalId", - "data": "RoleDefaultPolicy5FFB7DAB" + "data": "CustomCrossAccountZoneDelegationCustomResourceProviderHandler44A84265" } ], - "/aws-cdk-route53-cross-account-integ/BootstrapVersion": [ + "/child-opt-in-stack/BootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "BootstrapVersion" } ], - "/aws-cdk-route53-cross-account-integ/CheckBootstrapVersion": [ + "/child-opt-in-stack/CheckBootstrapVersion": [ { "type": "aws:cdk:logicalId", "data": "CheckBootstrapVersion" } ] }, - "displayName": "aws-cdk-route53-cross-account-integ" + "displayName": "child-opt-in-stack" }, "Route53CrossAccountIntegDefaultTestDeployAssertF1D808C9.assets": { "type": "cdk:asset-manifest", diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/parent-stack.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/parent-stack.assets.json new file mode 100644 index 0000000000000..f4fa37432241c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/parent-stack.assets.json @@ -0,0 +1,20 @@ +{ + "version": "34.0.0", + "files": { + "56fdc835ae6a670f2f958a73f56b508710e57cbe667bc0c562ed7a04dadd5cc4": { + "source": { + "path": "parent-stack.template.json", + "packaging": "file" + }, + "destinations": { + "12345678-us-east-1": { + "bucketName": "cdk-hnb659fds-assets-12345678-us-east-1", + "objectKey": "56fdc835ae6a670f2f958a73f56b508710e57cbe667bc0c562ed7a04dadd5cc4.json", + "region": "us-east-1", + "assumeRoleArn": "arn:${AWS::Partition}:iam::12345678:role/cdk-hnb659fds-file-publishing-role-12345678-us-east-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/parent-stack.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/parent-stack.template.json new file mode 100644 index 0000000000000..b3e0aa3918c48 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/parent-stack.template.json @@ -0,0 +1,109 @@ +{ + "Resources": { + "HostedZoneDB99F866": { + "Type": "AWS::Route53::HostedZone", + "Properties": { + "Name": "uniqueexample.com." + } + }, + "CrossAccountRoleFACE29D1": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::234567890123:root" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": "MyUniqueDelegationRole" + } + }, + "CrossAccountRoleDefaultPolicy212A317F": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "route53:ChangeResourceRecordSets", + "Condition": { + "ForAllValues:StringEquals": { + "route53:ChangeResourceRecordSetsRecordTypes": [ + "NS" + ], + "route53:ChangeResourceRecordSetsActions": [ + "UPSERT", + "DELETE" + ] + } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:route53:::hostedzone/", + { + "Ref": "HostedZoneDB99F866" + } + ] + ] + } + }, + { + "Action": "route53:ListHostedZonesByName", + "Effect": "Allow", + "Resource": "*" + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "CrossAccountRoleDefaultPolicy212A317F", + "Roles": [ + { + "Ref": "CrossAccountRoleFACE29D1" + } + ] + } + } + }, + "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/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-route53/test/integ.cross-account-zone-delegation.js.snapshot/tree.json index 80298da536950..3231749ae2402 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 @@ -4,148 +4,180 @@ "id": "App", "path": "", "children": { - "aws-cdk-route53-cross-account-integ": { - "id": "aws-cdk-route53-cross-account-integ", - "path": "aws-cdk-route53-cross-account-integ", + "parent-stack": { + "id": "parent-stack", + "path": "parent-stack", "children": { - "ParentHostedZone": { - "id": "ParentHostedZone", - "path": "aws-cdk-route53-cross-account-integ/ParentHostedZone", + "HostedZone": { + "id": "HostedZone", + "path": "parent-stack/HostedZone", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/ParentHostedZone/Resource", + "path": "parent-stack/HostedZone/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::Route53::HostedZone", "aws:cdk:cloudformation:props": { - "name": "myzone.com." + "name": "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" + } + }, + "CrossAccountRole": { + "id": "CrossAccountRole", + "path": "parent-stack/CrossAccountRole", + "children": { + "ImportCrossAccountRole": { + "id": "ImportCrossAccountRole", + "path": "parent-stack/CrossAccountRole/ImportCrossAccountRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "parent-stack/CrossAccountRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::234567890123:root" + } + } + ], + "Version": "2012-10-17" + }, + "roleName": "MyUniqueDelegationRole" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } }, - "CrossAccountZoneDelegationRole": { - "id": "CrossAccountZoneDelegationRole", - "path": "aws-cdk-route53-cross-account-integ/ParentHostedZone/CrossAccountZoneDelegationRole", + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "parent-stack/CrossAccountRole/DefaultPolicy", "children": { - "ImportCrossAccountZoneDelegationRole": { - "id": "ImportCrossAccountZoneDelegationRole", - "path": "aws-cdk-route53-cross-account-integ/ParentHostedZone/CrossAccountZoneDelegationRole/ImportCrossAccountZoneDelegationRole", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" - } - }, "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/ParentHostedZone/CrossAccountZoneDelegationRole/Resource", + "path": "parent-stack/CrossAccountRole/DefaultPolicy/Resource", "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { + "policyDocument": { "Statement": [ { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] + "Action": "route53:ChangeResourceRecordSets", + "Condition": { + "ForAllValues:StringEquals": { + "route53:ChangeResourceRecordSetsRecordTypes": [ + "NS" + ], + "route53:ChangeResourceRecordSetsActions": [ + "UPSERT", + "DELETE" ] } + }, + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:route53:::hostedzone/", + { + "Ref": "HostedZoneDB99F866" + } + ] + ] } + }, + { + "Action": "route53:ListHostedZonesByName", + "Effect": "Allow", + "Resource": "*" } ], "Version": "2012-10-17" }, - "policies": [ + "policyName": "CrossAccountRoleDefaultPolicy212A317F", + "roles": [ { - "policyName": "delegation", - "policyDocument": { - "Statement": [ - { - "Action": "route53:ChangeResourceRecordSets", - "Condition": { - "ForAllValues:StringEquals": { - "route53:ChangeResourceRecordSetsRecordTypes": [ - "NS" - ], - "route53:ChangeResourceRecordSetsActions": [ - "UPSERT", - "DELETE" - ] - } - }, - "Effect": "Allow", - "Resource": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/", - { - "Ref": "ParentHostedZoneC2BD86E1" - } - ] - ] - } - }, - { - "Action": "route53:ListHostedZonesByName", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - } + "Ref": "CrossAccountRoleFACE29D1" } ] } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_route53.PublicHostedZone", + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "parent-stack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" } }, - "ChildHostedZoneWithZoneId": { - "id": "ChildHostedZoneWithZoneId", - "path": "aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneId", + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "parent-stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "child-stack": { + "id": "child-stack", + "path": "child-stack", + "children": { + "SubZone": { + "id": "SubZone", + "path": "child-stack/SubZone", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneId/Resource", + "path": "child-stack/SubZone/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::Route53::HostedZone", "aws:cdk:cloudformation:props": { - "name": "sub.myzone.com." + "name": "sub.uniqueexample.com." } }, "constructInfo": { @@ -159,21 +191,37 @@ "version": "0.0.0" } }, - "DelegationWithZoneId": { - "id": "DelegationWithZoneId", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId", + "MutableRoleDelegationRole": { + "id": "MutableRoleDelegationRole", + "path": "child-stack/MutableRoleDelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "DelegationRole": { + "id": "DelegationRole", + "path": "child-stack/DelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "delegate": { + "id": "delegate", + "path": "child-stack/delegate", "children": { "cross-account-zone-delegation-handler-role": { "id": "cross-account-zone-delegation-handler-role", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId/cross-account-zone-delegation-handler-role", + "path": "child-stack/delegate/cross-account-zone-delegation-handler-role", "children": { - "Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473": { - "id": "Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473", + "PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E": { + "id": "PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E", + "path": "child-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473/Resource", + "path": "child-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::IAM::Policy", "aws:cdk:cloudformation:props": { @@ -182,17 +230,12 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - } + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" } ], "Version": "2012-10-17" }, - "policyName": "Policyawscdkroute53crossaccountintegDelegationWithZoneIdcrossaccountzonedelegationhandlerrole5AE6C473", + "policyName": "PolicychildstackdelegatecrossaccountzonedelegationhandlerroleCB13E48E", "roles": [ { "Fn::Select": [ @@ -242,11 +285,11 @@ }, "CrossAccountZoneDelegationCustomResource": { "id": "CrossAccountZoneDelegationCustomResource", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId/CrossAccountZoneDelegationCustomResource", + "path": "child-stack/delegate/CrossAccountZoneDelegationCustomResource", "children": { "Default": { "id": "Default", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneId/CrossAccountZoneDelegationCustomResource/Default", + "path": "child-stack/delegate/CrossAccountZoneDelegationCustomResource/Default", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" @@ -266,11 +309,11 @@ }, "Custom::CrossAccountZoneDelegationCustomResourceProvider": { "id": "Custom::CrossAccountZoneDelegationCustomResourceProvider", - "path": "aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider", + "path": "child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider", "children": { "Staging": { "id": "Staging", - "path": "aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider/Staging", + "path": "child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Staging", "constructInfo": { "fqn": "aws-cdk-lib.AssetStaging", "version": "0.0.0" @@ -278,7 +321,7 @@ }, "Role": { "id": "Role", - "path": "aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role", + "path": "child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" @@ -286,7 +329,7 @@ }, "Handler": { "id": "Handler", - "path": "aws-cdk-route53-cross-account-integ/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler", + "path": "child-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" @@ -298,17 +341,43 @@ "version": "0.0.0" } }, - "ChildHostedZoneWithZoneName": { - "id": "ChildHostedZoneWithZoneName", - "path": "aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneName", + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "child-stack/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "child-stack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "child-opt-in-stack": { + "id": "child-opt-in-stack", + "path": "child-opt-in-stack", + "children": { + "SubZone": { + "id": "SubZone", + "path": "child-opt-in-stack/SubZone", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/ChildHostedZoneWithZoneName/Resource", + "path": "child-opt-in-stack/SubZone/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::Route53::HostedZone", "aws:cdk:cloudformation:props": { - "name": "anothersub.myzone.com." + "name": "sub.uniqueexample.com." } }, "constructInfo": { @@ -322,21 +391,37 @@ "version": "0.0.0" } }, - "DelegationWithZoneName": { - "id": "DelegationWithZoneName", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName", + "MutableRoleDelegationRole": { + "id": "MutableRoleDelegationRole", + "path": "child-opt-in-stack/MutableRoleDelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "DelegationRole": { + "id": "DelegationRole", + "path": "child-opt-in-stack/DelegationRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "delegate": { + "id": "delegate", + "path": "child-opt-in-stack/delegate", "children": { "cross-account-zone-delegation-handler-role": { "id": "cross-account-zone-delegation-handler-role", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName/cross-account-zone-delegation-handler-role", + "path": "child-opt-in-stack/delegate/cross-account-zone-delegation-handler-role", "children": { - "Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782": { - "id": "Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782", + "PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D": { + "id": "PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D", + "path": "child-opt-in-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName/cross-account-zone-delegation-handler-role/Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782/Resource", + "path": "child-opt-in-stack/delegate/cross-account-zone-delegation-handler-role/PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::IAM::Policy", "aws:cdk:cloudformation:props": { @@ -345,17 +430,12 @@ { "Action": "sts:AssumeRole", "Effect": "Allow", - "Resource": { - "Fn::GetAtt": [ - "ParentHostedZoneCrossAccountZoneDelegationRole95B1C36E", - "Arn" - ] - } + "Resource": "arn:aws:iam::12345678:role/MyUniqueDelegationRole" } ], "Version": "2012-10-17" }, - "policyName": "Policyawscdkroute53crossaccountintegDelegationWithZoneNamecrossaccountzonedelegationhandlerroleC2880782", + "policyName": "PolicychildoptinstackdelegatecrossaccountzonedelegationhandlerroleD1C6F26D", "roles": [ { "Fn::Select": [ @@ -405,11 +485,11 @@ }, "CrossAccountZoneDelegationCustomResource": { "id": "CrossAccountZoneDelegationCustomResource", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName/CrossAccountZoneDelegationCustomResource", + "path": "child-opt-in-stack/delegate/CrossAccountZoneDelegationCustomResource", "children": { "Default": { "id": "Default", - "path": "aws-cdk-route53-cross-account-integ/DelegationWithZoneName/CrossAccountZoneDelegationCustomResource/Default", + "path": "child-opt-in-stack/delegate/CrossAccountZoneDelegationCustomResource/Default", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" @@ -427,183 +507,43 @@ "version": "0.0.0" } }, - "Role": { - "id": "Role", - "path": "aws-cdk-route53-cross-account-integ/Role", + "Custom::CrossAccountZoneDelegationCustomResourceProvider": { + "id": "Custom::CrossAccountZoneDelegationCustomResourceProvider", + "path": "child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider", "children": { - "ImportRole": { - "id": "ImportRole", - "path": "aws-cdk-route53-cross-account-integ/Role/ImportRole", + "Staging": { + "id": "Staging", + "path": "child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Staging", "constructInfo": { - "fqn": "aws-cdk-lib.Resource", + "fqn": "aws-cdk-lib.AssetStaging", "version": "0.0.0" } }, - "Resource": { - "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/Role/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Role", - "aws:cdk:cloudformation:props": { - "assumeRolePolicyDocument": { - "Statement": [ - { - "Action": "sts:AssumeRole", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - } - } - ], - "Version": "2012-10-17" - } - } - }, + "Role": { + "id": "Role", + "path": "child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Role", "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } }, - "DefaultPolicy": { - "id": "DefaultPolicy", - "path": "aws-cdk-route53-cross-account-integ/Role/DefaultPolicy", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-route53-cross-account-integ/Role/DefaultPolicy/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::IAM::Policy", - "aws:cdk:cloudformation:props": { - "policyDocument": { - "Statement": [ - { - "Action": "route53:ChangeResourceRecordSets", - "Condition": { - "ForAllValues:StringEquals": { - "route53:ChangeResourceRecordSetsRecordTypes": [ - "NS" - ], - "route53:ChangeResourceRecordSetsActions": [ - "UPSERT", - "DELETE" - ] - } - }, - "Effect": "Allow", - "Resource": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-private-zone-id" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-public-zone-id" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":route53:::hostedzone/imported-zone-id" - ] - ] - } - ] - }, - { - "Action": "route53:ListHostedZonesByName", - "Effect": "Allow", - "Resource": "*" - } - ], - "Version": "2012-10-17" - }, - "policyName": "RoleDefaultPolicy5FFB7DAB", - "roles": [ - { - "Ref": "Role1ABCC5F0" - } - ] - } - }, - "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", - "version": "0.0.0" - } - } - }, + "Handler": { + "id": "Handler", + "path": "child-opt-in-stack/Custom::CrossAccountZoneDelegationCustomResourceProvider/Handler", "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Policy", + "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "aws-cdk-lib.aws_iam.Role", - "version": "0.0.0" - } - }, - "ImportedZone": { - "id": "ImportedZone", - "path": "aws-cdk-route53-cross-account-integ/ImportedZone", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" - } - }, - "ImportedPublicZone": { - "id": "ImportedPublicZone", - "path": "aws-cdk-route53-cross-account-integ/ImportedPublicZone", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", - "version": "0.0.0" - } - }, - "ImportedPrivateZone": { - "id": "ImportedPrivateZone", - "path": "aws-cdk-route53-cross-account-integ/ImportedPrivateZone", - "constructInfo": { - "fqn": "aws-cdk-lib.Resource", + "fqn": "aws-cdk-lib.CustomResourceProvider", "version": "0.0.0" } }, "BootstrapVersion": { "id": "BootstrapVersion", - "path": "aws-cdk-route53-cross-account-integ/BootstrapVersion", + "path": "child-opt-in-stack/BootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnParameter", "version": "0.0.0" @@ -611,7 +551,7 @@ }, "CheckBootstrapVersion": { "id": "CheckBootstrapVersion", - "path": "aws-cdk-route53-cross-account-integ/CheckBootstrapVersion", + "path": "child-opt-in-stack/CheckBootstrapVersion", "constructInfo": { "fqn": "aws-cdk-lib.CfnRule", "version": "0.0.0" @@ -636,7 +576,7 @@ "path": "Route53CrossAccountInteg/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.2.70" } }, "DeployAssert": { @@ -682,7 +622,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.69" + "version": "10.2.70" } } }, 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 d4065c8a7fa3f..acc2563e9d74d 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 @@ -1,53 +1,86 @@ import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; -import { PublicHostedZone, CrossAccountZoneDelegationRecord, PrivateHostedZone, HostedZone } from 'aws-cdk-lib/aws-route53'; +import * as route53 from 'aws-cdk-lib/aws-route53'; +import { Construct } from 'constructs'; import { IntegTest } from '@aws-cdk/integ-tests-alpha'; const app = new cdk.App(); -const stack = new cdk.Stack(app, 'aws-cdk-route53-cross-account-integ'); +const account = process.env.CDK_INTEG_ACCOUNT || '123456789012'; // this account should NOT have af-south-1 enabled -const parentZone = new PublicHostedZone(stack, 'ParentHostedZone', { - zoneName: 'myzone.com', - crossAccountZoneDelegationPrincipal: new iam.AccountPrincipal(cdk.Aws.ACCOUNT_ID), -}); +// As the integ-runner doesnt provide a default cross account, we make our own. +const crossAccount = process.env.CDK_INTEG_CROSS_ACCOUNT || '234567890123'; // this account MUST have af-south-1 enabled -// with zoneId -const childZoneWithZoneId = new PublicHostedZone(stack, 'ChildHostedZoneWithZoneId', { - zoneName: 'sub.myzone.com', -}); -new CrossAccountZoneDelegationRecord(stack, 'DelegationWithZoneId', { - delegatedZone: childZoneWithZoneId, - parentHostedZoneId: parentZone.hostedZoneId, - delegationRole: parentZone.crossAccountZoneDelegationRole!, -}); +const delegationRoleName = 'MyUniqueDelegationRole'; -// with zoneName -const childZoneWithZoneName = new PublicHostedZone(stack, 'ChildHostedZoneWithZoneName', { - zoneName: 'anothersub.myzone.com', -}); -new CrossAccountZoneDelegationRecord(stack, 'DelegationWithZoneName', { - delegatedZone: childZoneWithZoneName, - parentHostedZoneName: 'myzone.com', - delegationRole: parentZone.crossAccountZoneDelegationRole!, -}); +const parentZoneName = 'uniqueexample.com'; +const subZoneName = 'sub.uniqueexample.com'; + +class ParentStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + const parentZone = new route53.PublicHostedZone(this, 'HostedZone', { + zoneName: parentZoneName, + }); + const crossAccountRole = new iam.Role(this, 'CrossAccountRole', { + roleName: delegationRoleName, + assumedBy: new iam.AccountPrincipal(crossAccount), + }); + parentZone.grantDelegation(crossAccountRole); + } +} + +class ChildStack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); -const role = new iam.Role(stack, 'Role', { - assumedBy: new iam.AccountRootPrincipal(), + const subZone = new route53.PublicHostedZone(this, 'SubZone', { + zoneName: subZoneName, + }); + + const delegationRoleArn = cdk.Stack.of(this).formatArn({ + region: '', + service: 'iam', + account: account, + resource: 'role', + resourceName: delegationRoleName, + }); + const delegationRole = iam.Role.fromRoleArn(this, 'DelegationRole', delegationRoleArn); + + new route53.CrossAccountZoneDelegationRecord(this, 'delegate', { + delegatedZone: subZone, + parentHostedZoneName: parentZoneName, + delegationRole, + }); + } +} + +const parentStack = new ParentStack(app, 'parent-stack', { + env: { + account: account, + region: 'us-east-1', + }, }); -const importedZone = HostedZone.fromHostedZoneId(stack, 'ImportedZone', 'imported-zone-id'); -importedZone.grantDelegation(role); +const childStack = new ChildStack(app, 'child-stack', { + env: { + account: crossAccount, + region: 'us-east-1', + }, +}); -const importedPublicZone = PublicHostedZone.fromPublicHostedZoneId(stack, 'ImportedPublicZone', 'imported-public-zone-id'); -importedPublicZone.grantDelegation(role); +const childOptInStack = new ChildStack(app, 'child-opt-in-stack', { + env: { + account: crossAccount, + region: 'af-south-1', + }, +}); -const importedPrivateZone = PrivateHostedZone.fromPrivateHostedZoneId(stack, 'ImportedPrivateZone', 'imported-private-zone-id'); -importedPrivateZone.grantDelegation(role); +childStack.addDependency(parentStack); +childOptInStack.addDependency(parentStack); new IntegTest(app, 'Route53CrossAccountInteg', { - testCases: [stack], + testCases: [childStack, childOptInStack], diffAssets: true, -}); - -app.synth(); +}); \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/index.ts b/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/index.ts index 7867e7a45a725..0be04017db9d9 100644 --- a/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/index.ts +++ b/packages/aws-cdk-lib/aws-route53/lib/cross-account-zone-delegation-handler/index.ts @@ -1,5 +1,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies -import { Credentials, Route53, STS } from 'aws-sdk'; +import { Route53 } from '@aws-sdk/client-route-53'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { fromTemporaryCredentials } from '@aws-sdk/credential-providers'; interface ResourceProperties { AssumeRoleArn: string, @@ -8,7 +10,6 @@ interface ResourceProperties { DelegatedZoneName: string, DelegatedZoneNameServers: string[], TTL: number, - UseRegionalStsEndpoint?: string, } export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent) { @@ -24,14 +25,24 @@ export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent } async function cfnEventHandler(props: ResourceProperties, isDeleteEvent: boolean) { - const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL, UseRegionalStsEndpoint } = props; + const { AssumeRoleArn, ParentZoneId, ParentZoneName, DelegatedZoneName, DelegatedZoneNameServers, TTL } = props; if (!ParentZoneId && !ParentZoneName) { throw Error('One of ParentZoneId or ParentZoneName must be specified'); } - const credentials = await getCrossAccountCredentials(AssumeRoleArn, !!UseRegionalStsEndpoint); - const route53 = new Route53({ credentials }); + const timestamp = (new Date()).getTime(); + const route53 = new Route53({ + credentials: fromTemporaryCredentials({ + clientConfig: { + region: route53Region(process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? ''), + }, + params: { + RoleArn: AssumeRoleArn, + RoleSessionName: `cross-account-zone-delegation-${timestamp}`, + }, + }), + }); const parentZoneId = ParentZoneId ?? await getHostedZoneIdByName(ParentZoneName!, route53); @@ -48,38 +59,54 @@ async function cfnEventHandler(props: ResourceProperties, isDeleteEvent: boolean }, }], }, - }).promise(); + }); } -async function getCrossAccountCredentials(roleArn: string, regionalEndpoint: boolean): Promise { - const sts = new STS(regionalEndpoint ? { stsRegionalEndpoints: 'regional' } : {}); - const timestamp = (new Date()).getTime(); - - const { Credentials: assumedCredentials } = await sts - .assumeRole({ - RoleArn: roleArn, - RoleSessionName: `cross-account-zone-delegation-${timestamp}`, - }) - .promise(); +async function getHostedZoneIdByName(name: string, route53: Route53): Promise { + const zones = await route53.listHostedZonesByName({ DNSName: name }); + const matchedZones = zones.HostedZones?.filter(zone => zone.Name === `${name}.`) ?? []; - if (!assumedCredentials) { - throw Error('Error getting assume role credentials'); + if (matchedZones && matchedZones.length !== 1) { + throw Error(`Expected one hosted zone to match the given name but found ${matchedZones.length}`); } - return new Credentials({ - accessKeyId: assumedCredentials.AccessKeyId, - secretAccessKey: assumedCredentials.SecretAccessKey, - sessionToken: assumedCredentials.SessionToken, - }); + // will always be defined because we throw if length !==1 + return matchedZones[0].Id!; } -async function getHostedZoneIdByName(name: string, route53: Route53): Promise { - const zones = await route53.listHostedZonesByName({ DNSName: name }).promise(); - const matchedZones = zones.HostedZones.filter(zone => zone.Name === `${name}.`); +/** + * Return the region that hosts the Route53 endpoint + * + * Route53 is a partitional service: the control plane lives in one particular region, + * which is different for every partition. + * + * The SDK knows how to convert a "target region" to a "route53 endpoint", which + * equates to a (potentially different) region. However, when we use STS + * AssumeRole credentials, we must grab credentials that will work in that + * region. + * + * By default, STS AssumeRole will call the STS endpoint for the same region + * as the Lambda runs in. Normally, this is all good. However, when the AssumeRole + * is used to assume a role in a different account A, the AssumeRole will fail if the + * Lambda is executing in an an opt-in region R to which account A has not been opted in. + * + * To solve this, we will always AssumeRole in the same region as the Route53 call will + * resolve to. + */ +function route53Region(region: string) { + const partitions = { + 'cn': 'cn-northwest-1', + 'us-gov': 'us-gov-west-1', + 'us-iso': 'us-iso-east-1', + 'us-isob': 'us-isob-east-1', + }; - if (matchedZones.length !== 1) { - throw Error(`Expected one hosted zone to match the given name but found ${matchedZones.length}`); + for (const [prefix, mainRegion] of Object.entries(partitions)) { + if (region.startsWith(`${prefix}-`)) { + return mainRegion; + } } - return matchedZones[0].Id; -} + // Default for commercial partition + return 'us-east-1'; +} \ No newline at end of file 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 db24f76df2971..fa8920f0eb7be 100644 --- a/packages/aws-cdk-lib/aws-route53/lib/record-set.ts +++ b/packages/aws-cdk-lib/aws-route53/lib/record-set.ts @@ -11,26 +11,6 @@ import { CustomResource, CustomResourceProvider, CustomResourceProviderRuntime, const CROSS_ACCOUNT_ZONE_DELEGATION_RESOURCE_TYPE = 'Custom::CrossAccountZoneDelegation'; const DELETE_EXISTING_RECORD_SET_RESOURCE_TYPE = 'Custom::DeleteExistingRecordSet'; -/** - * Context key to control whether to use the regional STS endpoint, instead of the global one - * - * There is only exactly one use case where you want to turn this on. If: - * - * - you are building an AWS service; AND - * - would like to your own Global Service Principal in the trust policy of the delegation role; AND - * - the target account is opted in in the same region as well - * - * Then you can turn this on. For all other use cases, the global endpoint is preferable: - * - * - if you are a regular customer, your trust policy would be in terms of account ids or - * organization ids, or ARNs, not Service Principals, so you don't care about this behavior. - * - if the target account is not opted in as well, the AssumeRole call would fail - * - * Because this configuration option is so rare, turn it into a context setting instead - * of a publicly available prop. - */ -const USE_REGIONAL_STS_ENDPOINT_CONTEXT_KEY = '@aws-cdk/aws-route53:useRegionalStsEndpoint'; - /** * A record set */ @@ -795,7 +775,7 @@ export class CrossAccountZoneDelegationRecord extends Construct { const provider = CustomResourceProvider.getOrCreateProvider(this, CROSS_ACCOUNT_ZONE_DELEGATION_RESOURCE_TYPE, { codeDirectory: path.join(__dirname, 'cross-account-zone-delegation-handler'), - runtime: CustomResourceProviderRuntime.NODEJS_16_X, + runtime: CustomResourceProviderRuntime.NODEJS_18_X, }); const role = iam.Role.fromRoleArn(this, 'cross-account-zone-delegation-handler-role', provider.roleArn); @@ -806,8 +786,6 @@ export class CrossAccountZoneDelegationRecord extends Construct { resources: [props.delegationRole.roleArn], })); - const useRegionalStsEndpoint = this.node.tryGetContext(USE_REGIONAL_STS_ENDPOINT_CONTEXT_KEY); - const customResource = new CustomResource(this, 'CrossAccountZoneDelegationCustomResource', { resourceType: CROSS_ACCOUNT_ZONE_DELEGATION_RESOURCE_TYPE, serviceToken: provider.serviceToken, @@ -819,7 +797,6 @@ export class CrossAccountZoneDelegationRecord extends Construct { DelegatedZoneName: props.delegatedZone.zoneName, DelegatedZoneNameServers: props.delegatedZone.hostedZoneNameServers!, TTL: (props.ttl || Duration.days(2)).toSeconds(), - UseRegionalStsEndpoint: useRegionalStsEndpoint ? 'true' : undefined, }, }); diff --git a/packages/aws-cdk-lib/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts b/packages/aws-cdk-lib/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts index 04f7a54b5f1a1..8696c93c62d3b 100644 --- a/packages/aws-cdk-lib/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts +++ b/packages/aws-cdk-lib/aws-route53/test/cross-account-zone-delegation-handler/index.test.ts @@ -1,31 +1,42 @@ import { handler } from '../../lib/cross-account-zone-delegation-handler'; +const mockAssumeRole = jest.fn(); +const mockChangeResourceRecordSets = jest.fn(); +const mockListHostedZonesByName = jest.fn(); + const mockStsClient = { - assumeRole: jest.fn().mockReturnThis(), - promise: jest.fn(), + assumeRole: mockAssumeRole, }; + const mockRoute53Client = { - changeResourceRecordSets: jest.fn().mockReturnThis(), - listHostedZonesByName: jest.fn().mockReturnThis(), - promise: jest.fn(), + changeResourceRecordSets: mockChangeResourceRecordSets, + listHostedZonesByName: mockListHostedZonesByName, }; -jest.mock('aws-sdk', () => { +jest.mock('@aws-sdk/client-sts', () => { return { - ...(jest.requireActual('aws-sdk') as any), - STS: jest.fn(() => mockStsClient), - Route53: jest.fn(() => mockRoute53Client), + STS: jest.fn().mockImplementation(() => { + return mockStsClient; + }), + }; +}); + +jest.mock('@aws-sdk/client-route-53', () => { + return { + Route53: jest.fn().mockImplementation(() => { + return mockRoute53Client; + }), }; }); beforeEach(() => { - mockStsClient.assumeRole.mockReturnThis(); - mockRoute53Client.changeResourceRecordSets.mockReturnThis(); - mockRoute53Client.listHostedZonesByName.mockReturnThis(); + mockStsClient.assumeRole.mockClear(); + mockRoute53Client.changeResourceRecordSets.mockClear(); + mockRoute53Client.listHostedZonesByName.mockClear(); }); -afterEach(() => { - jest.clearAllMocks(); +afterAll(() => { + jest.resetAllMocks(); }); test('throws error if both ParentZoneId and ParentZoneName are not provided', async () => { @@ -39,27 +50,10 @@ test('throws error if both ParentZoneId and ParentZoneName are not provided', as await expect(invokeHandler(event)).rejects.toThrow(/One of ParentZoneId or ParentZoneName must be specified/); }); -test('throws error if getting credentials fails', async () => { - // GIVEN - mockStsClient.promise.mockResolvedValueOnce({ Credentials: undefined }); - - // WHEN - const event= getCfnEvent(); - - // THEN - await expect(invokeHandler(event)).rejects.toThrow(/Error getting assume role credentials/); - - expect(mockStsClient.assumeRole).toHaveBeenCalledTimes(1); - expect(mockStsClient.assumeRole).toHaveBeenCalledWith({ - RoleArn: 'roleArn', - RoleSessionName: expect.any(String), - }); -}); - test('calls create resource record set with Upsert for Create event', async () => { // GIVEN - mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); - mockRoute53Client.promise.mockResolvedValueOnce({}); + mockStsClient.assumeRole.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.changeResourceRecordSets.mockResolvedValueOnce({}); // WHEN const event= getCfnEvent(); @@ -85,8 +79,8 @@ test('calls create resource record set with Upsert for Create event', async () = test('calls create resource record set with DELETE for Delete event', async () => { // GIVEN - mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); - mockRoute53Client.promise.mockResolvedValueOnce({}); + mockStsClient.assumeRole.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.changeResourceRecordSets.mockResolvedValueOnce({}); // WHEN const event= getCfnEvent({ RequestType: 'Delete' }); @@ -115,9 +109,9 @@ test('calls listHostedZonesByName to get zoneId if ParentZoneId is not provided' const parentZoneName = 'some.zone'; const parentZoneId = 'zone-id'; - mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); - mockRoute53Client.promise.mockResolvedValueOnce({ HostedZones: [{ Name: `${parentZoneName}.`, Id: parentZoneId }] }); - mockRoute53Client.promise.mockResolvedValueOnce({}); + mockStsClient.assumeRole.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.listHostedZonesByName.mockResolvedValueOnce({ HostedZones: [{ Name: `${parentZoneName}.`, Id: parentZoneId }] }); + mockRoute53Client.changeResourceRecordSets.mockResolvedValueOnce({}); // WHEN const event = getCfnEvent({}, { @@ -152,8 +146,8 @@ test('throws if more than one HostedZones are returnd for the provided ParentHos const parentZoneName = 'some.zone'; const parentZoneId = 'zone-id'; - mockStsClient.promise.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); - mockRoute53Client.promise.mockResolvedValueOnce({ + mockStsClient.assumeRole.mockResolvedValueOnce({ Credentials: { AccessKeyId: 'K', SecretAccessKey: 'S', SessionToken: 'T' } }); + mockRoute53Client.listHostedZonesByName.mockResolvedValueOnce({ HostedZones: [ { Name: `${parentZoneName}.`, Id: parentZoneId }, { Name: `${parentZoneName}.`, Id: parentZoneId }, @@ -195,4 +189,4 @@ function getCfnEvent( // even though our tests only need some of the fields async function invokeHandler(event: Partial) { return handler(event as AWSLambda.CloudFormationCustomResourceEvent); -} +} \ No newline at end of file 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 13f27f7eb6282..1fa9bf4eae2e1 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 @@ -1023,32 +1023,6 @@ describe('record set', () => { } }); - testDeprecated('Cross account zone context flag', () => { - // GIVEN - const stack = new Stack(); - stack.node.setContext('@aws-cdk/aws-route53:useRegionalStsEndpoint', true); - 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, - parentHostedZoneName: 'myzone.com', - delegationRole: parentZone.crossAccountZoneDelegationRole!, - ttl: Duration.seconds(60), - }); - - // THEN - Template.fromStack(stack).hasResourceProperties('Custom::CrossAccountZoneDelegation', { - UseRegionalStsEndpoint: 'true', - }); - }); - test('Delete existing record', () => { // GIVEN const stack = new Stack();