├── .gitignore ├── .npmrc ├── README.md ├── cdktf.json ├── help ├── jest.config.js ├── main.ts ├── package-lock.json ├── package.json ├── setup.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.d.ts 2 | *.js 3 | node_modules 4 | cdktf.out 5 | cdktf.log 6 | *terraform.*.tfstate* 7 | .gen 8 | .terraform 9 | tsconfig.tsbuildinfo 10 | !jest.config.js 11 | !setup.js -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | * Explore the Terraform for Terraform [CLI](https://www.terraform.io/downloads.html) >= v1.0+ 4 | * Explore the Nodejs for npm [CLI](https://nodejs.org/en/) >= v14+ 5 | * Explore the Yarn for Yarn [CLI](https://classic.yarnpkg.com/en/docs/install#debian-stable) >= v1.21 (optional - NPM will work as an alternative) 6 | * Explore the CDK for cdktf [CLI](https://github.com/hashicorp/terraform-cdk#build) 7 | 8 | 9 | Add your AWS credentials as two environment variables, AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY, replacing AAAAAA with each respective values. 10 | ```shell 11 | $ export AWS_ACCESS_KEY_ID=AAAAAA 12 | $ export AWS_SECRET_ACCESS_KEY=AAAAA 13 | ``` 14 | 15 | # typescript-aws-kms 16 | 17 | A CDK for Terraform application in TypeScript for kms configuraiton. 18 | 19 | ## Usage 20 | 21 | Install project dependencies 22 | 23 | ```shell 24 | yarn install 25 | ``` 26 | 27 | Generate CDK for Terraform constructs for Terraform provides and modules used in the project. 28 | 29 | ```bash 30 | cdktf get 31 | ``` 32 | 33 | You can now edit the `main.ts` file if you want to modify any code. 34 | 35 | ```typescript 36 | vim main.ts 37 | import { Construct } from "constructs"; 38 | import { App, TerraformStack, TerraformOutput } from "cdktf"; 39 | import { 40 | AwsProvider, 41 | datasources, 42 | kms 43 | } from "./.gen/providers/aws/"; 44 | 45 | class MyStack extends TerraformStack { 46 | constructor(scope: Construct, name: string) { 47 | super(scope, name); 48 | 49 | let ENV: string = "Devops"; 50 | let COMPANY: string = "yourCompany"; 51 | 52 | new AwsProvider(this, "Aws_provider", { 53 | region: "us-east-1", 54 | }); 55 | 56 | const awsAccountid = new datasources.DataAwsCallerIdentity(this, "aws_id", {}); 57 | 58 | const awskmsKey = new kms.KmsKey(this, "Aws_kms", { 59 | description: "Create KMS encryption for creating encryption on volume", 60 | enableKeyRotation: true, 61 | policy: `{ 62 | "Version": "2012-10-17", 63 | "Statement": [ 64 | { 65 | "Sid": "Enable IAM User Permissions", 66 | "Effect": "Allow", 67 | "Principal": { 68 | "AWS": "arn:aws:iam::${awsAccountid.id}:root" 69 | }, 70 | "Action": [ 71 | "kms:*" 72 | ], 73 | "Resource": [ 74 | "*" 75 | ] 76 | }, { 77 | "Sid": "Allow autoscalling to use the key", 78 | "Effect": "Allow", 79 | "Principal": { 80 | "AWS": [ 81 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 82 | ] 83 | }, 84 | "Action": [ 85 | "kms:Create*", 86 | "kms:Describe*", 87 | "kms:Enable*", 88 | "kms:List*", 89 | "kms:Put*", 90 | "kms:Update*", 91 | "kms:Revoke*", 92 | "kms:Disable*", 93 | "kms:Get*", 94 | "kms:Delete*", 95 | "kms:TagResource", 96 | "kms:UntagResource", 97 | "kms:ScheduleKeyDeletion", 98 | "kms:CancelKeyDeletion" 99 | ], 100 | "Resource": "*" 101 | },{ 102 | "Sid": "Allow use of the key", 103 | "Effect": "Allow", 104 | "Principal": { 105 | "AWS": [ 106 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 107 | ] 108 | }, 109 | "Action": [ 110 | "kms:Encrypt", 111 | "kms:Decrypt", 112 | "kms:ReEncrypt*", 113 | "kms:GenerateDataKey*", 114 | "kms:DescribeKey" 115 | ], 116 | "Resource": "*" 117 | }, { 118 | "Sid": "Allow attachment of persistent resources", 119 | "Effect": "Allow", 120 | "Principal": { 121 | "AWS": [ 122 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 123 | ] 124 | }, 125 | "Action": [ 126 | "kms:CreateGrant", 127 | "kms:ListGrants", 128 | "kms:RevokeGrant" 129 | ], 130 | "Resource": "*", 131 | "Condition": { 132 | "Bool": { 133 | "kms:GrantIsForAWSResource": "true" 134 | } 135 | } 136 | } 137 | ] 138 | }`, 139 | tags: { 140 | Name: "CDKtf-TypeScript-Demo-KMS-key", 141 | Team: `${ENV}`, 142 | Company: `${COMPANY}`, 143 | }, 144 | }); 145 | 146 | new kms.KmsAlias(this, "Aws_kms_alies", { 147 | name: `alias/${ENV}`, 148 | targetKeyId: awskmsKey.id, 149 | }); 150 | 151 | new TerraformOutput(this, "Aws_Kms_id", { 152 | value: awskmsKey.id, 153 | }); 154 | } 155 | } 156 | 157 | const app = new App(); 158 | new MyStack(app, "cdktf-typescript-aws-kms"); 159 | app.synth(); 160 | ``` 161 | 162 | Compile the TypeScript application 163 | 164 | ```bash 165 | tsc 166 | ``` 167 | At this step you can run code with two different way: 168 | 169 | # The first way: 170 | 171 | Generate Terraform configuration 172 | 173 | ```bash 174 | cdktf synth 175 | ``` 176 | 177 | The above command will create a folder called `cdktf.out` that contains all Terraform JSON configuration that was generated. 178 | 179 | Run Terraform commands 180 | 181 | ```bash 182 | cd cdktf.out 183 | terraform init 184 | terraform plan 185 | terraform apply 186 | ``` 187 | 188 | # The second way: 189 | 190 | Run cdktf commands 191 | 192 | ```bash 193 | cdktf deploy 194 | ``` 195 | -------------------------------------------------------------------------------- /cdktf.json: -------------------------------------------------------------------------------- 1 | { 2 | "language": "typescript", 3 | "app": "npx ts-node main.ts", 4 | "projectId": "74a6ca56-b96b-48de-a831-8c1dcff6a675", 5 | "terraformProviders": [ 6 | "aws@~>3.29.0" 7 | ], 8 | "terraformModules": [], 9 | "context": { 10 | "excludeStackIdFromLogicalIds": "true", 11 | "allowSepCharsInLogicalIds": "true" 12 | } 13 | } -------------------------------------------------------------------------------- /help: -------------------------------------------------------------------------------- 1 | ======================================================================================================== 2 | 3 | Your cdktf typescript project is ready! 4 | 5 | cat help Print this message 6 | 7 | Compile: 8 | npm run get Import/update Terraform providers and modules (you should check-in this directory) 9 | npm run compile Compile typescript code to javascript (or "npm run watch") 10 | npm run watch Watch for changes and compile typescript in the background 11 | npm run build Compile typescript 12 | 13 | Synthesize: 14 | cdktf synth [stack] Synthesize Terraform resources from stacks to cdktf.out/ (ready for 'terraform apply') 15 | 16 | Diff: 17 | cdktf diff [stack] Perform a diff (terraform plan) for the given stack 18 | 19 | Deploy: 20 | cdktf deploy [stack] Deploy the given stack 21 | 22 | Destroy: 23 | cdktf destroy [stack] Destroy the stack 24 | 25 | Test: 26 | npm run test Runs unit tests (edit __tests__/main-test.ts to add your own tests) 27 | npm run test:watch Watches the tests and reruns them on change 28 | 29 | Upgrades: 30 | npm run upgrade Upgrade cdktf modules to latest version 31 | npm run upgrade:next Upgrade cdktf modules to latest "@next" version (last commit) 32 | 33 | Use Prebuilt Providers: 34 | 35 | You can find all prebuilt providers on npm: https://www.npmjs.com/search?q=keywords:cdktf 36 | You can install these providers through npm: 37 | 38 | npm install @cdktf/provider-aws 39 | npm install @cdktf/provider-google 40 | npm install @cdktf/provider-azurerm 41 | npm install @cdktf/provider-docker 42 | npm install @cdktf/provider-github 43 | npm install @cdktf/provider-null 44 | 45 | You can also build any module or provider locally. Learn more https://cdk.tf/modules-and-providers 46 | 47 | ======================================================================================================== 48 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest/dist/types').InitialOptionsTsJest} */ 2 | /* 3 | * For a detailed explanation regarding each configuration property, visit: 4 | * https://jestjs.io/docs/configuration 5 | */ 6 | 7 | module.exports = { 8 | 9 | // All imported modules in your tests should be mocked automatically 10 | // automock: false, 11 | 12 | // Stop running tests after `n` failures 13 | // bail: 0, 14 | 15 | // The directory where Jest should store its cached dependency information 16 | // cacheDirectory: "/private/var/folders/z_/v03l33d55fb57nrr3b1q03ch0000gq/T/jest_dz", 17 | 18 | // Automatically clear mock calls and instances between every test 19 | clearMocks: true, 20 | 21 | // Indicates whether the coverage information should be collected while executing the test 22 | // collectCoverage: false, 23 | 24 | // An array of glob patterns indicating a set of files for which coverage information should be collected 25 | // collectCoverageFrom: undefined, 26 | 27 | // The directory where Jest should output its coverage files 28 | // coverageDirectory: undefined, 29 | 30 | // An array of regexp pattern strings used to skip coverage collection 31 | // coveragePathIgnorePatterns: [ 32 | // "/node_modules/" 33 | // ], 34 | 35 | // Indicates which provider should be used to instrument code for coverage 36 | coverageProvider: "v8", 37 | 38 | // A list of reporter names that Jest uses when writing coverage reports 39 | // coverageReporters: [ 40 | // "json", 41 | // "text", 42 | // "lcov", 43 | // "clover" 44 | // ], 45 | 46 | // An object that configures minimum threshold enforcement for coverage results 47 | // coverageThreshold: undefined, 48 | 49 | // A path to a custom dependency extractor 50 | // dependencyExtractor: undefined, 51 | 52 | // Make calling deprecated APIs throw helpful error messages 53 | // errorOnDeprecated: false, 54 | 55 | // Force coverage collection from ignored files using an array of glob patterns 56 | // forceCoverageMatch: [], 57 | 58 | // A path to a module which exports an async function that is triggered once before all test suites 59 | // globalSetup: undefined, 60 | 61 | // A path to a module which exports an async function that is triggered once after all test suites 62 | // globalTeardown: undefined, 63 | 64 | // A set of global variables that need to be available in all test environments 65 | // globals: {}, 66 | 67 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 68 | // maxWorkers: "50%", 69 | 70 | // An array of directory names to be searched recursively up from the requiring module's location 71 | // moduleDirectories: [ 72 | // "node_modules" 73 | // ], 74 | 75 | // An array of file extensions your modules use 76 | moduleFileExtensions: ["ts", "js", "json", "node"], 77 | 78 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 79 | // moduleNameMapper: {}, 80 | 81 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 82 | // modulePathIgnorePatterns: [], 83 | 84 | // Activates notifications for test results 85 | // notify: false, 86 | 87 | // An enum that specifies notification mode. Requires { notify: true } 88 | // notifyMode: "failure-change", 89 | 90 | // A preset that is used as a base for Jest's configuration 91 | preset: "ts-jest", 92 | 93 | // Run tests from one or more projects 94 | // projects: undefined, 95 | 96 | // Use this configuration option to add custom reporters to Jest 97 | // reporters: undefined, 98 | 99 | // Automatically reset mock state between every test 100 | // resetMocks: false, 101 | 102 | // Reset the module registry before running each individual test 103 | // resetModules: false, 104 | 105 | // A path to a custom resolver 106 | // resolver: undefined, 107 | 108 | // Automatically restore mock state between every test 109 | // restoreMocks: false, 110 | 111 | // The root directory that Jest should scan for tests and modules within 112 | // rootDir: undefined, 113 | 114 | // A list of paths to directories that Jest should use to search for files in 115 | // roots: [ 116 | // "" 117 | // ], 118 | 119 | // Allows you to use a custom runner instead of Jest's default test runner 120 | // runner: "jest-runner", 121 | 122 | // The paths to modules that run some code to configure or set up the testing environment before each test 123 | // setupFiles: [], 124 | 125 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 126 | setupFilesAfterEnv: ["/setup.js"], 127 | 128 | // The number of seconds after which a test is considered as slow and reported as such in the results. 129 | // slowTestThreshold: 5, 130 | 131 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 132 | // snapshotSerializers: [], 133 | 134 | // The test environment that will be used for testing 135 | testEnvironment: "node", 136 | 137 | // Options that will be passed to the testEnvironment 138 | // testEnvironmentOptions: {}, 139 | 140 | // Adds a location field to test results 141 | // testLocationInResults: false, 142 | 143 | // The glob patterns Jest uses to detect test files 144 | testMatch: [ 145 | "**/__tests__/**/*.ts", 146 | "**/?(*.)+(spec|test).ts" 147 | ], 148 | 149 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 150 | testPathIgnorePatterns: ["/node_modules/", ".d.ts", ".js"], 151 | 152 | // The regexp pattern or array of patterns that Jest uses to detect test files 153 | // testRegex: [], 154 | 155 | // This option allows the use of a custom results processor 156 | // testResultsProcessor: undefined, 157 | 158 | // This option allows use of a custom test runner 159 | // testRunner: "jest-circus/runner", 160 | 161 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 162 | // testURL: "http://localhost", 163 | 164 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 165 | // timers: "real", 166 | 167 | // A map from regular expressions to paths to transformers 168 | // transform: undefined, 169 | 170 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 171 | // transformIgnorePatterns: [ 172 | // "/node_modules/", 173 | // "\\.pnp\\.[^\\/]+$" 174 | // ], 175 | 176 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 177 | // unmockedModulePathPatterns: undefined, 178 | 179 | // Indicates whether each individual test should be reported during the run 180 | // verbose: undefined, 181 | 182 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 183 | // watchPathIgnorePatterns: [], 184 | 185 | // Whether to use watchman for file crawling 186 | // watchman: true, 187 | }; 188 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { App, TerraformStack, TerraformOutput } from "cdktf"; 3 | import { 4 | AwsProvider, 5 | datasources, 6 | kms 7 | } from "./.gen/providers/aws/"; 8 | 9 | class MyStack extends TerraformStack { 10 | constructor(scope: Construct, name: string) { 11 | super(scope, name); 12 | 13 | let ENV: string = "Devops"; 14 | let COMPANY: string = "yourCompany"; 15 | 16 | new AwsProvider(this, "Aws_provider", { 17 | region: "us-east-1", 18 | }); 19 | 20 | const awsAccountid = new datasources.DataAwsCallerIdentity(this, "aws_id", {}); 21 | 22 | const awskmsKey = new kms.KmsKey(this, "Aws_kms", { 23 | description: "Create KMS encryption for creating encryption on volume", 24 | enableKeyRotation: true, 25 | policy: `{ 26 | "Version": "2012-10-17", 27 | "Statement": [ 28 | { 29 | "Sid": "Enable IAM User Permissions", 30 | "Effect": "Allow", 31 | "Principal": { 32 | "AWS": "arn:aws:iam::${awsAccountid.id}:root" 33 | }, 34 | "Action": [ 35 | "kms:*" 36 | ], 37 | "Resource": [ 38 | "*" 39 | ] 40 | }, { 41 | "Sid": "Allow autoscalling to use the key", 42 | "Effect": "Allow", 43 | "Principal": { 44 | "AWS": [ 45 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 46 | ] 47 | }, 48 | "Action": [ 49 | "kms:Create*", 50 | "kms:Describe*", 51 | "kms:Enable*", 52 | "kms:List*", 53 | "kms:Put*", 54 | "kms:Update*", 55 | "kms:Revoke*", 56 | "kms:Disable*", 57 | "kms:Get*", 58 | "kms:Delete*", 59 | "kms:TagResource", 60 | "kms:UntagResource", 61 | "kms:ScheduleKeyDeletion", 62 | "kms:CancelKeyDeletion" 63 | ], 64 | "Resource": "*" 65 | },{ 66 | "Sid": "Allow use of the key", 67 | "Effect": "Allow", 68 | "Principal": { 69 | "AWS": [ 70 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 71 | ] 72 | }, 73 | "Action": [ 74 | "kms:Encrypt", 75 | "kms:Decrypt", 76 | "kms:ReEncrypt*", 77 | "kms:GenerateDataKey*", 78 | "kms:DescribeKey" 79 | ], 80 | "Resource": "*" 81 | }, { 82 | "Sid": "Allow attachment of persistent resources", 83 | "Effect": "Allow", 84 | "Principal": { 85 | "AWS": [ 86 | "arn:aws:iam::${awsAccountid.id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling" 87 | ] 88 | }, 89 | "Action": [ 90 | "kms:CreateGrant", 91 | "kms:ListGrants", 92 | "kms:RevokeGrant" 93 | ], 94 | "Resource": "*", 95 | "Condition": { 96 | "Bool": { 97 | "kms:GrantIsForAWSResource": "true" 98 | } 99 | } 100 | } 101 | ] 102 | }`, 103 | tags: { 104 | Name: "CDKtf-TypeScript-Demo-KMS-key", 105 | Team: `${ENV}`, 106 | Company: `${COMPANY}`, 107 | }, 108 | }); 109 | 110 | new kms.KmsAlias(this, "Aws_kms_alies", { 111 | name: `alias/${ENV}`, 112 | targetKeyId: awskmsKey.id, 113 | }); 114 | 115 | new TerraformOutput(this, "Aws_Kms_id", { 116 | value: awskmsKey.id, 117 | }); 118 | } 119 | } 120 | 121 | const app = new App(); 122 | new MyStack(app, "cdktf-typescript-aws-kms"); 123 | app.synth(); 124 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdktf-typescript-aws-kms", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "types": "main.ts", 6 | "license": "MPL-2.0", 7 | "private": true, 8 | "scripts": { 9 | "get": "cdktf get", 10 | "build": "tsc", 11 | "synth": "cdktf synth", 12 | "compile": "tsc --pretty", 13 | "watch": "tsc -w", 14 | "test": "jest", 15 | "test:watch": "jest --watch", 16 | "upgrade": "npm i cdktf@latest cdktf-cli@latest", 17 | "upgrade:next": "npm i cdktf@next cdktf-cli@next" 18 | }, 19 | "engines": { 20 | "node": ">=14.0" 21 | }, 22 | "dependencies": { 23 | "cdktf": "^0.9.4", 24 | "constructs": "^10.0.82" 25 | }, 26 | "devDependencies": { 27 | "@types/jest": "^27.4.1", 28 | "@types/node": "^17.0.21", 29 | "jest": "^27.5.1", 30 | "ts-jest": "^27.1.3", 31 | "ts-node": "^10.7.0", 32 | "typescript": "^4.6.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | const cdktf = require("cdktf"); 2 | cdktf.Testing.setupJest(); 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "alwaysStrict": true, 4 | "charset": "utf8", 5 | "declaration": true, 6 | "experimentalDecorators": true, 7 | "inlineSourceMap": true, 8 | "inlineSources": true, 9 | "lib": [ 10 | "es2018" 11 | ], 12 | "module": "CommonJS", 13 | "noEmitOnError": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "noImplicitAny": true, 16 | "noImplicitReturns": true, 17 | "noImplicitThis": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "resolveJsonModule": true, 21 | "strict": true, 22 | "strictNullChecks": true, 23 | "strictPropertyInitialization": true, 24 | "stripInternal": true, 25 | "target": "ES2018", 26 | "incremental": true 27 | }, 28 | "include": [ 29 | "**/*.ts" 30 | ], 31 | "exclude": [ 32 | "node_modules", 33 | "cdktf.out" 34 | ] 35 | } --------------------------------------------------------------------------------