Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(eks): private endpoint access doesn't work with Vpc.fromLookup #9544

Merged
merged 6 commits into from
Aug 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 28 additions & 2 deletions packages/@aws-cdk/aws-eks/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1018,13 +1018,20 @@ export class Cluster extends Resource implements ICluster {
};

if (!this.endpointAccess._config.publicAccess) {

const privateSubents = this.selectPrivateSubnets().slice(0, 16);

if (privateSubents.length === 0) {
throw new Error('Vpc must contain private subnets to configure private endpoint access');
}

// endpoint access is private only, we need to attach the
// provider to the VPC so that it can access the cluster.
providerProps = {
...providerProps,
vpc: this.vpc,
// lambda can only be accociated with max 16 subnets and they all need to be private.
vpcSubnets: {subnets: this.selectPrivateSubnets().slice(0, 16)},
vpcSubnets: {subnets: privateSubents},
securityGroups: [this.kubctlProviderSecurityGroup],
};
}
Expand All @@ -1049,7 +1056,26 @@ export class Cluster extends Resource implements ICluster {
const privateSubnets: ec2.ISubnet[] = [];

for (const placement of this.vpcSubnets) {
privateSubnets.push(...this.vpc.selectSubnets(placement).subnets.filter(s => s instanceof ec2.PrivateSubnet));

for (const subnet of this.vpc.selectSubnets(placement).subnets) {

if (this.vpc.privateSubnets.includes(subnet)) {
// definitely private, take it.
privateSubnets.push(subnet);
continue;
}

if (this.vpc.publicSubnets.includes(subnet)) {
// definitely public, skip it.
continue;
}

// neither public and nor private - what is it then? this means its a subnet instance that was explicitly passed
// in the subnet selection. since ISubnet doesn't contain information on type, we have to assume its private and let it
// fail at deploy time :\ (its better than filtering it out and preventing a possibly successful deployment)
privateSubnets.push(subnet);
}

}

return privateSubnets;
Expand Down
101 changes: 100 additions & 1 deletion packages/@aws-cdk/aws-eks/test/test.cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,105 @@ export = {

'endpoint access': {

'private endpoint access fails if selected subnets are empty'(test: Test) {

const { stack } = testFixture();

test.throws(() => {
new eks.Cluster(stack, 'Cluster', {
vpc: new ec2.Vpc(stack, 'Vpc'),
version: CLUSTER_VERSION,
endpointAccess: eks.EndpointAccess.PRIVATE,
vpcSubnets: [{ subnetType: ec2.SubnetType.PUBLIC }],
});
}, /Vpc must contain private subnets to configure private endpoint access/);

test.done();
},

'private endpoint access selects only private subnets from looked up vpc'(test: Test) {

const vpcId = 'vpc-12345';
// can't use the regular fixture because it also adds a VPC to the stack, which prevents
// us from setting context.
const stack = new cdk.Stack(new cdk.App(), 'Stack', {
env: {
account: '11112222',
region: 'us-east-1',
},
});
stack.node.setContext(`vpc-provider:account=${stack.account}:filter.vpc-id=${vpcId}:region=${stack.region}:returnAsymmetricSubnets=true`, {
vpcId: vpcId,
vpcCidrBlock: '10.0.0.0/16',
subnetGroups: [
{
name: 'Private',
type: 'Private',
subnets: [
{
subnetId: 'subnet-private-in-us-east-1a',
cidr: '10.0.1.0/24',
availabilityZone: 'us-east-1a',
routeTableId: 'rtb-06068e4c4049921ef',
},
],
},
{
name: 'Public',
type: 'Public',
subnets: [
{
subnetId: 'subnet-public-in-us-east-1c',
cidr: '10.0.0.0/24',
availabilityZone: 'us-east-1c',
routeTableId: 'rtb-0ff08e62195198dbb',
},
],
},
],
});
const vpc = ec2.Vpc.fromLookup(stack, 'Vpc', {
vpcId: vpcId,
});

new eks.Cluster(stack, 'Cluster', {
vpc,
version: CLUSTER_VERSION,
endpointAccess: eks.EndpointAccess.PRIVATE,
});

const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack;
const template = expect(nested).value;

test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [
'subnet-private-in-us-east-1a',
]);

test.done();
},

'private endpoint access considers specific subnet selection'(test: Test) {
const { stack } = testFixture();
new eks.Cluster(stack, 'Cluster', {
version: CLUSTER_VERSION, endpointAccess:
eks.EndpointAccess.PRIVATE,
vpcSubnets: [{subnets: [ec2.PrivateSubnet.fromSubnetAttributes(stack, 'Private1', {
subnetId: 'subnet1',
availabilityZone: 'us-east-1a',
})]}],
});

const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack;
const template = expect(nested).value;

test.deepEqual(template.Resources.Handler886CB40B.Properties.VpcConfig.SubnetIds, [
'subnet1',
]);

test.done();

},

'can configure private endpoint access'(test: Test) {
// GIVEN
const { stack } = testFixture();
Expand Down Expand Up @@ -1669,4 +1768,4 @@ export = {
},

},
};
};