Skip to content

Commit

Permalink
feat(appmesh): add listener TLS certificates for VirtualNodes and Vir…
Browse files Browse the repository at this point in the history
…tualGateways (#11863)

This change allows customers to include an ACM certificiate or specify a file certificate for their listeners to use to terminate TLS. #10051 

```typescript
const cert = new Certificate(stack, 'cert', {
  domainName: '',
});

new appmesh.VirtualNode(stack, 'test-node', {
  mesh,
  dnsHostName: 'test',
  listeners: [appmesh.VirtualNodeListener.grpc({
    port: 80,
    tlsCertificate: appmesh.TlsCertificate.acm({
      acmCertificate: cert,
      tlsMode: TlsMode.STRICT,
    }),
  },
  )],
});
```
----
*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
alexbrjo authored Jan 12, 2021
1 parent a0aad85 commit 175a257
Show file tree
Hide file tree
Showing 10 changed files with 601 additions and 87 deletions.
38 changes: 38 additions & 0 deletions packages/@aws-cdk/aws-appmesh/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,44 @@ The `backends` property can be added with `node.addBackend()`. We define a virtu

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

## Adding TLS to a listener

The `tlsCertificate` property can be added to a Virtual Node listener or Virtual Gateway listener to add TLS configuration.
A certificate from AWS Certificate Manager can be incorporated or a customer provided certificate can be specified with a `certificateChain` path file and a `privateKey` file path.

```typescript
import * as certificatemanager from '@aws-cdk/aws-certificatemanager';

// A Virtual Node with listener TLS from an ACM provided certificate
const cert = new certificatemanager.Certificate(this, 'cert', {...});

const node = new appmesh.VirtualNode(stack, 'node', {
mesh,
dnsHostName: 'node',
listeners: [appmesh.VirtualNodeListener.grpc({
port: 80,
tlsCertificate: appmesh.TlsCertificate.acm({
certificate: cert,
tlsMode: TlsMode.STRICT,
}),
})],
});

// A Virtual Gateway with listener TLS from a customer provided file certificate
const gateway = new appmesh.VirtualGateway(this, 'gateway', {
mesh: mesh,
listeners: [appmesh.VirtualGatewayListener.grpc({
port: 8080,
tlsCertificate: appmesh.TlsCertificate.file({
certificateChain: 'path/to/certChain',
privateKey: 'path/to/privateKey',
tlsMode: TlsMode.STRICT,
}),
})],
virtualGatewayName: 'gateway',
});
```

## 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
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 @@ -5,6 +5,7 @@ export * from './route';
export * from './service-discovery';
export * from './route-spec';
export * from './shared-interfaces';
export * from './tls-certificate';
export * from './virtual-node';
export * from './virtual-router';
export * from './virtual-router-listener';
Expand Down
173 changes: 173 additions & 0 deletions packages/@aws-cdk/aws-appmesh/lib/tls-certificate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
import * as acm from '@aws-cdk/aws-certificatemanager';
import * as cdk from '@aws-cdk/core';
import { CfnVirtualNode } from './appmesh.generated';

/**
* Enum of supported TLS modes
*/
export enum TlsMode {
/**
* Only accept encrypted traffic
*/
STRICT = 'STRICT',

/**
* Accept encrypted and plaintext traffic.
*/
PERMISSIVE = 'PERMISSIVE',

/**
* TLS is disabled, only accept plaintext traffic.
*/
DISABLED = 'DISABLED',
}

/**
* A wrapper for the tls config returned by {@link TlsCertificate.bind}
*/
export interface TlsCertificateConfig {
/**
* The CFN shape for a listener TLS certificate
*/
readonly tlsCertificate: CfnVirtualNode.ListenerTlsCertificateProperty,

/**
* The TLS mode.
*/
readonly tlsMode: TlsMode;
}

/**
* ACM Certificate Properties
*/
export interface AcmCertificateOptions {
/**
* The TLS mode.
*/
readonly tlsMode: TlsMode;

/**
* The ACM certificate
*/
readonly certificate: acm.ICertificate;
}

/**
* File Certificate Properties
*/
export interface FileCertificateOptions {
/**
* The TLS mode.
*/
readonly tlsMode: TlsMode;

/**
* The file path of the certificate chain file.
*/
readonly certificateChainPath: string;

/**
* The file path of the private key file.
*/
readonly privateKeyPath: string;
}

/**
* Represents a TLS certificate
*/
export abstract class TlsCertificate {
/**
* Returns an File TLS Certificate
*/
public static file(props: FileCertificateOptions): TlsCertificate {
return new FileTlsCertificate(props);
}

/**
* Returns an ACM TLS Certificate
*/
public static acm(props: AcmCertificateOptions): TlsCertificate {
return new AcmTlsCertificate(props);
}

/**
* Returns TLS certificate based provider.
*/
public abstract bind(_scope: cdk.Construct): TlsCertificateConfig;

}

/**
* Represents a ACM provided TLS certificate
*/
class AcmTlsCertificate extends TlsCertificate {
/**
* The TLS mode.
*
* @default - TlsMode.DISABLED
*/
readonly tlsMode: TlsMode;

/**
* The ARN of the ACM certificate
*/
readonly acmCertificate: acm.ICertificate;

constructor(props: AcmCertificateOptions) {
super();
this.tlsMode = props.tlsMode;
this.acmCertificate = props.certificate;
}

bind(_scope: cdk.Construct): TlsCertificateConfig {
return {
tlsCertificate: {
acm: {
certificateArn: this.acmCertificate.certificateArn,
},
},
tlsMode: this.tlsMode,
};
}
}

/**
* Represents a file provided TLS certificate
*/
class FileTlsCertificate extends TlsCertificate {
/**
* The TLS mode.
*
* @default - TlsMode.DISABLED
*/
readonly tlsMode: TlsMode;

/**
* The file path of the certificate chain file.
*/
readonly certificateChain: string;

/**
* The file path of the private key file.
*/
readonly privateKey: string;

constructor(props: FileCertificateOptions) {
super();
this.tlsMode = props.tlsMode;
this.certificateChain = props.certificateChainPath;
this.privateKey = props.privateKeyPath;
}

bind(_scope: cdk.Construct): TlsCertificateConfig {
return {
tlsCertificate: {
file: {
certificateChain: this.certificateChain,
privateKey: this.privateKey,
},
},
tlsMode: this.tlsMode,
};
}
}
Loading

0 comments on commit 175a257

Please sign in to comment.