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

feat(eks): Allow passing of custom IAM role to Kube Ctl Lambda #17196

Merged
merged 9 commits into from
Nov 11, 2021
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-eks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,8 @@ Breaking this down, it means that if the endpoint exposes private access (via `E

If the endpoint does not expose private access (via `EndpointAccess.PUBLIC`) **or** the VPC does not contain private subnets, the function will not be provisioned within the VPC.

If your use-case requires control over the IAM role that the KubeCtl Handler assumes, a custom role can be passed through the ClusterProps (as `kubectlLambdaRole`) of the EKS Cluster construct.

#### Cluster Handler

The `ClusterHandler` is a set of Lambda functions (`onEventHandler`, `isCompleteHandler`) responsible for interacting with the EKS API in order to control the cluster lifecycle. To provision these functions inside the VPC, set the `placeClusterHandlerInVpc` property to `true`. This will place the functions 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.
Expand Down
44 changes: 44 additions & 0 deletions packages/@aws-cdk/aws-eks/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ export interface ICluster extends IResource, ec2.IConnectable {
*/
readonly kubectlPrivateSubnets?: ec2.ISubnet[];

/**
* An IAM role that can perform kubectl operations against this cluster.
*
* The role should be mapped to the `system:masters` Kubernetes RBAC role.
*
* This role is directly passed to the lambda handler that sends Kube Ctl commands to the cluster.
*/
readonly kubectlLambdaRole?: iam.IRole;

/**
* An AWS Lambda layer that includes `kubectl`, `helm` and the `aws` CLI.
*
Expand Down Expand Up @@ -271,6 +280,18 @@ export interface ClusterAttributes {
*/
readonly kubectlRoleArn?: string;

/**
* An IAM role that can perform kubectl operations against this cluster.
*
* The role should be mapped to the `system:masters` Kubernetes RBAC role.
*
* This role is directly passed to the lambda handler that sends Kube Ctl commands
* to the cluster.
* @default - if not specified, the default role created by a lambda function will
* be used.
*/
readonly kubectlLambdaRole?: iam.IRole;

/**
* Environment variables to use when running `kubectl` against this cluster.
* @default - no additional variables
Expand Down Expand Up @@ -702,6 +723,14 @@ export interface ClusterProps extends ClusterOptions {
* @default NODEGROUP
*/
readonly defaultCapacityType?: DefaultCapacityType;


/**
* The IAM role to pass to the Kubectl Lambda Handler.
*
* @default - Default Lambda IAM Execution Role
*/
readonly kubectlLambdaRole?: iam.IRole;
}

/**
Expand Down Expand Up @@ -771,6 +800,7 @@ abstract class ClusterBase extends Resource implements ICluster {
public abstract readonly clusterSecurityGroup: ec2.ISecurityGroup;
public abstract readonly clusterEncryptionConfigKeyArn: string;
public abstract readonly kubectlRole?: iam.IRole;
public abstract readonly kubectlLambdaRole?: iam.IRole;
public abstract readonly kubectlEnvironment?: { [key: string]: string };
public abstract readonly kubectlSecurityGroup?: ec2.ISecurityGroup;
public abstract readonly kubectlPrivateSubnets?: ec2.ISubnet[];
Expand Down Expand Up @@ -1077,6 +1107,18 @@ export class Cluster extends ClusterBase {
*/
public readonly kubectlRole?: iam.IRole;

/**
* An IAM role that can perform kubectl operations against this cluster.
*
* The role should be mapped to the `system:masters` Kubernetes RBAC role.
*
* This role is directly passed to the lambda handler that sends Kube Ctl commands to the cluster.
* @default - if not specified, the default role created by a lambda function will
* be used.
*/

public readonly kubectlLambdaRole?: iam.IRole;

/**
* Custom environment variables when running `kubectl` against this cluster.
*/
Expand Down Expand Up @@ -1195,6 +1237,7 @@ export class Cluster extends ClusterBase {
this.prune = props.prune ?? true;
this.vpc = props.vpc || new ec2.Vpc(this, 'DefaultVpc');
this.version = props.version;
this.kubectlLambdaRole = props.kubectlLambdaRole ? props.kubectlLambdaRole : undefined;

this.tagSubnets();

Expand Down Expand Up @@ -1867,6 +1910,7 @@ class ImportedCluster extends ClusterBase {
public readonly clusterArn: string;
public readonly connections = new ec2.Connections();
public readonly kubectlRole?: iam.IRole;
public readonly kubectlLambdaRole?: iam.IRole;
public readonly kubectlEnvironment?: { [key: string]: string; } | undefined;
public readonly kubectlSecurityGroup?: ec2.ISecurityGroup | undefined;
public readonly kubectlPrivateSubnets?: ec2.ISubnet[] | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-eks/lib/kubectl-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export class KubectlProvider extends NestedStack {
description: 'onEvent handler for EKS kubectl resource provider',
memorySize,
environment: cluster.kubectlEnvironment,
role: cluster.kubectlLambdaRole ? cluster.kubectlLambdaRole : undefined,

// defined only when using private access
vpc: cluster.kubectlPrivateSubnets ? cluster.vpc : undefined,
Expand Down
36 changes: 36 additions & 0 deletions packages/@aws-cdk/aws-eks/test/cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2202,6 +2202,42 @@ describe('cluster', () => {
},
});

});

test('kubectl provider passes iam role environment to kube ctl lambda', () => {

const { stack } = testFixture();

const kubectlRole = new iam.Role(stack, 'KubectlIamRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
});

// using _ syntax to silence warning about _cluster not being used, when it is
const cluster = new eks.Cluster(stack, 'Cluster1', {
version: CLUSTER_VERSION,
prune: false,
endpointAccess: eks.EndpointAccess.PRIVATE,
kubectlLambdaRole: kubectlRole,
});

cluster.addManifest('resource', {
kind: 'ConfigMap',
apiVersion: 'v1',
data: {
hello: 'world',
},
metadata: {
name: 'config-map',
},
});

// the kubectl provider is inside a nested stack.
const nested = stack.node.tryFindChild('@aws-cdk/aws-eks.KubectlProvider') as cdk.NestedStack;
expect(nested).toHaveResourceLike('AWS::Lambda::Function', {
Role: {
Ref: 'referencetoStackKubectlIamRole02F8947EArn',
},
});

});

Expand Down