Skip to content

Commit

Permalink
feat(apprunner): VpcConnector construct (#20471)
Browse files Browse the repository at this point in the history
closes #18887

- Creates a new VpcConnector construct.
- Make the app runner service construct accept a `vpcConnector` property. When present, associate the service with the connector.

----

### All Submissions:

* [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md)

### Adding new Unconventional Dependencies:

* [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/master/CONTRIBUTING.md/#adding-new-unconventional-dependencies)

### New Features

* [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/master/INTEGRATION_TESTS.md)?
	* [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
DDynamic authored May 25, 2022
1 parent 3e6ec5c commit 5052191
Show file tree
Hide file tree
Showing 28 changed files with 2,180 additions and 23 deletions.
26 changes: 26 additions & 0 deletions packages/@aws-cdk/aws-apprunner/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,29 @@ ECR image repositories (but not for ECR Public repositories). If not defined, a
when required.

See [App Runner IAM Roles](https://docs.aws.amazon.com/apprunner/latest/dg/security_iam_service-with-iam.html#security_iam_service-with-iam-roles) for more details.

## VPC Connector

To associate an App Runner service with a custom VPC, define `vpcConnector` for the service.

```ts
import * as ec2 from '@aws-cdk/aws-ec2';

const vpc = new ec2.Vpc(this, 'Vpc', {
cidr: '10.0.0.0/16',
});

const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', {
vpc,
vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PUBLIC }),
vpcConnectorName: 'MyVpcConnector',
});

new apprunner.Service(this, 'Service', {
source: apprunner.Source.fromEcrPublic({
imageConfiguration: { port: 8000 },
imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest',
}),
vpcConnector,
});
```
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-apprunner/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// AWS::AppRunner CloudFormation Resources:
export * from './apprunner.generated';
export * from './service';
export * from './vpc-connector';
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-apprunner/lib/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as iam from '@aws-cdk/aws-iam';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnService } from './apprunner.generated';
import { IVpcConnector } from './vpc-connector';

/**
* The image repository types
Expand Down Expand Up @@ -524,6 +525,13 @@ export interface ServiceProps {
* @default - auto-generated if undefined.
*/
readonly serviceName?: string;

/**
* Settings for an App Runner VPC connector to associate with the service.
*
* @default - no VPC connector, uses the DEFAULT egress type instead
*/
readonly vpcConnector?: IVpcConnector;
}

/**
Expand Down Expand Up @@ -792,6 +800,12 @@ export class Service extends cdk.Resource {
imageRepository: source.imageRepository ? this.renderImageRepository() : undefined,
codeRepository: source.codeRepository ? this.renderCodeConfiguration() : undefined,
},
networkConfiguration: {
egressConfiguration: {
egressType: this.props.vpcConnector ? 'VPC' : 'DEFAULT',
vpcConnectorArn: this.props.vpcConnector?.vpcConnectorArn,
},
},
});

// grant required privileges for the role
Expand Down
154 changes: 154 additions & 0 deletions packages/@aws-cdk/aws-apprunner/lib/vpc-connector.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import * as ec2 from '@aws-cdk/aws-ec2';
import { Connections } from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnVpcConnector } from './apprunner.generated';

/**
* Properties of the AppRunner VPC Connector
*/
export interface VpcConnectorProps {
/**
* The VPC for the VPC Connector.
*/
readonly vpc: ec2.IVpc;

/**
* Where to place the VPC Connector within the VPC.
*
* @default - Private subnets.
*/
readonly vpcSubnets?: ec2.SubnetSelection;

/**
* A list of IDs of security groups that App Runner should use for access to AWS resources under the specified subnets.
*
* @default - a new security group will be created in the specified VPC
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* The name for the VpcConnector.
*
* @default - a name generated by CloudFormation
*/
readonly vpcConnectorName?: string;
}

/**
* Attributes for the App Runner VPC Connector
*/
export interface VpcConnectorAttributes {
/**
* The name of the VPC connector.
*/
readonly vpcConnectorName: string;

/**
* The ARN of the VPC connector.
*/
readonly vpcConnectorArn: string;

/**
* The revision of the VPC connector.
*/
readonly vpcConnectorRevision: number;

/**
* The security groups associated with the VPC connector.
*/
readonly securityGroups: ec2.ISecurityGroup[];
}

/**
* Represents the App Runner VPC Connector.
*/
export interface IVpcConnector extends cdk.IResource, ec2.IConnectable {
/**
* The Name of the VPC connector.
* @attribute
*/
readonly vpcConnectorName: string;

/**
* The ARN of the VPC connector.
* @attribute
*/
readonly vpcConnectorArn: string;

/**
* The revision of the VPC connector.
* @attribute
*/
readonly vpcConnectorRevision: number;
}

/**
* The App Runner VPC Connector
*
* @resource AWS::AppRunner::VpcConnector
*/
export class VpcConnector extends cdk.Resource implements IVpcConnector {
/**
* Import from VPC connector attributes.
*/
public static fromVpcConnectorAttributes(scope: Construct, id: string, attrs: VpcConnectorAttributes): IVpcConnector {
const vpcConnectorArn = attrs.vpcConnectorArn;
const vpcConnectorName = attrs.vpcConnectorName;
const vpcConnectorRevision = attrs.vpcConnectorRevision;
const securityGroups = attrs.securityGroups;

class Import extends cdk.Resource {
public readonly vpcConnectorArn = vpcConnectorArn
public readonly vpcConnectorName = vpcConnectorName
public readonly vpcConnectorRevision = vpcConnectorRevision
public readonly connections = new Connections({ securityGroups });
}

return new Import(scope, id);
}

/**
* The ARN of the VPC connector.
* @attribute
*/
readonly vpcConnectorArn: string;

/**
* The revision of the VPC connector.
* @attribute
*/
readonly vpcConnectorRevision: number;

/**
* The name of the VPC connector.
* @attribute
*/
readonly vpcConnectorName: string;

/**
* Allows specifying security group connections for the VPC connector.
*/
public readonly connections: Connections

public constructor(scope: Construct, id: string, props: VpcConnectorProps) {
super(scope, id, {
physicalName: props.vpcConnectorName,
});

const securityGroups = props.securityGroups?.length ?
props.securityGroups
: [new ec2.SecurityGroup(this, 'SecurityGroup', { vpc: props.vpc })];

const resource = new CfnVpcConnector(this, 'Resource', {
subnets: props.vpc.selectSubnets(props.vpcSubnets).subnetIds,
securityGroups: cdk.Lazy.list({ produce: () => this.connections.securityGroups.map(sg => sg.securityGroupId) }),
vpcConnectorName: this.physicalName,
});

this.vpcConnectorArn = resource.attrVpcConnectorArn;
this.vpcConnectorRevision = resource.attrVpcConnectorRevision;
this.vpcConnectorName = resource.ref;
this.connections = new Connections({ securityGroups });
}
}
3 changes: 3 additions & 0 deletions packages/@aws-cdk/aws-apprunner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
},
"license": "Apache-2.0",
"devDependencies": {
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/assertions": "0.0.0",
"@aws-cdk/cdk-build-tools": "0.0.0",
"@aws-cdk/integ-runner": "0.0.0",
Expand All @@ -91,13 +92,15 @@
"@types/jest": "^27.5.0"
},
"dependencies": {
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/aws-ecr": "0.0.0",
"@aws-cdk/aws-ecr-assets": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/core": "0.0.0",
"constructs": "^3.3.69"
},
"peerDependencies": {
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/aws-ecr": "0.0.0",
"@aws-cdk/aws-ecr-assets": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as ec2 from '@aws-cdk/aws-ec2';
import * as cdk from '@aws-cdk/core';
import { Service, Source, VpcConnector } from '../lib';


const app = new cdk.App();

const stack = new cdk.Stack(app, 'integ-apprunner');

// Scenario 6: Create the service from ECR public with a VPC Connector
const vpc = new ec2.Vpc(stack, 'Vpc', {
cidr: '10.0.0.0/16',
});

const securityGroup = new ec2.SecurityGroup(stack, 'SecurityGroup', { vpc });

const vpcConnector = new VpcConnector(stack, 'VpcConnector', {
vpc,
vpcSubnets: vpc.selectSubnets({ subnetType: ec2.SubnetType.PUBLIC }),
securityGroups: [securityGroup],
vpcConnectorName: 'MyVpcConnector',
});

const service6 = new Service(stack, 'Service6', {
source: Source.fromEcrPublic({
imageConfiguration: {
port: 8000,
},
imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest',
}),
vpcConnector,
});
new cdk.CfnOutput(stack, 'URL6', { value: `https://${service6.serviceUrl}` });

// Scenario 7: Create the service from ECR public and associate it with an existing VPC Connector

const service7 = new Service(stack, 'Service7', {
source: Source.fromEcrPublic({
imageConfiguration: {
port: 8000,
},
imageIdentifier: 'public.ecr.aws/aws-containers/hello-app-runner:latest',
}),
vpcConnector: VpcConnector.fromVpcConnectorAttributes(stack, 'ImportedVpcConnector', {
vpcConnectorArn: vpcConnector.vpcConnectorArn,
vpcConnectorName: vpcConnector.vpcConnectorName,
vpcConnectorRevision: vpcConnector.vpcConnectorRevision,
securityGroups: [securityGroup],
}),
});
new cdk.CfnOutput(stack, 'URL7', { value: `https://${service7.serviceUrl}` });
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"17.0.0"}
{"version":"19.0.0"}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
"ImageRepositoryType": "ECR_PUBLIC"
}
},
"InstanceConfiguration": {}
"InstanceConfiguration": {},
"NetworkConfiguration": {
"EgressConfiguration": {
"EgressType": "DEFAULT"
}
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "18.0.0",
"version": "19.0.0",
"testCases": {
"aws-apprunner/test/integ.service-ecr-public": {
"integ.service-ecr-public": {
"stacks": [
"integ-apprunner-ecr-public"
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "17.0.0",
"version": "19.0.0",
"artifacts": {
"Tree": {
"type": "cdk:tree",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@
"imageRepositoryType": "ECR_PUBLIC"
}
},
"instanceConfiguration": {}
"instanceConfiguration": {},
"networkConfiguration": {
"egressConfiguration": {
"egressType": "DEFAULT"
}
}
}
},
"constructInfo": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"17.0.0"}
{"version":"19.0.0"}
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,12 @@
"ImageRepositoryType": "ECR"
}
},
"InstanceConfiguration": {}
"InstanceConfiguration": {},
"NetworkConfiguration": {
"EgressConfiguration": {
"EgressType": "DEFAULT"
}
}
}
},
"Service2AccessRole759CA73D": {
Expand Down Expand Up @@ -211,7 +216,12 @@
"ImageRepositoryType": "ECR"
}
},
"InstanceConfiguration": {}
"InstanceConfiguration": {},
"NetworkConfiguration": {
"EgressConfiguration": {
"EgressType": "DEFAULT"
}
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "18.0.0",
"version": "19.0.0",
"testCases": {
"aws-apprunner/test/integ.service-ecr": {
"integ.service-ecr": {
"stacks": [
"integ-apprunner"
],
Expand Down
Loading

0 comments on commit 5052191

Please sign in to comment.