Skip to content

Commit 816a0b9

Browse files
fix(core): Regional Interface Endpoints (#410)
1 parent ec657b6 commit 816a0b9

File tree

21 files changed

+688
-174
lines changed

21 files changed

+688
-174
lines changed

src/core/runtime/src/load-limits-step.ts

Lines changed: 75 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@ export const handler = async (input: LoadLimitsInput) => {
7070
commitId: configCommitId,
7171
});
7272

73+
const defaultRegion: string = config['global-options']['aws-org-master'].region;
74+
7375
// Capture limit results
7476
const limits: LimitOutput[] = [];
7577

7678
const accountConfigs = config.getAccountConfigs();
79+
const sts = new STS();
7780
for (const [accountKey, accountConfig] of accountConfigs) {
7881
const accountId = getAccountId(accounts, accountKey);
7982

@@ -82,9 +85,18 @@ export const handler = async (input: LoadLimitsInput) => {
8285
continue;
8386
}
8487

85-
const sts = new STS();
86-
const credentials = await sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
87-
const quotas = new ServiceQuotas(credentials);
88+
const regions: string[] = Array.from(
89+
new Set(
90+
config
91+
.getVpcConfigs()
92+
.filter(vc => vc.accountKey === accountKey)
93+
.map(accConfig => accConfig.vpcConfig.region),
94+
),
95+
);
96+
97+
if (!regions.includes(defaultRegion)) {
98+
regions.push(defaultRegion);
99+
}
88100

89101
// First check that all limits in the config exist
90102
const limitConfig = accountConfig.limits;
@@ -97,59 +109,67 @@ export const handler = async (input: LoadLimitsInput) => {
97109
}
98110
}
99111

100-
// The fetch all supported limits and request an increase if necessary
101-
for (const [limitKey, limitCode] of Object.entries(LIMITS)) {
102-
if (!limitKeysFromConfig.includes(limitKey)) {
103-
console.info(`Cannot find limit with key "${limitKey}" in accelerator config`);
104-
continue;
105-
}
106-
if (!limitCode.enabled) {
107-
console.warn(`The limit "${limitKey}" is not enabled`);
108-
continue;
112+
for (const region of regions) {
113+
const credentials = await sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
114+
const quotas = new ServiceQuotas(credentials, region);
115+
116+
// The fetch all supported limits and request an increase if necessary
117+
for (const [limitKey, limitCode] of Object.entries(LIMITS)) {
118+
if (!limitKeysFromConfig.includes(limitKey)) {
119+
console.info(`Cannot find limit with key "${limitKey}" in accelerator config`);
120+
continue;
121+
}
122+
if (!limitCode.enabled) {
123+
console.warn(`The limit "${limitKey}" is not enabled`);
124+
continue;
125+
}
126+
127+
const quota = await quotas.getServiceQuotaOrDefault({
128+
ServiceCode: limitCode.serviceCode,
129+
QuotaCode: limitCode.quotaCode,
130+
});
131+
let value = quota.Value!;
132+
const accountLimitConfig = limitConfig[limitKey];
133+
if (accountLimitConfig && accountLimitConfig['customer-confirm-inplace']) {
134+
value = accountLimitConfig.value;
135+
}
136+
137+
// Keep track of limits so we can return them at the end of this function
138+
limits.push({
139+
accountKey,
140+
limitKey,
141+
serviceCode: limitCode.serviceCode,
142+
quotaCode: limitCode.quotaCode,
143+
value,
144+
region,
145+
});
146+
147+
if (!accountLimitConfig) {
148+
console.debug(`Quota "${limitKey}" has no desired value for account "${accountKey}"`);
149+
continue;
150+
}
151+
152+
const desiredValue = accountLimitConfig.value;
153+
154+
if (value >= desiredValue) {
155+
console.debug(`Quota "${limitKey}" already has a value equal or larger than the desired value`);
156+
continue;
157+
}
158+
if (!quota.Adjustable) {
159+
console.warn(`Quota "${limitKey}" is not adjustable`);
160+
continue;
161+
}
162+
163+
if (region === defaultRegion) {
164+
// Request the increase or renew if the previous request was more than two days ago
165+
await quotas.renewServiceQuotaIncrease({
166+
ServiceCode: limitCode.serviceCode,
167+
QuotaCode: limitCode.quotaCode,
168+
DesiredValue: desiredValue,
169+
MinTimeBetweenRequestsMillis: 1000 * 60 * 60 * 24 * 2, // Two days in milliseconds
170+
});
171+
}
109172
}
110-
111-
const quota = await quotas.getServiceQuotaOrDefault({
112-
ServiceCode: limitCode.serviceCode,
113-
QuotaCode: limitCode.quotaCode,
114-
});
115-
let value = quota.Value!;
116-
const accountLimitConfig = limitConfig[limitKey];
117-
if (accountLimitConfig && accountLimitConfig['customer-confirm-inplace']) {
118-
value = accountLimitConfig.value;
119-
}
120-
121-
// Keep track of limits so we can return them at the end of this function
122-
limits.push({
123-
accountKey,
124-
limitKey,
125-
serviceCode: limitCode.serviceCode,
126-
quotaCode: limitCode.quotaCode,
127-
value,
128-
});
129-
130-
if (!accountLimitConfig) {
131-
console.debug(`Quota "${limitKey}" has no desired value for account "${accountKey}"`);
132-
continue;
133-
}
134-
135-
const desiredValue = accountLimitConfig.value;
136-
137-
if (value >= desiredValue) {
138-
console.debug(`Quota "${limitKey}" already has a value equal or larger than the desired value`);
139-
continue;
140-
}
141-
if (!quota.Adjustable) {
142-
console.warn(`Quota "${limitKey}" is not adjustable`);
143-
continue;
144-
}
145-
146-
// Request the increase or renew if the previous request was more than two days ago
147-
await quotas.renewServiceQuotaIncrease({
148-
ServiceCode: limitCode.serviceCode,
149-
QuotaCode: limitCode.quotaCode,
150-
DesiredValue: desiredValue,
151-
MinTimeBetweenRequestsMillis: 1000 * 60 * 60 * 24 * 2, // Two days in milliseconds
152-
});
153173
}
154174
}
155175

src/core/runtime/src/store-stack-output-step.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ import { STS } from '@aws-accelerator/common/src/aws/sts';
22
import { DynamoDB } from '@aws-accelerator/common/src/aws/dynamodb';
33
import { CloudFormation } from '@aws-accelerator/common/src/aws/cloudformation';
44
import { StackOutput } from '@aws-accelerator/common-outputs/src/stack-output';
5-
import { Organizations } from '@aws-accelerator/common/src/aws/organizations';
6-
import { loadAcceleratorConfig } from '@aws-accelerator/common-config/src/load';
7-
import { LoadConfigurationInput } from './load-configuration-step';
85
import { Account } from '@aws-accelerator/common-outputs/src/accounts';
96
import { getUpdateValueInput } from './utils/dynamodb-requests';
107

@@ -53,7 +50,7 @@ export const handler = async (input: StoreStackOutputInput) => {
5350
stack.Outputs?.forEach(output =>
5451
outputs.push({
5552
accountKey,
56-
outputKey: `${output.OutputKey}sjkdh`,
53+
outputKey: `${output.OutputKey}`,
5754
outputValue: output.OutputValue,
5855
outputDescription: output.Description,
5956
outputExportName: output.ExportName,

src/deployments/cdk/src/apps/phase-1.ts

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -157,50 +157,6 @@ export async function deploy({ acceleratorConfig, accountStacks, accounts, conte
157157
const vpcStack = new VpcStack(accountStack, `VpcStack${vpcStackPrettyName}`, props);
158158
const vpc = vpcStack.vpc;
159159

160-
const endpointConfig = vpcConfig['interface-endpoints'];
161-
if (InterfaceEndpointConfig.is(endpointConfig)) {
162-
const subnetName = endpointConfig.subnet;
163-
const subnetIds = vpc.azSubnets.getAzSubnetIdsForSubnetName(subnetName);
164-
if (subnetIds.length === 0) {
165-
console.warn(`Cannot find subnet ID with name "${subnetName}'`);
166-
return;
167-
}
168-
169-
let endpointCount = 0;
170-
let endpointStackIndex = 0;
171-
let endpointStack;
172-
for (const endpoint of endpointConfig.endpoints) {
173-
if (!limiter.create(accountKey, Limit.VpcInterfaceEndpointsPerVpc, vpc.name)) {
174-
console.log(
175-
`Skipping endpoint "${endpoint}" creation in VPC "${vpc.name}". Reached maximum interface endpoints per VPC`,
176-
);
177-
continue;
178-
}
179-
180-
if (!endpointStack || endpointCount >= 30) {
181-
endpointStack = new NestedStack(accountStack, `Endpoint${endpointStackIndex++}`);
182-
endpointCount = 0;
183-
}
184-
const interfaceEndpoint = new InterfaceEndpoint(endpointStack, pascalCase(endpoint), {
185-
serviceName: endpoint,
186-
vpcId: vpc.vpcId,
187-
vpcRegion: vpc.region,
188-
subnetIds,
189-
});
190-
191-
new centralEndpoints.CfnHostedZoneOutput(endpointStack, `HostedZoneOutput-${endpoint}`, {
192-
accountKey,
193-
domain: interfaceEndpoint.hostedZone.name,
194-
hostedZoneId: interfaceEndpoint.hostedZone.ref,
195-
region: vpc.region,
196-
zoneType: 'PRIVATE',
197-
serviceName: endpoint,
198-
vpcName: vpc.name,
199-
});
200-
endpointCount++;
201-
}
202-
}
203-
204160
// Store the VPC output so that subsequent phases can access the output
205161
new vpcDeployment.CfnVpcOutput(vpc, `VpcOutput`, {
206162
accountKey,

src/deployments/cdk/src/apps/phase-2.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import * as snsDeployment from '../deployments/sns';
4545
* - TGW Peering Attachments
4646
*/
4747

48-
export async function deploy({ acceleratorConfig, accountStacks, accounts, context, outputs }: PhaseInput) {
48+
export async function deploy({ acceleratorConfig, accountStacks, accounts, context, outputs, limiter }: PhaseInput) {
4949
const securityAccountKey = acceleratorConfig.getMandatoryAccountKey('central-security');
5050

5151
// Find the account buckets in the outputs
@@ -330,4 +330,11 @@ export async function deploy({ acceleratorConfig, accountStacks, accounts, conte
330330
config: acceleratorConfig,
331331
outputs,
332332
});
333+
334+
await vpcDeployment.step3({
335+
accountStacks,
336+
config: acceleratorConfig,
337+
limiter,
338+
outputs,
339+
});
333340
}

src/deployments/cdk/src/common/interface-endpoints.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export class InterfaceEndpoint extends cdk.Construct {
7070
comment: `zzEndpoint - ${serviceName}`,
7171
},
7272
});
73+
7374
this._hostedZone.addDependsOn(endpoint);
7475

7576
const recordSet = new route53.CfnRecordSet(this, 'RecordSet', {

src/deployments/cdk/src/deployments/iam/central-endpoints-deployment-roles.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ export async function centralEndpointDeploymentRole(stack: AccountStack) {
5252
}),
5353
);
5454

55+
role.addToPrincipalPolicy(
56+
new iam.PolicyStatement({
57+
actions: ['route53:List*', 'route53:DeleteHostedZone', 'route53:CreateHostedZone'],
58+
resources: ['*'],
59+
}),
60+
);
61+
5562
role.addToPrincipalPolicy(
5663
new iam.PolicyStatement({
5764
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './outputs';
22
export * from './step-1';
33
export * from './step-2';
4+
export * from './step-3';
45
export * from './step-4';

0 commit comments

Comments
 (0)