Skip to content

Commit

Permalink
feat(eks): Allow passing of custom IAM role to Kube Ctl Lambda (aws#1…
Browse files Browse the repository at this point in the history
…7196)

Adds the parameter `kubectlLambdaRole?` to the EKS `Cluster` construct. This IAM role gets passed to the cluster's `KubeCtlProvider` nested stack's lambda handler for running KubeCtl commands against the cluster.
  • Loading branch information
pnathan-vr authored and TikiTDO committed Feb 21, 2022
1 parent 6409614 commit b14a403
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 0 deletions.
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

0 comments on commit b14a403

Please sign in to comment.