diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..12911c9 --- /dev/null +++ b/README.md @@ -0,0 +1,185 @@ +

+ + +

+ Terraform AWS KMS +

+ +

+ This terraform module creates a KMS Customer Master Key (CMK) and its alias. +

+ +

+ + + Terraform + + + Licence + + + +

+

+ + + + + + + + + + + +

+
+## Prerequisites + +This module has a few dependencies: + +- [Terraform 0.13](https://learn.hashicorp.com/terraform/getting-started/install.html) +- [Go](https://golang.org/doc/install) +- [github.com/stretchr/testify/assert](https://github.com/stretchr/testify) +- [github.com/gruntwork-io/terratest/modules/terraform](https://github.com/gruntwork-io/terratest) + +## Examples + + +**IMPORTANT:** Since the `master` branch used in `source` varies based on new modifications, we suggest that you use the release versions [here](https://github.com/devops4mecode/terraform-aws-kms/releases). + + +### Simple Example +Here is an example of how you can use this module in your inventory structure: +```hcl + module "kms_key" { + source = "devops4mecode/kms/aws" + version = "0.13.0" + name = "kms" + application = "devops4me" + environment = "test" + label_order = ["environment", "application", "name"] + enabled = true + description = "KMS key for cloudtrail" + deletion_window_in_days = 7 + enable_key_rotation = true + alias = "alias/cloudtrail" + policy = data.aws_iam_policy_document.default.json + } + + data "aws_iam_policy_document" "default" { + version = "2012-10-17" + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = ["kms:*"] + resources = ["*"] + } + statement { + sid = "Allow CloudTrail to encrypt logs" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = ["kms:GenerateDataKey*"] + resources = ["*"] + condition { + test = "StringLike" + variable = "kms:EncryptionContext:aws:cloudtrail:arn" + values = ["arn:aws:cloudtrail:*:XXXXXXXXXXXX:trail/*"] + } + } + + statement { + sid = "Allow CloudTrail to describe key" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = ["kms:DescribeKey"] + resources = ["*"] + } + + statement { + sid = "Allow principals in the account to decrypt log files" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Decrypt", + "kms:ReEncryptFrom" + ] + resources = ["*"] + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = [ + "XXXXXXXXXXXX"] + } + condition { + test = "StringLike" + variable = "kms:EncryptionContext:aws:cloudtrail:arn" + values = ["arn:aws:cloudtrail:*:XXXXXXXXXXXX:trail/*"] + } + } + + statement { + sid = "Allow alias creation during setup" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = ["kms:CreateAlias"] + resources = ["*"] + } + } + +``` + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| alias | The display name of the alias. The name must start with the word `alias` followed by a forward slash. | `string` | `""` | no | +| application | Application (e.g. `do4m` or `devops4me`). | `string` | `""` | no | +| attributes | Additional attributes (e.g. `1`). | `list(string)` | `[]` | no | +| customer\_master\_key\_spec | Specifies whether the key contains a symmetric key or an asymmetric key pair and the encryption algorithms or signing algorithms that the key supports. Valid values: SYMMETRIC\_DEFAULT, RSA\_2048, RSA\_3072, RSA\_4096, ECC\_NIST\_P256, ECC\_NIST\_P384, ECC\_NIST\_P521, or ECC\_SECG\_P256K1. Defaults to SYMMETRIC\_DEFAULT. | `string` | `"SYMMETRIC_DEFAULT"` | no | +| deletion\_window\_in\_days | Duration in days after which the key is deleted after destruction of the resource. | `number` | `10` | no | +| description | The description of the key as viewed in AWS console. | `string` | `"Parameter Store KMS master key"` | no | +| enable\_key\_rotation | Specifies whether key rotation is enabled. | `bool` | `true` | no | +| enabled | Specifies whether the kms is enabled or disabled. | `bool` | `true` | no | +| environment | Environment (e.g. `prod`, `dev`, `staging`). | `string` | `""` | no | +| is\_enabled | Specifies whether the key is enabled. | `bool` | `true` | no | +| key\_usage | Specifies the intended use of the key. Defaults to ENCRYPT\_DECRYPT, and only symmetric encryption and decryption are supported. | `string` | `"ENCRYPT_DECRYPT"` | no | +| label\_order | label order, e.g. `name`,`application`. | `list` | `[]` | no | +| managedby | ManagedBy, eg 'DevOps4Me' or 'NajibRadzuan'. | `string` | `"najibradzuan@devops4me.com"` | no | +| name | Name (e.g. `app` or `cluster`). | `string` | `""` | no | +| policy | A valid policy JSON document. For more information about building AWS IAM policy documents with Terraform. | `string` | `""` | no | +| tags | Additional tags (e.g. map(`BusinessUnit`,`XYZ`). | `map(string)` | `{}` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| alias\_arn | Alias ARN. | +| alias\_name | Alias name. | +| key\_arn | Key ARN. | +| key\_id | Key ID. | +| tags | A mapping of tags to assign to the resource. | + +## Testing +In this module testing is performed with [terratest](https://github.com/gruntwork-io/terratest) and it creates a small piece of infrastructure, matches the output like ARN, ID and Tags name etc and destroy infrastructure in your AWS account. This testing is written in GO, so you need a [GO environment](https://golang.org/doc/install) in your system. + +You need to run the following command in the testing folder: +```hcl + go test -run Test +``` \ No newline at end of file diff --git a/gorun/kms.tf b/gorun/kms.tf new file mode 100644 index 0000000..9b0325d --- /dev/null +++ b/gorun/kms.tf @@ -0,0 +1,95 @@ +provider "aws" { + region = "ap-southeast-1" +} + +module "kms_key" { + source = "./../" + + name = "kms" + application = "devops4me" + environment = "test" + label_order = ["environment", "application", "name"] + enabled = true + + description = "KMS key for cloudtrail" + deletion_window_in_days = 7 + enable_key_rotation = true + alias = "alias/cloudtrail_Name" + policy = data.aws_iam_policy_document.default.json +} + +data "aws_iam_policy_document" "default" { + version = "2012-10-17" + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = ["kms:*"] + resources = ["*"] + } + statement { + sid = "Allow CloudTrail to encrypt logs" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = ["kms:GenerateDataKey*"] + resources = ["*"] + condition { + test = "StringLike" + variable = "kms:EncryptionContext:aws:cloudtrail:arn" + values = ["arn:aws:cloudtrail:*:XXXXXXXXXXXX:trail/*"] + } + } + + statement { + sid = "Allow CloudTrail to describe key" + effect = "Allow" + principals { + type = "Service" + identifiers = ["cloudtrail.amazonaws.com"] + } + actions = ["kms:DescribeKey"] + resources = ["*"] + } + + statement { + sid = "Allow principals in the account to decrypt log files" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = [ + "kms:Decrypt", + "kms:ReEncryptFrom" + ] + resources = ["*"] + condition { + test = "StringEquals" + variable = "kms:CallerAccount" + values = [ + "XXXXXXXXXXXX"] + } + condition { + test = "StringLike" + variable = "kms:EncryptionContext:aws:cloudtrail:arn" + values = ["arn:aws:cloudtrail:*:XXXXXXXXXXXX:trail/*"] + } + } + + statement { + sid = "Allow alias creation during setup" + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + actions = ["kms:CreateAlias"] + resources = ["*"] + } +} \ No newline at end of file diff --git a/gorun/output.tf b/gorun/output.tf new file mode 100644 index 0000000..10cd3ac --- /dev/null +++ b/gorun/output.tf @@ -0,0 +1,9 @@ +output "key_arn" { + value = module.kms_key.key_arn + description = "Key ARN." +} + +output "tags" { + value = module.kms_key.tags + description = "A mapping of tags to assign to the KMS." +} \ No newline at end of file diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..b67d3e5 --- /dev/null +++ b/main.tf @@ -0,0 +1,39 @@ +## Managed By : DevOps4Me +# Description : This Script is used to create Cloudfront CDN on AWS. +## Copyright @ DevOps4Me. All Right Reserved. + +#Module : label +#Description : This terraform module is designed to generate consistent label names and tags +# for resources. You can use terraform-labels to implement a strict naming +# convention. +module "labels" { +source = "git::https://gitlab.com/devops4me-automation/terraform-label.git" + + name = var.name + application = var.application + environment = var.environment + managedby = var.managedby + label_order = var.label_order +} + +# Module : KMS KEY +# Description : This terraform module creates a KMS Customer Master Key (CMK) and its alias. +resource "aws_kms_key" "default" { + count = var.enabled ? 1 : 0 + description = var.description + key_usage = var.key_usage + deletion_window_in_days = var.deletion_window_in_days + is_enabled = var.is_enabled + enable_key_rotation = var.enable_key_rotation + customer_master_key_spec = var.customer_master_key_spec + policy = var.policy + tags = module.labels.tags +} + +# Module : KMS ALIAS +# Description : Provides an alias for a KMS customer master key.. +resource "aws_kms_alias" "default" { + count = var.enabled ? 1 : 0 + name = coalesce(var.alias, format("alias/%v", module.labels.id)) + target_key_id = join("", aws_kms_key.default.*.id) +} \ No newline at end of file diff --git a/output.tf b/output.tf new file mode 100644 index 0000000..ff71878 --- /dev/null +++ b/output.tf @@ -0,0 +1,26 @@ +# Module : KMS KEY +# Description : This terraform module creates a KMS Customer Master Key (CMK) and its alias. +output "key_arn" { + value = join("", aws_kms_key.default.*.arn) + description = "Key ARN." +} + +output "key_id" { + value = join("", aws_kms_key.default.*.key_id) + description = "Key ID." +} + +output "alias_arn" { + value = join("", aws_kms_alias.default.*.arn) + description = "Alias ARN." +} + +output "alias_name" { + value = join("", aws_kms_alias.default.*.name) + description = "Alias name." +} + +output "tags" { + value = module.labels.tags + description = "A mapping of tags to assign to the resource." +} \ No newline at end of file diff --git a/test/go.mod b/test/go.mod new file mode 100644 index 0000000..ada19cb --- /dev/null +++ b/test/go.mod @@ -0,0 +1,8 @@ +module github.com/devops4mecode/terraform-aws-kms + +go 1.13 + +require ( + github.com/gruntwork-io/terratest v0.30.6 + github.com/stretchr/testify v1.6.1 +) diff --git a/test/kms_test.go b/test/kms_test.go new file mode 100644 index 0000000..6231e17 --- /dev/null +++ b/test/kms_test.go @@ -0,0 +1,34 @@ +// Managed By : DevOps4Me +// Description : This Terratest is used to test the Terraform VPC module. +// Copyright @ DevOps4Me. All Right Reserved. + +package test + +import ( + "testing" + + "github.com/gruntwork-io/terratest/modules/terraform" + "github.com/stretchr/testify/assert" +) + +func Test(t *testing.T) { + t.Parallel() + + terraformOptions := &terraform.Options{ + // Source path of Terraform directory. + TerraformDir: "../gorun", + } + + // This will run `terraform init` and `terraform apply` and fail the test if there are any errors + terraform.InitAndApply(t, terraformOptions) + + // To clean up any resources that have been created, run 'terraform destroy' towards the end of the test + defer terraform.Destroy(t, terraformOptions) + + // To get the value of an output variable, run 'terraform output' + keyArn := terraform.Output(t, terraformOptions, "key_arn") + Tags := terraform.OutputMap(t, terraformOptions, "tags") + + // Check that we get back the outputs that we expect + assert.Contains(t, keyArn, "arn:aws:kms") + assert.Equal(t, "test-devops4me-kms", Tags["Name"]) diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..28986ec --- /dev/null +++ b/variables.tf @@ -0,0 +1,99 @@ +#Module : LABEL +#Description : Terraform label module variables. +variable "name" { + type = string + default = "" + description = "Name (e.g. `app` or `cluster`)." +} + +variable "application" { + type = string + default = "" + description = "Application (e.g. `do4m` or `devops4me`)." +} + +variable "environment" { + type = string + default = "" + description = "Environment (e.g. `prod`, `dev`, `staging`)." +} + +variable "label_order" { + type = list + default = [] + description = "label order, e.g. `name`,`application`." +} + +variable "attributes" { + type = list(string) + default = [] + description = "Additional attributes (e.g. `1`)." +} + +variable "tags" { + type = map(string) + default = {} + description = "Additional tags (e.g. map(`BusinessUnit`,`XYZ`)." +} + +variable "managedby" { + type = string + default = "najibradzuan@devops4me.com" + description = "ManagedBy, eg 'DevOps4Me' or 'NajibRadzuan'." +} + +# Module : KMS KEY +# Description : Provides a KMS customer master key. +variable "deletion_window_in_days" { + type = number + default = 10 + description = "Duration in days after which the key is deleted after destruction of the resource." +} + +variable "enable_key_rotation" { + type = bool + default = true + description = "Specifies whether key rotation is enabled." +} + +variable "description" { + type = string + default = "Parameter Store KMS master key" + description = "The description of the key as viewed in AWS console." +} + +variable "is_enabled" { + type = bool + default = true + description = "Specifies whether the key is enabled." +} + +variable "enabled" { + type = bool + default = true + description = "Specifies whether the kms is enabled or disabled." +} + +variable "key_usage" { + type = string + default = "ENCRYPT_DECRYPT" + description = "Specifies the intended use of the key. Defaults to ENCRYPT_DECRYPT, and only symmetric encryption and decryption are supported." +} + +variable "alias" { + type = string + default = "" + description = "The display name of the alias. The name must start with the word `alias` followed by a forward slash." +} + +variable "policy" { + type = string + default = "" + description = "A valid policy JSON document. For more information about building AWS IAM policy documents with Terraform." +} + +variable "customer_master_key_spec" { + type = string + default = "SYMMETRIC_DEFAULT" + description = "Specifies whether the key contains a symmetric key or an asymmetric key pair and the encryption algorithms or signing algorithms that the key supports. Valid values: SYMMETRIC_DEFAULT, RSA_2048, RSA_3072, RSA_4096, ECC_NIST_P256, ECC_NIST_P384, ECC_NIST_P521, or ECC_SECG_P256K1. Defaults to SYMMETRIC_DEFAULT." +} \ No newline at end of file diff --git a/version.tf b/version.tf new file mode 100644 index 0000000..5587ad2 --- /dev/null +++ b/version.tf @@ -0,0 +1,9 @@ +# Terraform version +terraform { + required_version = ">= 0.12.0, < 0.14.0" + required_providers { + aws = { + source = "hashicorp/aws" + } + } +}