Skip to content

Commit 767cd31

Browse files
authored
feat(elasticsearch): graduate to stable 🚀 (#13900)
This PR includes a last minute API change that standardizes the way VPC configuration is passed to the domain. It also provides sane defaults, enabling users to simply pass `vpc` in order to connect a domain to a VPC. In addition, I added a missing integration test for VPC enabled domains. Resolves #10965 BREAKING CHANGE: `vpcOptions` was removed. Use `vpc`, `vpcSubnets` and `securityGroups` instead. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 56c6f98 commit 767cd31

File tree

6 files changed

+809
-90
lines changed

6 files changed

+809
-90
lines changed

packages/@aws-cdk/aws-elasticsearch/README.md

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
Features | Stability
77
-----------------------------------|----------------------------------------------------------------
88
CFN Resources | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge)
9-
Higher level constructs for Domain | ![Experimental](https://img.shields.io/badge/experimental-important.svg?style=for-the-badge)
9+
Higher level constructs for Domain | ![Stable](https://img.shields.io/badge/stable-success.svg?style=for-the-badge)
1010

1111
> **CFN Resources:** All classes with the `Cfn` prefix in this module ([CFN Resources]) are always
1212
> stable and safe to use.
@@ -15,11 +15,8 @@ Higher level constructs for Domain | ![Experimental](https://img.shields.io/badg
1515
1616
<!-- -->
1717

18-
> **Experimental:** Higher level constructs in this module that are marked as experimental are
19-
> under active development. They are subject to non-backward compatible changes or removal in any
20-
> future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and
21-
> breaking changes will be announced in the release notes. This means that while you may use them,
22-
> you may need to update your source code when upgrading to a newer version of this package.
18+
> **Stable:** Higher level constructs in this module that are marked stable will not undergo any
19+
> breaking changes. They will strictly follow the [Semantic Versioning](https://semver.org/) model.
2320
2421
---
2522

@@ -146,6 +143,33 @@ This sets up the domain with node to node encryption and encryption at
146143
rest. You can also choose to supply your own KMS key to use for encryption at
147144
rest.
148145

146+
## VPC Support
147+
148+
Elasticsearch domains can be placed inside a VPC, providing a secure communication between Amazon ES and other services within the VPC without the need for an internet gateway, NAT device, or VPN connection.
149+
150+
> Visit [VPC Support for Amazon Elasticsearch Service Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html) for more details.
151+
152+
```ts
153+
const vpc = new ec2.Vpc(this, 'Vpc');
154+
const domainProps: es.DomainProps = {
155+
version: es.ElasticsearchVersion.V7_1,
156+
removalPolicy: RemovalPolicy.DESTROY,
157+
vpc,
158+
// must be enabled since our VPC contains multiple private subnets.
159+
zoneAwareness: {
160+
enabled: true,
161+
},
162+
capacity: {
163+
// must be an even number since the default az count is 2.
164+
dataNodes: 2,
165+
},
166+
};
167+
new es.Domain(this, 'Domain', domainProps);
168+
```
169+
170+
In addition, you can use the `vpcSubnets` property to control which specific subnets will be used, and the `securityGroups` property to control
171+
which security groups will be attached to the domain. By default, CDK will select all *private* subnets in the VPC, and create one dedicated security group.
172+
149173
## Metrics
150174

151175
Helper methods exist to access common domain metrics for example:

packages/@aws-cdk/aws-elasticsearch/lib/domain.ts

Lines changed: 71 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -331,32 +331,6 @@ export interface CognitoOptions {
331331
readonly userPoolId: string;
332332
}
333333

334-
/**
335-
* The virtual private cloud (VPC) configuration for the Amazon ES domain. For
336-
* more information, see [VPC Support for Amazon Elasticsearch Service
337-
* Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html)
338-
* in the Amazon Elasticsearch Service Developer Guide.
339-
*/
340-
export interface VpcOptions {
341-
/**
342-
* The list of security groups that are associated with the VPC endpoints
343-
* for the domain. If you don't provide a security group ID, Amazon ES uses
344-
* the default security group for the VPC. To learn more, see [Security Groups for your VPC]
345-
* (https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html) in the Amazon VPC
346-
* User Guide.
347-
*/
348-
readonly securityGroups: ec2.ISecurityGroup[];
349-
350-
/**
351-
* Provide one subnet for each Availability Zone that your domain uses. For
352-
* example, you must specify three subnet IDs for a three Availability Zone
353-
* domain. To learn more, see [VPCs and Subnets]
354-
* (https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) in the
355-
* Amazon VPC User Guide.
356-
*/
357-
readonly subnets: ec2.ISubnet[];
358-
}
359-
360334
/**
361335
* The minimum TLS version required for traffic to the domain.
362336
*/
@@ -513,14 +487,35 @@ export interface DomainProps {
513487
readonly automatedSnapshotStartHour?: number;
514488

515489
/**
516-
* The virtual private cloud (VPC) configuration for the Amazon ES domain. For
517-
* more information, see [VPC Support for Amazon Elasticsearch Service
518-
* Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html)
519-
* in the Amazon Elasticsearch Service Developer Guide.
490+
* Place the domain inside this VPC.
491+
*
492+
* @see https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html
493+
* @default - Domain is not placed in a VPC.
494+
*/
495+
readonly vpc?: ec2.IVpc;
496+
497+
/**
498+
* The list of security groups that are associated with the VPC endpoints
499+
* for the domain.
500+
*
501+
* Only used if `vpc` is specified.
520502
*
521-
* @default - VPC not used
503+
* @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html
504+
* @default - One new security group is created.
522505
*/
523-
readonly vpcOptions?: VpcOptions;
506+
readonly securityGroups?: ec2.ISecurityGroup[];
507+
508+
/**
509+
* The specific vpc subnets the domain will be placed in. You must provide one subnet for each Availability Zone
510+
* that your domain uses. For example, you must specify three subnet IDs for a three Availability Zone
511+
* domain.
512+
*
513+
* Only used if `vpc` is specified.
514+
*
515+
* @see https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html
516+
* @default - All private subnets.
517+
*/
518+
readonly vpcSubnets?: ec2.SubnetSelection[];
524519

525520
/**
526521
* True to require that all traffic to the domain arrive over HTTPS.
@@ -719,7 +714,7 @@ export interface IDomain extends cdk.IResource {
719714
*
720715
* @default maximum over 1 minute
721716
*/
722-
metricClusterIndexWriteBlocked(props?: MetricOptions): Metric;
717+
metricClusterIndexWritesBlocked(props?: MetricOptions): Metric;
723718

724719
/**
725720
* Metric for the number of nodes.
@@ -1002,8 +997,8 @@ abstract class DomainBase extends cdk.Resource implements IDomain {
1002997
*
1003998
* @default maximum over 1 minute
1004999
*/
1005-
public metricClusterIndexWriteBlocked(props?: MetricOptions): Metric {
1006-
return this.metric('ClusterIndexWriteBlocked', {
1000+
public metricClusterIndexWritesBlocked(props?: MetricOptions): Metric {
1001+
return this.metric('ClusterIndexWritesBlocked', {
10071002
statistic: Statistic.MAXIMUM,
10081003
period: cdk.Duration.minutes(1),
10091004
...props,
@@ -1177,7 +1172,7 @@ export interface DomainAttributes {
11771172
/**
11781173
* Provides an Elasticsearch domain.
11791174
*/
1180-
export class Domain extends DomainBase implements IDomain {
1175+
export class Domain extends DomainBase implements IDomain, ec2.IConnectable {
11811176
/**
11821177
* Creates a Domain construct that represents an external domain via domain endpoint.
11831178
*
@@ -1264,6 +1259,8 @@ export class Domain extends DomainBase implements IDomain {
12641259

12651260
private readonly domain: CfnDomain;
12661261

1262+
private readonly _connections: ec2.Connections | undefined;
1263+
12671264
constructor(scope: Construct, id: string, props: DomainProps) {
12681265
super(scope, id, {
12691266
physicalName: props.domainName,
@@ -1300,11 +1297,23 @@ export class Domain extends DomainBase implements IDomain {
13001297
props.zoneAwareness?.enabled ??
13011298
props.zoneAwareness?.availabilityZoneCount != null;
13021299

1300+
1301+
let securityGroups: ec2.ISecurityGroup[] | undefined;
1302+
let subnets: ec2.ISubnet[] | undefined;
1303+
1304+
if (props.vpc) {
1305+
subnets = selectSubnets(props.vpc, props.vpcSubnets ?? [{ subnetType: ec2.SubnetType.PRIVATE }]);
1306+
securityGroups = props.securityGroups ?? [new ec2.SecurityGroup(this, 'SecurityGroup', {
1307+
vpc: props.vpc,
1308+
description: `Security group for domain ${this.node.id}`,
1309+
})];
1310+
this._connections = new ec2.Connections({ securityGroups });
1311+
}
1312+
13031313
// If VPC options are supplied ensure that the number of subnets matches the number AZ
1304-
if (props.vpcOptions != null && zoneAwarenessEnabled &&
1305-
new Set(props.vpcOptions?.subnets.map((subnet) => subnet.availabilityZone)).size < availabilityZoneCount) {
1314+
if (subnets && zoneAwarenessEnabled && new Set(subnets.map((subnet) => subnet.availabilityZone)).size < availabilityZoneCount) {
13061315
throw new Error('When providing vpc options you need to provide a subnet for each AZ you are using');
1307-
};
1316+
}
13081317

13091318
if ([dedicatedMasterType, instanceType, warmType].some(t => !t.endsWith('.elasticsearch'))) {
13101319
throw new Error('Master, data and UltraWarm node instance types must end with ".elasticsearch".');
@@ -1491,10 +1500,11 @@ export class Domain extends DomainBase implements IDomain {
14911500
}
14921501

14931502
let cfnVpcOptions: CfnDomain.VPCOptionsProperty | undefined;
1494-
if (props.vpcOptions) {
1503+
1504+
if (securityGroups && subnets) {
14951505
cfnVpcOptions = {
1496-
securityGroupIds: props.vpcOptions.securityGroups.map((sg) => sg.securityGroupId),
1497-
subnetIds: props.vpcOptions.subnets.map((subnet) => subnet.subnetId),
1506+
securityGroupIds: securityGroups.map((sg) => sg.securityGroupId),
1507+
subnetIds: subnets.map((subnet) => subnet.subnetId),
14981508
};
14991509
}
15001510

@@ -1730,6 +1740,17 @@ export class Domain extends DomainBase implements IDomain {
17301740
accessPolicy.node.addDependency(this.domain);
17311741
}
17321742
}
1743+
1744+
/**
1745+
* Manages network connections to the domain. This will throw an error in case the domain
1746+
* is not placed inside a VPC.
1747+
*/
1748+
public get connections(): ec2.Connections {
1749+
if (!this._connections) {
1750+
throw new Error("Connections are only available on VPC enabled domains. Use the 'vpc' property to place a domain inside a VPC");
1751+
}
1752+
return this._connections;
1753+
}
17331754
}
17341755

17351756
/**
@@ -1778,3 +1799,11 @@ function parseVersion(version: ElasticsearchVersion): number {
17781799
throw new Error(`Invalid Elasticsearch version: ${versionStr}. Version string needs to start with major and minor version (x.y).`);
17791800
}
17801801
}
1802+
1803+
function selectSubnets(vpc: ec2.IVpc, vpcSubnets: ec2.SubnetSelection[]): ec2.ISubnet[] {
1804+
const selected = [];
1805+
for (const selection of vpcSubnets) {
1806+
selected.push(...vpc.selectSubnets(selection).subnets);
1807+
}
1808+
return selected;
1809+
}

packages/@aws-cdk/aws-elasticsearch/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,12 @@
107107
"engines": {
108108
"node": ">= 10.13.0 <13 || >=13.7.0"
109109
},
110-
"stability": "experimental",
111-
"maturity": "experimental",
110+
"stability": "stable",
111+
"maturity": "stable",
112112
"features": [
113113
{
114114
"name": "Higher level constructs for Domain",
115-
"stability": "Experimental"
115+
"stability": "Stable"
116116
}
117117
],
118118
"awscdkio": {

0 commit comments

Comments
 (0)