There are two types of KMS keys:
- AWS Managed Key (AMK)
- Customer Managed Key (CMK):
- Only CMKs are permitted
- CMKs CANNOT DELETE via Self-Serve Stack Deletion Feature
- CMKs can ONLY be deleted through ServiceNow Portal
- Service Catalog: Cloud Services - Stack Update/Deletion Request
- can “borrow” Cloud Engineering CMKs, for example, BMO-SBX-USE1-{S3, Aurora, RDS, EFS, DMS, SES, EBS…..} for simple use cases
How to “borrow” Cloud Engineering CMKs? For example,
- Login to BMO AWS Portal
- Select BMO Sandbox (520049198415), us-east-1 region
- Opts for Key Management Service (KMS) from the AWS console
- Select Customer managed keys (CMKs) from the left navigation pane
- Search: BMO-SBX-USE1 and pick the CMK we like want to use
- BMO-SBX-USE1-S3
- BMO-SBX-USE1-Aurora
- BMO-SBX-USE1-RDS
- BMO-SBX-USE1-EFS
- BMO-SBX-USE1-DMS
- BMO-SBX-USE1-SES
- BMO-SBX-USE1-EBS etc etc
- Search: BMO-SBX-USE1 and pick the CMK we like want to use
- Select Customer managed keys (CMKs) from the left navigation pane
- Opts for Key Management Service (KMS) from the AWS console
To deploy our own CMK:
kaau@OCLT71159526 ~/myproj/EPRE_NACB_DB_Deployment_and_Support_87735 (epre-nacb-db-deployment-and-support-kms)$ tree .
.
├── build.sh
├── infra
│ ├── bin
│ │ └── infra.ts
│ ├── cdk.json
│ ├── cdk.out
│ ├── config
│ │ └── index.ts
│ ├── controller.json
│ ├── lib
│ │ └── epre-nacb-db-deployment-and-support-kms-stack.ts
│ ├── node_modules
│ ├── package.json
│ └── tsconfig.json
├── readme.md
└── service
infra/package.json
[[blue:{]]
[[blue: "name": "infra",]]
[[blue: "version": "0.1.0",]]
[[blue: "bin": {]]
[[blue: "infra": "bin/infra.js"]]
[[blue: },]]
[[blue: "scripts": {]]
[[blue: "build": "tsc",]]
[[blue: "watch": "tsc -w",]]
[[blue: "test": "jest",]]
[[blue: "cdk": "cdk"]]
[[blue: },]]
[[blue: "devDependencies": {]]
[[blue: "@types/jest": "^26.0.24",]]
[[blue: "@types/node": "^26.1.1",]]
[[blue: "aws-cdk-lib": "^2.261.0",]]
[[blue: "jest": "^26.6.3",]]
[[blue: "ts-jest": "^26.5.6",]]
[[blue: "ts-node": "^10.9.2",]]
[[blue: "typescript": "^6.0.3"]]
[[blue: },]]
[[blue: "dependencies": {]]
[[blue: "@bmo-cdk/common": "^11.0.0",]]
[[blue: "@bmo-cdk/kms": "^11.0.0",]]
[[blue: "constructs": "^10.7.0",]]
[[blue: "source-map-support": "^0.5.21"]]
[[blue: }]]
[[blue:}]]
infra/tsconfig.json
[[blue:{]]
[[blue:"compilerOptions": {]]
[[blue: "target": "ES2023",]]
[[blue: "module": "commonjs",]]
[[blue: "lib": ["ES2023"]]]
[[blue: "skipLibCheck": true,]]
[[blue: "declaration": true,]]
[[blue: "strict": true,]]
[[blue: "noImplicitAny": true,]]
[[blue: "strictNullChecks": true,]]
[[blue: "noImplicitThis": true,]]
[[blue: "alwaysStrict": true,]]
[[blue: "noUnusedLocals": false,]]
[[blue: "noUnusedParameters": false,]]
[[blue: "noImplicitReturns": true,]]
[[blue: "noFallthroughCasesInSwitch": false,]]
[[blue: "inlineSourceMap": true,]]
[[blue: "inlineSources": true,]]
[[blue: "experimentalDecorators": true,]]
[[blue: "resolveJsonModule": true,]]
[[blue: "strictPropertyInitialization": false,]]
[[blue: "esModuleInterop": true,]]
[[blue: "types": [ "node"],]]
[[blue: "typeRoots": []]
[[blue: "./node_modules/@types"]]
[[blue: ]]]
[[blue: },]]
[[blue: "exclude": []]
[[blue: "node_modules",]]
[[blue: "cdk.out"]]
[[blue: ]]]
[[blue:}]]
infra/controller.json:
[[blue:{]]
[[blue:"stacks": "null"]]
[[blue:[[}]]
infra/config/index.ts
import { configurationHelperFactory } from '@bmo-cdk/common'
import { PurposeCode } from '@bmo-cdk/common/lib/configurationHelper/CommonConfigurationHelperTypes'
export const createBmoCdkHelper = configurationHelperFactory({
appCatId: '87735',
projectName: 'TREONACB', // Alphanumeric only, the project name (e.g., CENG)
serviceName: 'NACBDBDeploymentandSupport', // Alphanumeric and hyphens only
serviceDescription: 'ERRE NACB DB Development and Support',
purposeCode: PurposeCode.DATA_AND_ANALYTICS, // Purpose code of the multi account. Use PurposeCode.NONE for old account.
costCenter: 'H9395',
supportTeam: 'RUN_EPRE_NACB_DBA_Deploy_Support'
})
infra/bin/infra.ts
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { createBmoCdkHelper } from '../config';
import { EpreNacbDbDevelopAndSupportKmsStack } from '../lib/epre-nacb-db-deployment-and-support-kms-stack';
const app = new cdk.App();
const helper = createBmoCdkHelper(app)
const env = {
account: helper.deployment.accountId,
region: helper.deployment.region
}
const stage = process.env.Stage;
var isAccountStage = (stage == "sbx" || stage == "dev") ? true : false;
if (isAccountStage) {
const rdsMonitoringKMSStack = new EpreNacbDbDevelopAndSupportKmsStack(app, "epre-nacb-db-development-and-support-kms-stack", { env })
}
infra/lib/epre-nacb-db-deployment-and-support-kms-stack.ts:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { createBmoCdkHelper } from '../config';
import { BMOKMSConstruct } from '@bmo-cdk/kms';
export class EpreNacbDbDevelopAndSupportKmsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const helper = createBmoCdkHelper(this);
const accountId = helper.deployment.accountId;
const region = helper.deployment.region;
const myKms = new BMOKMSConstruct(this, 'epre-nacb-db-development-and-support-kms-key', {
alias: 'epre-nacb-db-development-and-support-kms-key',
keyType: 'application',
applicationKeyAppCatIdForTagBasedAccess: helper.tags.AppCatID,
description: 'EPRE NACB DB Development and Support KMS key',
enabled: true,
keyUsage: 'ENCRYPT_DECRYPT',
pendingWindowInDaysForDeletion: 7,
keyPolicy: {
"Version": "2012-10-17",
"Id": "EPRE NACB DB Development and Support KMS IAM access roles",
"Statement": [
{
"Sid": "EnableRootAndNacbDbServicesL2SupportTeamPermissions",
"Effect": "Allow",
"Principal": {
"AWS": [
`arn:aws:iam::${accountId}:root`,
`arn:aws:iam::${accountId}:role/aws-reserved/sso.amazonaws.com/ca-central-1/AWSReservedSSO_AWS-NACB-DBServices-L2Support_f580d021a6d473fe`
]
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "AllowAwsServiceUsageViaServiceCondition",
"Effect": "Allow",
"Principal": {
"Service": [
"s3.amazonaws.com",
"lambda.amazonaws.com",
"sns.amazonaws.com",
"sqs.amazonaws.com",
"ec2.amazonaws.com",
"rds.amazonaws.com",
"redshift.amazonaws.com",
"redshift-serverless.amazonaws.com"
]
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:CallerAccount": accountId
},
"StringLike": {
"kms:ViaService": [
`s3.${region}.amazonaws.com`,
`lambda.${region}.amazonaws.com`,
`sns.${region}.amazonaws.com`,
`sqs.${region}.amazonaws.com`,
`ec2.${region}.amazonaws.com`,
`rds.${region}.amazonaws.com`,
`redshift.${region}.amazonaws.com`,
`redshift-serverless.${region}.amazonaws.com`
]
}
}
},
{
"Sid": "AllowCloudWatchLogsUsage",
"Effect": "Allow",
"Principal": {
"Service": `logs.${region}.amazonaws.com`
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"kms:CallerAccount": accountId
}
}
}
]
},
multiRegion: true,
wizScanAccess: true,
tags: {
AppCatID: helper.tags.AppCatID,
Cost_Center: helper.tags.Cost_Center,
Description: helper.tags.Description,
Environment: helper.tags.Environment,
ServiceName: helper.tags.ServiceName,
Stage: helper.tags.Stage,
'Support-Team': helper.tags['Support-Team']
}
});
new cdk.CfnOutput(this, 'EpreNacbDbDevelopmentAndSupportKmsKeyArn', {
value: myKms.kmsKey.attrArn,
description: 'EPRE NACB DB Development and Support KMS key ARN',
exportName: 'epre-nacb-db-development-and-support-kms-key-arn'
});
}
}