Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
5326284
Added BackendDefaults to Virtual Node
sshver Oct 29, 2020
e476ae7
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 3, 2020
dbc5870
Modeled TLSClientValidation to enforce trust in file or acm cetificate
sshver Nov 4, 2020
5b4c97b
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 10, 2020
b4b7f95
Added check to have only one backendDefault per virtual node
sshver Nov 11, 2020
ce35692
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 11, 2020
4aea038
adding backend validation context
sshver Nov 12, 2020
25208a4
created a seperate module validation-context
sshver Nov 12, 2020
5b260be
Created a seperate client-policy file as client policy wont be only s…
sshver Nov 18, 2020
a55a305
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 18, 2020
7ca64da
Updated comments and removed newlines
sshver Nov 18, 2020
01be91b
1. Addressed comments
sshver Nov 24, 2020
7e2ddbc
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 24, 2020
49824b1
Added skeleton L2 for ACMPCA and addressed comments
sshver Nov 30, 2020
0306a36
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Nov 30, 2020
045d2a7
Fixed minor comments
sshver Dec 2, 2020
2cad882
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Dec 2, 2020
20c0e96
Fixed comments
sshver Dec 3, 2020
d36fc42
Added validation check to ensure certificateAuthorityArns is not empty
sshver Dec 4, 2020
4e07587
Minor fix
sshver Dec 4, 2020
da25261
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Dec 4, 2020
41d2c12
Updated README and fixed build errors
sshver Dec 4, 2020
d18fdc4
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Dec 4, 2020
4ec4b21
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Dec 4, 2020
8b0b863
Minor changes
sshver Dec 7, 2020
bd2d85e
Updated README.md
sshver Dec 7, 2020
8b707ce
Merge remote-tracking branch 'upstream/master' into feature/backendDe…
sshver Dec 7, 2020
de939c3
Merge branch 'master' into feature/backendDefaults
mergify[bot] Dec 7, 2020
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
33 changes: 33 additions & 0 deletions packages/@aws-cdk/aws-acmpca/lib/certificate-authority.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';

/**
* Interface which all CertificateAuthority based class must implement
*/
export interface ICertificateAuthority extends cdk.IResource {
/**
* The Amazon Resource Name of the Certificate
*
* @attribute
*/
readonly certificateAuthorityArn: string;
}

/**
* Defines a Certificate for ACMPCA
*
* @resource AWS::ACMPCA::CertificateAuthority
*/
export class CertificateAuthority {
/**
* Import an existing Certificate given an ARN
*/
public static fromCertificateAuthorityArn(scope: Construct, id: string, certificateAuthorityArn: string): ICertificateAuthority {
return new class extends cdk.Resource implements ICertificateAuthority {
readonly certificateAuthorityArn = certificateAuthorityArn;
}(scope, id);
}

private constructor() {
}
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-acmpca/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// AWS::ACMPCA CloudFormation Resources:
export * from './acmpca.generated';
export * from './certificate-authority';
53 changes: 52 additions & 1 deletion packages/@aws-cdk/aws-appmesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ const node = mesh.addVirtualNode('virtual-node', {
});
```

Create a `VirtualNode` with the the constructor and add tags.
Create a `VirtualNode` with the constructor and add tags.

```ts
const node = new VirtualNode(this, 'node', {
Expand All @@ -184,14 +184,57 @@ const node = new VirtualNode(this, 'node', {
idle: cdk.Duration.seconds(5),
},
})],
backendsDefaultClientPolicy: appmesh.ClientPolicy.fileTrust({
certificateChain: '/keys/local_cert_chain.pem',
}),
accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'),
});

cdk.Tag.add(node, 'Environment', 'Dev');
```

Create a `VirtualNode` with the constructor and add backend virtual service.

```ts
const node = new VirtualNode(this, 'node', {
mesh,
cloudMapService: service,
listeners: [appmesh.VirtualNodeListener.httpNodeListener({
port: 8080,
healthCheck: {
healthyThreshold: 3,
interval: Duration.seconds(5), // min
path: '/ping',
port: 8080,
protocol: Protocol.HTTP,
timeout: Duration.seconds(2), // min
unhealthyThreshold: 2,
},
timeout: {
idle: cdk.Duration.seconds(5),
},
})],
accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'),
});

const virtualService = new appmesh.VirtualService(stack, 'service-1', {
virtualServiceName: 'service1.domain.local',
mesh,
clientPolicy: appmesh.ClientPolicy.fileTrust({
certificateChain: '/keys/local_cert_chain.pem',
ports: [8080, 8081],
}),
});

node.addBackend(virtualService);
```

The `listeners` property can be left blank and added later with the `node.addListener()` method. The `healthcheck` and `timeout` properties are optional but if specifying a listener, the `port` must be added.

The `backends` property can be added with `node.addBackend()`. We define a virtual service and add it to the virtual node to allow egress traffic to other node.

The `backendsDefaultClientPolicy` property are added to the node while creating the virtual node. These are virtual node's service backends client policy defaults.

## Adding a Route

A `route` is associated with a virtual router, and it's used to match requests for a virtual router and distribute traffic accordingly to its associated virtual nodes.
Expand Down Expand Up @@ -269,6 +312,8 @@ using rules defined in gateway routes which can be added to your virtual gateway
Create a virtual gateway with the constructor:

```ts
const certificateAuthorityArn = 'arn:aws:acm-pca:us-east-1:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012';

const gateway = new appmesh.VirtualGateway(stack, 'gateway', {
mesh: mesh,
listeners: [appmesh.VirtualGatewayListener.http({
Expand All @@ -277,6 +322,10 @@ const gateway = new appmesh.VirtualGateway(stack, 'gateway', {
interval: cdk.Duration.seconds(10),
},
})],
backendsDefaultClientPolicy: appmesh.ClientPolicy.acmTrust({
certificateAuthorities: [acmpca.CertificateAuthority.fromCertificateAuthorityArn(stack, 'certificate', certificateAuthorityArn)],
ports: [8080, 8081],
}),
accessLog: appmesh.AccessLog.fromFilePath('/dev/stdout'),
virtualGatewayName: 'virtualGateway',
});
Expand All @@ -300,6 +349,8 @@ const gateway = mesh.addVirtualGateway('gateway', {
The listeners field can be omitted which will default to an HTTP Listener on port 8080.
A gateway route can be added using the `gateway.addGatewayRoute()` method.

The `backendsDefaultClientPolicy` property are added to the node while creating the virtual gateway. These are virtual gateway's service backends client policy defaults.

## Adding a Gateway Route

A _gateway route_ is attached to a virtual gateway and routes traffic to an existing virtual service.
Expand Down
110 changes: 110 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/client-policy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import * as acmpca from '@aws-cdk/aws-acmpca';
import * as cdk from '@aws-cdk/core';
import { CfnVirtualNode } from './appmesh.generated';

enum CertificateType {
ACMPCA = 'acm',
FILE = 'file',
}

/**
* Properties of TLS Client Policy
*/
export interface ClientPolicyConfig {
/**
* Represents single Client Policy property
*/
readonly clientPolicy: CfnVirtualNode.ClientPolicyProperty;
}

/**
* Represents the property needed to define a Client Policy
*/
export interface ClientPolicyOptions {
/**
* TLS is enforced on the ports specified here.
* If no ports are specified, TLS will be enforced on all the ports.
*
* @default - none
*/
readonly ports?: number[];
}

/**
* ACM Trust Properties
*/
export interface AcmTrustOptions extends ClientPolicyOptions {
/**
* Contains information for your private certificate authority
*/
readonly certificateAuthorities: acmpca.ICertificateAuthority[];
}

/**
* File Trust Properties
*/
export interface FileTrustOptions extends ClientPolicyOptions {
/**
* Path to the Certificate Chain file on the file system where the Envoy is deployed.
*/
readonly certificateChain: string;
}

/**
* Defines the TLS validation context trust.
*/
export abstract class ClientPolicy {
/**
* Tells envoy where to fetch the validation context from
*/
public static fileTrust(props: FileTrustOptions): ClientPolicy {
return new ClientPolicyImpl(props.ports, CertificateType.FILE, props.certificateChain, undefined);
}

/**
* TLS validation context trust for ACM Private Certificate Authority (CA).
*/
public static acmTrust(props: AcmTrustOptions): ClientPolicy {
return new ClientPolicyImpl(props.ports, CertificateType.ACMPCA, undefined, props.certificateAuthorities);
}

/**
* Returns Trust context based on trust type.
*/
public abstract bind(scope: cdk.Construct): ClientPolicyConfig;

}

class ClientPolicyImpl extends ClientPolicy {
constructor (private readonly ports: number[] | undefined,
private readonly certificateType: CertificateType,
private readonly certificateChain: string | undefined,
private readonly certificateAuthorityArns: acmpca.ICertificateAuthority[] | undefined) { super(); }

public bind(_scope: cdk.Construct): ClientPolicyConfig {
if (this.certificateType === CertificateType.ACMPCA && this.certificateAuthorityArns?.map(certificateArn =>
certificateArn.certificateAuthorityArn).length === 0) {
throw new Error('You must provide at least one Certificate Authority when creating an ACM Trust ClientPolicy');
} else {
return {
clientPolicy: {
tls: {
ports: this.ports,
validation: {
trust: {
[this.certificateType]: this.certificateType === CertificateType.FILE
? {
certificateChain: this.certificateChain,
}
: {
certificateAuthorityArns: this.certificateAuthorityArns?.map(certificateArn =>
certificateArn.certificateAuthorityArn),
},
},
},
},
},
};
}
}
}
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-appmesh/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export * from './virtual-gateway';
export * from './virtual-gateway-listener';
export * from './gateway-route';
export * from './gateway-route-spec';
export * from './client-policy';
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,5 @@ class FileAccessLog extends AccessLog {
},
};
}
}
}

10 changes: 9 additions & 1 deletion packages/@aws-cdk/aws-appmesh/lib/virtual-gateway.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnVirtualGateway } from './appmesh.generated';
import { ClientPolicy } from './client-policy';
import { GatewayRoute, GatewayRouteBaseProps } from './gateway-route';

import { IMesh, Mesh } from './mesh';
import { AccessLog } from './shared-interfaces';
import { VirtualGatewayListener, VirtualGatewayListenerConfig } from './virtual-gateway-listener';
Expand Down Expand Up @@ -60,6 +60,13 @@ export interface VirtualGatewayBaseProps {
* @default - no access logging
*/
readonly accessLog?: AccessLog;

/**
* Default Configuration Virtual Node uses to communicate with Virtual Service
*
* @default - No Config
*/
readonly backendsDefaultClientPolicy?: ClientPolicy;
}

/**
Expand Down Expand Up @@ -173,6 +180,7 @@ export class VirtualGateway extends VirtualGatewayBase {
meshName: this.mesh.meshName,
spec: {
listeners: this.listeners.map(listener => listener.listener),
backendDefaults: props.backendsDefaultClientPolicy?.bind(this),
logging: accessLogging !== undefined ? {
accessLog: accessLogging.virtualGatewayAccessLog,
} : undefined,
Expand Down
14 changes: 12 additions & 2 deletions packages/@aws-cdk/aws-appmesh/lib/virtual-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as cloudmap from '@aws-cdk/aws-servicediscovery';
import * as cdk from '@aws-cdk/core';
import { Construct } from 'constructs';
import { CfnVirtualNode } from './appmesh.generated';
import { ClientPolicy } from './client-policy';
import { IMesh, Mesh } from './mesh';
import { AccessLog } from './shared-interfaces';
import { VirtualNodeListener, VirtualNodeListenerConfig } from './virtual-node-listener';
Expand Down Expand Up @@ -94,6 +95,13 @@ export interface VirtualNodeBaseProps {
* @default - No access logging
*/
readonly accessLog?: AccessLog;

/**
* Default Configuration Virtual Node uses to communicate with Virtual Service
*
* @default - No Config
*/
readonly backendsDefaultClientPolicy?: ClientPolicy;
}

/**
Expand Down Expand Up @@ -193,8 +201,9 @@ export class VirtualNode extends VirtualNodeBase {
virtualNodeName: this.physicalName,
meshName: this.mesh.meshName,
spec: {
backends: cdk.Lazy.any({ produce: () => this.backends }, { omitEmptyArray: true }),
listeners: cdk.Lazy.any({ produce: () => this.listeners.map(listener => listener.listener) }, { omitEmptyArray: true }),
backends: cdk.Lazy.anyValue({ produce: () => this.backends }, { omitEmptyArray: true }),
listeners: cdk.Lazy.anyValue({ produce: () => this.listeners.map(listener => listener.listener) }, { omitEmptyArray: true }),
backendDefaults: props.backendsDefaultClientPolicy?.bind(this),
serviceDiscovery: {
dns: props.dnsHostName !== undefined ? { hostname: props.dnsHostName } : undefined,
awsCloudMap: props.cloudMapService !== undefined ? {
Expand Down Expand Up @@ -231,6 +240,7 @@ export class VirtualNode extends VirtualNodeBase {
this.backends.push({
virtualService: {
virtualServiceName: virtualService.virtualServiceName,
clientPolicy: virtualService.clientPolicy?.bind(this).clientPolicy,
},
});
}
Expand Down
Loading