├── .editorconfig ├── .github └── workflows │ ├── lock.yml │ ├── pr-title.yml │ ├── pre-commit.yml │ ├── release.yml │ └── stale-actions.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .releaserc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples ├── README.md └── complete │ ├── README.md │ ├── main.tf │ ├── outputs.tf │ ├── variables.tf │ └── versions.tf ├── main.tf ├── outputs.tf ├── variables.tf ├── versions.tf └── wrappers ├── README.md ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Uses editorconfig to maintain consistent coding styles 3 | 4 | # top-most EditorConfig file 5 | root = true 6 | 7 | # Unix-style newlines with a newline ending every file 8 | [*] 9 | charset = utf-8 10 | end_of_line = lf 11 | indent_size = 2 12 | indent_style = space 13 | insert_final_newline = true 14 | max_line_length = 80 15 | trim_trailing_whitespace = true 16 | 17 | [*.{tf,tfvars}] 18 | indent_size = 2 19 | indent_style = space 20 | 21 | [*.md] 22 | max_line_length = 0 23 | trim_trailing_whitespace = false 24 | 25 | [Makefile] 26 | tab_width = 2 27 | indent_style = tab 28 | 29 | [COMMIT_EDITMSG] 30 | max_line_length = 0 31 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Threads' 2 | 3 | on: 4 | schedule: 5 | - cron: '50 1 * * *' 6 | 7 | jobs: 8 | lock: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: dessant/lock-threads@v5 12 | with: 13 | github-token: ${{ secrets.GITHUB_TOKEN }} 14 | issue-comment: > 15 | I'm going to lock this issue because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 16 | If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 17 | issue-inactive-days: '30' 18 | pr-comment: > 19 | I'm going to lock this pull request because it has been closed for _30 days_ ⏳. This helps our maintainers find and focus on the active issues. 20 | If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. 21 | pr-inactive-days: '30' 22 | -------------------------------------------------------------------------------- /.github/workflows/pr-title.yml: -------------------------------------------------------------------------------- 1 | name: 'Validate PR title' 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | - edited 8 | - synchronize 9 | 10 | jobs: 11 | main: 12 | name: Validate PR title 13 | runs-on: ubuntu-latest 14 | steps: 15 | # Please look up the latest version from 16 | # https://github.com/amannn/action-semantic-pull-request/releases 17 | - uses: amannn/action-semantic-pull-request@v5.5.3 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | with: 21 | # Configure which types are allowed. 22 | # Default: https://github.com/commitizen/conventional-commit-types 23 | types: | 24 | fix 25 | feat 26 | docs 27 | ci 28 | chore 29 | # Configure that a scope must always be provided. 30 | requireScope: false 31 | # Configure additional validation for the subject based on a regex. 32 | # This example ensures the subject starts with an uppercase character. 33 | subjectPattern: ^[A-Z].+$ 34 | # If `subjectPattern` is configured, you can use this property to override 35 | # the default error message that is shown when the pattern doesn't match. 36 | # The variables `subject` and `title` can be used within the message. 37 | subjectPatternError: | 38 | The subject "{subject}" found in the pull request title "{title}" 39 | didn't match the configured pattern. Please ensure that the subject 40 | starts with an uppercase character. 41 | # For work-in-progress PRs you can typically use draft pull requests 42 | # from Github. However, private repositories on the free plan don't have 43 | # this option and therefore this action allows you to opt-in to using the 44 | # special "[WIP]" prefix to indicate this state. This will avoid the 45 | # validation of the PR title and the pull request checks remain pending. 46 | # Note that a second check will be reported if this is enabled. 47 | wip: true 48 | # When using "Squash and merge" on a PR with only one commit, GitHub 49 | # will suggest using that commit message instead of the PR title for the 50 | # merge commit, and it's easy to commit this by mistake. Enable this option 51 | # to also validate the commit message for one commit PRs. 52 | validateSingleCommit: false 53 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: Pre-Commit 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - master 8 | 9 | env: 10 | TERRAFORM_DOCS_VERSION: v0.19.0 11 | TFLINT_VERSION: v0.53.0 12 | 13 | jobs: 14 | collectInputs: 15 | name: Collect workflow inputs 16 | runs-on: ubuntu-latest 17 | outputs: 18 | directories: ${{ steps.dirs.outputs.directories }} 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v4 22 | 23 | - name: Get root directories 24 | id: dirs 25 | uses: clowdhaus/terraform-composite-actions/directories@v1.9.0 26 | 27 | preCommitMinVersions: 28 | name: Min TF pre-commit 29 | needs: collectInputs 30 | runs-on: ubuntu-latest 31 | strategy: 32 | matrix: 33 | directory: ${{ fromJson(needs.collectInputs.outputs.directories) }} 34 | steps: 35 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 36 | - name: Delete huge unnecessary tools folder 37 | run: | 38 | rm -rf /opt/hostedtoolcache/CodeQL 39 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk 40 | rm -rf /opt/hostedtoolcache/Ruby 41 | rm -rf /opt/hostedtoolcache/go 42 | 43 | - name: Checkout 44 | uses: actions/checkout@v4 45 | 46 | - name: Terraform min/max versions 47 | id: minMax 48 | uses: clowdhaus/terraform-min-max@v1.3.1 49 | with: 50 | directory: ${{ matrix.directory }} 51 | 52 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 53 | # Run only validate pre-commit check on min version supported 54 | if: ${{ matrix.directory != '.' }} 55 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 56 | with: 57 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 58 | tflint-version: ${{ env.TFLINT_VERSION }} 59 | args: 'terraform_validate --color=always --show-diff-on-failure --files ${{ matrix.directory }}/*' 60 | 61 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.minVersion }} 62 | # Run only validate pre-commit check on min version supported 63 | if: ${{ matrix.directory == '.' }} 64 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 65 | with: 66 | terraform-version: ${{ steps.minMax.outputs.minVersion }} 67 | tflint-version: ${{ env.TFLINT_VERSION }} 68 | args: 'terraform_validate --color=always --show-diff-on-failure --files $(ls *.tf)' 69 | 70 | preCommitMaxVersion: 71 | name: Max TF pre-commit 72 | runs-on: ubuntu-latest 73 | needs: collectInputs 74 | steps: 75 | # https://github.com/orgs/community/discussions/25678#discussioncomment-5242449 76 | - name: Delete huge unnecessary tools folder 77 | run: | 78 | rm -rf /opt/hostedtoolcache/CodeQL 79 | rm -rf /opt/hostedtoolcache/Java_Temurin-Hotspot_jdk 80 | rm -rf /opt/hostedtoolcache/Ruby 81 | rm -rf /opt/hostedtoolcache/go 82 | 83 | - name: Checkout 84 | uses: actions/checkout@v4 85 | with: 86 | ref: ${{ github.event.pull_request.head.ref }} 87 | repository: ${{github.event.pull_request.head.repo.full_name}} 88 | 89 | - name: Terraform min/max versions 90 | id: minMax 91 | uses: clowdhaus/terraform-min-max@v1.3.1 92 | 93 | - name: Pre-commit Terraform ${{ steps.minMax.outputs.maxVersion }} 94 | uses: clowdhaus/terraform-composite-actions/pre-commit@v1.11.1 95 | with: 96 | terraform-version: ${{ steps.minMax.outputs.maxVersion }} 97 | tflint-version: ${{ env.TFLINT_VERSION }} 98 | terraform-docs-version: ${{ env.TERRAFORM_DOCS_VERSION }} 99 | install-hcledit: true 100 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - master 9 | paths: 10 | - '**/*.tpl' 11 | - '**/*.py' 12 | - '**/*.tf' 13 | - '.github/workflows/release.yml' 14 | 15 | jobs: 16 | release: 17 | name: Release 18 | runs-on: ubuntu-latest 19 | # Skip running release workflow on forks 20 | if: github.repository_owner == 'terraform-aws-modules' 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v4 24 | with: 25 | persist-credentials: false 26 | fetch-depth: 0 27 | 28 | - name: Release 29 | uses: cycjimmy/semantic-release-action@v4 30 | with: 31 | semantic_version: 23.0.2 32 | extra_plugins: | 33 | @semantic-release/changelog@6.0.3 34 | @semantic-release/git@10.0.1 35 | conventional-changelog-conventionalcommits@7.0.2 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_TOKEN }} 38 | -------------------------------------------------------------------------------- /.github/workflows/stale-actions.yaml: -------------------------------------------------------------------------------- 1 | name: 'Mark or close stale issues and PRs' 2 | on: 3 | schedule: 4 | - cron: '0 0 * * *' 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v9 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | # Staling issues and PR's 14 | days-before-stale: 30 15 | stale-issue-label: stale 16 | stale-pr-label: stale 17 | stale-issue-message: | 18 | This issue has been automatically marked as stale because it has been open 30 days 19 | with no activity. Remove stale label or comment or this issue will be closed in 10 days 20 | stale-pr-message: | 21 | This PR has been automatically marked as stale because it has been open 30 days 22 | with no activity. Remove stale label or comment or this PR will be closed in 10 days 23 | # Not stale if have this labels or part of milestone 24 | exempt-issue-labels: bug,wip,on-hold 25 | exempt-pr-labels: bug,wip,on-hold 26 | exempt-all-milestones: true 27 | # Close issue operations 28 | # Label will be automatically removed if the issues are no longer closed nor locked. 29 | days-before-close: 10 30 | delete-branch: true 31 | close-issue-message: This issue was automatically closed because of stale in 10 days 32 | close-pr-message: This PR was automatically closed because of stale in 10 days 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # terraform lockfile 9 | .terraform.lock.hcl 10 | 11 | # Crash log files 12 | crash.log 13 | 14 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 15 | # password, private keys, and other secrets. These should not be part of version 16 | # control as they are data points which are potentially sensitive and subject 17 | # to change depending on the environment. 18 | # 19 | *.tfvars 20 | 21 | # Ignore override files as they are usually used to override resources locally and so 22 | # are not checked in 23 | override.tf 24 | override.tf.json 25 | *_override.tf 26 | *_override.tf.json 27 | 28 | # Include override files you do wish to add to version control using negated pattern 29 | # 30 | # !example_override.tf 31 | 32 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 33 | # example: *tfplan* 34 | 35 | # Ignore CLI configuration files 36 | .terraformrc 37 | terraform.rc 38 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.96.1 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_wrapper_module_for_each 7 | - id: terraform_docs 8 | args: 9 | - '--args=--lockfile=false' 10 | - id: terraform_tflint 11 | args: 12 | - '--args=--only=terraform_deprecated_interpolation' 13 | - '--args=--only=terraform_deprecated_index' 14 | - '--args=--only=terraform_unused_declarations' 15 | - '--args=--only=terraform_comment_syntax' 16 | - '--args=--only=terraform_documented_outputs' 17 | - '--args=--only=terraform_documented_variables' 18 | - '--args=--only=terraform_typed_variables' 19 | - '--args=--only=terraform_module_pinned_source' 20 | - '--args=--only=terraform_naming_convention' 21 | - '--args=--only=terraform_required_version' 22 | - '--args=--only=terraform_required_providers' 23 | - '--args=--only=terraform_standard_module_structure' 24 | - '--args=--only=terraform_workspace_remote' 25 | - id: terraform_validate 26 | - repo: https://github.com/pre-commit/pre-commit-hooks 27 | rev: v5.0.0 28 | hooks: 29 | - id: check-merge-conflict 30 | - id: end-of-file-fixer 31 | - id: trailing-whitespace 32 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": [ 3 | "main", 4 | "master" 5 | ], 6 | "ci": false, 7 | "plugins": [ 8 | [ 9 | "@semantic-release/commit-analyzer", 10 | { 11 | "preset": "conventionalcommits" 12 | } 13 | ], 14 | [ 15 | "@semantic-release/release-notes-generator", 16 | { 17 | "preset": "conventionalcommits" 18 | } 19 | ], 20 | [ 21 | "@semantic-release/github", 22 | { 23 | "successComment": "This ${issue.pull_request ? 'PR is included' : 'issue has been resolved'} in version ${nextRelease.version} :tada:", 24 | "labels": false, 25 | "releasedLabels": false 26 | } 27 | ], 28 | [ 29 | "@semantic-release/changelog", 30 | { 31 | "changelogFile": "CHANGELOG.md", 32 | "changelogTitle": "# Changelog\n\nAll notable changes to this project will be documented in this file." 33 | } 34 | ], 35 | [ 36 | "@semantic-release/git", 37 | { 38 | "assets": [ 39 | "CHANGELOG.md" 40 | ], 41 | "message": "chore(release): version ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" 42 | } 43 | ] 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [3.1.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v3.1.0...v3.1.1) (2024-10-11) 6 | 7 | 8 | ### Bug Fixes 9 | 10 | * Update CI workflow versions to latest ([#35](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/35)) ([c248050](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/c2480502618251c45ab8bcf6c57ec37bd08a8370)) 11 | 12 | ## [3.1.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v3.0.0...v3.1.0) (2024-06-12) 13 | 14 | 15 | ### Features 16 | 17 | * Grants output marked as sensitive data ([#33](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/33)) ([965a52d](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/965a52d6686898897bce31d2f409e2ff9e8d5268)) 18 | 19 | ## [3.0.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v2.2.1...v3.0.0) (2024-05-11) 20 | 21 | 22 | ### ⚠ BREAKING CHANGES 23 | 24 | * Support `rotation_period_in_days`, AWS Provider v5, Terraform MSV 1.3 (#32) 25 | 26 | ### Features 27 | 28 | * Support `rotation_period_in_days`, AWS Provider v5, Terraform MSV 1.3 ([#32](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/32)) ([f8c96ce](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/f8c96ce4bfc45fa2cb2e2cfa346d0d1930cdfce3)) 29 | 30 | ## [2.2.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v2.2.0...v2.2.1) (2024-03-06) 31 | 32 | 33 | ### Bug Fixes 34 | 35 | * Update CI workflow versions to remove deprecated runtime warnings ([#28](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/28)) ([866950f](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/866950f91b3bc4411fa14d1f5c2c304145540d7f)) 36 | 37 | ## [2.2.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v2.1.0...v2.2.0) (2024-02-02) 38 | 39 | 40 | ### Features 41 | 42 | * Add wrapper modules ([#26](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/26)) ([e6eba07](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/e6eba07467818a27670db60b3eb46f98dff19ef9)) 43 | 44 | ## [2.1.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v2.0.1...v2.1.0) (2023-11-03) 45 | 46 | 47 | ### Features 48 | 49 | * Do not call data resources when `create` is `false` ([#25](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/25)) ([4951c38](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/4951c38f3cd569411eb53476ac8502981083f5d2)) 50 | 51 | ### [2.0.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v2.0.0...v2.0.1) (2023-09-18) 52 | 53 | 54 | ### Bug Fixes 55 | 56 | * Default admin permissions for special keys ([#24](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/24)) ([c975efd](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/c975efda5686fd7c9fb98518332617e4876e5317)) 57 | 58 | ## [2.0.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.5.0...v2.0.0) (2023-09-05) 59 | 60 | 61 | ### ⚠ BREAKING CHANGES 62 | 63 | * Added `custom_key_store_id`, bump version of AWS provider to 4.x (#23) 64 | 65 | ### Features 66 | 67 | * Added `custom_key_store_id`, bump version of AWS provider to 4.x ([#23](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/23)) ([beb5667](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/beb56674a6e5db7dfa6cf70c9e953183d6574472)) 68 | 69 | ## [1.5.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.4.0...v1.5.0) (2023-02-09) 70 | 71 | 72 | ### Features 73 | 74 | * Add specific policy for Autoscaling service linked roles ([#15](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/15)) ([217ac76](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/217ac76868ac3624bb89e183372d25d2da67bd8b)) 75 | 76 | ## [1.4.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.3.1...v1.4.0) (2023-01-28) 77 | 78 | 79 | ### Features 80 | 81 | * Support adding KMS replica keys ([#9](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/9)) ([9a7080b](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/9a7080bb00c468a55a85a0584648b51a68807024)) 82 | 83 | ### [1.3.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.3.0...v1.3.1) (2023-01-24) 84 | 85 | 86 | ### Bug Fixes 87 | 88 | * Use a version for to avoid GitHub API rate limiting on CI workflows ([#12](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/12)) ([040736e](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/040736eca2e82f27ac1219dcf4f10ee0eb24ff6d)) 89 | 90 | ## [1.3.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.2.2...v1.3.0) (2022-11-21) 91 | 92 | 93 | ### Features 94 | 95 | * Add support for creating customer managed keys used for Route53 DNSSEC signing ([#10](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/10)) ([d694450](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/d6944500aa33aafa19027facb1828ed3cf837196)) 96 | 97 | ### [1.2.2](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.2.1...v1.2.2) (2022-11-07) 98 | 99 | 100 | ### Bug Fixes 101 | 102 | * Update CI configuration files to use latest version ([#8](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/8)) ([01bd36b](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/01bd36b2a07830fe91184c69f3e70c975a1fdd62)) 103 | 104 | ### [1.2.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.2.0...v1.2.1) (2022-10-14) 105 | 106 | 107 | ### Bug Fixes 108 | 109 | * Modify `key_service_principals` to be generic to support conditions for confused deputy problem ([#7](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/7)) ([7b85239](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/7b85239466b365c31d7e976f82964789d4215c0e)) 110 | 111 | ## [1.2.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.1.0...v1.2.0) (2022-10-14) 112 | 113 | 114 | ### Features 115 | 116 | * Adding Key Service Principals ([#6](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/6)) ([4841f28](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/4841f28bc1366a789df97f022b42881d5d73421d)) 117 | 118 | ## [1.1.0](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.0.3...v1.1.0) (2022-08-17) 119 | 120 | 121 | ### Features 122 | 123 | * Add support for providing aliases using computed attributes ([#4](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/4)) ([8150812](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/81508121e16b9da133259763cca1fe98485a38b7)) 124 | 125 | ### [1.0.3](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.0.2...v1.0.3) (2022-08-15) 126 | 127 | 128 | ### Bug Fixes 129 | 130 | * Add support for aliases and grants on `aws_kms_external_key` ([#3](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/3)) ([beea8d6](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/beea8d64e3680978785b1b0a93911c5d602f98fe)) 131 | 132 | ### [1.0.2](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.0.1...v1.0.2) (2022-07-14) 133 | 134 | 135 | ### Bug Fixes 136 | 137 | * Correct boolean logic for enabling/disabling key owners policy statement ([#2](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/2)) ([944ea72](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/944ea72ac38f85af0a58f10650285958e78cac0c)) 138 | 139 | ### [1.0.1](https://github.com/terraform-aws-modules/terraform-aws-kms/compare/v1.0.0...v1.0.1) (2022-06-28) 140 | 141 | 142 | ### Bug Fixes 143 | 144 | * Reduce required versions for Terraform and AWS provider ([#1](https://github.com/terraform-aws-modules/terraform-aws-kms/issues/1)) ([f80bc66](https://github.com/terraform-aws-modules/terraform-aws-kms/commit/f80bc665e11d7aabacc8be397e782a1dcc1e1148)) 145 | 146 | ## 1.0.0 (2022-06-25) 147 | 148 | 149 | ### Features 150 | 151 | * Add support for external key using externally provided material ([2726c25](https://github.com/clowdhaus/terraform-aws-kms/commit/2726c2517fb203b6c3cf3b6e5cec00442336d88e)) 152 | * Add support for source and override policy documents ([5a01134](https://github.com/clowdhaus/terraform-aws-kms/commit/5a01134f4358e55cd2b65bfd1a1b6d8c91988dc1)) 153 | * Initial implementation of module ([a8a4f33](https://github.com/clowdhaus/terraform-aws-kms/commit/a8a4f33b95320b1d7457cefef3759f3544498f23)) 154 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS KMS Terraform module 2 | 3 | Terraform module which creates AWS KMS resources. 4 | 5 | [![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md) 6 | 7 | ## Usage 8 | 9 | See [`examples`](https://github.com/terraform-aws-modules/terraform-aws-kms/tree/master/examples) directory for working examples to reference: 10 | 11 | ### Autoscaling Service Linked Role 12 | 13 | Reference usage for EC2 AutoScaling service linked role to launch encrypted EBS volumes: 14 | 15 | ```hcl 16 | module "kms" { 17 | source = "terraform-aws-modules/kms/aws" 18 | 19 | description = "EC2 AutoScaling key usage" 20 | key_usage = "ENCRYPT_DECRYPT" 21 | 22 | # Policy 23 | key_administrators = ["arn:aws:iam::012345678901:role/admin"] 24 | key_service_roles_for_autoscaling = ["arn:aws:iam::012345678901:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] 25 | 26 | # Aliases 27 | aliases = ["mycompany/ebs"] 28 | 29 | tags = { 30 | Terraform = "true" 31 | Environment = "dev" 32 | } 33 | } 34 | ``` 35 | 36 | ### External Key 37 | 38 | Reference usage for external CMK (externally provided encryption material): 39 | 40 | ```hcl 41 | module "kms" { 42 | source = "terraform-aws-modules/kms/aws" 43 | 44 | description = "External key example" 45 | key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" 46 | valid_to = "2085-04-12T23:20:50.52Z" 47 | 48 | # Policy 49 | key_owners = ["arn:aws:iam::012345678901:role/owner"] 50 | key_administrators = ["arn:aws:iam::012345678901:role/admin"] 51 | key_users = ["arn:aws:iam::012345678901:role/user"] 52 | key_service_users = ["arn:aws:iam::012345678901:role/ec2-role"] 53 | 54 | # Aliases 55 | aliases = ["mycompany/external"] 56 | aliases_use_name_prefix = true 57 | 58 | # Grants 59 | grants = { 60 | lambda = { 61 | grantee_principal = "arn:aws:iam::012345678901:role/lambda-function" 62 | operations = ["Encrypt", "Decrypt", "GenerateDataKey"] 63 | constraints = { 64 | encryption_context_equals = { 65 | Department = "Finance" 66 | } 67 | } 68 | } 69 | } 70 | 71 | tags = { 72 | Terraform = "true" 73 | Environment = "dev" 74 | } 75 | } 76 | ``` 77 | 78 | ### Reference 79 | 80 | Reference usage showing available configurations. 81 | 82 | ```hcl 83 | module "kms" { 84 | source = "terraform-aws-modules/kms/aws" 85 | 86 | description = "Complete key example showing various configurations available" 87 | deletion_window_in_days = 7 88 | enable_key_rotation = true 89 | is_enabled = true 90 | key_usage = "ENCRYPT_DECRYPT" 91 | multi_region = false 92 | 93 | # Policy 94 | enable_default_policy = true 95 | key_owners = ["arn:aws:iam::012345678901:role/owner"] 96 | key_administrators = ["arn:aws:iam::012345678901:role/admin"] 97 | key_users = ["arn:aws:iam::012345678901:role/user"] 98 | key_service_users = ["arn:aws:iam::012345678901:role/ec2-role"] 99 | key_symmetric_encryption_users = ["arn:aws:iam::012345678901:role/symmetric-user"] 100 | key_hmac_users = ["arn:aws:iam::012345678901:role/hmac-user"] 101 | key_asymmetric_public_encryption_users = ["arn:aws:iam::012345678901:role/asymmetric-public-user"] 102 | key_asymmetric_sign_verify_users = ["arn:aws:iam::012345678901:role/sign-verify-user"] 103 | 104 | # Aliases 105 | aliases = ["one", "foo/bar"] # accepts static strings only 106 | computed_aliases = { 107 | ex = { 108 | # Sometimes you want to pass in an upstream attribute as the name and 109 | # that conflicts with using `for_each over a `toset()` since the value is not 110 | # known until after applying. Instead, we can use `computed_aliases` to work 111 | # around this limitation 112 | # Reference: https://github.com/hashicorp/terraform/issues/30937 113 | name = aws_iam_role.lambda.name 114 | } 115 | } 116 | aliases_use_name_prefix = true 117 | 118 | # Grants 119 | grants = { 120 | lambda = { 121 | grantee_principal = "arn:aws:iam::012345678901:role/lambda-function" 122 | operations = ["Encrypt", "Decrypt", "GenerateDataKey"] 123 | constraints = { 124 | encryption_context_equals = { 125 | Department = "Finance" 126 | } 127 | } 128 | } 129 | } 130 | 131 | tags = { 132 | Terraform = "true" 133 | Environment = "dev" 134 | } 135 | } 136 | ``` 137 | 138 | ## Examples 139 | 140 | Examples codified under the [`examples`](https://github.com/terraform-aws-modules/terraform-aws-kms/tree/master/examples) are intended to give users references for how to use the module(s) as well as testing/validating changes to the source code of the module. If contributing to the project, please be sure to make any appropriate updates to the relevant examples to allow maintainers to test your changes and to keep the examples up to date for users. Thank you! 141 | 142 | - [Complete](https://github.com/terraform-aws-modules/terraform-aws-kms/tree/master/examples/complete) 143 | 144 | 145 | ## Requirements 146 | 147 | | Name | Version | 148 | |------|---------| 149 | | [terraform](#requirement\_terraform) | >= 1.3 | 150 | | [aws](#requirement\_aws) | >= 5.49 | 151 | 152 | ## Providers 153 | 154 | | Name | Version | 155 | |------|---------| 156 | | [aws](#provider\_aws) | >= 5.49 | 157 | 158 | ## Modules 159 | 160 | No modules. 161 | 162 | ## Resources 163 | 164 | | Name | Type | 165 | |------|------| 166 | | [aws_kms_alias.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource | 167 | | [aws_kms_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_external_key) | resource | 168 | | [aws_kms_grant.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_grant) | resource | 169 | | [aws_kms_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource | 170 | | [aws_kms_replica_external_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_external_key) | resource | 171 | | [aws_kms_replica_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_replica_key) | resource | 172 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 173 | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 174 | | [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | 175 | 176 | ## Inputs 177 | 178 | | Name | Description | Type | Default | Required | 179 | |------|-------------|------|---------|:--------:| 180 | | [aliases](#input\_aliases) | A list of aliases to create. Note - due to the use of `toset()`, values must be static strings and not computed values | `list(string)` | `[]` | no | 181 | | [aliases\_use\_name\_prefix](#input\_aliases\_use\_name\_prefix) | Determines whether the alias name is used as a prefix | `bool` | `false` | no | 182 | | [bypass\_policy\_lockout\_safety\_check](#input\_bypass\_policy\_lockout\_safety\_check) | 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 | `bool` | `null` | no | 183 | | [computed\_aliases](#input\_computed\_aliases) | A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources | `any` | `{}` | no | 184 | | [create](#input\_create) | Determines whether resources will be created (affects all resources) | `bool` | `true` | no | 185 | | [create\_external](#input\_create\_external) | Determines whether an external CMK (externally provided material) will be created or a standard CMK (AWS provided material) | `bool` | `false` | no | 186 | | [create\_replica](#input\_create\_replica) | Determines whether a replica standard CMK will be created (AWS provided material) | `bool` | `false` | no | 187 | | [create\_replica\_external](#input\_create\_replica\_external) | Determines whether a replica external CMK will be created (externally provided material) | `bool` | `false` | no | 188 | | [custom\_key\_store\_id](#input\_custom\_key\_store\_id) | ID of the KMS Custom Key Store where the key will be stored instead of KMS (eg CloudHSM). | `string` | `null` | no | 189 | | [customer\_master\_key\_spec](#input\_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`, `HMAC_256`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, or `ECC_SECG_P256K1`. Defaults to `SYMMETRIC_DEFAULT` | `string` | `null` | no | 190 | | [deletion\_window\_in\_days](#input\_deletion\_window\_in\_days) | The waiting period, specified in number of days. After the waiting period ends, AWS KMS deletes the KMS key. If you specify a value, it must be between `7` and `30`, inclusive. If you do not specify a value, it defaults to `30` | `number` | `null` | no | 191 | | [description](#input\_description) | The description of the key as viewed in AWS console | `string` | `null` | no | 192 | | [enable\_default\_policy](#input\_enable\_default\_policy) | Specifies whether to enable the default key policy. Defaults to `true` | `bool` | `true` | no | 193 | | [enable\_key\_rotation](#input\_enable\_key\_rotation) | Specifies whether key rotation is enabled. Defaults to `true` | `bool` | `true` | no | 194 | | [enable\_route53\_dnssec](#input\_enable\_route53\_dnssec) | Determines whether the KMS policy used for Route53 DNSSEC signing is enabled | `bool` | `false` | no | 195 | | [grants](#input\_grants) | A map of grant definitions to create | `any` | `{}` | no | 196 | | [is\_enabled](#input\_is\_enabled) | Specifies whether the key is enabled. Defaults to `true` | `bool` | `null` | no | 197 | | [key\_administrators](#input\_key\_administrators) | A list of IAM ARNs for [key administrators](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators) | `list(string)` | `[]` | no | 198 | | [key\_asymmetric\_public\_encryption\_users](#input\_key\_asymmetric\_public\_encryption\_users) | A list of IAM ARNs for [key asymmetric public encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | 199 | | [key\_asymmetric\_sign\_verify\_users](#input\_key\_asymmetric\_sign\_verify\_users) | A list of IAM ARNs for [key asymmetric sign and verify users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | 200 | | [key\_hmac\_users](#input\_key\_hmac\_users) | A list of IAM ARNs for [key HMAC users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | 201 | | [key\_material\_base64](#input\_key\_material\_base64) | Base64 encoded 256-bit symmetric encryption key material to import. The CMK is permanently associated with this key material. External key only | `string` | `null` | no | 202 | | [key\_owners](#input\_key\_owners) | A list of IAM ARNs for those who will have full key permissions (`kms:*`) | `list(string)` | `[]` | no | 203 | | [key\_service\_roles\_for\_autoscaling](#input\_key\_service\_roles\_for\_autoscaling) | A list of IAM ARNs for [AWSServiceRoleForAutoScaling roles](https://docs.aws.amazon.com/autoscaling/ec2/userguide/key-policy-requirements-EBS-encryption.html#policy-example-cmk-access) | `list(string)` | `[]` | no | 204 | | [key\_service\_users](#input\_key\_service\_users) | A list of IAM ARNs for [key service users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-service-integration) | `list(string)` | `[]` | no | 205 | | [key\_statements](#input\_key\_statements) | A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage | `any` | `{}` | no | 206 | | [key\_symmetric\_encryption\_users](#input\_key\_symmetric\_encryption\_users) | A list of IAM ARNs for [key symmetric encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto) | `list(string)` | `[]` | no | 207 | | [key\_usage](#input\_key\_usage) | Specifies the intended use of the key. Valid values: `ENCRYPT_DECRYPT` or `SIGN_VERIFY`. Defaults to `ENCRYPT_DECRYPT` | `string` | `null` | no | 208 | | [key\_users](#input\_key\_users) | A list of IAM ARNs for [key users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-users) | `list(string)` | `[]` | no | 209 | | [multi\_region](#input\_multi\_region) | Indicates whether the KMS key is a multi-Region (`true`) or regional (`false`) key. Defaults to `false` | `bool` | `false` | no | 210 | | [override\_policy\_documents](#input\_override\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid` | `list(string)` | `[]` | no | 211 | | [policy](#input\_policy) | 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 | `string` | `null` | no | 212 | | [primary\_external\_key\_arn](#input\_primary\_external\_key\_arn) | The primary external key arn of a multi-region replica external key | `string` | `null` | no | 213 | | [primary\_key\_arn](#input\_primary\_key\_arn) | The primary key arn of a multi-region replica key | `string` | `null` | no | 214 | | [rotation\_period\_in\_days](#input\_rotation\_period\_in\_days) | Custom period of time between each rotation date. Must be a number between 90 and 2560 (inclusive) | `number` | `null` | no | 215 | | [route53\_dnssec\_sources](#input\_route53\_dnssec\_sources) | A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records | `list(any)` | `[]` | no | 216 | | [source\_policy\_documents](#input\_source\_policy\_documents) | List of IAM policy documents that are merged together into the exported document. Statements must have unique `sid`s | `list(string)` | `[]` | no | 217 | | [tags](#input\_tags) | A map of tags to add to all resources | `map(string)` | `{}` | no | 218 | | [valid\_to](#input\_valid\_to) | Time at which the imported key material expires. When the key material expires, AWS KMS deletes the key material and the CMK becomes unusable. If not specified, key material does not expire | `string` | `null` | no | 219 | 220 | ## Outputs 221 | 222 | | Name | Description | 223 | |------|-------------| 224 | | [aliases](#output\_aliases) | A map of aliases created and their attributes | 225 | | [external\_key\_expiration\_model](#output\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 226 | | [external\_key\_state](#output\_external\_key\_state) | The state of the CMK | 227 | | [external\_key\_usage](#output\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | 228 | | [grants](#output\_grants) | A map of grants created and their attributes | 229 | | [key\_arn](#output\_key\_arn) | The Amazon Resource Name (ARN) of the key | 230 | | [key\_id](#output\_key\_id) | The globally unique identifier for the key | 231 | | [key\_policy](#output\_key\_policy) | The IAM resource policy set on the key | 232 | 233 | 234 | ## License 235 | 236 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE). 237 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Please note - the examples provided serve two primary means: 4 | 5 | 1. Show users working examples of the various ways in which the module can be configured and features supported 6 | 2. A means of testing/validating module changes 7 | 8 | Please do not mistake the examples provided as "best practices". It is up to users to consult the AWS service documentation for best practices, usage recommendations, etc. 9 | -------------------------------------------------------------------------------- /examples/complete/README.md: -------------------------------------------------------------------------------- 1 | # Complete AWS KMS Example 2 | 3 | Configuration in this directory creates: 4 | 5 | - Complete KMS key example with key policy, aliases, and grants 6 | - External KMS key example 7 | - Default KMS key example with default policy 8 | - Disable KMS key example 9 | 10 | ## Usage 11 | 12 | To run this example you need to execute: 13 | 14 | ```bash 15 | $ terraform init 16 | $ terraform plan 17 | $ terraform apply 18 | ``` 19 | 20 | Note that this example may create resources which will incur monetary charges on your AWS bill. Run `terraform destroy` when you no longer need these resources. 21 | 22 | 23 | ## Requirements 24 | 25 | | Name | Version | 26 | |------|---------| 27 | | [terraform](#requirement\_terraform) | >= 1.3 | 28 | | [aws](#requirement\_aws) | >= 5.49 | 29 | 30 | ## Providers 31 | 32 | | Name | Version | 33 | |------|---------| 34 | | [aws](#provider\_aws) | >= 5.49 | 35 | 36 | ## Modules 37 | 38 | | Name | Source | Version | 39 | |------|--------|---------| 40 | | [kms\_complete](#module\_kms\_complete) | ../.. | n/a | 41 | | [kms\_default](#module\_kms\_default) | ../.. | n/a | 42 | | [kms\_disabled](#module\_kms\_disabled) | ../.. | n/a | 43 | | [kms\_dnssec\_signing](#module\_kms\_dnssec\_signing) | ../.. | n/a | 44 | | [kms\_external](#module\_kms\_external) | ../.. | n/a | 45 | | [kms\_primary](#module\_kms\_primary) | ../.. | n/a | 46 | | [kms\_primary\_external](#module\_kms\_primary\_external) | ../.. | n/a | 47 | | [kms\_replica](#module\_kms\_replica) | ../.. | n/a | 48 | | [kms\_replica\_external](#module\_kms\_replica\_external) | ../.. | n/a | 49 | 50 | ## Resources 51 | 52 | | Name | Type | 53 | |------|------| 54 | | [aws_iam_role.lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 55 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 56 | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | 57 | 58 | ## Inputs 59 | 60 | No inputs. 61 | 62 | ## Outputs 63 | 64 | | Name | Description | 65 | |------|-------------| 66 | | [complete\_aliases](#output\_complete\_aliases) | A map of aliases created and their attributes | 67 | | [complete\_external\_key\_expiration\_model](#output\_complete\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 68 | | [complete\_external\_key\_state](#output\_complete\_external\_key\_state) | The state of the CMK | 69 | | [complete\_external\_key\_usage](#output\_complete\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | 70 | | [complete\_grants](#output\_complete\_grants) | A map of grants created and their attributes | 71 | | [complete\_key\_arn](#output\_complete\_key\_arn) | The Amazon Resource Name (ARN) of the key | 72 | | [complete\_key\_id](#output\_complete\_key\_id) | The globally unique identifier for the key | 73 | | [complete\_key\_policy](#output\_complete\_key\_policy) | The IAM resource policy set on the key | 74 | | [default\_aliases](#output\_default\_aliases) | A map of aliases created and their attributes | 75 | | [default\_external\_key\_expiration\_model](#output\_default\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 76 | | [default\_external\_key\_state](#output\_default\_external\_key\_state) | The state of the CMK | 77 | | [default\_external\_key\_usage](#output\_default\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | 78 | | [default\_grants](#output\_default\_grants) | A map of grants created and their attributes | 79 | | [default\_key\_arn](#output\_default\_key\_arn) | The Amazon Resource Name (ARN) of the key | 80 | | [default\_key\_id](#output\_default\_key\_id) | The globally unique identifier for the key | 81 | | [default\_key\_policy](#output\_default\_key\_policy) | The IAM resource policy set on the key | 82 | | [external\_aliases](#output\_external\_aliases) | A map of aliases created and their attributes | 83 | | [external\_external\_key\_expiration\_model](#output\_external\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 84 | | [external\_external\_key\_state](#output\_external\_external\_key\_state) | The state of the CMK | 85 | | [external\_external\_key\_usage](#output\_external\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | 86 | | [external\_grants](#output\_external\_grants) | A map of grants created and their attributes | 87 | | [external\_key\_arn](#output\_external\_key\_arn) | The Amazon Resource Name (ARN) of the key | 88 | | [external\_key\_id](#output\_external\_key\_id) | The globally unique identifier for the key | 89 | | [external\_key\_policy](#output\_external\_key\_policy) | The IAM resource policy set on the key | 90 | | [replica\_aliases](#output\_replica\_aliases) | A map of aliases created and their attributes | 91 | | [replica\_external\_aliases](#output\_replica\_external\_aliases) | A map of aliases created and their attributes | 92 | | [replica\_external\_arn](#output\_replica\_external\_arn) | The Amazon Resource Name (ARN) of the key | 93 | | [replica\_external\_grants](#output\_replica\_external\_grants) | A map of grants created and their attributes | 94 | | [replica\_external\_key\_expiration\_model](#output\_replica\_external\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 95 | | [replica\_external\_key\_id](#output\_replica\_external\_key\_id) | The globally unique identifier for the key | 96 | | [replica\_external\_key\_policy](#output\_replica\_external\_key\_policy) | The IAM resource policy set on the key | 97 | | [replica\_external\_key\_state](#output\_replica\_external\_key\_state) | The state of the CMK | 98 | | [replica\_external\_key\_usage](#output\_replica\_external\_key\_usage) | The cryptographic operations for which you can use the CMK | 99 | | [replica\_grants](#output\_replica\_grants) | A map of grants created and their attributes | 100 | | [replica\_key\_arn](#output\_replica\_key\_arn) | The Amazon Resource Name (ARN) of the key | 101 | | [replica\_key\_expiration\_model](#output\_replica\_key\_expiration\_model) | Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE` | 102 | | [replica\_key\_id](#output\_replica\_key\_id) | The globally unique identifier for the key | 103 | | [replica\_key\_policy](#output\_replica\_key\_policy) | The IAM resource policy set on the key | 104 | | [replica\_key\_state](#output\_replica\_key\_state) | The state of the CMK | 105 | | [replica\_key\_usage](#output\_replica\_key\_usage) | The cryptographic operations for which you can use the CMK | 106 | 107 | 108 | Apache-2.0 Licensed. See [LICENSE](https://github.com/terraform-aws-modules/terraform-aws-kms/blob/master/LICENSE). 109 | -------------------------------------------------------------------------------- /examples/complete/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = local.region 3 | } 4 | 5 | locals { 6 | region = "us-east-1" 7 | name = "kms-ex-${replace(basename(path.cwd), "_", "-")}" 8 | current_identity = data.aws_caller_identity.current.arn 9 | 10 | tags = { 11 | Name = local.name 12 | Example = "complete" 13 | Repository = "https://github.com/terraform-aws-modules/terraform-aws-kms" 14 | } 15 | } 16 | 17 | data "aws_caller_identity" "current" {} 18 | data "aws_region" "current" {} 19 | 20 | ################################################################################ 21 | # KMS Module 22 | ################################################################################ 23 | 24 | module "kms_complete" { 25 | source = "../.." 26 | 27 | deletion_window_in_days = 7 28 | description = "Complete key example showing various configurations available" 29 | enable_key_rotation = false 30 | is_enabled = true 31 | key_usage = "ENCRYPT_DECRYPT" 32 | multi_region = false 33 | 34 | # Policy 35 | enable_default_policy = true 36 | key_owners = [local.current_identity] 37 | key_administrators = [local.current_identity] 38 | key_users = [local.current_identity] 39 | key_service_users = [local.current_identity] 40 | key_service_roles_for_autoscaling = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"] 41 | key_symmetric_encryption_users = [local.current_identity] 42 | key_hmac_users = [local.current_identity] 43 | key_asymmetric_public_encryption_users = [local.current_identity] 44 | key_asymmetric_sign_verify_users = [local.current_identity] 45 | key_statements = [ 46 | { 47 | sid = "CloudWatchLogs" 48 | actions = [ 49 | "kms:Encrypt*", 50 | "kms:Decrypt*", 51 | "kms:ReEncrypt*", 52 | "kms:GenerateDataKey*", 53 | "kms:Describe*" 54 | ] 55 | resources = ["*"] 56 | 57 | principals = [ 58 | { 59 | type = "Service" 60 | identifiers = ["logs.${data.aws_region.current.name}.amazonaws.com"] 61 | } 62 | ] 63 | 64 | conditions = [ 65 | { 66 | test = "ArnLike" 67 | variable = "kms:EncryptionContext:aws:logs:arn" 68 | values = [ 69 | "arn:aws:logs:${local.region}:${data.aws_caller_identity.current.account_id}:log-group:*", 70 | ] 71 | } 72 | ] 73 | } 74 | ] 75 | 76 | # Aliases 77 | aliases = ["one", "foo/bar"] 78 | computed_aliases = { 79 | ex = { 80 | # Sometimes you want to pass in an upstream attribute as the name and 81 | # that conflicts with using `for_each over a `toset()` since the value is not 82 | # known until after applying. Instead, we can use `computed_aliases` to work 83 | # around this limitation 84 | # Reference: https://github.com/hashicorp/terraform/issues/30937 85 | name = aws_iam_role.lambda.name 86 | } 87 | } 88 | aliases_use_name_prefix = true 89 | 90 | # Grants 91 | grants = { 92 | lambda = { 93 | grantee_principal = aws_iam_role.lambda.arn 94 | operations = ["Encrypt", "Decrypt", "GenerateDataKey"] 95 | constraints = { 96 | encryption_context_equals = { 97 | Department = "Finance" 98 | } 99 | } 100 | } 101 | } 102 | 103 | tags = local.tags 104 | } 105 | 106 | module "kms_external" { 107 | source = "../.." 108 | 109 | deletion_window_in_days = 7 110 | description = "External key example" 111 | create_external = true 112 | is_enabled = true 113 | key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" 114 | multi_region = false 115 | valid_to = "2023-11-21T23:20:50Z" 116 | 117 | tags = local.tags 118 | } 119 | 120 | module "kms_dnssec_signing" { 121 | source = "../.." 122 | 123 | description = "CMK for Route53 DNSSEC signing" 124 | 125 | key_usage = "SIGN_VERIFY" 126 | customer_master_key_spec = "ECC_NIST_P256" 127 | 128 | enable_route53_dnssec = true 129 | enable_key_rotation = false 130 | route53_dnssec_sources = [ 131 | { 132 | accounts_ids = [data.aws_caller_identity.current.account_id] # can ommit if using current account ID which is default 133 | hosted_zone_arn = "arn:aws:route53:::hostedzone/*" # can ommit, this is default value 134 | } 135 | ] 136 | 137 | aliases = ["route53/dnssec-ex"] 138 | 139 | tags = local.tags 140 | } 141 | 142 | module "kms_default" { 143 | source = "../.." 144 | 145 | tags = local.tags 146 | } 147 | 148 | module "kms_disabled" { 149 | source = "../.." 150 | 151 | create = false 152 | } 153 | 154 | ################################################################################ 155 | # Replica Key Example 156 | ################################################################################ 157 | 158 | module "kms_primary" { 159 | source = "../.." 160 | 161 | deletion_window_in_days = 7 162 | description = "Primary key of replica key example" 163 | enable_key_rotation = false 164 | is_enabled = true 165 | key_usage = "ENCRYPT_DECRYPT" 166 | multi_region = true 167 | 168 | aliases = ["primary-standard"] 169 | 170 | tags = local.tags 171 | } 172 | 173 | provider "aws" { 174 | region = "eu-west-1" 175 | alias = "replica" 176 | } 177 | 178 | module "kms_replica" { 179 | source = "../.." 180 | 181 | deletion_window_in_days = 7 182 | description = "Replica key example showing various configurations available" 183 | create_replica = true 184 | primary_key_arn = module.kms_primary.key_arn 185 | enable_default_policy = true 186 | 187 | key_owners = [local.current_identity] 188 | key_administrators = [local.current_identity] 189 | key_users = [local.current_identity] 190 | 191 | # Aliases 192 | aliases = ["replica-standard"] 193 | computed_aliases = { 194 | ex = { 195 | # Sometimes you want to pass in an upstream attribute as the name and 196 | # that conflicts with using `for_each over a `toset()` since the value is not 197 | # known until after applying. Instead, we can use `computed_aliases` to work 198 | # around this limitation 199 | # Reference: https://github.com/hashicorp/terraform/issues/30937 200 | name = aws_iam_role.lambda.name 201 | } 202 | } 203 | 204 | # Grants 205 | grants = { 206 | lambda = { 207 | grantee_principal = aws_iam_role.lambda.arn 208 | operations = ["Encrypt", "Decrypt", "GenerateDataKey"] 209 | constraints = { 210 | encryption_context_equals = { 211 | Department = "Finance" 212 | } 213 | } 214 | } 215 | } 216 | 217 | tags = local.tags 218 | 219 | providers = { 220 | aws = aws.replica 221 | } 222 | } 223 | 224 | ################################################################################ 225 | # Replica External Key Example 226 | ################################################################################ 227 | 228 | module "kms_primary_external" { 229 | source = "../.." 230 | 231 | deletion_window_in_days = 7 232 | description = "Primary external key of replica external key example" 233 | is_enabled = true 234 | create_external = true 235 | key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" 236 | multi_region = true 237 | valid_to = "2023-11-21T23:20:50Z" 238 | 239 | aliases = ["primary-external"] 240 | 241 | tags = local.tags 242 | } 243 | 244 | module "kms_replica_external" { 245 | source = "../.." 246 | 247 | deletion_window_in_days = 7 248 | description = "Replica external key example showing various configurations available" 249 | create_replica_external = true 250 | is_enabled = true 251 | # key material must be the same as the primary's 252 | key_material_base64 = "Wblj06fduthWggmsT0cLVoIMOkeLbc2kVfMud77i/JY=" 253 | primary_external_key_arn = module.kms_primary_external.key_arn 254 | valid_to = "2023-11-21T23:20:50Z" 255 | 256 | aliases = ["replica-external"] 257 | 258 | # Grants 259 | grants = { 260 | lambda = { 261 | grantee_principal = aws_iam_role.lambda.arn 262 | operations = ["Encrypt", "Decrypt", "GenerateDataKey"] 263 | constraints = { 264 | encryption_context_equals = { 265 | Department = "Finance" 266 | } 267 | } 268 | } 269 | } 270 | 271 | tags = local.tags 272 | 273 | providers = { 274 | aws = aws.replica 275 | } 276 | } 277 | 278 | ################################################################################ 279 | # Supporting Resources 280 | ################################################################################ 281 | 282 | resource "aws_iam_role" "lambda" { 283 | name_prefix = local.name 284 | 285 | assume_role_policy = jsonencode({ 286 | Version = "2012-10-17" 287 | Statement = [ 288 | { 289 | Effect = "Allow" 290 | Action = "sts:AssumeRole" 291 | Principal = { 292 | Service = "lambda.amazonaws.com" 293 | } 294 | } 295 | ] 296 | }) 297 | } 298 | -------------------------------------------------------------------------------- /examples/complete/outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Complete 3 | ################################################################################ 4 | 5 | output "complete_key_arn" { 6 | description = "The Amazon Resource Name (ARN) of the key" 7 | value = module.kms_complete.key_arn 8 | } 9 | 10 | output "complete_key_id" { 11 | description = "The globally unique identifier for the key" 12 | value = module.kms_complete.key_id 13 | } 14 | 15 | output "complete_key_policy" { 16 | description = "The IAM resource policy set on the key" 17 | value = module.kms_complete.key_policy 18 | } 19 | 20 | output "complete_external_key_expiration_model" { 21 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 22 | value = module.kms_complete.external_key_expiration_model 23 | } 24 | 25 | output "complete_external_key_state" { 26 | description = "The state of the CMK" 27 | value = module.kms_complete.external_key_state 28 | } 29 | 30 | output "complete_external_key_usage" { 31 | description = "The cryptographic operations for which you can use the CMK" 32 | value = module.kms_complete.external_key_usage 33 | } 34 | 35 | output "complete_aliases" { 36 | description = "A map of aliases created and their attributes" 37 | value = module.kms_complete.aliases 38 | } 39 | 40 | output "complete_grants" { 41 | description = "A map of grants created and their attributes" 42 | value = module.kms_complete.grants 43 | } 44 | 45 | ################################################################################ 46 | # External 47 | ################################################################################ 48 | 49 | output "external_key_arn" { 50 | description = "The Amazon Resource Name (ARN) of the key" 51 | value = module.kms_external.key_arn 52 | } 53 | 54 | output "external_key_id" { 55 | description = "The globally unique identifier for the key" 56 | value = module.kms_external.key_id 57 | } 58 | 59 | output "external_key_policy" { 60 | description = "The IAM resource policy set on the key" 61 | value = module.kms_external.key_policy 62 | } 63 | 64 | output "external_external_key_expiration_model" { 65 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 66 | value = module.kms_external.external_key_expiration_model 67 | } 68 | 69 | output "external_external_key_state" { 70 | description = "The state of the CMK" 71 | value = module.kms_external.external_key_state 72 | } 73 | 74 | output "external_external_key_usage" { 75 | description = "The cryptographic operations for which you can use the CMK" 76 | value = module.kms_external.external_key_usage 77 | } 78 | 79 | output "external_aliases" { 80 | description = "A map of aliases created and their attributes" 81 | value = module.kms_external.aliases 82 | } 83 | 84 | output "external_grants" { 85 | description = "A map of grants created and their attributes" 86 | value = module.kms_external.grants 87 | } 88 | 89 | ################################################################################ 90 | # Default 91 | ################################################################################ 92 | 93 | output "default_key_arn" { 94 | description = "The Amazon Resource Name (ARN) of the key" 95 | value = module.kms_default.key_arn 96 | } 97 | 98 | output "default_key_id" { 99 | description = "The globally unique identifier for the key" 100 | value = module.kms_default.key_id 101 | } 102 | 103 | output "default_key_policy" { 104 | description = "The IAM resource policy set on the key" 105 | value = module.kms_default.key_policy 106 | } 107 | 108 | output "default_external_key_expiration_model" { 109 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 110 | value = module.kms_default.external_key_expiration_model 111 | } 112 | 113 | output "default_external_key_state" { 114 | description = "The state of the CMK" 115 | value = module.kms_default.external_key_state 116 | } 117 | 118 | output "default_external_key_usage" { 119 | description = "The cryptographic operations for which you can use the CMK" 120 | value = module.kms_default.external_key_usage 121 | } 122 | 123 | output "default_aliases" { 124 | description = "A map of aliases created and their attributes" 125 | value = module.kms_default.aliases 126 | } 127 | 128 | output "default_grants" { 129 | description = "A map of grants created and their attributes" 130 | value = module.kms_default.grants 131 | } 132 | 133 | 134 | ################################################################################ 135 | # Replica 136 | ################################################################################ 137 | 138 | output "replica_key_arn" { 139 | description = "The Amazon Resource Name (ARN) of the key" 140 | value = module.kms_replica.key_arn 141 | } 142 | 143 | output "replica_key_id" { 144 | description = "The globally unique identifier for the key" 145 | value = module.kms_replica.key_id 146 | } 147 | 148 | output "replica_key_policy" { 149 | description = "The IAM resource policy set on the key" 150 | value = module.kms_replica.key_policy 151 | } 152 | 153 | output "replica_key_expiration_model" { 154 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 155 | value = module.kms_replica.external_key_expiration_model 156 | } 157 | 158 | output "replica_key_state" { 159 | description = "The state of the CMK" 160 | value = module.kms_replica.external_key_state 161 | } 162 | 163 | output "replica_key_usage" { 164 | description = "The cryptographic operations for which you can use the CMK" 165 | value = module.kms_replica.external_key_usage 166 | } 167 | 168 | output "replica_aliases" { 169 | description = "A map of aliases created and their attributes" 170 | value = module.kms_replica.aliases 171 | } 172 | 173 | output "replica_grants" { 174 | description = "A map of grants created and their attributes" 175 | value = module.kms_replica.grants 176 | } 177 | 178 | 179 | ################################################################################ 180 | # Replica External 181 | ################################################################################ 182 | 183 | output "replica_external_arn" { 184 | description = "The Amazon Resource Name (ARN) of the key" 185 | value = module.kms_replica_external.key_arn 186 | } 187 | 188 | output "replica_external_key_id" { 189 | description = "The globally unique identifier for the key" 190 | value = module.kms_replica_external.key_id 191 | } 192 | 193 | output "replica_external_key_policy" { 194 | description = "The IAM resource policy set on the key" 195 | value = module.kms_replica_external.key_policy 196 | } 197 | 198 | output "replica_external_key_expiration_model" { 199 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 200 | value = module.kms_replica_external.external_key_expiration_model 201 | } 202 | 203 | output "replica_external_key_state" { 204 | description = "The state of the CMK" 205 | value = module.kms_replica_external.external_key_state 206 | } 207 | 208 | output "replica_external_key_usage" { 209 | description = "The cryptographic operations for which you can use the CMK" 210 | value = module.kms_replica_external.external_key_usage 211 | } 212 | 213 | output "replica_external_aliases" { 214 | description = "A map of aliases created and their attributes" 215 | value = module.kms_replica_external.aliases 216 | } 217 | 218 | output "replica_external_grants" { 219 | description = "A map of grants created and their attributes" 220 | value = module.kms_replica_external.grants 221 | } 222 | -------------------------------------------------------------------------------- /examples/complete/variables.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/terraform-aws-modules/terraform-aws-kms/c20bffd41ce9716140cb9938faf0aa147b38ca2a/examples/complete/variables.tf -------------------------------------------------------------------------------- /examples/complete/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.49" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "aws_partition" "current" { 2 | count = var.create ? 1 : 0 3 | } 4 | data "aws_caller_identity" "current" { 5 | count = var.create ? 1 : 0 6 | } 7 | 8 | locals { 9 | account_id = try(data.aws_caller_identity.current[0].account_id, "") 10 | partition = try(data.aws_partition.current[0].partition, "") 11 | dns_suffix = try(data.aws_partition.current[0].dns_suffix, "") 12 | } 13 | 14 | ################################################################################ 15 | # Key 16 | ################################################################################ 17 | 18 | resource "aws_kms_key" "this" { 19 | count = var.create && !var.create_external && !var.create_replica && !var.create_replica_external ? 1 : 0 20 | 21 | bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check 22 | customer_master_key_spec = var.customer_master_key_spec 23 | custom_key_store_id = var.custom_key_store_id 24 | deletion_window_in_days = var.deletion_window_in_days 25 | description = var.description 26 | enable_key_rotation = var.enable_key_rotation 27 | is_enabled = var.is_enabled 28 | key_usage = var.key_usage 29 | multi_region = var.multi_region 30 | policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) 31 | rotation_period_in_days = var.rotation_period_in_days 32 | 33 | tags = var.tags 34 | } 35 | 36 | ################################################################################ 37 | # External Key 38 | ################################################################################ 39 | 40 | resource "aws_kms_external_key" "this" { 41 | count = var.create && var.create_external && !var.create_replica && !var.create_replica_external ? 1 : 0 42 | 43 | bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check 44 | deletion_window_in_days = var.deletion_window_in_days 45 | description = var.description 46 | enabled = var.is_enabled 47 | key_material_base64 = var.key_material_base64 48 | multi_region = var.multi_region 49 | policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) 50 | valid_to = var.valid_to 51 | 52 | tags = var.tags 53 | } 54 | 55 | ################################################################################ 56 | # Replica Key 57 | ################################################################################ 58 | 59 | resource "aws_kms_replica_key" "this" { 60 | count = var.create && var.create_replica && !var.create_external && !var.create_replica_external ? 1 : 0 61 | 62 | bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check 63 | deletion_window_in_days = var.deletion_window_in_days 64 | description = var.description 65 | primary_key_arn = var.primary_key_arn 66 | enabled = var.is_enabled 67 | policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) 68 | 69 | tags = var.tags 70 | } 71 | 72 | ################################################################################ 73 | # Replica External Key 74 | ################################################################################ 75 | 76 | resource "aws_kms_replica_external_key" "this" { 77 | count = var.create && !var.create_replica && !var.create_external && var.create_replica_external ? 1 : 0 78 | 79 | bypass_policy_lockout_safety_check = var.bypass_policy_lockout_safety_check 80 | deletion_window_in_days = var.deletion_window_in_days 81 | description = var.description 82 | enabled = var.is_enabled 83 | key_material_base64 = var.key_material_base64 84 | policy = coalesce(var.policy, data.aws_iam_policy_document.this[0].json) 85 | primary_key_arn = var.primary_external_key_arn 86 | valid_to = var.valid_to 87 | 88 | tags = var.tags 89 | } 90 | 91 | ################################################################################ 92 | # Policy 93 | ################################################################################ 94 | 95 | data "aws_iam_policy_document" "this" { 96 | count = var.create ? 1 : 0 97 | 98 | source_policy_documents = var.source_policy_documents 99 | override_policy_documents = var.override_policy_documents 100 | 101 | # Default policy - account wide access to all key operations 102 | dynamic "statement" { 103 | for_each = var.enable_default_policy ? [1] : [] 104 | 105 | content { 106 | sid = "Default" 107 | actions = ["kms:*"] 108 | resources = ["*"] 109 | 110 | principals { 111 | type = "AWS" 112 | identifiers = ["arn:${local.partition}:iam::${local.account_id}:root"] 113 | } 114 | } 115 | } 116 | 117 | # Key owner - all key operations 118 | dynamic "statement" { 119 | for_each = length(var.key_owners) > 0 ? [1] : [] 120 | 121 | content { 122 | sid = "KeyOwner" 123 | actions = ["kms:*"] 124 | resources = ["*"] 125 | 126 | principals { 127 | type = "AWS" 128 | identifiers = var.key_owners 129 | } 130 | } 131 | } 132 | 133 | # Key administrators - https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators 134 | dynamic "statement" { 135 | for_each = length(var.key_administrators) > 0 ? [1] : [] 136 | 137 | content { 138 | sid = "KeyAdministration" 139 | actions = [ 140 | "kms:Create*", 141 | "kms:Describe*", 142 | "kms:Enable*", 143 | "kms:List*", 144 | "kms:Put*", 145 | "kms:Update*", 146 | "kms:Revoke*", 147 | "kms:Disable*", 148 | "kms:Get*", 149 | "kms:Delete*", 150 | "kms:TagResource", 151 | "kms:UntagResource", 152 | "kms:ScheduleKeyDeletion", 153 | "kms:CancelKeyDeletion", 154 | "kms:ReplicateKey", 155 | "kms:ImportKeyMaterial" 156 | ] 157 | resources = ["*"] 158 | 159 | principals { 160 | type = "AWS" 161 | identifiers = var.key_administrators 162 | } 163 | } 164 | } 165 | 166 | # Key users - https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-users 167 | dynamic "statement" { 168 | for_each = length(var.key_users) > 0 ? [1] : [] 169 | 170 | content { 171 | sid = "KeyUsage" 172 | actions = [ 173 | "kms:Encrypt", 174 | "kms:Decrypt", 175 | "kms:ReEncrypt*", 176 | "kms:GenerateDataKey*", 177 | "kms:DescribeKey", 178 | ] 179 | resources = ["*"] 180 | 181 | principals { 182 | type = "AWS" 183 | identifiers = var.key_users 184 | } 185 | } 186 | } 187 | 188 | # Key service users - https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-service-integration 189 | dynamic "statement" { 190 | for_each = length(var.key_service_users) > 0 ? [1] : [] 191 | 192 | content { 193 | sid = "KeyServiceUsage" 194 | actions = [ 195 | "kms:CreateGrant", 196 | "kms:ListGrants", 197 | "kms:RevokeGrant", 198 | ] 199 | resources = ["*"] 200 | 201 | principals { 202 | type = "AWS" 203 | identifiers = var.key_service_users 204 | } 205 | 206 | condition { 207 | test = "Bool" 208 | variable = "kms:GrantIsForAWSResource" 209 | values = [true] 210 | } 211 | } 212 | } 213 | 214 | # Key service roles for autoscaling - https://docs.aws.amazon.com/autoscaling/ec2/userguide/key-policy-requirements-EBS-encryption.html#policy-example-cmk-access 215 | dynamic "statement" { 216 | for_each = length(var.key_service_roles_for_autoscaling) > 0 ? [1] : [] 217 | 218 | content { 219 | sid = "KeyServiceRolesASG" 220 | actions = [ 221 | "kms:Encrypt", 222 | "kms:Decrypt", 223 | "kms:ReEncrypt*", 224 | "kms:GenerateDataKey*", 225 | "kms:DescribeKey", 226 | ] 227 | resources = ["*"] 228 | 229 | principals { 230 | type = "AWS" 231 | identifiers = var.key_service_roles_for_autoscaling 232 | } 233 | } 234 | } 235 | 236 | dynamic "statement" { 237 | for_each = length(var.key_service_roles_for_autoscaling) > 0 ? [1] : [] 238 | 239 | content { 240 | sid = "KeyServiceRolesASGPersistentVol" 241 | actions = [ 242 | "kms:CreateGrant" 243 | ] 244 | resources = ["*"] 245 | 246 | principals { 247 | type = "AWS" 248 | identifiers = var.key_service_roles_for_autoscaling 249 | } 250 | 251 | condition { 252 | test = "Bool" 253 | variable = "kms:GrantIsForAWSResource" 254 | values = [true] 255 | } 256 | } 257 | } 258 | 259 | # Key cryptographic operations - https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto 260 | dynamic "statement" { 261 | for_each = length(var.key_symmetric_encryption_users) > 0 ? [1] : [] 262 | 263 | content { 264 | sid = "KeySymmetricEncryption" 265 | actions = [ 266 | "kms:Decrypt", 267 | "kms:DescribeKey", 268 | "kms:Encrypt", 269 | "kms:GenerateDataKey*", 270 | "kms:ReEncrypt*", 271 | ] 272 | resources = ["*"] 273 | 274 | principals { 275 | type = "AWS" 276 | identifiers = var.key_symmetric_encryption_users 277 | } 278 | } 279 | } 280 | 281 | dynamic "statement" { 282 | for_each = length(var.key_hmac_users) > 0 ? [1] : [] 283 | 284 | content { 285 | sid = "KeyHMAC" 286 | actions = [ 287 | "kms:DescribeKey", 288 | "kms:GenerateMac", 289 | "kms:VerifyMac", 290 | ] 291 | resources = ["*"] 292 | 293 | principals { 294 | type = "AWS" 295 | identifiers = var.key_hmac_users 296 | } 297 | } 298 | } 299 | 300 | dynamic "statement" { 301 | for_each = length(var.key_asymmetric_public_encryption_users) > 0 ? [1] : [] 302 | 303 | content { 304 | sid = "KeyAsymmetricPublicEncryption" 305 | actions = [ 306 | "kms:Encrypt", 307 | "kms:Decrypt", 308 | "kms:ReEncrypt*", 309 | "kms:DescribeKey", 310 | "kms:GetPublicKey", 311 | ] 312 | resources = ["*"] 313 | 314 | principals { 315 | type = "AWS" 316 | identifiers = var.key_asymmetric_public_encryption_users 317 | } 318 | } 319 | } 320 | 321 | dynamic "statement" { 322 | for_each = length(var.key_asymmetric_sign_verify_users) > 0 ? [1] : [] 323 | 324 | content { 325 | sid = "KeyAsymmetricSignVerify" 326 | actions = [ 327 | "kms:DescribeKey", 328 | "kms:GetPublicKey", 329 | "kms:Sign", 330 | "kms:Verify", 331 | ] 332 | resources = ["*"] 333 | 334 | principals { 335 | type = "AWS" 336 | identifiers = var.key_asymmetric_sign_verify_users 337 | } 338 | } 339 | } 340 | 341 | # https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/access-control-managing-permissions.html#KMS-key-policy-for-DNSSEC 342 | dynamic "statement" { 343 | for_each = var.enable_route53_dnssec ? [1] : [] 344 | 345 | content { 346 | sid = "Route53DnssecService" 347 | actions = [ 348 | "kms:DescribeKey", 349 | "kms:GetPublicKey", 350 | "kms:Sign", 351 | ] 352 | resources = ["*"] 353 | 354 | principals { 355 | type = "Service" 356 | identifiers = ["dnssec-route53.${local.dns_suffix}"] 357 | } 358 | } 359 | } 360 | 361 | # https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/access-control-managing-permissions.html#KMS-key-policy-for-DNSSEC 362 | dynamic "statement" { 363 | for_each = var.enable_route53_dnssec ? [1] : [] 364 | 365 | content { 366 | sid = "Route53DnssecGrant" 367 | actions = ["kms:CreateGrant"] 368 | resources = ["*"] 369 | 370 | principals { 371 | type = "Service" 372 | identifiers = ["dnssec-route53.${local.dns_suffix}"] 373 | } 374 | 375 | condition { 376 | test = "Bool" 377 | variable = "kms:GrantIsForAWSResource" 378 | values = ["true"] 379 | } 380 | 381 | dynamic "condition" { 382 | for_each = var.route53_dnssec_sources 383 | 384 | content { 385 | test = "StringEquals" 386 | variable = "aws:SourceAccount" 387 | values = try(condition.value.account_ids, [local.account_id]) 388 | } 389 | } 390 | 391 | dynamic "condition" { 392 | for_each = var.route53_dnssec_sources 393 | 394 | content { 395 | test = "ArnLike" 396 | variable = "aws:SourceArn" 397 | values = [try(condition.value.hosted_zone_arn, "arn:${local.partition}:route53:::hostedzone/*")] 398 | } 399 | } 400 | } 401 | } 402 | 403 | dynamic "statement" { 404 | for_each = var.key_statements 405 | 406 | content { 407 | sid = try(statement.value.sid, null) 408 | actions = try(statement.value.actions, null) 409 | not_actions = try(statement.value.not_actions, null) 410 | effect = try(statement.value.effect, null) 411 | resources = try(statement.value.resources, null) 412 | not_resources = try(statement.value.not_resources, null) 413 | 414 | dynamic "principals" { 415 | for_each = try(statement.value.principals, []) 416 | 417 | content { 418 | type = principals.value.type 419 | identifiers = principals.value.identifiers 420 | } 421 | } 422 | 423 | dynamic "not_principals" { 424 | for_each = try(statement.value.not_principals, []) 425 | 426 | content { 427 | type = not_principals.value.type 428 | identifiers = not_principals.value.identifiers 429 | } 430 | } 431 | 432 | dynamic "condition" { 433 | for_each = try(statement.value.conditions, []) 434 | 435 | content { 436 | test = condition.value.test 437 | values = condition.value.values 438 | variable = condition.value.variable 439 | } 440 | } 441 | } 442 | } 443 | } 444 | 445 | ################################################################################ 446 | # Alias 447 | ################################################################################ 448 | 449 | locals { 450 | aliases = { for k, v in toset(var.aliases) : k => { name = v } } 451 | } 452 | 453 | resource "aws_kms_alias" "this" { 454 | for_each = { for k, v in merge(local.aliases, var.computed_aliases) : k => v if var.create } 455 | 456 | name = var.aliases_use_name_prefix ? null : "alias/${each.value.name}" 457 | name_prefix = var.aliases_use_name_prefix ? "alias/${each.value.name}-" : null 458 | target_key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) 459 | } 460 | 461 | ################################################################################ 462 | # Grant 463 | ################################################################################ 464 | 465 | resource "aws_kms_grant" "this" { 466 | for_each = { for k, v in var.grants : k => v if var.create } 467 | 468 | name = try(each.value.name, each.key) 469 | key_id = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id) 470 | grantee_principal = each.value.grantee_principal 471 | operations = each.value.operations 472 | 473 | dynamic "constraints" { 474 | for_each = length(lookup(each.value, "constraints", {})) == 0 ? [] : [each.value.constraints] 475 | 476 | content { 477 | encryption_context_equals = try(constraints.value.encryption_context_equals, null) 478 | encryption_context_subset = try(constraints.value.encryption_context_subset, null) 479 | } 480 | } 481 | 482 | retiring_principal = try(each.value.retiring_principal, null) 483 | grant_creation_tokens = try(each.value.grant_creation_tokens, null) 484 | retire_on_delete = try(each.value.retire_on_delete, null) 485 | } 486 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Key 3 | ################################################################################ 4 | 5 | output "key_arn" { 6 | description = "The Amazon Resource Name (ARN) of the key" 7 | value = try(aws_kms_key.this[0].arn, aws_kms_external_key.this[0].arn, aws_kms_replica_key.this[0].arn, aws_kms_replica_external_key.this[0].arn, null) 8 | } 9 | 10 | output "key_id" { 11 | description = "The globally unique identifier for the key" 12 | value = try(aws_kms_key.this[0].key_id, aws_kms_external_key.this[0].id, aws_kms_replica_key.this[0].key_id, aws_kms_replica_external_key.this[0].key_id, null) 13 | } 14 | 15 | output "key_policy" { 16 | description = "The IAM resource policy set on the key" 17 | value = try(aws_kms_key.this[0].policy, aws_kms_external_key.this[0].policy, aws_kms_replica_key.this[0].policy, aws_kms_replica_external_key.this[0].policy, null) 18 | } 19 | 20 | output "external_key_expiration_model" { 21 | description = "Whether the key material expires. Empty when pending key material import, otherwise `KEY_MATERIAL_EXPIRES` or `KEY_MATERIAL_DOES_NOT_EXPIRE`" 22 | value = try(aws_kms_external_key.this[0].expiration_model, aws_kms_replica_external_key.this[0].expiration_model, null) 23 | } 24 | 25 | output "external_key_state" { 26 | description = "The state of the CMK" 27 | value = try(aws_kms_external_key.this[0].key_state, aws_kms_replica_external_key.this[0].key_state, null) 28 | } 29 | 30 | output "external_key_usage" { 31 | description = "The cryptographic operations for which you can use the CMK" 32 | value = try(aws_kms_external_key.this[0].key_usage, aws_kms_replica_external_key.this[0].key_usage, null) 33 | } 34 | 35 | ################################################################################ 36 | # Alias 37 | ################################################################################ 38 | 39 | output "aliases" { 40 | description = "A map of aliases created and their attributes" 41 | value = aws_kms_alias.this 42 | } 43 | 44 | ################################################################################ 45 | # Grant 46 | ################################################################################ 47 | 48 | output "grants" { 49 | description = "A map of grants created and their attributes" 50 | value = aws_kms_grant.this 51 | sensitive = true 52 | } 53 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "create" { 2 | description = "Determines whether resources will be created (affects all resources)" 3 | type = bool 4 | default = true 5 | } 6 | 7 | variable "tags" { 8 | description = "A map of tags to add to all resources" 9 | type = map(string) 10 | default = {} 11 | } 12 | 13 | ################################################################################ 14 | # Key 15 | ################################################################################ 16 | 17 | variable "create_external" { 18 | description = "Determines whether an external CMK (externally provided material) will be created or a standard CMK (AWS provided material)" 19 | type = bool 20 | default = false 21 | } 22 | 23 | variable "bypass_policy_lockout_safety_check" { 24 | 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" 25 | type = bool 26 | default = null 27 | } 28 | 29 | variable "customer_master_key_spec" { 30 | 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`, `HMAC_256`, `ECC_NIST_P256`, `ECC_NIST_P384`, `ECC_NIST_P521`, or `ECC_SECG_P256K1`. Defaults to `SYMMETRIC_DEFAULT`" 31 | type = string 32 | default = null 33 | } 34 | 35 | variable "custom_key_store_id" { 36 | description = "ID of the KMS Custom Key Store where the key will be stored instead of KMS (eg CloudHSM)." 37 | type = string 38 | default = null 39 | } 40 | 41 | variable "deletion_window_in_days" { 42 | description = "The waiting period, specified in number of days. After the waiting period ends, AWS KMS deletes the KMS key. If you specify a value, it must be between `7` and `30`, inclusive. If you do not specify a value, it defaults to `30`" 43 | type = number 44 | default = null 45 | } 46 | 47 | variable "description" { 48 | description = "The description of the key as viewed in AWS console" 49 | type = string 50 | default = null 51 | } 52 | 53 | variable "enable_key_rotation" { 54 | description = "Specifies whether key rotation is enabled. Defaults to `true`" 55 | type = bool 56 | default = true 57 | } 58 | 59 | variable "is_enabled" { 60 | description = "Specifies whether the key is enabled. Defaults to `true`" 61 | type = bool 62 | default = null 63 | } 64 | 65 | variable "key_material_base64" { 66 | description = "Base64 encoded 256-bit symmetric encryption key material to import. The CMK is permanently associated with this key material. External key only" 67 | type = string 68 | default = null 69 | } 70 | 71 | variable "key_usage" { 72 | description = "Specifies the intended use of the key. Valid values: `ENCRYPT_DECRYPT` or `SIGN_VERIFY`. Defaults to `ENCRYPT_DECRYPT`" 73 | type = string 74 | default = null 75 | } 76 | 77 | variable "multi_region" { 78 | description = "Indicates whether the KMS key is a multi-Region (`true`) or regional (`false`) key. Defaults to `false`" 79 | type = bool 80 | default = false 81 | } 82 | 83 | variable "policy" { 84 | 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" 85 | type = string 86 | default = null 87 | } 88 | 89 | variable "valid_to" { 90 | description = "Time at which the imported key material expires. When the key material expires, AWS KMS deletes the key material and the CMK becomes unusable. If not specified, key material does not expire" 91 | type = string 92 | default = null 93 | } 94 | 95 | variable "enable_default_policy" { 96 | description = "Specifies whether to enable the default key policy. Defaults to `true`" 97 | type = bool 98 | default = true 99 | } 100 | 101 | variable "key_owners" { 102 | description = "A list of IAM ARNs for those who will have full key permissions (`kms:*`)" 103 | type = list(string) 104 | default = [] 105 | } 106 | 107 | variable "key_administrators" { 108 | description = "A list of IAM ARNs for [key administrators](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-administrators)" 109 | type = list(string) 110 | default = [] 111 | } 112 | 113 | variable "key_users" { 114 | description = "A list of IAM ARNs for [key users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-default-allow-users)" 115 | type = list(string) 116 | default = [] 117 | } 118 | 119 | variable "key_service_users" { 120 | description = "A list of IAM ARNs for [key service users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-service-integration)" 121 | type = list(string) 122 | default = [] 123 | } 124 | 125 | variable "key_service_roles_for_autoscaling" { 126 | description = "A list of IAM ARNs for [AWSServiceRoleForAutoScaling roles](https://docs.aws.amazon.com/autoscaling/ec2/userguide/key-policy-requirements-EBS-encryption.html#policy-example-cmk-access)" 127 | type = list(string) 128 | default = [] 129 | } 130 | 131 | variable "key_symmetric_encryption_users" { 132 | description = "A list of IAM ARNs for [key symmetric encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto)" 133 | type = list(string) 134 | default = [] 135 | } 136 | 137 | variable "key_hmac_users" { 138 | description = "A list of IAM ARNs for [key HMAC users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto)" 139 | type = list(string) 140 | default = [] 141 | } 142 | 143 | variable "key_asymmetric_public_encryption_users" { 144 | description = "A list of IAM ARNs for [key asymmetric public encryption users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto)" 145 | type = list(string) 146 | default = [] 147 | } 148 | 149 | variable "key_asymmetric_sign_verify_users" { 150 | description = "A list of IAM ARNs for [key asymmetric sign and verify users](https://docs.aws.amazon.com/kms/latest/developerguide/key-policy-default.html#key-policy-users-crypto)" 151 | type = list(string) 152 | default = [] 153 | } 154 | 155 | variable "key_statements" { 156 | description = "A map of IAM policy [statements](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document#statement) for custom permission usage" 157 | type = any 158 | default = {} 159 | } 160 | 161 | variable "source_policy_documents" { 162 | description = "List of IAM policy documents that are merged together into the exported document. Statements must have unique `sid`s" 163 | type = list(string) 164 | default = [] 165 | } 166 | 167 | variable "override_policy_documents" { 168 | description = "List of IAM policy documents that are merged together into the exported document. In merging, statements with non-blank `sid`s will override statements with the same `sid`" 169 | type = list(string) 170 | default = [] 171 | } 172 | 173 | variable "enable_route53_dnssec" { 174 | description = "Determines whether the KMS policy used for Route53 DNSSEC signing is enabled" 175 | type = bool 176 | default = false 177 | } 178 | 179 | variable "route53_dnssec_sources" { 180 | description = "A list of maps containing `account_ids` and Route53 `hosted_zone_arn` that will be allowed to sign DNSSEC records" 181 | type = list(any) 182 | default = [] 183 | } 184 | 185 | variable "rotation_period_in_days" { 186 | description = "Custom period of time between each rotation date. Must be a number between 90 and 2560 (inclusive)" 187 | type = number 188 | default = null 189 | } 190 | 191 | ################################################################################ 192 | # Replica Key 193 | ################################################################################ 194 | 195 | variable "create_replica" { 196 | description = "Determines whether a replica standard CMK will be created (AWS provided material)" 197 | type = bool 198 | default = false 199 | } 200 | 201 | variable "primary_key_arn" { 202 | description = "The primary key arn of a multi-region replica key" 203 | type = string 204 | default = null 205 | } 206 | 207 | ################################################################################ 208 | # Replica External Key 209 | ################################################################################ 210 | 211 | variable "create_replica_external" { 212 | description = "Determines whether a replica external CMK will be created (externally provided material)" 213 | type = bool 214 | default = false 215 | } 216 | 217 | variable "primary_external_key_arn" { 218 | description = "The primary external key arn of a multi-region replica external key" 219 | type = string 220 | default = null 221 | } 222 | 223 | ################################################################################ 224 | # Alias 225 | ################################################################################ 226 | 227 | variable "aliases" { 228 | description = "A list of aliases to create. Note - due to the use of `toset()`, values must be static strings and not computed values" 229 | type = list(string) 230 | default = [] 231 | } 232 | 233 | variable "computed_aliases" { 234 | description = "A map of aliases to create. Values provided via the `name` key of the map can be computed from upstream resources" 235 | type = any 236 | default = {} 237 | } 238 | 239 | variable "aliases_use_name_prefix" { 240 | description = "Determines whether the alias name is used as a prefix" 241 | type = bool 242 | default = false 243 | } 244 | 245 | ################################################################################ 246 | # Grant 247 | ################################################################################ 248 | 249 | variable "grants" { 250 | description = "A map of grant definitions to create" 251 | type = any 252 | default = {} 253 | } 254 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.49" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /wrappers/README.md: -------------------------------------------------------------------------------- 1 | # Wrapper for the root module 2 | 3 | The configuration in this directory contains an implementation of a single module wrapper pattern, which allows managing several copies of a module in places where using the native Terraform 0.13+ `for_each` feature is not feasible (e.g., with Terragrunt). 4 | 5 | You may want to use a single Terragrunt configuration file to manage multiple resources without duplicating `terragrunt.hcl` files for each copy of the same module. 6 | 7 | This wrapper does not implement any extra functionality. 8 | 9 | ## Usage with Terragrunt 10 | 11 | `terragrunt.hcl`: 12 | 13 | ```hcl 14 | terraform { 15 | source = "tfr:///terraform-aws-modules/kms/aws//wrappers" 16 | # Alternative source: 17 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-kms.git//wrappers?ref=master" 18 | } 19 | 20 | inputs = { 21 | defaults = { # Default values 22 | create = true 23 | tags = { 24 | Terraform = "true" 25 | Environment = "dev" 26 | } 27 | } 28 | 29 | items = { 30 | my-item = { 31 | # omitted... can be any argument supported by the module 32 | } 33 | my-second-item = { 34 | # omitted... can be any argument supported by the module 35 | } 36 | # omitted... 37 | } 38 | } 39 | ``` 40 | 41 | ## Usage with Terraform 42 | 43 | ```hcl 44 | module "wrapper" { 45 | source = "terraform-aws-modules/kms/aws//wrappers" 46 | 47 | defaults = { # Default values 48 | create = true 49 | tags = { 50 | Terraform = "true" 51 | Environment = "dev" 52 | } 53 | } 54 | 55 | items = { 56 | my-item = { 57 | # omitted... can be any argument supported by the module 58 | } 59 | my-second-item = { 60 | # omitted... can be any argument supported by the module 61 | } 62 | # omitted... 63 | } 64 | } 65 | ``` 66 | 67 | ## Example: Manage multiple S3 buckets in one Terragrunt layer 68 | 69 | `eu-west-1/s3-buckets/terragrunt.hcl`: 70 | 71 | ```hcl 72 | terraform { 73 | source = "tfr:///terraform-aws-modules/s3-bucket/aws//wrappers" 74 | # Alternative source: 75 | # source = "git::git@github.com:terraform-aws-modules/terraform-aws-s3-bucket.git//wrappers?ref=master" 76 | } 77 | 78 | inputs = { 79 | defaults = { 80 | force_destroy = true 81 | 82 | attach_elb_log_delivery_policy = true 83 | attach_lb_log_delivery_policy = true 84 | attach_deny_insecure_transport_policy = true 85 | attach_require_latest_tls_policy = true 86 | } 87 | 88 | items = { 89 | bucket1 = { 90 | bucket = "my-random-bucket-1" 91 | } 92 | bucket2 = { 93 | bucket = "my-random-bucket-2" 94 | tags = { 95 | Secure = "probably" 96 | } 97 | } 98 | } 99 | } 100 | ``` 101 | -------------------------------------------------------------------------------- /wrappers/main.tf: -------------------------------------------------------------------------------- 1 | module "wrapper" { 2 | source = "../" 3 | 4 | for_each = var.items 5 | 6 | aliases = try(each.value.aliases, var.defaults.aliases, []) 7 | aliases_use_name_prefix = try(each.value.aliases_use_name_prefix, var.defaults.aliases_use_name_prefix, false) 8 | bypass_policy_lockout_safety_check = try(each.value.bypass_policy_lockout_safety_check, var.defaults.bypass_policy_lockout_safety_check, null) 9 | computed_aliases = try(each.value.computed_aliases, var.defaults.computed_aliases, {}) 10 | create = try(each.value.create, var.defaults.create, true) 11 | create_external = try(each.value.create_external, var.defaults.create_external, false) 12 | create_replica = try(each.value.create_replica, var.defaults.create_replica, false) 13 | create_replica_external = try(each.value.create_replica_external, var.defaults.create_replica_external, false) 14 | custom_key_store_id = try(each.value.custom_key_store_id, var.defaults.custom_key_store_id, null) 15 | customer_master_key_spec = try(each.value.customer_master_key_spec, var.defaults.customer_master_key_spec, null) 16 | deletion_window_in_days = try(each.value.deletion_window_in_days, var.defaults.deletion_window_in_days, null) 17 | description = try(each.value.description, var.defaults.description, null) 18 | enable_default_policy = try(each.value.enable_default_policy, var.defaults.enable_default_policy, true) 19 | enable_key_rotation = try(each.value.enable_key_rotation, var.defaults.enable_key_rotation, true) 20 | enable_route53_dnssec = try(each.value.enable_route53_dnssec, var.defaults.enable_route53_dnssec, false) 21 | grants = try(each.value.grants, var.defaults.grants, {}) 22 | is_enabled = try(each.value.is_enabled, var.defaults.is_enabled, null) 23 | key_administrators = try(each.value.key_administrators, var.defaults.key_administrators, []) 24 | key_asymmetric_public_encryption_users = try(each.value.key_asymmetric_public_encryption_users, var.defaults.key_asymmetric_public_encryption_users, []) 25 | key_asymmetric_sign_verify_users = try(each.value.key_asymmetric_sign_verify_users, var.defaults.key_asymmetric_sign_verify_users, []) 26 | key_hmac_users = try(each.value.key_hmac_users, var.defaults.key_hmac_users, []) 27 | key_material_base64 = try(each.value.key_material_base64, var.defaults.key_material_base64, null) 28 | key_owners = try(each.value.key_owners, var.defaults.key_owners, []) 29 | key_service_roles_for_autoscaling = try(each.value.key_service_roles_for_autoscaling, var.defaults.key_service_roles_for_autoscaling, []) 30 | key_service_users = try(each.value.key_service_users, var.defaults.key_service_users, []) 31 | key_statements = try(each.value.key_statements, var.defaults.key_statements, {}) 32 | key_symmetric_encryption_users = try(each.value.key_symmetric_encryption_users, var.defaults.key_symmetric_encryption_users, []) 33 | key_usage = try(each.value.key_usage, var.defaults.key_usage, null) 34 | key_users = try(each.value.key_users, var.defaults.key_users, []) 35 | multi_region = try(each.value.multi_region, var.defaults.multi_region, false) 36 | override_policy_documents = try(each.value.override_policy_documents, var.defaults.override_policy_documents, []) 37 | policy = try(each.value.policy, var.defaults.policy, null) 38 | primary_external_key_arn = try(each.value.primary_external_key_arn, var.defaults.primary_external_key_arn, null) 39 | primary_key_arn = try(each.value.primary_key_arn, var.defaults.primary_key_arn, null) 40 | rotation_period_in_days = try(each.value.rotation_period_in_days, var.defaults.rotation_period_in_days, null) 41 | route53_dnssec_sources = try(each.value.route53_dnssec_sources, var.defaults.route53_dnssec_sources, []) 42 | source_policy_documents = try(each.value.source_policy_documents, var.defaults.source_policy_documents, []) 43 | tags = try(each.value.tags, var.defaults.tags, {}) 44 | valid_to = try(each.value.valid_to, var.defaults.valid_to, null) 45 | } 46 | -------------------------------------------------------------------------------- /wrappers/outputs.tf: -------------------------------------------------------------------------------- 1 | output "wrapper" { 2 | description = "Map of outputs of a wrapper." 3 | value = module.wrapper 4 | sensitive = true # At least one sensitive module output (grants) found (requires Terraform 0.14+) 5 | } 6 | -------------------------------------------------------------------------------- /wrappers/variables.tf: -------------------------------------------------------------------------------- 1 | variable "defaults" { 2 | description = "Map of default values which will be used for each item." 3 | type = any 4 | default = {} 5 | } 6 | 7 | variable "items" { 8 | description = "Maps of items to create a wrapper from. Values are passed through to the module." 9 | type = any 10 | default = {} 11 | } 12 | -------------------------------------------------------------------------------- /wrappers/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.3" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.49" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------