From f59fbc375ebd5b50f4e7035c109aa664c80d06a3 Mon Sep 17 00:00:00 2001 From: Himanshu Ahirwar Date: Thu, 10 Aug 2023 22:29:10 +0530 Subject: [PATCH 1/5] feat: added Replica-Key and Replica-External-Key(CMK) --- _example/example.tf | 1 - main.tf | 58 +++++++++++++++++++++++++++++++++++++-------- outputs.tf | 4 ++-- variables.tf | 18 +++++--------- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/_example/example.tf b/_example/example.tf index cddfa03..4051c0a 100644 --- a/_example/example.tf +++ b/_example/example.tf @@ -20,7 +20,6 @@ module "kms_key" { deletion_window_in_days = 7 alias = "alias/cloudtrail_Name" - enabled = true kms_key_enabled = true multi_region = true create_external_enabled = true diff --git a/main.tf b/main.tf index 3f6c38e..4980579 100644 --- a/main.tf +++ b/main.tf @@ -9,6 +9,7 @@ module "labels" { environment = var.environment managedby = var.managedby label_order = var.label_order + attributes = var.attributes } ####---------------------------------------------------------------------------------- @@ -17,15 +18,16 @@ module "labels" { resource "aws_kms_key" "default" { count = var.enabled && var.kms_key_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 - multi_region = var.multi_region - tags = module.labels.tags + 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 + multi_region = var.multi_region + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check + tags = module.labels.tags } ####---------------------------------------------------------------------------------- @@ -46,6 +48,42 @@ resource "aws_kms_external_key" "external" { tags = module.labels.tags } +####---------------------------------------------------------------------------------- +## Replica Key +####---------------------------------------------------------------------------------- + +resource "aws_kms_replica_key" "replica" { + count = var.enabled && var.create_replica_enabled ? 1 : 0 + + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check + deletion_window_in_days = var.deletion_window_in_days + description = var.description + primary_key_arn = var.primary_key_arn + enabled = var.is_enabled + policy = var.policy + + tags = module.labels.tags +} + +####---------------------------------------------------------------------------------- +## Replica External Key +####---------------------------------------------------------------------------------- + +resource "aws_kms_replica_external_key" "replica_external" { + count = var.enabled && var.create_replica_external_enabled ? 1 : 0 + + bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check + deletion_window_in_days = var.deletion_window_in_days + description = var.description + enabled = var.is_enabled + key_material_base64 = var.key_material_base64 + policy = var.policy + primary_key_arn = var.primary_external_key_arn + valid_to = var.valid_to + + tags = module.labels.tags +} + ##---------------------------------------------------------------------------------- ## Provides an alias for a KMS customer master key. ##---------------------------------------------------------------------------------- @@ -53,5 +91,5 @@ 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) + target_key_id = try(aws_kms_key.default[0].key_id, aws_kms_external_key.external[0].id, aws_kms_replica_key.replica[0].key_id, aws_kms_replica_external_key.replica_external[0].key_id) } \ No newline at end of file diff --git a/outputs.tf b/outputs.tf index 6c6483e..cc883bf 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,10 +1,10 @@ output "key_arn" { - value = join("", aws_kms_key.default.*.arn) + value = try(aws_kms_key.default[0].arn, aws_kms_external_key.external[0].arn, aws_kms_replica_key.replica[0].arn, aws_kms_replica_external_key.replica_external[0].arn) description = "Key ARN." } output "key_id" { - value = join("", aws_kms_key.default.*.key_id) + value = try(aws_kms_key.default[0].key_id, aws_kms_external_key.external[0].id, aws_kms_replica_key.replica[0].key_id, aws_kms_replica_external_key.replica_external[0].key_id) description = "Key ID." } diff --git a/variables.tf b/variables.tf index b2ee96b..24f82c1 100644 --- a/variables.tf +++ b/variables.tf @@ -30,12 +30,6 @@ variable "attributes" { 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 = "hello@clouddrove.com" @@ -148,14 +142,14 @@ variable "policy" { description = "A valid policy JSON document. Although this is a key policy, not an IAM policy, an `aws_iam_policy_document`, in the form that designates a principal, can be used" } -variable "computed_aliases" { - description = "A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources" - type = any - default = {} +variable "create_replica_enabled" { + type = bool + default = false + description = "Determines whether a replica standard CMK will be created (AWS provided material)" } -variable "aliases_use_name_prefix" { - description = "Determines whether the alias name is used as a prefix" +variable "create_replica_external_enabled" { type = bool default = false + description = "Determines whether a replica external CMK will be created (externally provided material)" } \ No newline at end of file From 95144e7a4192733a2275ac849133c81218534652 Mon Sep 17 00:00:00 2001 From: Archit Chopra Date: Fri, 11 Aug 2023 17:04:58 +0530 Subject: [PATCH 2/5] fix: Update workflows and examples --- .github/workflows/auto_assignee.yml | 14 ++++ .github/workflows/readme.yml | 23 +++-- .github/workflows/terraform.yml | 84 ------------------- .github/workflows/terratest.yml | 40 --------- .github/workflows/tf-checks.yml | 15 ++++ .github/workflows/tflint.yml | 15 ++++ .github/workflows/tfsec.yml | 16 ++-- _example/{ => complete}/example.tf | 12 +-- _example/{ => complete}/outputs.tf | 0 _example/external_key/example.tf | 126 ++++++++++++++++++++++++++++ _example/external_key/outputs.tf | 19 +++++ _test/kms_test.go | 33 -------- main.tf | 18 ++-- variables.tf | 2 +- 14 files changed, 220 insertions(+), 197 deletions(-) create mode 100644 .github/workflows/auto_assignee.yml delete mode 100644 .github/workflows/terraform.yml delete mode 100644 .github/workflows/terratest.yml create mode 100644 .github/workflows/tf-checks.yml create mode 100644 .github/workflows/tflint.yml rename _example/{ => complete}/example.tf (94%) rename _example/{ => complete}/outputs.tf (100%) create mode 100644 _example/external_key/example.tf create mode 100644 _example/external_key/outputs.tf delete mode 100644 _test/kms_test.go diff --git a/.github/workflows/auto_assignee.yml b/.github/workflows/auto_assignee.yml new file mode 100644 index 0000000..77d5fdf --- /dev/null +++ b/.github/workflows/auto_assignee.yml @@ -0,0 +1,14 @@ +name: Auto Assign PRs + +on: + pull_request: + types: [opened, reopened] + + workflow_dispatch: +jobs: + assignee: + uses: clouddrove/github-shared-workflows/.github/workflows/auto_assignee.yml@master + secrets: + GITHUB: ${{ secrets.GITHUB }} + with: + assignees: 'clouddrove-ci' \ No newline at end of file diff --git a/.github/workflows/readme.yml b/.github/workflows/readme.yml index f2f68a1..7173905 100644 --- a/.github/workflows/readme.yml +++ b/.github/workflows/readme.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - name: 'Checkout' - uses: actions/checkout@v2.3.4 + uses: actions/checkout@master - - name: Set up Python 3.7. - uses: actions/setup-python@v2 + - name: 'Set up Python 3.7' + uses: actions/setup-python@v4 with: python-version: '3.x' @@ -21,17 +21,16 @@ jobs: uses: 'clouddrove/github-actions@v9.0.2' with: actions_subcommand: 'readme' - github_token: '${{ secrets.GITHUB}}' + github_token: '${{ secrets.GITHUB }}' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: pre-commit check errors - uses: pre-commit/action@v2.0.0 + - name: 'pre-commit check errors' + uses: pre-commit/action@v3.0.0 continue-on-error: true - - name: pre-commit fix erros - uses: pre-commit/action@v2.0.0 + - name: 'pre-commit fix erros' + uses: pre-commit/action@v3.0.0 continue-on-error: true - name: 'push readme' @@ -40,7 +39,7 @@ jobs: with: actions_subcommand: 'push' env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: 'Slack Notification' uses: clouddrove/action-slack@v2 @@ -51,4 +50,4 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # required SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_TERRAFORM }} # required - if: always() + if: always() \ No newline at end of file diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml deleted file mode 100644 index d73d44f..0000000 --- a/.github/workflows/terraform.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: static-checks - -on: - pull_request: - -jobs: - versionExtract: - name: Get min/max versions - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Terraform min/max versions - id: minMax - uses: clowdhaus/terraform-min-max@main - outputs: - minVersion: ${{ steps.minMax.outputs.minVersion }} - maxVersion: ${{ steps.minMax.outputs.maxVersion }} - - - versionEvaluate: - name: Evaluate Terraform versions - runs-on: ubuntu-latest - needs: versionExtract - strategy: - fail-fast: false - matrix: - version: - - ${{ needs.versionExtract.outputs.minVersion }} - - ${{ needs.versionExtract.outputs.maxVersion }} - directory: - - _example/ - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install Terraform v${{ matrix.version }} - uses: hashicorp/setup-terraform@v1 - with: - terraform_version: ${{ matrix.version }} - - - name: 'Configure AWS Credentials' - uses: clouddrove/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.TEST_AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.TEST_AWS_ACCESS_SECRET_KEY }} - aws-region: us-east-2 - - - name: Init & validate v${{ matrix.version }} - run: | - cd ${{ matrix.directory }} - terraform init - terraform validate - terraform plan -input=false -no-color - - - name: tflint - uses: reviewdog/action-tflint@master - with: - tflint_version: v0.29.0 - github_token: ${{ secrets.GITHUB }} - working_directory: ${{ matrix.directory }} - fail_on_error: 'true' - filter_mode: 'nofilter' - flags: '--module' - - format: - name: Check code format - runs-on: ubuntu-latest - needs: versionExtract - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Install Terraform v${{ needs.versionExtract.outputs.maxVersion }} - uses: hashicorp/setup-terraform@v1 - with: - terraform_version: ${{ needs.versionExtract.outputs.maxVersion }} - - - name: Check Terraform format changes - run: terraform fmt --recursive \ No newline at end of file diff --git a/.github/workflows/terratest.yml b/.github/workflows/terratest.yml deleted file mode 100644 index 00f2fe2..0000000 --- a/.github/workflows/terratest.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: 'Terratest GitHub Actions' -on: - pull_request: - branches: - - master - types: [labeled] - -jobs: - Terratest: - name: 'Terratest' - runs-on: ubuntu-latest - steps: - - - name: 'Checkout' - uses: actions/checkout@v2.3.4 - - - name: 'Configure AWS Credentials' - uses: clouddrove/configure-aws-credentials@v1 - with: - aws-access-key-id: ${{ secrets.TEST_AWS_ACCESS_KEY }} - aws-secret-access-key: ${{ secrets.TEST_AWS_ACCESS_SECRET_KEY }} - aws-region: us-east-2 - - - name: 'Terratest' - uses: 'clouddrove/github-actions@v9.0.2' - with: - actions_subcommand: 'terratest' - if: ${{ github.event.label.name == 'terratest' }} - tf_actions_working_dir: '_test' - - - name: 'Slack Notification' - uses: clouddrove/action-slack@v2 - with: - status: ${{ job.status }} - fields: repo,author - author_name: 'CloudDrove' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # required - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_TERRAFORM }} # required - if: always() diff --git a/.github/workflows/tf-checks.yml b/.github/workflows/tf-checks.yml new file mode 100644 index 0000000..511db7c --- /dev/null +++ b/.github/workflows/tf-checks.yml @@ -0,0 +1,15 @@ +name: tf-checks +on: + push: + branches: [ master ] + pull_request: + workflow_dispatch: +jobs: + basic: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/complete/' + complete: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/external_key/' \ No newline at end of file diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml new file mode 100644 index 0000000..c541617 --- /dev/null +++ b/.github/workflows/tflint.yml @@ -0,0 +1,15 @@ +name: tf-checks +on: + push: + branches: [ master ] + pull_request: + workflow_dispatch: +jobs: + basic: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/basic/' + complete: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/complete/' \ No newline at end of file diff --git a/.github/workflows/tfsec.yml b/.github/workflows/tfsec.yml index 9aaf588..511db7c 100644 --- a/.github/workflows/tfsec.yml +++ b/.github/workflows/tfsec.yml @@ -1,11 +1,15 @@ -name: tfsec -permissions: write-all +name: tf-checks on: + push: + branches: [ master ] pull_request: workflow_dispatch: jobs: - tfsec: - uses: clouddrove/github-shared-workflows/.github/workflows/tfsec.yml@master - secrets: inherit + basic: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master with: - working_directory: '.' \ No newline at end of file + working_directory: './_example/complete/' + complete: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/external_key/' \ No newline at end of file diff --git a/_example/example.tf b/_example/complete/example.tf similarity index 94% rename from _example/example.tf rename to _example/complete/example.tf index 4051c0a..fb93b8a 100644 --- a/_example/example.tf +++ b/_example/complete/example.tf @@ -11,20 +11,14 @@ provider "aws" { ## AWS Key Management Service (AWS KMS) is a managed service that makes it easy for you to create and control the cryptographic keys that are used to protect your data. ####---------------------------------------------------------------------------------- module "kms_key" { - - source = "./../" - - name = "kms" - environment = "test" - label_order = ["name", "environment"] - + source = "./../../" + name = "kms" + environment = "test" deletion_window_in_days = 7 alias = "alias/cloudtrail_Name" kms_key_enabled = true multi_region = true - create_external_enabled = true valid_to = "2023-11-21T23:20:50Z" - key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" policy = data.aws_iam_policy_document.default.json } diff --git a/_example/outputs.tf b/_example/complete/outputs.tf similarity index 100% rename from _example/outputs.tf rename to _example/complete/outputs.tf diff --git a/_example/external_key/example.tf b/_example/external_key/example.tf new file mode 100644 index 0000000..93c253f --- /dev/null +++ b/_example/external_key/example.tf @@ -0,0 +1,126 @@ +####---------------------------------------------------------------------------------- +## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. +####---------------------------------------------------------------------------------- + + +provider "aws" { + region = "us-east-1" +} + +####---------------------------------------------------------------------------------- +## AWS Key Management Service (AWS KMS) is a managed service that makes it easy for you to create and control the cryptographic keys that are used to protect your data. +####---------------------------------------------------------------------------------- +module "kms_key" { + source = "./../../" + name = "kms" + environment = "test" + deletion_window_in_days = 7 + alias = "alias/external_key" + kms_key_enabled = false + enabled = true + multi_region = true + create_external_enabled = true + valid_to = "2023-11-21T23:20:50Z" + key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" + policy = data.aws_iam_policy_document.default.json +} + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +##---------------------------------------------------------------------------------- +## Data block called to get Permissions that will be used in creating policy. +##---------------------------------------------------------------------------------- +data "aws_iam_policy_document" "default" { + version = "2012-10-17" + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + principals { + type = "AWS" + identifiers = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + actions = ["kms:CreateAlias"] + resources = ["*"] + } +} \ No newline at end of file diff --git a/_example/external_key/outputs.tf b/_example/external_key/outputs.tf new file mode 100644 index 0000000..6a1f266 --- /dev/null +++ b/_example/external_key/outputs.tf @@ -0,0 +1,19 @@ +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." +} + +output "key_id" { + value = module.kms_key.key_id + description = "The globally unique identifier for the key." +} + +output "target_key_id" { + value = module.kms_key.target_key_id + description = "Identifier for the key for which the alias is for, can be either an ARN or key_id." +} \ No newline at end of file diff --git a/_test/kms_test.go b/_test/kms_test.go deleted file mode 100644 index 8fb1f55..0000000 --- a/_test/kms_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Managed By : CloudDrove -// Description : This Terratest is used to test the Terraform KMS module. -// Copyright @ CloudDrove. 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: "../_example", - } - - // 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' - Tags := terraform.OutputMap(t, terraformOptions, "tags") - - // Check that we get back the outputs that we expect - assert.Equal(t, "kms-test", Tags["Name"]) -} diff --git a/main.tf b/main.tf index 4980579..b7ae004 100644 --- a/main.tf +++ b/main.tf @@ -16,8 +16,7 @@ module "labels" { ## This terraform resource creates a KMS Customer Master Key (CMK) and its alias. ####---------------------------------------------------------------------------------- resource "aws_kms_key" "default" { - count = var.enabled && var.kms_key_enabled ? 1 : 0 - + count = var.enabled && var.kms_key_enabled ? 1 : 0 description = var.description key_usage = var.key_usage deletion_window_in_days = var.deletion_window_in_days @@ -34,8 +33,7 @@ resource "aws_kms_key" "default" { ## Create KMS keys in an external key store backed by your cryptographic keys outside of AWS. ####---------------------------------------------------------------------------------- resource "aws_kms_external_key" "external" { - count = var.enabled && var.create_external_enabled ? 1 : 0 - + count = var.enabled && var.create_external_enabled ? 1 : 0 bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description @@ -44,8 +42,7 @@ resource "aws_kms_external_key" "external" { multi_region = var.multi_region policy = var.policy valid_to = var.valid_to - - tags = module.labels.tags + tags = module.labels.tags } ####---------------------------------------------------------------------------------- @@ -53,8 +50,7 @@ resource "aws_kms_external_key" "external" { ####---------------------------------------------------------------------------------- resource "aws_kms_replica_key" "replica" { - count = var.enabled && var.create_replica_enabled ? 1 : 0 - + count = var.enabled && var.create_replica_enabled ? 1 : 0 bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description @@ -70,8 +66,7 @@ resource "aws_kms_replica_key" "replica" { ####---------------------------------------------------------------------------------- resource "aws_kms_replica_external_key" "replica_external" { - count = var.enabled && var.create_replica_external_enabled ? 1 : 0 - + count = var.enabled && var.create_replica_external_enabled ? 1 : 0 bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check deletion_window_in_days = var.deletion_window_in_days description = var.description @@ -88,8 +83,7 @@ resource "aws_kms_replica_external_key" "replica_external" { ## Provides an alias for a KMS customer master key. ##---------------------------------------------------------------------------------- resource "aws_kms_alias" "default" { - count = var.enabled ? 1 : 0 - + count = var.enabled ? 1 : 0 name = coalesce(var.alias, format("alias/%v", module.labels.id)) target_key_id = try(aws_kms_key.default[0].key_id, aws_kms_external_key.external[0].id, aws_kms_replica_key.replica[0].key_id, aws_kms_replica_external_key.replica_external[0].key_id) } \ No newline at end of file diff --git a/variables.tf b/variables.tf index 24f82c1..6125ee1 100644 --- a/variables.tf +++ b/variables.tf @@ -20,7 +20,7 @@ variable "environment" { variable "label_order" { type = list(any) - default = [] + default = ["name", "environment"] description = "label order, e.g. `name`,`application`." } From caa35b8899864631f08959d43d17d6b3d0a5611c Mon Sep 17 00:00:00 2001 From: Archit Chopra Date: Fri, 11 Aug 2023 17:08:10 +0530 Subject: [PATCH 3/5] fix: Update tf-checks workflow --- .github/workflows/tf-checks.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tf-checks.yml b/.github/workflows/tf-checks.yml index 511db7c..c50c45f 100644 --- a/.github/workflows/tf-checks.yml +++ b/.github/workflows/tf-checks.yml @@ -5,11 +5,11 @@ on: pull_request: workflow_dispatch: jobs: - basic: + complete: uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master with: working_directory: './_example/complete/' - complete: + external_key: uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master with: working_directory: './_example/external_key/' \ No newline at end of file From 0d236376fb3bfabb24b56ac51d80d49a72c49d56 Mon Sep 17 00:00:00 2001 From: Archit Chopra Date: Fri, 11 Aug 2023 17:11:11 +0530 Subject: [PATCH 4/5] fix: Fixed tfsec and tflint workflow --- .github/workflows/tflint.yml | 14 +++++--------- .github/workflows/tfsec.yml | 16 ++++++---------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/.github/workflows/tflint.yml b/.github/workflows/tflint.yml index c541617..d1b5a64 100644 --- a/.github/workflows/tflint.yml +++ b/.github/workflows/tflint.yml @@ -1,15 +1,11 @@ -name: tf-checks +name: tf-lint on: push: branches: [ master ] pull_request: workflow_dispatch: jobs: - basic: - uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master - with: - working_directory: './_example/basic/' - complete: - uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master - with: - working_directory: './_example/complete/' \ No newline at end of file + tflint: + uses: clouddrove/test-tfsec/.github/workflows/tflint.yaml@master + secrets: + GITHUB: ${{ secrets.GITHUB }} \ No newline at end of file diff --git a/.github/workflows/tfsec.yml b/.github/workflows/tfsec.yml index 511db7c..9aaf588 100644 --- a/.github/workflows/tfsec.yml +++ b/.github/workflows/tfsec.yml @@ -1,15 +1,11 @@ -name: tf-checks +name: tfsec +permissions: write-all on: - push: - branches: [ master ] pull_request: workflow_dispatch: jobs: - basic: - uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + tfsec: + uses: clouddrove/github-shared-workflows/.github/workflows/tfsec.yml@master + secrets: inherit with: - working_directory: './_example/complete/' - complete: - uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master - with: - working_directory: './_example/external_key/' \ No newline at end of file + working_directory: '.' \ No newline at end of file From bb380b0cb14bd0b85e34d6d18d6adccc0d23e557 Mon Sep 17 00:00:00 2001 From: Archit Chopra Date: Fri, 11 Aug 2023 20:58:12 +0530 Subject: [PATCH 5/5] feat: Added example for replica key. --- .github/dependabot.yml | 59 ++++++++++- .github/workflows/tf-checks.yml | 10 +- README.yaml | 18 ++-- _example/external_replica_key/example.tf | 125 +++++++++++++++++++++++ _example/external_replica_key/outputs.tf | 19 ++++ _example/replica_key/example.tf | 124 ++++++++++++++++++++++ _example/replica_key/outputs.tf | 19 ++++ main.tf | 3 +- variables.tf | 2 +- 9 files changed, 363 insertions(+), 16 deletions(-) create mode 100644 _example/external_replica_key/example.tf create mode 100644 _example/external_replica_key/outputs.tf create mode 100644 _example/replica_key/example.tf create mode 100644 _example/replica_key/outputs.tf diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 9067e3f..d16f0ff 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,9 +2,18 @@ # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - version: 2 updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + open-pull-requests-limit: 3 + assignees: + - "clouddrove-ci" + reviewers: + - "approvers" + - package-ecosystem: "terraform" # See documentation for possible values directory: "/" # Location of package manifests schedule: @@ -15,8 +24,24 @@ updates: # Add reviewer reviewers: - "approvers" + # Allow up to 3 open pull requests for pip dependencies + open-pull-requests-limit: 3 + + - package-ecosystem: "terraform" # See documentation for possible values + directory: "/_example/complete" # Location of package manifests + schedule: + interval: "weekly" + # Add assignees + assignees: + - "clouddrove-ci" + # Add reviewer + reviewers: + - "approvers" + # Allow up to 3 open pull requests for pip dependencies + open-pull-requests-limit: 3 + - package-ecosystem: "terraform" # See documentation for possible values - directory: "_example/" # Location of package manifests + directory: "/_example/external_key" # Location of package manifests schedule: interval: "weekly" # Add assignees @@ -24,4 +49,32 @@ updates: - "clouddrove-ci" # Add reviewer reviewers: - - "approvers" \ No newline at end of file + - "approvers" + # Allow up to 3 open pull requests for pip dependencies + open-pull-requests-limit: 3 + + - package-ecosystem: "terraform" # See documentation for possible values + directory: "/_example/external_replica_key" # Location of package manifests + schedule: + interval: "weekly" + # Add assignees + assignees: + - "clouddrove-ci" + # Add reviewer + reviewers: + - "approvers" + # Allow up to 3 open pull requests for pip dependencies + open-pull-requests-limit: 3 + + - package-ecosystem: "terraform" # See documentation for possible values + directory: "/_example/replica_key" # Location of package manifests + schedule: + interval: "weekly" + # Add assignees + assignees: + - "clouddrove-ci" + # Add reviewer + reviewers: + - "approvers" + # Allow up to 3 open pull requests for pip dependencies + open-pull-requests-limit: 3 \ No newline at end of file diff --git a/.github/workflows/tf-checks.yml b/.github/workflows/tf-checks.yml index c50c45f..a5cabf8 100644 --- a/.github/workflows/tf-checks.yml +++ b/.github/workflows/tf-checks.yml @@ -12,4 +12,12 @@ jobs: external_key: uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master with: - working_directory: './_example/external_key/' \ No newline at end of file + working_directory: './_example/external_key/' + external_replica_key: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/external_replica_key/' + replica_key: + uses: clouddrove/github-shared-workflows/.github/workflows/tf-checks.yml@master + with: + working_directory: './_example/replica_key/' \ No newline at end of file diff --git a/README.yaml b/README.yaml index b5acaf5..6e16984 100644 --- a/README.yaml +++ b/README.yaml @@ -15,19 +15,19 @@ github_repo: clouddrove/terraform-aws-kms # Badges to display badges: - - name: "Terraform" - image: "https://img.shields.io/badge/Terraform-v1.1.7-green" - url: "https://www.terraform.io" + - name: "Latest Release" + image: "https://img.shields.io/github/release/clouddrove/terraform-aws-subnet.svg" + url: "https://github.com/clouddrove/terraform-aws-subnet/releases/latest" + - name: "tfsec" + image: "https://github.com/clouddrove/terraform-aws-subnet/actions/workflows/tfsec.yml/badge.svg" + url: "https://github.com/clouddrove/terraform-aws-kms/actions/workflows/tfsec.yml" - name: "Licence" image: "https://img.shields.io/badge/License-APACHE-blue.svg" url: "LICENSE.md" - - name: "tfsec" - image: "https://github.com/clouddrove/terraform-aws-kms/actions/workflows/tfsec.yml/badge.svg" - url: "https://github.com/clouddrove/terraform-aws-kms/actions/workflows/tfsec.yml" - - name: "static-checks" - image: "https://github.com/clouddrove/terraform-aws-kms/actions/workflows/terraform.yml/badge.svg" - url: "https://github.com/clouddrove/terraform-aws-kms/actions/workflows/terraform.yml" +prerequesties: + - name: Terraform 1.5.4 + url: https://learn.hashicorp.com/terraform/getting-started/install.html # description of this project description: |- This terraform module creates a KMS Customer Master Key (CMK) and its alias. diff --git a/_example/external_replica_key/example.tf b/_example/external_replica_key/example.tf new file mode 100644 index 0000000..e1ca10d --- /dev/null +++ b/_example/external_replica_key/example.tf @@ -0,0 +1,125 @@ +####---------------------------------------------------------------------------------- +## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. +####---------------------------------------------------------------------------------- +provider "aws" { + region = "us-east-1" +} + +####---------------------------------------------------------------------------------- +## AWS External KMS Key Replica. +## Should be deployed in different region as of primary key. +####---------------------------------------------------------------------------------- +module "kms_key" { + source = "./../../" + name = "kms" + environment = "test" + deletion_window_in_days = 7 + alias = "alias/replicate_key" + kms_key_enabled = false + create_replica_external_enabled = true + enabled = true + multi_region = false + key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" + primary_key_arn = "arn:aws:kms:xxxxxxxxxxxxxxxxxxxxx" + policy = data.aws_iam_policy_document.default.json +} + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +##---------------------------------------------------------------------------------- +## Data block called to get Permissions that will be used in creating policy. +##---------------------------------------------------------------------------------- +data "aws_iam_policy_document" "default" { + version = "2012-10-17" + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + principals { + type = "AWS" + identifiers = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + actions = ["kms:CreateAlias"] + resources = ["*"] + } +} \ No newline at end of file diff --git a/_example/external_replica_key/outputs.tf b/_example/external_replica_key/outputs.tf new file mode 100644 index 0000000..6a1f266 --- /dev/null +++ b/_example/external_replica_key/outputs.tf @@ -0,0 +1,19 @@ +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." +} + +output "key_id" { + value = module.kms_key.key_id + description = "The globally unique identifier for the key." +} + +output "target_key_id" { + value = module.kms_key.target_key_id + description = "Identifier for the key for which the alias is for, can be either an ARN or key_id." +} \ No newline at end of file diff --git a/_example/replica_key/example.tf b/_example/replica_key/example.tf new file mode 100644 index 0000000..09cc803 --- /dev/null +++ b/_example/replica_key/example.tf @@ -0,0 +1,124 @@ +####---------------------------------------------------------------------------------- +## Provider block added, Use the Amazon Web Services (AWS) provider to interact with the many resources supported by AWS. +####---------------------------------------------------------------------------------- +provider "aws" { + region = "us-east-1" +} + +####---------------------------------------------------------------------------------- +## AWS KMS Key Replica. +## Should be deployed in different region as of primary key. +####---------------------------------------------------------------------------------- +module "kms_key" { + source = "./../../" + name = "kms" + environment = "test" + deletion_window_in_days = 7 + alias = "alias/replicate_key" + kms_key_enabled = false + create_replica_enabled = true + enabled = true + multi_region = false + primary_key_arn = "arn:aws:kms:xxxxxxxxxxxxxxxxxxxxx" + policy = data.aws_iam_policy_document.default.json +} + +data "aws_caller_identity" "current" {} +data "aws_partition" "current" {} + +##---------------------------------------------------------------------------------- +## Data block called to get Permissions that will be used in creating policy. +##---------------------------------------------------------------------------------- +data "aws_iam_policy_document" "default" { + version = "2012-10-17" + statement { + sid = "Enable IAM User Permissions" + effect = "Allow" + principals { + type = "AWS" + identifiers = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + 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 = [ + format( + "arn:%s:iam::%s:root", + join("", data.aws_partition.current.*.partition), + data.aws_caller_identity.current.account_id + ) + ] + } + actions = ["kms:CreateAlias"] + resources = ["*"] + } +} \ No newline at end of file diff --git a/_example/replica_key/outputs.tf b/_example/replica_key/outputs.tf new file mode 100644 index 0000000..6a1f266 --- /dev/null +++ b/_example/replica_key/outputs.tf @@ -0,0 +1,19 @@ +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." +} + +output "key_id" { + value = module.kms_key.key_id + description = "The globally unique identifier for the key." +} + +output "target_key_id" { + value = module.kms_key.target_key_id + description = "Identifier for the key for which the alias is for, can be either an ARN or key_id." +} \ No newline at end of file diff --git a/main.tf b/main.tf index b7ae004..d881afc 100644 --- a/main.tf +++ b/main.tf @@ -57,8 +57,7 @@ resource "aws_kms_replica_key" "replica" { primary_key_arn = var.primary_key_arn enabled = var.is_enabled policy = var.policy - - tags = module.labels.tags + tags = module.labels.tags } ####---------------------------------------------------------------------------------- diff --git a/variables.tf b/variables.tf index 6125ee1..b0b94fb 100644 --- a/variables.tf +++ b/variables.tf @@ -102,7 +102,7 @@ variable "multi_region" { variable "bypass_policy_lockout_safety_check" { type = bool - default = null + default = false description = "A flag to indicate whether to bypass the key policy lockout safety check. Setting this value to true increases the risk that the KMS key becomes unmanageable" }