Skip to content

Commit b80c271

Browse files
author
Elad Ben-Israel
authored
feat(eks): default masters role (#9464)
If `mastersRole` is not specified, we now define a default IAM role that can be assumed by anyone (with permissions) in the account. This will allow users to interact with the cluster through `kubectl` by issuing the `aws eks update-kubeconfig` command with the appropriate `--role-arn` option, as specified in the CFN output. Fixes #9463 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 93657b7 commit b80c271

File tree

6 files changed

+167
-101
lines changed

6 files changed

+167
-101
lines changed

packages/@aws-cdk/aws-eks/README.md

Lines changed: 42 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## Amazon EKS Construct Library
2+
23
<!--BEGIN STABILITY BANNER-->
34
---
45

@@ -29,6 +30,7 @@ const cluster = new eks.Cluster(this, 'hello-eks', {
2930
version: eks.KubernetesVersion.V1_16,
3031
});
3132

33+
// apply a kubernetes manifest to the cluster
3234
cluster.addResource('mypod', {
3335
apiVersion: 'v1',
3436
kind: 'Pod',
@@ -45,6 +47,46 @@ cluster.addResource('mypod', {
4547
});
4648
```
4749

50+
In order to interact with your cluster through `kubectl`, you can use the `aws
51+
eks update-kubeconfig` [AWS CLI](https://docs.aws.amazon.com/cli/latest/reference/eks/update-kubeconfig.html) command
52+
to configure your local kubeconfig.
53+
54+
The EKS module will define a CloudFormation output in your stack which contains
55+
the command to run. For example:
56+
57+
```
58+
Outputs:
59+
ClusterConfigCommand43AAE40F = aws eks update-kubeconfig --name cluster-xxxxx --role-arn arn:aws:iam::112233445566:role/yyyyy
60+
```
61+
62+
> The IAM role specified in this command is called the "**masters role**". This is
63+
> an IAM role that is associated with the `system:masters` [RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/)
64+
> group and has super-user access to the cluster.
65+
>
66+
> You can specify this role using the `mastersRole` option, or otherwise a role will be
67+
> automatically created for you. This role can be assumed by anyone in the account with
68+
> `sts:AssumeRole` permissions for this role.
69+
70+
Execute the `aws eks update-kubeconfig ...` command in your terminal to create a
71+
local kubeconfig:
72+
73+
```console
74+
$ aws eks update-kubeconfig --name cluster-xxxxx --role-arn arn:aws:iam::112233445566:role/yyyyy
75+
Added new context arn:aws:eks:rrrrr:112233445566:cluster/cluster-xxxxx to /home/boom/.kube/config
76+
```
77+
78+
And now you can simply use `kubectl`:
79+
80+
```console
81+
$ kubectl get all -n kube-system
82+
NAME READY STATUS RESTARTS AGE
83+
pod/aws-node-fpmwv 1/1 Running 0 21m
84+
pod/aws-node-m9htf 1/1 Running 0 21m
85+
pod/coredns-5cb4fb54c7-q222j 1/1 Running 0 23m
86+
pod/coredns-5cb4fb54c7-v9nxx 1/1 Running 0 23m
87+
...
88+
```
89+
4890
### Endpoint Access
4991

5092
You can configure the [cluster endpoint access](https://docs.aws.amazon.com/eks/latest/userguide/cluster-endpoint.html) by using the `endpointAccess` property:
@@ -58,7 +100,6 @@ const cluster = new eks.Cluster(this, 'hello-eks', {
58100

59101
The default value is `eks.EndpointAccess.PUBLIC_AND_PRIVATE`. Which means the cluster endpoint is accessible from outside of your VPC, and worker node traffic to the endpoint will stay within your VPC.
60102

61-
62103
### Capacity
63104

64105
By default, `eks.Cluster` is created with a managed nodegroup with x2 `m5.large` instances. You must specify the kubernetes version for the cluster with the `version` property.
@@ -208,7 +249,6 @@ When adding capacity, you can specify options for
208249
which is responsible for associating the node to the EKS cluster. For example,
209250
you can use `kubeletExtraArgs` to add custom node labels or taints.
210251

211-
212252
```ts
213253
// up to ten spot instances
214254
cluster.addCapacity('spot', {
@@ -224,90 +264,6 @@ cluster.addCapacity('spot', {
224264
To disable bootstrapping altogether (i.e. to fully customize user-data), set `bootstrapEnabled` to `false` when you add
225265
the capacity.
226266

227-
### Masters Role
228-
229-
The Amazon EKS construct library allows you to specify an IAM role that will be
230-
granted `system:masters` privileges on your cluster.
231-
232-
Without specifying a `mastersRole`, you will not be able to interact manually
233-
with the cluster.
234-
235-
The following example defines an IAM role that can be assumed by all users
236-
in the account and shows how to use the `mastersRole` property to map this
237-
role to the Kubernetes `system:masters` group:
238-
239-
```ts
240-
// first define the role
241-
const clusterAdmin = new iam.Role(this, 'AdminRole', {
242-
assumedBy: new iam.AccountRootPrincipal()
243-
});
244-
245-
// now define the cluster and map role to "masters" RBAC group
246-
new eks.Cluster(this, 'Cluster', {
247-
mastersRole: clusterAdmin,
248-
version: eks.KubernetesVersion.V1_16,
249-
});
250-
```
251-
252-
When you `cdk deploy` this CDK app, you will notice that an output will be printed
253-
with the `update-kubeconfig` command.
254-
255-
Something like this:
256-
257-
```
258-
Outputs:
259-
eks-integ-defaults.ClusterConfigCommand43AAE40F = aws eks update-kubeconfig --name cluster-ba7c166b-c4f3-421c-bf8a-6812e4036a33 --role-arn arn:aws:iam::112233445566:role/eks-integ-defaults-Role1ABCC5F0-1EFK2W5ZJD98Y
260-
```
261-
262-
Copy & paste the "`aws eks update-kubeconfig ...`" command to your shell in
263-
order to connect to your EKS cluster with the "masters" role.
264-
265-
Now, given [AWS CLI](https://aws.amazon.com/cli/) is configured to use AWS
266-
credentials for a user that is trusted by the masters role, you should be able
267-
to interact with your cluster through `kubectl` (the above example will trust
268-
all users in the account).
269-
270-
For example:
271-
272-
```console
273-
$ aws eks update-kubeconfig --name cluster-ba7c166b-c4f3-421c-bf8a-6812e4036a33 --role-arn arn:aws:iam::112233445566:role/eks-integ-defaults-Role1ABCC5F0-1EFK2W5ZJD98Y
274-
Added new context arn:aws:eks:eu-west-2:112233445566:cluster/cluster-ba7c166b-c4f3-421c-bf8a-6812e4036a33 to /Users/boom/.kube/config
275-
276-
$ kubectl get nodes # list all nodes
277-
NAME STATUS ROLES AGE VERSION
278-
ip-10-0-147-66.eu-west-2.compute.internal Ready <none> 21m v1.13.7-eks-c57ff8
279-
ip-10-0-169-151.eu-west-2.compute.internal Ready <none> 21m v1.13.7-eks-c57ff8
280-
281-
$ kubectl get all -n kube-system
282-
NAME READY STATUS RESTARTS AGE
283-
pod/aws-node-fpmwv 1/1 Running 0 21m
284-
pod/aws-node-m9htf 1/1 Running 0 21m
285-
pod/coredns-5cb4fb54c7-q222j 1/1 Running 0 23m
286-
pod/coredns-5cb4fb54c7-v9nxx 1/1 Running 0 23m
287-
pod/kube-proxy-d4jrh 1/1 Running 0 21m
288-
pod/kube-proxy-q7hh7 1/1 Running 0 21m
289-
290-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
291-
service/kube-dns ClusterIP 172.20.0.10 <none> 53/UDP,53/TCP 23m
292-
293-
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
294-
daemonset.apps/aws-node 2 2 2 2 2 <none> 23m
295-
daemonset.apps/kube-proxy 2 2 2 2 2 <none> 23m
296-
297-
NAME READY UP-TO-DATE AVAILABLE AGE
298-
deployment.apps/coredns 2/2 2 2 23m
299-
300-
NAME DESIRED CURRENT READY AGE
301-
replicaset.apps/coredns-5cb4fb54c7 2 2 2 23m
302-
```
303-
304-
For your convenience, an AWS CloudFormation output will automatically be
305-
included in your template and will be printed when running `cdk deploy`.
306-
307-
**NOTE**: if the cluster is configured with `kubectlEnabled: false`, it
308-
will be created with the role/user that created the AWS CloudFormation
309-
stack. See [Kubectl Support](#kubectl-support) for details.
310-
311267
### Kubernetes Resources
312268

313269
The `KubernetesResource` construct or `cluster.addResource` method can be used

packages/@aws-cdk/aws-eks/lib/cluster.ts

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,8 @@ export interface ClusterOptions {
175175
*
176176
* @see https://kubernetes.io/docs/reference/access-authn-authz/rbac/#default-roles-and-role-bindings
177177
*
178-
* @default - By default, it will only possible to update this Kubernetes
179-
* system by adding resources to this cluster via `addResource` or
180-
* by defining `KubernetesResource` resources in your AWS CDK app.
181-
* Use this if you wish to grant cluster administration privileges
182-
* to another role.
178+
* @default - a role that assumable by anyone with permissions in the same
179+
* account will automatically be defined
183180
*/
184181
readonly mastersRole?: iam.IRole;
185182

@@ -689,19 +686,25 @@ export class Cluster extends Resource implements ICluster {
689686
new CfnOutput(this, 'ClusterName', { value: this.clusterName });
690687
}
691688

692-
// map the IAM role to the `system:masters` group.
693-
if (props.mastersRole) {
694-
if (!this.kubectlEnabled) {
689+
if (!this.kubectlEnabled) {
690+
if (props.mastersRole) {
695691
throw new Error('Cannot specify a "masters" role if kubectl is disabled');
696692
}
693+
} else {
694+
// if an explicit role is not configured, define a masters role that can
695+
// be assumed by anyone in the account (with sts:AssumeRole permissions of
696+
// course)
697+
const mastersRole = props.mastersRole ?? new iam.Role(this, 'MastersRole', {
698+
assumedBy: new iam.AccountRootPrincipal(),
699+
});
697700

698-
this.awsAuth.addMastersRole(props.mastersRole);
701+
this.awsAuth.addMastersRole(mastersRole);
699702

700703
if (props.outputMastersRoleArn) {
701-
new CfnOutput(this, 'MastersRoleArn', { value: props.mastersRole.roleArn });
704+
new CfnOutput(this, 'MastersRoleArn', { value: mastersRole.roleArn });
702705
}
703706

704-
commonCommandOptions.push(`--role-arn ${props.mastersRole.roleArn}`);
707+
commonCommandOptions.push(`--role-arn ${mastersRole.roleArn}`);
705708
}
706709

707710
// allocate default capacity if non-zero (or default).

packages/@aws-cdk/aws-eks/test/test.awsauth.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ export = {
5353
'',
5454
[
5555
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
56+
{
57+
'Fn::GetAtt': [
58+
'ClusterMastersRole9AA35625',
59+
'Arn',
60+
],
61+
},
62+
'\\",\\"username\\":\\"',
63+
{
64+
'Fn::GetAtt': [
65+
'ClusterMastersRole9AA35625',
66+
'Arn',
67+
],
68+
},
69+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
5670
{
5771
'Fn::GetAtt': [
5872
'ClusterNodegroupDefaultCapacityNodeGroupRole55953B04',
@@ -128,13 +142,27 @@ export = {
128142
'',
129143
[
130144
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
145+
{
146+
'Fn::GetAtt': [
147+
'ClusterMastersRole9AA35625',
148+
'Arn',
149+
],
150+
},
151+
'\\",\\"username\\":\\"',
152+
{
153+
'Fn::GetAtt': [
154+
'ClusterMastersRole9AA35625',
155+
'Arn',
156+
],
157+
},
158+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
131159
{
132160
'Fn::GetAtt': [
133161
'ClusterNodegroupDefaultCapacityNodeGroupRole55953B04',
134162
'Arn',
135163
],
136164
},
137-
'\\",\\"username\\":\\"system:node:{{EC2PrivateDNSName}}\\",\\"groups\\":[\\"system:bootstrappers\\",\\"system:nodes\\"]},{\\"rolearn\\":\\"arn:aws:iam::123456789012:role/S3Access\\",\\"username\\":\\"arn:aws:iam::123456789012:role/S3Access\\",\\"groups\\":[\\"group1\\"]}]\",\"mapUsers\":\"[{\\"userarn\\":\\"arn:',
165+
'\\",\\"username\\":\\"system:node:{{EC2PrivateDNSName}}\\",\\"groups\\":[\\"system:bootstrappers\\",\\"system:nodes\\"]},{\\"rolearn\\":\\"arn:aws:iam::123456789012:role/S3Access\\",\\"username\\":\\"arn:aws:iam::123456789012:role/S3Access\\",\\"groups\\":[\\"group1\\"]}]","mapUsers":"[{\\"userarn\\":\\"arn:',
138166
{
139167
Ref: 'AWS::Partition',
140168
},
@@ -175,6 +203,20 @@ export = {
175203
'',
176204
[
177205
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
206+
{
207+
'Fn::GetAtt': [
208+
'ClusterMastersRole9AA35625',
209+
'Arn',
210+
],
211+
},
212+
'\\",\\"username\\":\\"',
213+
{
214+
'Fn::GetAtt': [
215+
'ClusterMastersRole9AA35625',
216+
'Arn',
217+
],
218+
},
219+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
178220
{
179221
'Fn::GetAtt': [
180222
'ClusterNodegroupDefaultCapacityNodeGroupRole55953B04',

packages/@aws-cdk/aws-eks/test/test.cluster.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,20 @@ export = {
496496
'',
497497
[
498498
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
499+
{
500+
'Fn::GetAtt': [
501+
'ClusterMastersRole9AA35625',
502+
'Arn',
503+
],
504+
},
505+
'\\",\\"username\\":\\"',
506+
{
507+
'Fn::GetAtt': [
508+
'ClusterMastersRole9AA35625',
509+
'Arn',
510+
],
511+
},
512+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
499513
{
500514
'Fn::GetAtt': [
501515
'ClusterdefaultInstanceRoleF20A29CD',
@@ -527,7 +541,30 @@ export = {
527541
});
528542

529543
// THEN
530-
expect(stack).to(not(haveResource(eks.KubernetesResource.RESOURCE_TYPE)));
544+
expect(stack).to(haveResource(eks.KubernetesResource.RESOURCE_TYPE, {
545+
Manifest: {
546+
'Fn::Join': [
547+
'',
548+
[
549+
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
550+
{
551+
'Fn::GetAtt': [
552+
'ClusterMastersRole9AA35625',
553+
'Arn',
554+
],
555+
},
556+
'\\",\\"username\\":\\"',
557+
{
558+
'Fn::GetAtt': [
559+
'ClusterMastersRole9AA35625',
560+
'Arn',
561+
],
562+
},
563+
'\\",\\"groups\\":[\\"system:masters\\"]}]","mapUsers":"[]","mapAccounts":"[]"}}]',
564+
],
565+
],
566+
},
567+
}));
531568
test.done();
532569
},
533570

@@ -563,8 +600,8 @@ export = {
563600
const assembly = app.synth();
564601
const template = assembly.getStackByName(stack.stackName).template;
565602
test.deepEqual(template.Outputs, {
566-
ClusterConfigCommand43AAE40F: { Value: { 'Fn::Join': ['', ['aws eks update-kubeconfig --name ', { Ref: 'Cluster9EE0221C' }, ' --region us-east-1']] } },
567-
ClusterGetTokenCommand06AE992E: { Value: { 'Fn::Join': ['', ['aws eks get-token --cluster-name ', { Ref: 'Cluster9EE0221C' }, ' --region us-east-1']] } },
603+
ClusterConfigCommand43AAE40F: { Value: { 'Fn::Join': ['', ['aws eks update-kubeconfig --name ', { Ref: 'Cluster9EE0221C' }, ' --region us-east-1 --role-arn ', { 'Fn::GetAtt': [ 'ClusterMastersRole9AA35625', 'Arn' ] } ] ] } },
604+
ClusterGetTokenCommand06AE992E: { Value: { 'Fn::Join': ['', ['aws eks get-token --cluster-name ', { Ref: 'Cluster9EE0221C' }, ' --region us-east-1 --role-arn ', { 'Fn::GetAtt': [ 'ClusterMastersRole9AA35625', 'Arn' ] } ] ] } },
568605
});
569606
test.done();
570607
},

packages/@aws-cdk/aws-eks/test/test.fargate.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,20 @@ export = {
313313
'',
314314
[
315315
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
316+
{
317+
'Fn::GetAtt': [
318+
'FargateClusterMastersRole50BAF9FD',
319+
'Arn',
320+
],
321+
},
322+
'\\",\\"username\\":\\"',
323+
{
324+
'Fn::GetAtt': [
325+
'FargateClusterMastersRole50BAF9FD',
326+
'Arn',
327+
],
328+
},
329+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
316330
{
317331
'Fn::GetAtt': [
318332
'FargateClusterfargateprofiledefaultPodExecutionRole66F2610E',

packages/@aws-cdk/aws-eks/test/test.nodegroup.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ export = {
7373
'',
7474
[
7575
'[{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"aws-auth","namespace":"kube-system"},"data":{"mapRoles":"[{\\"rolearn\\":\\"',
76+
{
77+
'Fn::GetAtt': [
78+
'ClusterMastersRole9AA35625',
79+
'Arn',
80+
],
81+
},
82+
'\\",\\"username\\":\\"',
83+
{
84+
'Fn::GetAtt': [
85+
'ClusterMastersRole9AA35625',
86+
'Arn',
87+
],
88+
},
89+
'\\",\\"groups\\":[\\"system:masters\\"]},{\\"rolearn\\":\\"',
7690
{
7791
'Fn::GetAtt': [
7892
'NodegroupNodeGroupRole038A128B',

0 commit comments

Comments
 (0)