Skip to content
Open
Show file tree
Hide file tree
Changes from 13 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
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-eks-v2-alpha/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1294,6 +1294,7 @@ export class Cluster extends ClusterBase {
kubectlLayer: this._kubectlProviderOptions!.kubectlLayer,
environment: this._kubectlProviderOptions?.environment,
memory: this._kubectlProviderOptions?.memory,
securityGroup: this._kubectlProviderOptions?.securityGroup,
privateSubnets: kubectlSubnets,
});

Expand Down
6 changes: 5 additions & 1 deletion packages/@aws-cdk/aws-eks-v2-alpha/lib/kubectl-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,11 @@ export class KubectlProvider extends Construct implements IKubectlProvider {

const vpc = props.privateSubnets ? props.cluster.vpc : undefined;
let securityGroups;
if (props.privateSubnets && props.cluster.clusterSecurityGroup) {
if (props.privateSubnets && props.securityGroup) {
// if the user has provided a security group, use it
securityGroups = [props.securityGroup];
} else if (props.privateSubnets && props.cluster.clusterSecurityGroup) {
// if the user has not provided a security group, use the cluster security group
securityGroups = [props.cluster.clusterSecurityGroup];
}
const privateSubnets = props.privateSubnets ? { subnets: props.privateSubnets } : undefined;
Expand Down
49 changes: 49 additions & 0 deletions packages/@aws-cdk/aws-eks-v2-alpha/test/cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,55 @@ describe('cluster', () => {
});
});

test('kubectl provider uses the explicitly provided security group for the handler lambda', ()=> {
const { stack, vpc } = testFixture();

const kubectlSecurityGroup = new ec2.SecurityGroup(stack, 'KubectlSecurityGroup', {
vpc: vpc,
description: 'for kubectl handler',
});

new eks.Cluster(stack, 'Cluster1', {
version: CLUSTER_VERSION,
prune: false,
endpointAccess: eks.EndpointAccess.PRIVATE,
kubectlProviderOptions: {
kubectlLayer: new KubectlV33Layer(stack, 'kubectlLayer'),
securityGroup: kubectlSecurityGroup,
privateSubnets: vpc.privateSubnets,
},
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
VpcConfig: {
SecurityGroupIds: [{ 'Fn::GetAtt': ['KubectlSecurityGroupF060FCAE', 'GroupId'] }],
},
});
});

test('kubectl provider uses the cluster security group for the handler lambda when no SG is provided', () => {
const { stack, vpc } = testFixture();

new eks.Cluster(stack, 'Cluster1', {
version: CLUSTER_VERSION,
prune: false,
endpointAccess: eks.EndpointAccess.PRIVATE,
kubectlProviderOptions: {
kubectlLayer: new KubectlV33Layer(stack, 'kubectlLayer'),
privateSubnets: vpc.privateSubnets,
environment: {
Foo: 'Bar',
},
},
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::Function', {
VpcConfig: {
SecurityGroupIds: [{ 'Fn::GetAtt': ['Cluster192CD0375', 'ClusterSecurityGroupId'] }],
},
});
});

test('kubectl provider passes environment to lambda', () => {
const { stack } = testFixture();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/// !cdk-integ pragma:disable-update-workflow
import * as integ from '@aws-cdk/integ-tests-alpha';
import { KubectlV34Layer } from '@aws-cdk/lambda-layer-kubectl-v34';
import { App, Stack } from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as eks from '../lib';

/**
* Integration test for custom security group in kubectlProviderOptions
*
* This test verifies that when a custom security group is specified in
* kubectlProviderOptions, it is correctly applied to the Kubectl Handler
* Lambda function instead of the cluster's security group.
cd */
class EksKubectlCustomSecurityGroupStack extends Stack {
constructor(scope: App, id: string) {
super(scope, id);

// allow account users to assume this role in order to admin the cluster
// Condition restricts to roles in the same account to satisfy security guard requirements
const mastersRole = new iam.Role(this, 'AdminRole', {
assumedBy: new iam.AccountRootPrincipal().withConditions({
StringEquals: {
'aws:PrincipalAccount': this.account,
},
}),
});

// just need one nat gateway to simplify the test
const vpc = new ec2.Vpc(this, 'Vpc', {
maxAzs: 2,
natGateways: 1,
restrictDefaultSecurityGroup: false,
});

// Create a custom security group for the kubectl provider
// This security group will be used instead of the cluster security group
const kubectlSecurityGroup = new ec2.SecurityGroup(this, 'KubectlSecurityGroup', {
vpc,
description: 'Custom security group for kubectl provider Lambda function',
allowAllOutbound: true,
});

// Get private subnets for the kubectl provider
const privateSubnets = vpc.selectSubnets({
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
}).subnets;

const cluster = new eks.Cluster(this, 'Cluster', {
vpc,
mastersRole,
endpointAccess: eks.EndpointAccess.PRIVATE,
version: eks.KubernetesVersion.V1_34,
kubectlProviderOptions: {
kubectlLayer: new KubectlV34Layer(this, 'kubectlLayer'),
securityGroup: kubectlSecurityGroup,
privateSubnets,
},
});

// Add ingress rule to allow the kubectl provider to communicate with the cluster
// The cluster security group needs to allow traffic from the kubectl security group
cluster.connections.allowFrom(
new ec2.Connections({
securityGroups: [kubectlSecurityGroup],
}),
ec2.Port.tcp(443),
'Allow kubectl provider to access EKS cluster',
);

// This is the validation. It won't work if the custom security group
// is not properly configured and applied to the kubectl provider Lambda.
cluster.addManifest('test-config-map', {
kind: 'ConfigMap',
apiVersion: 'v1',
data: {
test: 'custom-security-group',
message: 'This manifest verifies the kubectl provider uses the custom security group',
},
metadata: {
name: 'test-config-map',
},
});
}
}

const app = new App({
postCliContext: {
'@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy': true,
'@aws-cdk/aws-lambda:useCdkManagedLogGroup': false,
},
});

const stack = new EksKubectlCustomSecurityGroupStack(app, 'aws-cdk-eks-kubectl-custom-security-group-test');
new integ.IntegTest(app, 'aws-cdk-eks-kubectl-custom-security-group', {
testCases: [stack],
// Test includes assets that are updated weekly. If not disabled, the upgrade PR will fail.
diffAssets: false,
});
Loading