Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 75 additions & 55 deletions src/core/runtime/src/load-limits-step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@ export const handler = async (input: LoadLimitsInput) => {
commitId: configCommitId,
});

const defaultRegion: string = config['global-options']['aws-org-master'].region;

// Capture limit results
const limits: LimitOutput[] = [];

const accountConfigs = config.getAccountConfigs();
const sts = new STS();
for (const [accountKey, accountConfig] of accountConfigs) {
const accountId = getAccountId(accounts, accountKey);

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

const sts = new STS();
const credentials = await sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
const quotas = new ServiceQuotas(credentials);
const regions: string[] = Array.from(
new Set(
config
.getVpcConfigs()
.filter(vc => vc.accountKey === accountKey)
.map(accConfig => accConfig.vpcConfig.region),
),
);

if (!regions.includes(defaultRegion)) {
regions.push(defaultRegion);
}

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

// The fetch all supported limits and request an increase if necessary
for (const [limitKey, limitCode] of Object.entries(LIMITS)) {
if (!limitKeysFromConfig.includes(limitKey)) {
console.info(`Cannot find limit with key "${limitKey}" in accelerator config`);
continue;
}
if (!limitCode.enabled) {
console.warn(`The limit "${limitKey}" is not enabled`);
continue;
for (const region of regions) {
const credentials = await sts.getCredentialsForAccountAndRole(accountId, assumeRoleName);
const quotas = new ServiceQuotas(credentials, region);

// The fetch all supported limits and request an increase if necessary
for (const [limitKey, limitCode] of Object.entries(LIMITS)) {
if (!limitKeysFromConfig.includes(limitKey)) {
console.info(`Cannot find limit with key "${limitKey}" in accelerator config`);
continue;
}
if (!limitCode.enabled) {
console.warn(`The limit "${limitKey}" is not enabled`);
continue;
}

const quota = await quotas.getServiceQuotaOrDefault({
ServiceCode: limitCode.serviceCode,
QuotaCode: limitCode.quotaCode,
});
let value = quota.Value!;
const accountLimitConfig = limitConfig[limitKey];
if (accountLimitConfig && accountLimitConfig['customer-confirm-inplace']) {
value = accountLimitConfig.value;
}

// Keep track of limits so we can return them at the end of this function
limits.push({
accountKey,
limitKey,
serviceCode: limitCode.serviceCode,
quotaCode: limitCode.quotaCode,
value,
region,
});

if (!accountLimitConfig) {
console.debug(`Quota "${limitKey}" has no desired value for account "${accountKey}"`);
continue;
}

const desiredValue = accountLimitConfig.value;

if (value >= desiredValue) {
console.debug(`Quota "${limitKey}" already has a value equal or larger than the desired value`);
continue;
}
if (!quota.Adjustable) {
console.warn(`Quota "${limitKey}" is not adjustable`);
continue;
}

if (region === defaultRegion) {
// Request the increase or renew if the previous request was more than two days ago
await quotas.renewServiceQuotaIncrease({
ServiceCode: limitCode.serviceCode,
QuotaCode: limitCode.quotaCode,
DesiredValue: desiredValue,
MinTimeBetweenRequestsMillis: 1000 * 60 * 60 * 24 * 2, // Two days in milliseconds
});
}
}

const quota = await quotas.getServiceQuotaOrDefault({
ServiceCode: limitCode.serviceCode,
QuotaCode: limitCode.quotaCode,
});
let value = quota.Value!;
const accountLimitConfig = limitConfig[limitKey];
if (accountLimitConfig && accountLimitConfig['customer-confirm-inplace']) {
value = accountLimitConfig.value;
}

// Keep track of limits so we can return them at the end of this function
limits.push({
accountKey,
limitKey,
serviceCode: limitCode.serviceCode,
quotaCode: limitCode.quotaCode,
value,
});

if (!accountLimitConfig) {
console.debug(`Quota "${limitKey}" has no desired value for account "${accountKey}"`);
continue;
}

const desiredValue = accountLimitConfig.value;

if (value >= desiredValue) {
console.debug(`Quota "${limitKey}" already has a value equal or larger than the desired value`);
continue;
}
if (!quota.Adjustable) {
console.warn(`Quota "${limitKey}" is not adjustable`);
continue;
}

// Request the increase or renew if the previous request was more than two days ago
await quotas.renewServiceQuotaIncrease({
ServiceCode: limitCode.serviceCode,
QuotaCode: limitCode.quotaCode,
DesiredValue: desiredValue,
MinTimeBetweenRequestsMillis: 1000 * 60 * 60 * 24 * 2, // Two days in milliseconds
});
}
}

Expand Down
5 changes: 1 addition & 4 deletions src/core/runtime/src/store-stack-output-step.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { STS } from '@aws-accelerator/common/src/aws/sts';
import { DynamoDB } from '@aws-accelerator/common/src/aws/dynamodb';
import { CloudFormation } from '@aws-accelerator/common/src/aws/cloudformation';
import { StackOutput } from '@aws-accelerator/common-outputs/src/stack-output';
import { Organizations } from '@aws-accelerator/common/src/aws/organizations';
import { loadAcceleratorConfig } from '@aws-accelerator/common-config/src/load';
import { LoadConfigurationInput } from './load-configuration-step';
import { Account } from '@aws-accelerator/common-outputs/src/accounts';
import { getUpdateValueInput } from './utils/dynamodb-requests';

Expand Down Expand Up @@ -53,7 +50,7 @@ export const handler = async (input: StoreStackOutputInput) => {
stack.Outputs?.forEach(output =>
outputs.push({
accountKey,
outputKey: `${output.OutputKey}sjkdh`,
outputKey: `${output.OutputKey}`,
outputValue: output.OutputValue,
outputDescription: output.Description,
outputExportName: output.ExportName,
Expand Down
44 changes: 0 additions & 44 deletions src/deployments/cdk/src/apps/phase-1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,50 +157,6 @@ export async function deploy({ acceleratorConfig, accountStacks, accounts, conte
const vpcStack = new VpcStack(accountStack, `VpcStack${vpcStackPrettyName}`, props);
const vpc = vpcStack.vpc;

const endpointConfig = vpcConfig['interface-endpoints'];
if (InterfaceEndpointConfig.is(endpointConfig)) {
const subnetName = endpointConfig.subnet;
const subnetIds = vpc.azSubnets.getAzSubnetIdsForSubnetName(subnetName);
if (subnetIds.length === 0) {
console.warn(`Cannot find subnet ID with name "${subnetName}'`);
return;
}

let endpointCount = 0;
let endpointStackIndex = 0;
let endpointStack;
for (const endpoint of endpointConfig.endpoints) {
if (!limiter.create(accountKey, Limit.VpcInterfaceEndpointsPerVpc, vpc.name)) {
console.log(
`Skipping endpoint "${endpoint}" creation in VPC "${vpc.name}". Reached maximum interface endpoints per VPC`,
);
continue;
}

if (!endpointStack || endpointCount >= 30) {
endpointStack = new NestedStack(accountStack, `Endpoint${endpointStackIndex++}`);
endpointCount = 0;
}
const interfaceEndpoint = new InterfaceEndpoint(endpointStack, pascalCase(endpoint), {
serviceName: endpoint,
vpcId: vpc.vpcId,
vpcRegion: vpc.region,
subnetIds,
});

new centralEndpoints.CfnHostedZoneOutput(endpointStack, `HostedZoneOutput-${endpoint}`, {
accountKey,
domain: interfaceEndpoint.hostedZone.name,
hostedZoneId: interfaceEndpoint.hostedZone.ref,
region: vpc.region,
zoneType: 'PRIVATE',
serviceName: endpoint,
vpcName: vpc.name,
});
endpointCount++;
}
}

// Store the VPC output so that subsequent phases can access the output
new vpcDeployment.CfnVpcOutput(vpc, `VpcOutput`, {
accountKey,
Expand Down
9 changes: 8 additions & 1 deletion src/deployments/cdk/src/apps/phase-2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import * as snsDeployment from '../deployments/sns';
* - TGW Peering Attachments
*/

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

// Find the account buckets in the outputs
Expand Down Expand Up @@ -330,4 +330,11 @@ export async function deploy({ acceleratorConfig, accountStacks, accounts, conte
config: acceleratorConfig,
outputs,
});

await vpcDeployment.step3({
accountStacks,
config: acceleratorConfig,
limiter,
outputs,
});
}
1 change: 1 addition & 0 deletions src/deployments/cdk/src/common/interface-endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class InterfaceEndpoint extends cdk.Construct {
comment: `zzEndpoint - ${serviceName}`,
},
});

this._hostedZone.addDependsOn(endpoint);

const recordSet = new route53.CfnRecordSet(this, 'RecordSet', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export async function centralEndpointDeploymentRole(stack: AccountStack) {
}),
);

role.addToPrincipalPolicy(
new iam.PolicyStatement({
actions: ['route53:List*', 'route53:DeleteHostedZone', 'route53:CreateHostedZone'],
resources: ['*'],
}),
);

role.addToPrincipalPolicy(
new iam.PolicyStatement({
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
Expand Down
1 change: 1 addition & 0 deletions src/deployments/cdk/src/deployments/vpc/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './outputs';
export * from './step-1';
export * from './step-2';
export * from './step-3';
export * from './step-4';
Loading