Skip to content

Commit

Permalink
feat(apprunner): VpcConnector construct
Browse files Browse the repository at this point in the history
  • Loading branch information
DDynamic committed May 24, 2022
1 parent dd4c2b5 commit 16bc397
Show file tree
Hide file tree
Showing 28 changed files with 2,091 additions and 27 deletions.
28 changes: 28 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,31 @@ 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 securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc });

const vpcConnector = new apprunner.VpcConnector(this, 'VpcConnector', {
subnets: vpc.publicSubnets,
securityGroups: [securityGroup],
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
135 changes: 135 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,135 @@
import * as ec2 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 {
/**
* A list of IDs of security groups that App Runner should use for access to AWS resources under the specified subnets.
*
* @default - the default security group of the VPC which allows all outbound traffic.
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* A list of subnets that App Runner should use when it associates the service with a custom Amazon VPC.
*/
readonly subnets: ec2.ISubnet[];

/**
* 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;
}

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

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

/**
* The App Runner VPC Connector
*/
export class VpcConnector extends cdk.Resource {
/**
* Import from VPC connector name.
*/
public static fromVpcConnectorName(scope: Construct, id: string, vpcConnectorName: string): IVpcConnector {
class Import extends cdk.Resource {
public vpcConnectorName = vpcConnectorName;
public vpcConnectorArn = cdk.Stack.of(this).formatArn({
resource: 'vpcconnector',
service: 'apprunner',
resourceName: vpcConnectorName,
})
}
return new Import(scope, id);
}

/**
* Import from VPC connector attributes.
*/
public static fromServiceAttributes(scope: Construct, id: string, attrs: VpcConnectorAttributes): IVpcConnector {
const vpcConnectorArn = attrs.vpcConnectorArn;
const vpcConnectorName = attrs.vpcConnectorName;
const vpcConnectorRevision = attrs.vpcConnectorRevision;

class Import extends cdk.Resource {
public readonly vpcConnectorArn = vpcConnectorArn
public readonly vpcConnectorName = vpcConnectorName
public readonly vpcConnectorRevision = vpcConnectorRevision
}

return new Import(scope, id);
}
private readonly props: VpcConnectorProps;

/**
* 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;

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

this.props = props;

const resource = new CfnVpcConnector(this, 'VpcConnector', {
subnets: this.props.subnets.map(subnet => subnet.subnetId),
securityGroups: this.props.securityGroups?.map(securityGroup => securityGroup.securityGroupId),
vpcConnectorName: this.props.vpcConnectorName,
});

this.vpcConnectorArn = resource.attrVpcConnectorArn;
this.vpcConnectorRevision = resource.attrVpcConnectorRevision;
this.vpcConnectorName = resource.ref;
}
}
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,49 @@
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', {
subnets: vpc.publicSubnets,
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.fromServiceAttributes(stack, 'ImportedVpcConnector', {
vpcConnectorArn: vpcConnector.vpcConnectorArn,
vpcConnectorName: vpcConnector.vpcConnectorName,
vpcConnectorRevision: vpcConnector.vpcConnectorRevision,
}),
});
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
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
Loading

0 comments on commit 16bc397

Please sign in to comment.