diff --git a/packages/@aws-cdk/aws-eks/README.md b/packages/@aws-cdk/aws-eks/README.md index 903636c5d4e89..6a8d633e907a9 100644 --- a/packages/@aws-cdk/aws-eks/README.md +++ b/packages/@aws-cdk/aws-eks/README.md @@ -431,8 +431,7 @@ cluster.addAutoScalingGroupCapacity('nodes', { }); ``` -In addition to the cluster and the capacity, there are two additional components you might want to -provision within a VPC. +There are two additional components you might want to provision within a VPC. #### Kubectl Handler @@ -446,7 +445,8 @@ If the endpoint does not expose private access (via `EndpointAccess.PUBLIC`) **o #### Cluster Handler -The `ClusterHandler` is a Lambda function responsible to interact the EKS API in order to control the cluster lifecycle. At the moment, this function cannot be provisioned inside the VPC. See [Attach all Lambda Function to a VPC](https://github.com/aws/aws-cdk/issues/9509) for more details. +The `ClusterHandler` is a Lambda function responsible to interact with the EKS API in order to control the cluster lifecycle. To provision this function inside the VPC, set the `placeClusterHandlerInVpc` property to `true`. This will place the function inside the private subnets of the VPC based on the selection strategy specified in the [`vpcSubnets`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-eks.Cluster.html#vpcsubnetsspan-classapi-icon-api-icon-experimental-titlethis-api-element-is-experimental-it-may-change-without-noticespan) property. + ### Kubectl Support diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts index fa5da2d80807e..9e702ec5ec90c 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource-provider.ts @@ -1,4 +1,5 @@ import * as path from 'path'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as lambda from '@aws-cdk/aws-lambda'; import { Duration, NestedStack, Stack } from '@aws-cdk/core'; @@ -17,6 +18,16 @@ export interface ClusterResourceProviderProps { * The IAM role to assume in order to interact with the cluster. */ readonly adminRole: iam.IRole; + + /** + * The VPC to provision the functions in. + */ + readonly vpc?: ec2.IVpc; + + /** + * The subnets to place the functions in. + */ + readonly subnets?: ec2.ISubnet[]; } /** @@ -48,6 +59,8 @@ export class ClusterResourceProvider extends NestedStack { runtime: HANDLER_RUNTIME, handler: 'index.onEvent', timeout: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); const isComplete = new lambda.Function(this, 'IsCompleteHandler', { @@ -56,6 +69,8 @@ export class ClusterResourceProvider extends NestedStack { runtime: HANDLER_RUNTIME, handler: 'index.isComplete', timeout: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); this.provider = new cr.Provider(this, 'Provider', { @@ -63,6 +78,8 @@ export class ClusterResourceProvider extends NestedStack { isCompleteHandler: isComplete, totalTimeout: Duration.hours(1), queryInterval: Duration.minutes(1), + vpc: props.subnets ? props.vpc : undefined, + vpcSubnets: props.subnets ? { subnets: props.subnets } : undefined, }); props.adminRole.grant(onEvent.role!, 'sts:AssumeRole'); diff --git a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts index 788210c987dbe..3260f3b16e7ef 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster-resource.ts @@ -21,6 +21,7 @@ export interface ClusterResourceProps { readonly endpointPublicAccess: boolean; readonly publicAccessCidrs?: string[]; readonly vpc: ec2.IVpc; + readonly subnets?: ec2.ISubnet[]; readonly secretsEncryptionKey?: kms.IKey; } @@ -57,6 +58,8 @@ export class ClusterResource extends CoreConstruct { const provider = ClusterResourceProvider.getOrCreate(this, { adminRole: this.adminRole, + subnets: props.subnets, + vpc: props.vpc, }); const resource = new CustomResource(this, 'Resource', { diff --git a/packages/@aws-cdk/aws-eks/lib/cluster.ts b/packages/@aws-cdk/aws-eks/lib/cluster.ts index fcbc2aaffdf10..98409be0575a4 100644 --- a/packages/@aws-cdk/aws-eks/lib/cluster.ts +++ b/packages/@aws-cdk/aws-eks/lib/cluster.ts @@ -462,6 +462,14 @@ export interface ClusterOptions extends CommonClusterOptions { * @default true */ readonly prune?: boolean; + + /** + * If set to true, the cluster handler functions will be placed in the private subnets + * of the cluster vpc, subject to the `vpcSubnets` selection strategy. + * + * @default false + */ + readonly placeClusterHandlersInVpc?: boolean; } /** @@ -1029,6 +1037,7 @@ export class Cluster extends ClusterBase { publicAccessCidrs: this.endpointAccess._config.publicCidrs, secretsEncryptionKey: props.secretsEncryptionKey, vpc: this.vpc, + subnets: (props.placeClusterHandlersInVpc ?? false) ? privateSubents : undefined, }); if (this.endpointAccess._config.privateAccess && privateSubents.length !== 0) { diff --git a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts index 4cf2d254099f6..359eb79b970a5 100644 --- a/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts +++ b/packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts @@ -97,6 +97,8 @@ export class KubectlProvider extends NestedStack { const provider = new cr.Provider(this, 'Provider', { onEventHandler: handler, + vpc: cluster.kubectlPrivateSubnets ? cluster.vpc : undefined, + vpcSubnets: cluster.kubectlPrivateSubnets ? { subnets: cluster.kubectlPrivateSubnets } : undefined, }); this.serviceToken = provider.serviceToken; diff --git a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts index a61e7ab475939..7a974f3141f1c 100644 --- a/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts +++ b/packages/@aws-cdk/custom-resources/lib/provider-framework/provider.ts @@ -1,5 +1,6 @@ import * as path from 'path'; import * as cfn from '@aws-cdk/aws-cloudformation'; +import * as ec2 from '@aws-cdk/aws-ec2'; import * as lambda from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import { Construct as CoreConstruct, Duration } from '@aws-cdk/core'; @@ -70,6 +71,21 @@ export interface ProviderProps { * @default logs.RetentionDays.INFINITE */ readonly logRetention?: logs.RetentionDays; + + /** + * The vpc to provision the lambda functions in. + * + * @default - functions are not provisioned inside a vpc. + */ + readonly vpc?: ec2.IVpc; + + /** + * Which subnets from the VPC to place the lambda functions in. + * + * @default - functions are not provisioned inside a vpc. + */ + readonly vpcSubnets?: ec2.SubnetSelection; + } /** @@ -97,6 +113,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid private readonly entrypoint: lambda.Function; private readonly logRetention?: logs.RetentionDays; + private readonly vpc?: ec2.IVpc; + private readonly vpcSubnets?: ec2.SubnetSelection; constructor(scope: Construct, id: string, props: ProviderProps) { super(scope, id); @@ -110,6 +128,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid this.isCompleteHandler = props.isCompleteHandler; this.logRetention = props.logRetention; + this.vpc = props.vpc; + this.vpcSubnets = props.vpcSubnets; const onEventFunction = this.createFunction(consts.FRAMEWORK_ON_EVENT_HANDLER_NAME); @@ -153,6 +173,8 @@ export class Provider extends CoreConstruct implements cfn.ICustomResourceProvid handler: `framework.${entrypoint}`, timeout: FRAMEWORK_HANDLER_TIMEOUT, logRetention: this.logRetention, + vpc: this.vpc, + vpcSubnets: this.vpcSubnets, }); fn.addEnvironment(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, this.onEventHandler.functionArn); diff --git a/packages/@aws-cdk/custom-resources/package.json b/packages/@aws-cdk/custom-resources/package.json index 61908e19814c2..d291d6b66815b 100644 --- a/packages/@aws-cdk/custom-resources/package.json +++ b/packages/@aws-cdk/custom-resources/package.json @@ -96,6 +96,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" }, @@ -106,6 +107,7 @@ "@aws-cdk/aws-lambda": "0.0.0", "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-sns": "0.0.0", + "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.2.0" },