Skip to content

Commit

Permalink
Merge branch 'main' into 22012-arm64-docker-python-layer
Browse files Browse the repository at this point in the history
  • Loading branch information
TheRealAmazonKendra authored Oct 19, 2022
2 parents 4664d9d + 914185b commit 3b675d7
Show file tree
Hide file tree
Showing 98 changed files with 8,631 additions and 873 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/auto-approve.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ jobs:
permissions:
pull-requests: write
steps:
- uses: hmarr/auto-approve-action@v2.4.0
- uses: hmarr/auto-approve-action@v3.0.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
39 changes: 39 additions & 0 deletions packages/@aws-cdk/aws-apigateway/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1083,6 +1083,45 @@ new route53.ARecord(this, 'CustomDomainAliasRecord', {
});
```

### Custom Domains with multi-level api mapping

Additional requirements for creating multi-level path mappings for RestApis:

(both are defaults)

- Must use `SecurityPolicy.TLS_1_2`
- DomainNames must be `EndpointType.REGIONAL`

```ts
declare const acmCertificateForExampleCom: any;
declare const restApi: apigateway.RestApi;

new apigateway.DomainName(this, 'custom-domain', {
domainName: 'example.com',
certificate: acmCertificateForExampleCom,
mapping: restApi,
basePath: 'orders/v1/api',
});
```

To then add additional mappings to a domain you can use the `addApiMapping` method.

```ts
declare const acmCertificateForExampleCom: any;
declare const restApi: apigateway.RestApi;
declare const secondRestApi: apigateway.RestApi;

const domain = new apigateway.DomainName(this, 'custom-domain', {
domainName: 'example.com',
certificate: acmCertificateForExampleCom,
mapping: restApi,
});

domain.addApiMapping(secondRestApi.deploymentStage, {
basePath: 'orders/v2/api',
});
```

## Access Logging

Access logging creates logs every time an API method is accessed. Access logs can have information on
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/authorizers/lambda.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface LambdaAuthorizerProps {
/**
* An optional human friendly name for the authorizer. Note that, this is not the primary identifier of the authorizer.
*
* @default - the unique construcrt ID
* @default - the unique construct ID
*/
readonly authorizerName?: string;

Expand Down
101 changes: 90 additions & 11 deletions packages/@aws-cdk/aws-apigateway/lib/domain-name.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import * as apigwv2 from '@aws-cdk/aws-apigatewayv2';
import * as acm from '@aws-cdk/aws-certificatemanager';
import { IBucket } from '@aws-cdk/aws-s3';
import { IResource, Names, Resource, Token } from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnDomainName } from './apigateway.generated';
import { BasePathMapping, BasePathMappingOptions } from './base-path-mapping';
import { EndpointType, IRestApi } from './restapi';
import { IStage } from './stage';

/**
* Options for creating an api mapping
*/
export interface ApiMappingOptions {
/**
* The api path name that callers of the API must provide in the URL after
* the domain name (e.g. `example.com/base-path`). If you specify this
* property, it can't be an empty string.
*
* If this is undefined, a mapping will be added for the empty path. Any request
* that does not match a mapping will get sent to the API that has been mapped
* to the empty path.
*
* @default - map requests from the domain root (e.g. `example.com`).
*/
readonly basePath?: string;
}

/**
* The minimum version of the SSL protocol that you want API Gateway to use for HTTPS connections.
Expand Down Expand Up @@ -54,8 +74,7 @@ export interface DomainNameOptions {
* the domain name (e.g. `example.com/base-path`). If you specify this
* property, it can't be an empty string.
*
* @default - map requests from the domain root (e.g. `example.com`). If this
* is undefined, no additional mappings will be allowed on this domain name.
* @default - map requests from the domain root (e.g. `example.com`).
*/
readonly basePath?: string;
}
Expand All @@ -64,8 +83,7 @@ export interface DomainNameProps extends DomainNameOptions {
/**
* If specified, all requests to this domain will be mapped to the production
* deployment of this API. If you wish to map this domain to multiple APIs
* with different base paths, don't specify this option and use
* `addBasePathMapping`.
* with different base paths, use `addBasePathMapping` or `addApiMapping`.
*
* @default - you will have to call `addBasePathMapping` to map this domain to
* API endpoints.
Expand Down Expand Up @@ -115,12 +133,15 @@ export class DomainName extends Resource implements IDomainName {
public readonly domainNameAliasDomainName: string;
public readonly domainNameAliasHostedZoneId: string;
private readonly basePaths = new Set<string | undefined>();
private readonly securityPolicy?: SecurityPolicy;
private readonly endpointType: EndpointType;

constructor(scope: Construct, id: string, props: DomainNameProps) {
super(scope, id);

const endpointType = props.endpointType || EndpointType.REGIONAL;
const edge = endpointType === EndpointType.EDGE;
this.endpointType = props.endpointType || EndpointType.REGIONAL;
const edge = this.endpointType === EndpointType.EDGE;
this.securityPolicy = props.securityPolicy;

if (!Token.isUnresolved(props.domainName) && /[A-Z]/.test(props.domainName)) {
throw new Error(`Domain name does not support uppercase letters. Got: ${props.domainName}`);
Expand All @@ -131,7 +152,7 @@ export class DomainName extends Resource implements IDomainName {
domainName: props.domainName,
certificateArn: edge ? props.certificate.certificateArn : undefined,
regionalCertificateArn: edge ? undefined : props.certificate.certificateArn,
endpointConfiguration: { types: [endpointType] },
endpointConfiguration: { types: [this.endpointType] },
mutualTlsAuthentication: mtlsConfig,
securityPolicy: props.securityPolicy,
});
Expand All @@ -146,22 +167,54 @@ export class DomainName extends Resource implements IDomainName {
? resource.attrDistributionHostedZoneId
: resource.attrRegionalHostedZoneId;

if (props.mapping) {

const multiLevel = this.validateBasePath(props.basePath);
if (props.mapping && !multiLevel) {
this.addBasePathMapping(props.mapping, {
basePath: props.basePath,
});
} else if (props.mapping && multiLevel) {
this.addApiMapping(props.mapping.deploymentStage, {
basePath: props.basePath,
});
}
}

private validateBasePath(path?: string): boolean {
if (this.isMultiLevel(path)) {
if (this.endpointType === EndpointType.EDGE) {
throw new Error('multi-level basePath is only supported when endpointType is EndpointType.REGIONAL');
}
if (this.securityPolicy && this.securityPolicy !== SecurityPolicy.TLS_1_2) {
throw new Error('securityPolicy must be set to TLS_1_2 if multi-level basePath is provided');
}
return true;
}
return false;
}

private isMultiLevel(path?: string): boolean {
return (path?.split('/').filter(x => !!x) ?? []).length >= 2;
}

/**
* Maps this domain to an API endpoint.
*
* This uses the BasePathMapping from ApiGateway v1 which does not support multi-level paths.
*
* If you need to create a mapping for a multi-level path use `addApiMapping` instead.
*
* @param targetApi That target API endpoint, requests will be mapped to the deployment stage.
* @param options Options for mapping to base path with or without a stage
*/
public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }) {
if (this.basePaths.has(undefined)) {
throw new Error('This domain name already has an empty base path. No additional base paths are allowed.');
public addBasePathMapping(targetApi: IRestApi, options: BasePathMappingOptions = { }): BasePathMapping {
if (this.basePaths.has(options.basePath)) {
throw new Error(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`);
}
if (this.isMultiLevel(options.basePath)) {
throw new Error('BasePathMapping does not support multi-level paths. Use "addApiMapping instead.');
}

this.basePaths.add(options.basePath);
const basePath = options.basePath || '/';
const id = `Map:${basePath}=>${Names.nodeUniqueId(targetApi.node)}`;
Expand All @@ -172,6 +225,32 @@ export class DomainName extends Resource implements IDomainName {
});
}

/**
* Maps this domain to an API endpoint.
*
* This uses the ApiMapping from ApiGatewayV2 which supports multi-level paths, but
* also only supports:
* - SecurityPolicy.TLS_1_2
* - EndpointType.REGIONAL
*
* @param targetStage the target API stage.
* @param options Options for mapping to a stage
*/
public addApiMapping(targetStage: IStage, options: ApiMappingOptions = {}): void {
if (this.basePaths.has(options.basePath)) {
throw new Error(`DomainName ${this.node.id} already has a mapping for path ${options.basePath}`);
}
this.validateBasePath(options.basePath);
this.basePaths.add(options.basePath);
const id = `Map:${options.basePath ?? 'none'}=>${Names.nodeUniqueId(targetStage.node)}`;
new apigwv2.CfnApiMapping(this, id, {
apiId: targetStage.restApi.restApiId,
stage: targetStage.stageName,
domainName: this.domainName,
apiMappingKey: options.basePath,
});
}

private configureMTLS(mtlsConfig?: MTLSConfig): CfnDomainName.MutualTlsAuthenticationProperty | undefined {
if (!mtlsConfig) return undefined;
return {
Expand Down
8 changes: 8 additions & 0 deletions packages/@aws-cdk/aws-apigateway/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"@aws-cdk/assertions": "0.0.0",
"@aws-cdk/cdk-build-tools": "0.0.0",
"@aws-cdk/integ-runner": "0.0.0",
"@aws-cdk/aws-route53": "0.0.0",
"@aws-cdk/cfn2ts": "0.0.0",
"@aws-cdk/pkglint": "0.0.0",
"@types/jest": "^27.5.2"
Expand All @@ -100,6 +101,7 @@
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-s3-assets": "0.0.0",
"@aws-cdk/aws-stepfunctions": "0.0.0",
"@aws-cdk/aws-apigatewayv2": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
"constructs": "^10.0.0"
Expand All @@ -117,6 +119,7 @@
"@aws-cdk/aws-s3": "0.0.0",
"@aws-cdk/aws-s3-assets": "0.0.0",
"@aws-cdk/aws-stepfunctions": "0.0.0",
"@aws-cdk/aws-apigatewayv2": "0.0.0",
"@aws-cdk/core": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
"constructs": "^10.0.0"
Expand All @@ -132,6 +135,11 @@
"lib/apigatewayv2.js"
]
},
"pkglint": {
"exclude": [
"no-experimental-dependencies"
]
},
"awslint": {
"exclude": [
"from-method:@aws-cdk/aws-apigateway.Resource",
Expand Down
Loading

0 comments on commit 3b675d7

Please sign in to comment.