Skip to content

Commit d8b25fd

Browse files
authored
Merge pull request #16 from doitintl/feature/storage-class-gp3-aws-encryption
Feature/storage class gp3 aws encryption
2 parents d132c55 + e229f12 commit d8b25fd

File tree

4 files changed

+164
-10
lines changed

4 files changed

+164
-10
lines changed

config/eks/dev_eks_config.ts

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,75 @@ export function deploy_dependencies(config: Easy_EKS_Config_Data, stack: cdk.Sta
2323
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2424

2525
export function deploy_workload_dependencies(config: Easy_EKS_Config_Data, stack: cdk.Stack, cluster: eks.Cluster){
26-
26+
// This is an example of a workload that uses a PersistentVolumeClaim with a storage class that is encrypted
27+
// with AWS KMS key.
28+
// IMPORTANT: if the cdk insfrastructure is destroyed it will leave the volume orphans, and they will
29+
// need to be manually deleted.
30+
let name="test-claim-gp3";
31+
let size="10Gi";
32+
const volume_claim_gp3 = {
33+
"apiVersion": "v1",
34+
"kind": "PersistentVolumeClaim",
35+
"metadata": {
36+
"name": `${name}`,
37+
"namespace": "default"
38+
},
39+
"spec": {
40+
"accessModes": [
41+
"ReadWriteOnce"
42+
],
43+
"storageClassName": "kms-encrypted-gp3",
44+
"resources": {
45+
"requests": {
46+
"storage": `${size}`
47+
}
48+
}
49+
}
50+
}
51+
const pod_using_volume_claim = {
52+
"apiVersion": "v1",
53+
"kind": "Pod",
54+
"metadata": {
55+
"name": "app"
56+
},
57+
"spec": {
58+
"containers": [
59+
{
60+
"name": "app",
61+
"image": "ubuntu:latest",
62+
"command": [
63+
"/bin/sh"
64+
],
65+
"args": [
66+
"-c",
67+
"while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"
68+
],
69+
"volumeMounts": [
70+
{
71+
"name": "persistent-storage",
72+
"mountPath": "/data"
73+
}
74+
]
75+
}
76+
],
77+
"volumes": [
78+
{
79+
"name": "persistent-storage",
80+
"persistentVolumeClaim": {
81+
"claimName": `${name}`
82+
}
83+
}
84+
]
85+
}
86+
}
87+
const pvc_demo_construct = new eks.KubernetesManifest(stack, "persistentVolumeClaimManifest",
88+
{
89+
cluster: cluster,
90+
manifest: [volume_claim_gp3, pod_using_volume_claim],
91+
overwrite: true,
92+
prune: true,
93+
});
94+
pvc_demo_construct.node.addDependency(cluster.awsAuth);
2795
}//end deploy_workload_dependencies()
2896

2997
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

config/eks/my_orgs_baseline_eks_config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,35 @@ export function deploy_workload_dependencies(config: Easy_EKS_Config_Data, stack
268268
},
269269
}`, //end aws-ebs-csi-driver configurationValues override
270270
});
271+
// adding gp3 storage class
272+
const storage_class_gp3_manifest = {
273+
"apiVersion": "storage.k8s.io/v1",
274+
"kind": "StorageClass",
275+
"metadata": {
276+
"name": "kms-encrypted-gp3",
277+
"annotations": {
278+
"storageclass.kubernetes.io/is-default-class": "true"
279+
}
280+
},
281+
"provisioner": "ebs.csi.aws.com",
282+
"volumeBindingMode": "WaitForFirstConsumer",
283+
"allowVolumeExpansion": true,
284+
"reclaimPolicy": "Delete",
285+
"parameters": {
286+
"type": "gp3",
287+
"encrypted": "true",
288+
//"kmsKeyId": `${config.kmsKey.keyArn}` //commentig it out as while we test the logic to add permissions to customer's KMS key
289+
}
290+
}
291+
const storage_class_gp3_construct = new eks.KubernetesManifest(stack, "StorageClassManifest",
292+
{
293+
cluster: cluster,
294+
manifest: [storage_class_gp3_manifest],
295+
overwrite: true,
296+
prune: true,
297+
}
298+
);
299+
storage_class_gp3_construct.node.addDependency(cluster.awsAuth);
271300
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
272301

273302
// v-- most won't need this, disabling by default

lib/Easy_EKS.ts

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,8 @@ export class Easy_EKS{ //purposefully don't extend stack, to implement builder p
239239
// this.config.kmsKeyAlias, {description: "Easy EKS generated kms key, used to encrypt etcd and ebs-csi-driver provisioned volumes"}
240240
// ));}
241241
// else { eksBlueprint.resourceProvider(blueprints.GlobalResources.KmsKey, new blueprints.LookupKmsKeyProvider(this.config.kmsKeyAlias)); }
242-
ensure_existance_of_aliased_kms_key(this.config.kmsKeyAlias);
243-
const kms_key = kms.Key.fromLookup(this.stack, 'pre-existing-kms-key', { aliasName: this.config.kmsKeyAlias });
244-
242+
ensure_existance_of_aliased_kms_key(this.config.kmsKeyAlias, this.stack.stackName, this.stack.region);
243+
const kms_key = this.config.kmsKey;
245244
this.cluster = new eks.Cluster(this.stack, this.config.id, {
246245
clusterName: this.config.id,
247246
version: this.config.kubernetesVersion,
@@ -632,7 +631,7 @@ const enhanced_viewer_cr = {
632631
}
633632
///////////////////////////////////////////////////////////////////////////////////////////////////
634633

635-
function ensure_existance_of_aliased_kms_key(kmsKeyAlias: string){
634+
function ensure_existance_of_aliased_kms_key(kmsKeyAlias: string, stackName: string, region: string){
636635
/*UX Improvement: By default EKS Blueprint will make new KMS key everytime you make a cluster.
637636
This logic checks for pre-existing keys, and prefers to reuse them. Else create if needed, reuse next time.
638637
The intent is to achieve the following EasyEKS default: (which is overrideable):
@@ -641,15 +640,69 @@ function ensure_existance_of_aliased_kms_key(kmsKeyAlias: string){
641640
* prod envs share a kms key: "alias/eks/prod"
642641
*/
643642
let kms_key:kms.Key;
644-
const cmd = `aws kms list-aliases | jq '.Aliases[] | select(.AliasName == "${kmsKeyAlias}") | .TargetKeyId'`
643+
const cmd = `aws kms list-aliases --region ${region} | jq '.Aliases[] | select(.AliasName == "${kmsKeyAlias}") | .TargetKeyId'`
645644
const cmd_results = execSync(cmd).toString();
645+
let key_id = "";
646646
if(cmd_results===""){ //if alias not found, then make a kms key with the alias
647-
const create_key_cmd = `aws kms create-key --description="Easy EKS generated kms key, used to encrypt etcd and ebs-csi-driver provisioned volumes"`
647+
const create_key_cmd = `aws kms create-key --region ${region} --description="Easy EKS generated kms key, used to encrypt etcd and ebs-csi-driver provisioned volumes"`
648648
const results = JSON.parse( execSync(create_key_cmd).toString() );
649-
const key_id = results.KeyMetadata.KeyId;
650-
const add_alias_cmd = `aws kms create-alias --alias-name ${kmsKeyAlias} --target-key-id ${key_id}`;
649+
key_id = results.KeyMetadata.KeyId;
650+
const add_alias_cmd = `aws kms create-alias --alias-name ${kmsKeyAlias} --target-key-id ${key_id} --region ${region}`;
651651
execSync(add_alias_cmd);
652+
//get the ebs csi role, so it can be used to add permissions to the new key
652653
}
654+
// disabled for now, as we need to test that it assigns the permissions correctly before enable customer eks
655+
// for encription.
656+
//else { //if alias found, then get the key id
657+
// key_id = cmd_results.replace(/"/g, ''); //remove quotes from string
658+
//}
659+
//give_kms_access_to_ebs_csi_role(stackName, region, key_id);
660+
653661
}
654662

663+
664+
/*function give_kms_access_to_ebs_csi_role(stackName: string, region: string, KeyId: string){
665+
const roleName = stackName + '-awsebscsidriveriamrole';
666+
const cdm_list_ebs_csi_role = `aws iam list-roles --query "Roles[?contains(RoleName, '${roleName}')].Arn" --output text`;
667+
const list_roles = execSync(cdm_list_ebs_csi_role);
668+
if (list_roles.toString() !== '') {
669+
const policy = `{
670+
"Version": "2012-10-17",
671+
"Id": "key-default-1",
672+
"Statement": [
673+
{
674+
"Sid": "Enable IAM User Permissions",
675+
"Effect": "Allow",
676+
"Principal": {
677+
"AWS": "arn:aws:iam::381492072749:root"
678+
},
679+
"Action": "kms:*",
680+
"Resource": "*"
681+
},
682+
{
683+
"Sid": "Enable IAM User Permissions",
684+
"Effect": "Allow",
685+
"Principal": {
686+
"AWS": "${list_roles.toString().trim()}"
687+
},
688+
"Action": [
689+
"kms:Encrypt",
690+
"kms:Decrypt",
691+
"kms:ReEncrypt*",
692+
"kms:GenerateDataKey*",
693+
"kms:DescribeKey",
694+
"kms:CreateGrant",
695+
"kms:ListGrants",
696+
"kms:RevokeGrant"
697+
],
698+
"Resource": "*"
699+
}
700+
]
701+
}`;
702+
const cmp_policy = `aws kms put-key-policy --policy-name default --key-id ${KeyId.trim()} --region ${region} --policy '${policy}'`;
703+
execSync(cmp_policy);
704+
} else {
705+
console.log(`EBS CSI Role with name: ${roleName} already exists.`);
706+
}
707+
}*/
655708
///////////////////////////////////////////////////////////////////////////////////////////////////

lib/Easy_EKS_Config_Data.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as cdk from 'aws-cdk-lib';
33
import * as eks from 'aws-cdk-lib/aws-eks';
44
import * as ec2 from 'aws-cdk-lib/aws-ec2';
55
import * as iam from 'aws-cdk-lib/aws-iam';
6+
import * as kms from 'aws-cdk-lib/aws-kms';
67
import { execSync } from 'child_process';
78
import { validateTag } from './Utilities';
89

@@ -23,6 +24,7 @@ export class Easy_EKS_Config_Data { //This object just holds config data.
2324
clusterAdminAccessEksApiArns?: string[];
2425
clusterViewerAccessAwsAuthConfigmapAccounts?: string[]; //only aws-auth configmap supports accounts
2526
kmsKeyAlias: string; //kms key with this alias will be created or reused if pre-existing
27+
kmsKey: kms.IKey; //store pre-existing KMS key
2628
baselineNodesNumber: number;
2729
baselineNodesType: eks.CapacityType; //enum eks.CapacityType.SPOT or eks.CapacityType.ON_DEMAND
2830
workerNodeRole: iam.Role; //used by baselineMNG & Karpenter
@@ -119,5 +121,7 @@ export class Easy_EKS_Config_Data { //This object just holds config data.
119121
if(kms_key_alias.startsWith('alias/')){ this.kmsKeyAlias = kms_key_alias; }
120122
else{ this.kmsKeyAlias = `alias/${kms_key_alias}`; }
121123
}
122-
124+
setKmsKey(stack: cdk.Stack){
125+
this.kmsKey = kms.Key.fromLookup(stack, 'pre-existing-kms-key', { aliasName: this.kmsKeyAlias });
126+
}
123127
}//end of Easy_EKS_Config_Data

0 commit comments

Comments
 (0)