Skip to content

Commit

Permalink
feat: Harden NodeGroupRole by denying VPC actions. (#37)
Browse files Browse the repository at this point in the history
* feat: Harden NodeGroupRole by denying VPC actions.

These actions are not necessary, since they are performed by the
managed VPC CNI Addon, which uses its own role via IRSA.
Therefore the Node Roles shouldn't be allowed to perform them.

* Update README.md

Co-authored-by: Jan Brauer <jan.brauer@superluminar.io>
  • Loading branch information
Miradorn and bracki committed Feb 5, 2021
1 parent c683657 commit 8e6dabe
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 2 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ __super-eks__ solves this problem by making a few choices for you as outlined be
- :white_check_mark: Forwarding logs to CloudWatch Logs with [fluent-bit](https://github.com/aws/aws-for-fluent-bit)
- :white_check_mark: Ingress management with the [AWS Load Balancer Controller](https://github.com/kubernetes-sigs/aws-load-balancer-controller)
- :white_check_mark: Isolated node groups, one for the shipped components, the other one for your workloads
- :white_check_mark: Hardened node setup, deny nodes altering the VPC setup.
- :white_check_mark: Default to [managed cluster add-ons](https://docs.aws.amazon.com/eks/latest/userguide/update-cluster.html#update-cluster-add-ons) where possible.

### :world_map: Roadmap

- :hammer_and_wrench: Hardened node setup
- :hammer_and_wrench: Monitoring with Prometheus and CloudWatch
- :hammer_and_wrench: Backup solution for cluster recovery
- :hammer_and_wrench: Authentication/authorization for workloads with Amazon Cognito
Expand Down
32 changes: 32 additions & 0 deletions src/constructs/super-eks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export class SuperEks extends cdk.Construct {
this.additionalNodegroups.push(this.addSuperEksNodegroup());

this.addManagedVpcCniAddon();
this.hardenNodes();

this.configureExternalDNS();
this.configureAwsLoadBalancerController();
Expand Down Expand Up @@ -122,6 +123,37 @@ export class SuperEks extends cdk.Construct {
this.additionalNodegroups.forEach((nodegroup) => {nodegroup.node.addDependency(vpcCniAddon); });
}

private hardenNodes() {
const policy = new iam.Policy(this, 'NodeHardeningPolicy', {
statements: [
new iam.PolicyStatement({
effect: iam.Effect.DENY,
actions: [
'ec2:AssignPrivateIpAddresses',
'ec2:AttachNetworkInterface',
'ec2:CreateNetworkInterface',
'ec2:DeleteNetworkInterface',
'ec2:DetachNetworkInterface',
'ec2:ModifyNetworkInterfaceAttribute',
'ec2:UnassignPrivateIpAddresses',
],
resources: ['*'],
}),
new iam.PolicyStatement({
effect: iam.Effect.DENY,
actions: ['ec2:CreateTags'],
resources: ['arn:aws:ec2:*:*:network-interface/*'],
}),
],
});

if (this.cluster.defaultNodegroup?.role) {
policy.attachToRole(this.cluster.defaultNodegroup.role);
}

this.additionalNodegroups.forEach((nodeGroup) => policy.attachToRole(nodeGroup.role));
}

private configureExternalDNS(): void {
new ExternalDNS(this, 'ExternalDNS', {
cluster: this.cluster,
Expand Down
22 changes: 21 additions & 1 deletion test/constructs/super-eks.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import '@aws-cdk/assert/jest';
import { ABSENT, arrayWith, ResourcePart, stringLike } from '@aws-cdk/assert';
import { arrayWith, objectLike, stringLike, ResourcePart, ABSENT } from '@aws-cdk/assert';
import * as route53 from '@aws-cdk/aws-route53';
import * as cdk from '@aws-cdk/core';

Expand Down Expand Up @@ -103,3 +103,23 @@ test('It installs external-dns', () => {
Chart: 'external-dns',
});
});

test('It hardens all Nodes', () => {
const app = new cdk.App();
const stack = new cdk.Stack(app, 'Stack', {
env: { region: 'eu-central-1', account: '1234567891011' },
});
// WHEN
new SuperEks(stack, 'TestCluster', {
hostedZone: route53.HostedZone.fromHostedZoneId(stack, 'HostedZone', '123'),
});

// THEN
expect(stack).toHaveResource('AWS::IAM::Policy', {
PolicyName: stringLike('*NodeHardeningPolicy*'),
Roles: arrayWith(
objectLike( { Ref: stringLike('*EksClusterNodegroupSuperEksNodegroupNodeGroupRole*') }),
objectLike( { Ref: stringLike('*EksClusterNodegroupDefaultCapacityNodeGroupRole*') }),
),
});
});

0 comments on commit 8e6dabe

Please sign in to comment.