@aws-amplify/amplify-category-api
Version:
Amplify CLI API Category Plugin
283 lines • 11.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EcsAlbStack = void 0;
const acm = __importStar(require("aws-cdk-lib/aws-certificatemanager"));
const cloudfront = __importStar(require("aws-cdk-lib/aws-cloudfront"));
const cognito = __importStar(require("aws-cdk-lib/aws-cognito"));
const ec2 = __importStar(require("aws-cdk-lib/aws-ec2"));
const elb2 = __importStar(require("aws-cdk-lib/aws-elasticloadbalancingv2"));
const route53 = __importStar(require("aws-cdk-lib/aws-route53"));
const route53targets = __importStar(require("aws-cdk-lib/aws-route53-targets"));
const cdk = __importStar(require("aws-cdk-lib"));
const uuid_1 = require("uuid");
const base_api_stack_1 = require("./base-api-stack");
class EcsAlbStack extends base_api_stack_1.ContainersStack {
constructor(scope, id, ecsProps) {
super(scope, id, {
...ecsProps,
skipWait: true,
createCloudMapService: false,
});
this.ecsProps = ecsProps;
const { authName, restrictAccess } = ecsProps;
if (restrictAccess) {
const param = this.parameters.get(`auth${authName}HostedUIDomain`);
this.userPoolDomain = param.valueAsString;
}
this.parameters.get('ParamZipPath').default = 'site.zip';
this.alb();
}
alb() {
const { domainName, hostedZoneId, exposedContainer: { name: containerName, port }, restrictAccess, } = this.ecsProps;
const sharedSecretHeaderName = 'x-cf-token';
const sharedSecretHeader = (0, uuid_1.v4)();
const userPoolDomain = this.userPoolDomain;
const vpcId = this.vpcId;
const subnets = this.subnets;
const userPoolArn = cdk.Fn.join('', [
'arn:',
cdk.Aws.PARTITION,
':cognito-idp:',
cdk.Aws.REGION,
':',
cdk.Aws.ACCOUNT_ID,
':userpool/',
this.userPoolId,
]);
const [distributionDomainName, , domainNameSuffix] = domainName.match(/([^\.]+)\.(.*)/);
const lbPrefix = `lb-${this.envName}`;
const albDomainName = `${lbPrefix}.${domainNameSuffix}`;
const wildcardDomainName = `*.${domainNameSuffix}`;
const wildcardCertificate = new acm.CfnCertificate(this, 'Certificate', {
domainName: wildcardDomainName,
validationMethod: hostedZoneId ? acm.ValidationMethod.DNS : acm.ValidationMethod.EMAIL,
domainValidationOptions: [
{
domainName: wildcardDomainName,
validationDomain: hostedZoneId === undefined ? domainNameSuffix : undefined,
hostedZoneId,
},
],
});
const userPoolClient = restrictAccess
? new cognito.CfnUserPoolClient(this, 'UserPoolClient', {
userPoolId: this.userPoolId,
allowedOAuthFlows: [
'code',
],
allowedOAuthFlowsUserPoolClient: true,
allowedOAuthScopes: ['profile', 'phone', 'email', 'openid', 'aws.cognito.signin.user.admin'],
generateSecret: true,
supportedIdentityProviders: ['COGNITO'],
callbackUrLs: [`https://${distributionDomainName}/oauth2/idpresponse`],
logoutUrLs: [`https://${distributionDomainName}/oauth2/idpresponse`],
})
: undefined;
const targetGroup = new elb2.CfnTargetGroup(this, 'TargetGroup', {
healthCheckIntervalSeconds: cdk.Duration.seconds(90).toSeconds(),
healthCheckPath: '/',
healthCheckTimeoutSeconds: cdk.Duration.minutes(1).toSeconds(),
healthyThresholdCount: 2,
port,
protocol: elb2.Protocol.HTTP,
targetType: elb2.TargetType.IP,
unhealthyThresholdCount: 2,
vpcId,
});
const albSecurityGroup = new ec2.CfnSecurityGroup(this, 'AlbSecurityGroup', {
vpcId,
groupDescription: 'ALB Security Group',
securityGroupEgress: [
{
description: 'Allow all outbound traffic by default',
ipProtocol: '-1',
cidrIp: '0.0.0.0/0',
},
],
securityGroupIngress: [
{
description: 'Allow from anyone on port 443',
ipProtocol: ec2.Protocol.TCP,
cidrIp: '0.0.0.0/0',
fromPort: 443,
toPort: 443,
},
],
});
const loadBalancer = new elb2.CfnLoadBalancer(this, 'LoadBalancer', {
type: 'application',
securityGroups: [albSecurityGroup.attrGroupId],
loadBalancerAttributes: [
{
key: 'deletion_protection.enabled',
value: 'false',
},
],
scheme: 'internet-facing',
subnets,
});
this.ecsService.loadBalancers = [
{
containerName,
containerPort: port,
targetGroupArn: targetGroup.ref,
},
];
this.ecsServiceSecurityGroup.securityGroupIngress.push({
ipProtocol: ec2.Protocol.TCP,
fromPort: port,
toPort: port,
sourceSecurityGroupId: albSecurityGroup.attrGroupId,
});
const listener = new elb2.CfnListener(this, 'AlbListener', {
defaultActions: [
{
fixedResponseConfig: {
statusCode: '403',
},
type: 'fixed-response',
},
],
loadBalancerArn: loadBalancer.ref,
port: 443,
protocol: elb2.Protocol.HTTPS,
certificates: [{ certificateArn: wildcardCertificate.ref }],
});
this.ecsService.addDependency(listener);
let actionsOrderCounter = 1;
const listenerRule = new elb2.CfnListenerRule(this, 'AlbListenerRule', {
priority: 1,
listenerArn: listener.ref,
actions: [].concat(restrictAccess
? {
order: actionsOrderCounter++,
type: 'authenticate-cognito',
authenticateCognitoConfig: {
userPoolArn,
userPoolClientId: userPoolClient.ref,
userPoolDomain,
},
}
: undefined, {
order: actionsOrderCounter++,
type: 'forward',
targetGroupArn: targetGroup.ref,
}),
conditions: [
{
field: 'host-header',
hostHeaderConfig: {
values: [distributionDomainName],
},
},
{
field: 'http-header',
httpHeaderConfig: {
httpHeaderName: sharedSecretHeaderName,
values: [sharedSecretHeader],
},
},
],
});
this.ecsService.addDependency(listenerRule);
const originId = `${loadBalancer.logicalId}-origin`;
const distribution = new cloudfront.CfnDistribution(this, 'Distribution', {
distributionConfig: {
enabled: true,
httpVersion: 'http2',
ipv6Enabled: true,
aliases: [distributionDomainName],
defaultCacheBehavior: {
forwardedValues: {
cookies: { forward: 'all' },
headers: ['*'],
queryString: true,
},
targetOriginId: originId,
viewerProtocolPolicy: 'redirect-to-https',
},
origins: [
{
customOriginConfig: {
originProtocolPolicy: 'https-only',
},
domainName: albDomainName,
id: originId,
originCustomHeaders: [
{
headerName: sharedSecretHeaderName,
headerValue: sharedSecretHeader,
},
],
},
],
viewerCertificate: {
acmCertificateArn: wildcardCertificate.ref,
minimumProtocolVersion: 'TLSv1.2_2019',
sslSupportMethod: 'sni-only',
},
},
});
if (hostedZoneId) {
new route53.CfnRecordSetGroup(this, 'RecordSetGroup', {
hostedZoneId,
recordSets: [
{
name: albDomainName,
type: route53.RecordType.A,
aliasTarget: {
hostedZoneId: loadBalancer.attrCanonicalHostedZoneId,
dnsName: loadBalancer.attrDnsName,
},
},
{
name: distributionDomainName,
type: route53.RecordType.A,
aliasTarget: {
hostedZoneId: route53targets.CloudFrontTarget.CLOUDFRONT_ZONE_ID,
dnsName: distribution.attrDomainName,
},
},
],
});
}
new cdk.CfnOutput(this, 'PipelineUrl', {
value: cdk.Fn.join('', [
'https://',
cdk.Aws.REGION,
'.console.aws.amazon.com/codesuite/codepipeline/pipelines/',
this.getPipelineName(),
'/view',
]),
});
new cdk.CfnOutput(this, 'LoadBalancerAliasDomainName', { value: loadBalancer.attrDnsName });
new cdk.CfnOutput(this, 'LoadBalancerCnameDomainName', { value: albDomainName });
new cdk.CfnOutput(this, 'CloudfrontDistributionAliasDomainName', { value: distribution.attrDomainName });
new cdk.CfnOutput(this, 'CloudfrontDistributionCnameDomainName', { value: distributionDomainName });
}
}
exports.EcsAlbStack = EcsAlbStack;
//# sourceMappingURL=ecs-alb-stack.js.map