├── .editorconfig ├── .github ├── CODEOWNERS ├── dependabot.yml ├── labeler.yaml ├── labels.yaml └── workflows │ ├── pull-request-labeler.yaml │ ├── sync-labels.yaml │ ├── terraform.integration.yaml │ ├── welcome.yaml │ └── yaml.integration.yaml ├── .gitignore ├── .pre-commit-config.yaml ├── .tflint.hcl ├── .yamllint.yaml ├── LICENSE ├── README.md ├── VERSION ├── examples ├── elasticache-redis-full │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── elasticache-redis-muti-az │ ├── main.tf │ ├── outputs.tf │ └── versions.tf ├── elasticache-redis-single │ ├── main.tf │ ├── outputs.tf │ └── versions.tf └── elasticache-redis-with-users │ ├── main.tf │ ├── outputs.tf │ └── versions.tf └── modules ├── elasticache-redis-cluster ├── README.md ├── main.tf ├── outputs.tf ├── resource-group.tf ├── security-group.tf ├── variables.tf └── versions.tf ├── elasticache-redis-user-group ├── README.md ├── main.tf ├── outputs.tf ├── resource-group.tf ├── variables.tf └── versions.tf └── elasticache-redis-user ├── README.md ├── main.tf ├── outputs.tf ├── resource-group.tf ├── variables.tf └── versions.tf /.editorconfig: -------------------------------------------------------------------------------- 1 | # Top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 150 12 | 13 | [*.{tf,tfvars}] 14 | indent_size = 2 15 | indent_style = space 16 | 17 | [*.md] 18 | max_line_length = 0 19 | 20 | [COMMIT_EDITMSG] 21 | max_line_length = 0 22 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @posquit0 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | 8 | - package-ecosystem: terraform 9 | directories: 10 | - /modules/* 11 | schedule: 12 | interval: weekly 13 | -------------------------------------------------------------------------------- /.github/labeler.yaml: -------------------------------------------------------------------------------- 1 | # Modules 2 | ":floppy_disk: elasticache-redis-cluster": 3 | - changed-files: 4 | - any-glob-to-any-file: 5 | - modules/elasticache-redis-cluster/**/* 6 | -------------------------------------------------------------------------------- /.github/labels.yaml: -------------------------------------------------------------------------------- 1 | # Warning 2 | - color: "ee0701" 3 | description: "Categorize bug reports." 4 | name: ":warning: bug" 5 | - color: "ee0701" 6 | description: "Categorize vulnerability reports." 7 | name: ":warning: vulnerability" 8 | 9 | # Highlight 10 | - color: "0e8a16" 11 | description: "Good for newcomers." 12 | name: ":fire: good first issue" 13 | - color: "0e8a16" 14 | description: "Extra attention is needed." 15 | name: ":fire: help wanted" 16 | 17 | # Cancel 18 | - color: "b60205" 19 | description: "This issue or pull request already exists." 20 | name: ":pray: duplicate" 21 | - color: "b60205" 22 | description: "This will not be worked on." 23 | name: ":pray: wontfix" 24 | 25 | # Size 26 | - color: "cfd3d7" 27 | description: "Extra Small size issue or PR." 28 | name: "size/XS" 29 | - color: "cfd3d7" 30 | description: "Small size issue or PR." 31 | name: "size/S" 32 | - color: "cfd3d7" 33 | description: "Medium size issue or PR." 34 | name: "size/M" 35 | - color: "cfd3d7" 36 | description: "Large size issue or PR." 37 | name: "size/L" 38 | - color: "cfd3d7" 39 | description: "Extra Large size issue or PR." 40 | name: "size/XL" 41 | 42 | # Modules 43 | - color: "fbca04" 44 | description: "This issue or pull request is related to elasticache-redis-cluster module." 45 | name: ":floppy_disk: elasticache-redis-cluster" 46 | -------------------------------------------------------------------------------- /.github/workflows/pull-request-labeler.yaml: -------------------------------------------------------------------------------- 1 | name: Label Pull Requests 2 | 3 | on: 4 | - pull_request_target 5 | 6 | jobs: 7 | label-pr: 8 | runs-on: ubuntu-latest 9 | 10 | permissions: 11 | contents: read 12 | pull-requests: write 13 | 14 | steps: 15 | - name: Add Labels for PR 16 | uses: actions/labeler@v5 17 | with: 18 | repo-token: "${{ secrets.GITHUB_TOKEN }}" 19 | configuration-path: .github/labeler.yaml 20 | dot: true 21 | sync-labels: true 22 | 23 | - name: Add PR Size Labels for PR 24 | uses: codelytv/pr-size-labeler@v1 25 | with: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | xs_label: 'size/XS' 28 | xs_max_size: '20' 29 | s_label: 'size/S' 30 | s_max_size: '50' 31 | m_label: 'size/M' 32 | m_max_size: '150' 33 | l_label: 'size/L' 34 | l_max_size: '300' 35 | xl_label: 'size/XL' 36 | fail_if_xl: 'false' 37 | message_if_xl: > 38 | 'This PR has too many changes. 39 | Please make sure you are NOT addressing multiple issues with one PR.' 40 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yaml: -------------------------------------------------------------------------------- 1 | name: Sync labels 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - .github/labels.yaml 9 | workflow_dispatch: {} 10 | 11 | jobs: 12 | sync-labels: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - name: Sync labels 20 | uses: crazy-max/ghaction-github-labeler@v5 21 | with: 22 | github-token: ${{ secrets.GITHUB_TOKEN }} 23 | yaml-file: .github/labels.yaml 24 | skip-delete: false 25 | dry-run: false 26 | # exclude: | 27 | -------------------------------------------------------------------------------- /.github/workflows/terraform.integration.yaml: -------------------------------------------------------------------------------- 1 | name: Integration (Terraform) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: {} 8 | 9 | concurrency: 10 | group: terraform-integration-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | changed: 15 | name: Filter Changed Files and Directories 16 | runs-on: ubuntu-latest 17 | 18 | outputs: 19 | changed: ${{ steps.set-outputs.outputs.changed }} 20 | modified: ${{ steps.set-outputs.outputs.modified }} 21 | changed_files: ${{ steps.set-outputs.outputs.changed_files }} 22 | modified_files: ${{ steps.set-outputs.outputs.modified_files }} 23 | changed_directories: ${{ steps.set-outputs.outputs.changed_directories }} 24 | modified_directories: ${{ steps.set-outputs.outputs.modified_directories }} 25 | 26 | steps: 27 | - name: Checkout 28 | uses: actions/checkout@v4 29 | with: 30 | fetch-depth: 0 31 | 32 | - name: Get Changed Files 33 | id: changed-files 34 | uses: tj-actions/changed-files@v42 35 | with: 36 | files: | 37 | modules/** 38 | examples/** 39 | json: true 40 | 41 | - name: Get Changed Directories 42 | id: changed-directories 43 | uses: tj-actions/changed-files@v42 44 | with: 45 | files: | 46 | modules/** 47 | examples/** 48 | dir_names: "true" 49 | dir_names_max_depth: 2 50 | json: true 51 | 52 | - name: Set outputs 53 | id: set-outputs 54 | run: | 55 | echo "changed=${{ steps.changed-directories.outputs.any_changed }}" >> $GITHUB_OUTPUT 56 | echo "modified=${{ steps.changed-directories.outputs.any_modified }}" >> $GITHUB_OUTPUT 57 | 58 | echo "changed_files=${{ steps.changed-files.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 59 | echo "modified_files=${{ steps.changed-files.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 60 | 61 | echo "changed_directories=${{ steps.changed-directories.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 62 | echo "modified_directories=${{ steps.changed-directories.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 63 | 64 | 65 | terraform: 66 | name: Lint (terraform) 67 | needs: 68 | - changed 69 | if: ${{ needs.changed.outputs.modified == 'true' }} 70 | uses: tedilabs/.github/.github/workflows/terraform.terraform.yaml@main 71 | 72 | strategy: 73 | matrix: 74 | path: ${{ fromJson(needs.changed.outputs.modified_directories) }} 75 | 76 | with: 77 | terraform_target_dir: ${{ matrix.path }} 78 | terraform_version: latest 79 | terraform_host: app.terraform.io 80 | secrets: 81 | gh_token: ${{ secrets.GITHUB_TOKEN }} 82 | token: ${{ secrets.GITHUB_TOKEN }} 83 | terraform_token: ${{ secrets.TERRAFORM_TOKEN }} 84 | 85 | 86 | tflint: 87 | name: Lint (tflint) 88 | needs: 89 | - changed 90 | if: ${{ needs.changed.outputs.modified == 'true' }} 91 | uses: tedilabs/.github/.github/workflows/terraform.tflint.yaml@main 92 | 93 | strategy: 94 | matrix: 95 | path: ${{ fromJson(needs.changed.outputs.modified_directories) }} 96 | 97 | with: 98 | tflint_version: latest 99 | tflint_config_file: .tflint.hcl 100 | tflint_target_dir: ${{ matrix.path }} 101 | tflint_recursive_enabled: false 102 | tflint_terraform_init_enabled: true 103 | terraform_version: latest 104 | terraform_host: app.terraform.io 105 | secrets: 106 | gh_token: ${{ secrets.GITHUB_TOKEN }} 107 | token: ${{ secrets.GITHUB_TOKEN }} 108 | terraform_token: ${{ secrets.TERRAFORM_TOKEN }} 109 | -------------------------------------------------------------------------------- /.github/workflows/welcome.yaml: -------------------------------------------------------------------------------- 1 | name: Welcome for First Issue or Pull Request 2 | 3 | on: 4 | pull_request_target: 5 | types: 6 | - opened 7 | issues: 8 | types: 9 | - opened 10 | 11 | jobs: 12 | welcome: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Welcome for First Issue or Pull Request 17 | uses: actions/first-interaction@v1 18 | with: 19 | repo-token: ${{ secrets.GITHUB_TOKEN }} 20 | issue-message: | 21 | ### :wave: Welcome! Looks like this is your first issue. 22 | 23 | Hey, thanks for your contribution! Please give us a bit of time to review it. 😄 24 | 25 | **Be sure to follow the issue template!** 26 | pr-message: | 27 | ### :wave: Welcome! Looks like this is your first pull request. 28 | 29 | Hey, thanks for your contribution! Please give us a bit of time to review it. 😄 30 | 31 | **Please check out our contributing guidelines.** 32 | -------------------------------------------------------------------------------- /.github/workflows/yaml.integration.yaml: -------------------------------------------------------------------------------- 1 | name: Integration (YAML) 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: {} 8 | 9 | concurrency: 10 | group: yaml-integration-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | changed: 15 | name: Filter Changed Files and Directories 16 | runs-on: ubuntu-latest 17 | 18 | outputs: 19 | changed: ${{ steps.set-outputs.outputs.changed }} 20 | modified: ${{ steps.set-outputs.outputs.modified }} 21 | changed_files: ${{ steps.set-outputs.outputs.changed_files }} 22 | modified_files: ${{ steps.set-outputs.outputs.modified_files }} 23 | 24 | steps: 25 | - name: Checkout 26 | uses: actions/checkout@v4 27 | with: 28 | fetch-depth: 0 29 | 30 | - name: Get Changed Files 31 | id: changed-files 32 | uses: tj-actions/changed-files@v42 33 | with: 34 | files: | 35 | **/*.yaml 36 | **/*.yml 37 | json: true 38 | 39 | - name: Set outputs 40 | id: set-outputs 41 | run: | 42 | echo "changed=${{ steps.changed-files.outputs.any_changed }}" >> $GITHUB_OUTPUT 43 | echo "modified=${{ steps.changed-files.outputs.any_modified }}" >> $GITHUB_OUTPUT 44 | 45 | echo "changed_files=${{ steps.changed-files.outputs.all_changed_files }}" >> $GITHUB_OUTPUT 46 | echo "modified_files=${{ steps.changed-files.outputs.all_modified_files }}" >> $GITHUB_OUTPUT 47 | 48 | lint: 49 | name: Lint (yamllint) 50 | needs: 51 | - changed 52 | if: ${{ needs.changed.outputs.modified == 'true' }} 53 | uses: tedilabs/.github/.github/workflows/yaml.yamllint.yaml@main 54 | 55 | with: 56 | yamllint_version: latest 57 | yamllint_config_file: .yamllint.yaml 58 | yamllint_target_dir: ./ 59 | secrets: 60 | token: ${{ secrets.GITHUB_TOKEN }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### OSX ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | 30 | ### Terraform ### 31 | # Lock file 32 | .terraform.lock.hcl 33 | 34 | # Local .terraform directories 35 | **/.terraform/* 36 | 37 | # .tfstate files 38 | *.tfstate 39 | *.tfstate.* 40 | 41 | # Crash log files 42 | crash.log 43 | 44 | # Ignore any .tfvars files that are generated automatically for each Terraform run. Most 45 | # .tfvars files are managed as part of configuration and so should be included in 46 | # version control. 47 | # 48 | # example.tfvars 49 | 50 | # Ignore override files as they are usually used to override resources locally and so 51 | # are not checked in 52 | override.tf 53 | override.tf.json 54 | *_override.tf 55 | *_override.tf.json 56 | 57 | # Include override files you do wish to add to version control using negated pattern 58 | # !example_override.tf 59 | 60 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 61 | # example: *tfplan* 62 | 63 | 64 | ### Vim ### 65 | # Swap 66 | [._]*.s[a-v][a-z] 67 | !*.svg # comment out if you don't need vector files 68 | [._]*.sw[a-p] 69 | [._]s[a-rt-v][a-z] 70 | [._]ss[a-gi-z] 71 | [._]sw[a-p] 72 | 73 | # Session 74 | Session.vim 75 | Sessionx.vim 76 | 77 | # Temporary 78 | .netrwhist 79 | *~ 80 | # Auto-generated tag files 81 | tags 82 | # Persistent undo 83 | [._]*.un~ 84 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_install_hook_types: 2 | - pre-commit 3 | - commit-msg 4 | 5 | repos: 6 | - repo: https://github.com/antonbabenko/pre-commit-terraform 7 | rev: v1.97.4 8 | hooks: 9 | - id: terraform_fmt 10 | name: (terraform) Format .tf files with `terraform fmt` 11 | args: 12 | - --args=-diff 13 | - id: terraform_validate 14 | name: (terraform) Check with `terraform validate` 15 | args: 16 | - --hook-config=--retry-once-with-cleanup=true 17 | - --tf-init-args=-upgrade 18 | - id: terraform_tflint 19 | name: (terraform) Check with `tflint` 20 | args: 21 | - --args=--config=__GIT_WORKING_DIR__/.tflint.hcl 22 | files: ^modules/ 23 | - id: terraform_docs 24 | name: (terraform) Generate docs with `terraform-docs` 25 | args: ["--args=--sort-by required"] 26 | 27 | - repo: https://github.com/adrienverge/yamllint 28 | rev: v1.36.2 29 | hooks: 30 | - id: yamllint 31 | name: (yaml) Check with `yamllint` 32 | 33 | - repo: https://github.com/compilerla/conventional-pre-commit 34 | rev: v4.0.0 35 | hooks: 36 | - id: conventional-pre-commit 37 | name: (commit-message) Check conventional commit 38 | stages: [commit-msg] 39 | args: [] 40 | -------------------------------------------------------------------------------- /.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | plugin_dir = "~/.tflint.d/plugins" 3 | 4 | format = "compact" 5 | call_module_type = "local" 6 | force = false 7 | disabled_by_default = false 8 | 9 | ignore_module = {} 10 | } 11 | 12 | 13 | ################################################### 14 | # Rule Sets - Terraform 15 | ################################################### 16 | 17 | plugin "terraform" { 18 | enabled = true 19 | preset = "recommended" 20 | } 21 | 22 | rule "terraform_comment_syntax" { 23 | enabled = true 24 | } 25 | 26 | rule "terraform_documented_variables" { 27 | enabled = true 28 | } 29 | 30 | rule "terraform_documented_outputs" { 31 | enabled = true 32 | } 33 | 34 | rule "terraform_naming_convention" { 35 | enabled = true 36 | format = "snake_case" 37 | 38 | custom_formats = { 39 | extended_snake_case = { 40 | description = "Extended snake_case Format which allows double underscore like `a__b`." 41 | regex = "^[a-z][a-z0-9]+([_]{1,2}[a-z0-9]+)*$" 42 | } 43 | } 44 | 45 | module { 46 | format = "extended_snake_case" 47 | } 48 | 49 | resource { 50 | format = "extended_snake_case" 51 | } 52 | 53 | data { 54 | format = "extended_snake_case" 55 | } 56 | } 57 | 58 | rule "terraform_unused_declarations" { 59 | enabled = false 60 | } 61 | 62 | rule "terraform_unused_required_providers" { 63 | enabled = true 64 | } 65 | 66 | 67 | ################################################### 68 | # Rule Sets - AWS 69 | ################################################### 70 | 71 | plugin "aws" { 72 | source = "github.com/terraform-linters/tflint-ruleset-aws" 73 | version = "0.38.0" 74 | 75 | enabled = true 76 | deep_check = false 77 | } 78 | -------------------------------------------------------------------------------- /.yamllint.yaml: -------------------------------------------------------------------------------- 1 | yaml-files: 2 | - '*.yaml' 3 | - '*.yml' 4 | 5 | rules: 6 | braces: 7 | min-spaces-inside: 0 8 | max-spaces-inside: 1 9 | min-spaces-inside-empty: 0 10 | max-spaces-inside-empty: 0 11 | brackets: 12 | min-spaces-inside: 0 13 | max-spaces-inside: 1 14 | min-spaces-inside-empty: 0 15 | max-spaces-inside-empty: 0 16 | colons: 17 | max-spaces-before: 0 18 | max-spaces-after: 1 19 | commas: 20 | max-spaces-before: 0 21 | comments: 22 | level: warning 23 | require-starting-space: true 24 | min-spaces-from-content: 1 25 | comments-indentation: disable 26 | document-end: disable 27 | document-start: disable 28 | empty-lines: 29 | level: warning 30 | max: 2 31 | max-start: 0 32 | max-end: 1 33 | empty-values: 34 | forbid-in-block-mappings: true 35 | forbid-in-flow-mappings: true 36 | hyphens: 37 | max-spaces-after: 1 38 | indentation: 39 | spaces: consistent 40 | indent-sequences: false 41 | key-duplicates: enable 42 | key-ordering: disable 43 | line-length: disable 44 | new-line-at-end-of-file: enable 45 | # Use UNIX new line characters `\n` instead of DOS new line characters `\r\n` 46 | new-lines: 47 | type: unix 48 | octal-values: disable 49 | quoted-strings: 50 | quote-type: any 51 | required: false 52 | trailing-spaces: enable 53 | truthy: disable 54 | -------------------------------------------------------------------------------- /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 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-aws-db 2 | 3 | ![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/tedilabs/terraform-aws-db?color=blue&sort=semver&style=flat-square) 4 | ![GitHub](https://img.shields.io/github/license/tedilabs/terraform-aws-db?color=blue&style=flat-square) 5 | [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square)](https://github.com/pre-commit/pre-commit) 6 | 7 | Terraform module which creates db related resources on AWS. 8 | 9 | - [elasticache-redis-cluster](./modules/elasticache-redis-cluster) 10 | - [elasticache-redis-user](./modules/elasticache-redis-user) 11 | - [elasticache-redis-user-group](./modules/elasticache-redis-user-group) 12 | 13 | 14 | ## Target AWS Services 15 | 16 | Terraform Modules from [this package](https://github.com/tedilabs/terraform-aws-db) were written to manage the following AWS Services with Terraform. 17 | 18 | - **AWS RDS (Relational Database Service)** 19 | - (comming sooon!) 20 | - **AWS ElastiCache** 21 | - Redis Cluster 22 | - Redis User RBAC 23 | 24 | 25 | ## Usage 26 | 27 | ### ElastiCache Redis 28 | 29 | ```tf 30 | module "cluster" { 31 | source = "tedilabs/db/aws//modules/elasticache-redis-cluster" 32 | version = "~> 0.2.0" 33 | 34 | name = "example-redis-full" 35 | description = "Managed by Terraform." 36 | 37 | redis_version = "6.2" 38 | node_instance_type = "cache.t4g.micro" 39 | # node_size = 1 40 | sharding = { 41 | enabled = true 42 | shard_size = 3 43 | replicas = 2 44 | } 45 | 46 | 47 | ## Network 48 | port = 6379 49 | vpc_id = null 50 | subnet_group = null 51 | preferred_availability_zones = [] 52 | 53 | default_security_group = { 54 | eanbled = true 55 | name = "example-redis-full-default-sg" 56 | description = "Managed by Terraform." 57 | 58 | ingress_rules = [ 59 | { 60 | cidr_blocks = ["0.0.0.0/0"] 61 | } 62 | ] 63 | } 64 | security_groups = [] 65 | 66 | 67 | ## Parameters 68 | parameter_group = { 69 | enabled = true 70 | name = "example-redis-full-parameter-group" 71 | description = "Managed by Terraform." 72 | parameters = { 73 | "lazyfree-lazy-eviction" = "yes" 74 | "lazyfree-lazy-expire" = "yes" 75 | "lazyfree-lazy-server-del" = "yes" 76 | "rename-commands" = "KEYS BLOCKED" 77 | } 78 | } 79 | custom_parameter_group = null 80 | 81 | 82 | ## Auth 83 | password = sensitive("helloworld!#!!1234") 84 | user_groups = [] 85 | 86 | 87 | ## Encryption 88 | encryption_at_rest = { 89 | enabled = true 90 | kms_key = null 91 | } 92 | encryption_in_transit = { 93 | enabled = true 94 | } 95 | 96 | 97 | ## Backup 98 | backup_enabled = true 99 | backup_window = "16:00-17:00" 100 | backup_retention = 1 101 | backup_final_snapshot_name = "example-redis-full-final" 102 | 103 | 104 | ## Source 105 | source_backup_name = null 106 | source_rdb_s3_arns = null 107 | 108 | 109 | ## Maintenance 110 | maintenance_window = "fri:18:00-fri:20:00" 111 | auto_upgrade_minor_version_enabled = true 112 | notification_sns_topic = null 113 | 114 | 115 | ## Logging 116 | logging_slow_log = { 117 | enabled = false 118 | format = "JSON" 119 | 120 | destination_type = "CLOUDWATCH_LOGS" 121 | destination = null 122 | } 123 | logging_engine_log = { 124 | enabled = false 125 | format = "JSON" 126 | 127 | destination_type = "CLOUDWATCH_LOGS" 128 | destination = null 129 | } 130 | 131 | 132 | ## Attributes 133 | multi_az_enabled = true 134 | auto_failover_enabled = true 135 | apply_immediately = true 136 | 137 | timeouts = { 138 | create = "60m" 139 | update = "40m" 140 | delete = "40m" 141 | } 142 | 143 | tags = { 144 | "project" = "terraform-aws-db-examples" 145 | } 146 | } 147 | ``` 148 | 149 | 150 | ## Examples 151 | 152 | ### ElastiCache Redis 153 | 154 | - [Singie Redis Instance](./examples/elasticache-redis-single) 155 | - [Multi-AZs Redis Cluster (Sharding Disabled)](./examples/elasticache-redis-multi-az) 156 | - [Full Redis Cluster (Sharding Enabled)](./examples/elasticache-redis-full) 157 | - [Redis Cluster with RBAC(Role Based Access Control)](./examples/elasticache-redis-with-users) 158 | 159 | 160 | ## Self Promotion 161 | 162 | Like this project? Follow the repository on [GitHub](https://github.com/tedilabs/terraform-aws-db). And if you're feeling especially charitable, follow **[posquit0](https://github.com/posquit0)** on GitHub. 163 | 164 | 165 | ## License 166 | 167 | Provided under the terms of the [Apache License](LICENSE). 168 | 169 | Copyright © 2022-2023, [Byungjin Park](https://www.posquit0.com). 170 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.1.4 2 | -------------------------------------------------------------------------------- /examples/elasticache-redis-full/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # ElastiCache Redis Cluster 8 | ################################################### 9 | 10 | module "cluster" { 11 | source = "../../modules/elasticache-redis-cluster" 12 | # source = "tedilabs/db/aws//modules/elasticache-redis-cluster" 13 | # version = "~> 0.2.0" 14 | 15 | name = "example-redis-full" 16 | description = "Managed by Terraform." 17 | 18 | redis_version = "6.2" 19 | node_instance_type = "cache.t4g.micro" 20 | # node_size = 1 21 | sharding = { 22 | enabled = true 23 | shard_size = 3 24 | replicas = 2 25 | } 26 | 27 | 28 | ## Network 29 | port = 6379 30 | vpc_id = null 31 | subnet_group = null 32 | preferred_availability_zones = [] 33 | 34 | default_security_group = { 35 | eanbled = true 36 | name = "example-redis-full-default-sg" 37 | description = "Managed by Terraform." 38 | 39 | ingress_rules = [ 40 | { 41 | cidr_blocks = ["0.0.0.0/0"] 42 | } 43 | ] 44 | } 45 | security_groups = [] 46 | 47 | 48 | ## Parameters 49 | parameter_group = { 50 | enabled = true 51 | name = "example-redis-full-parameter-group" 52 | description = "Managed by Terraform." 53 | parameters = { 54 | "lazyfree-lazy-eviction" = "yes" 55 | "lazyfree-lazy-expire" = "yes" 56 | "lazyfree-lazy-server-del" = "yes" 57 | "rename-commands" = "KEYS BLOCKED" 58 | } 59 | } 60 | custom_parameter_group = null 61 | 62 | 63 | ## Auth 64 | password = sensitive("helloworld!#!!1234") 65 | user_groups = [] 66 | 67 | 68 | ## Encryption 69 | encryption_at_rest = { 70 | enabled = true 71 | kms_key = null 72 | } 73 | encryption_in_transit = { 74 | enabled = true 75 | } 76 | 77 | 78 | ## Backup 79 | backup_enabled = true 80 | backup_window = "16:00-17:00" 81 | backup_retention = 1 82 | backup_final_snapshot_name = "example-redis-full-final" 83 | 84 | 85 | ## Source 86 | source_backup_name = null 87 | source_rdb_s3_arns = null 88 | 89 | 90 | ## Maintenance 91 | maintenance_window = "fri:18:00-fri:20:00" 92 | auto_upgrade_minor_version_enabled = true 93 | notification_sns_topic = null 94 | 95 | 96 | ## Logging 97 | logging_slow_log = { 98 | enabled = false 99 | format = "JSON" 100 | 101 | destination_type = "CLOUDWATCH_LOGS" 102 | destination = null 103 | } 104 | logging_engine_log = { 105 | enabled = false 106 | format = "JSON" 107 | 108 | destination_type = "CLOUDWATCH_LOGS" 109 | destination = null 110 | } 111 | 112 | 113 | ## Attributes 114 | multi_az_enabled = true 115 | auto_failover_enabled = true 116 | apply_immediately = true 117 | 118 | timeouts = { 119 | create = "60m" 120 | update = "40m" 121 | delete = "40m" 122 | } 123 | 124 | tags = { 125 | "project" = "terraform-aws-db-examples" 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /examples/elasticache-redis-full/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster" { 2 | value = module.cluster 3 | } 4 | -------------------------------------------------------------------------------- /examples/elasticache-redis-full/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/elasticache-redis-muti-az/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # ElastiCache Redis Cluster 8 | ################################################### 9 | 10 | module "cluster" { 11 | source = "../../modules/elasticache-redis-cluster" 12 | # source = "tedilabs/db/aws//modules/elasticache-redis-cluster" 13 | # version = "~> 0.2.0" 14 | 15 | name = "example-redis-multi-az" 16 | description = "Managed by Terraform." 17 | 18 | redis_version = "6.2" 19 | node_instance_type = "cache.t4g.micro" 20 | node_size = 2 21 | 22 | multi_az_enabled = true 23 | auto_failover_enabled = true 24 | 25 | tags = { 26 | "project" = "terraform-aws-db-examples" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/elasticache-redis-muti-az/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster" { 2 | value = module.cluster 3 | } 4 | -------------------------------------------------------------------------------- /examples/elasticache-redis-muti-az/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/elasticache-redis-single/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # ElastiCache Redis Cluster 8 | ################################################### 9 | 10 | module "cluster" { 11 | source = "../../modules/elasticache-redis-cluster" 12 | # source = "tedilabs/db/aws//modules/elasticache-redis-cluster" 13 | # version = "~> 0.2.0" 14 | 15 | name = "example-redis-single" 16 | description = "Managed by Terraform." 17 | 18 | redis_version = "6.2" 19 | node_instance_type = "cache.t4g.micro" 20 | node_size = 1 21 | 22 | tags = { 23 | "project" = "terraform-aws-db-examples" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/elasticache-redis-single/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster" { 2 | value = module.cluster 3 | } 4 | -------------------------------------------------------------------------------- /examples/elasticache-redis-single/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/elasticache-redis-with-users/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = "us-east-1" 3 | } 4 | 5 | 6 | ################################################### 7 | # ElastiCache Redis Cluster 8 | ################################################### 9 | 10 | module "cluster" { 11 | source = "../../modules/elasticache-redis-cluster" 12 | # source = "tedilabs/db/aws//modules/elasticache-redis-cluster" 13 | # version = "~> 0.2.0" 14 | 15 | name = "example-redis-single" 16 | description = "Managed by Terraform." 17 | 18 | redis_version = "6.2" 19 | node_instance_type = "cache.t4g.micro" 20 | node_size = 1 21 | 22 | user_groups = [module.user_group.id] 23 | 24 | encryption_in_transit = { 25 | enabled = true 26 | } 27 | 28 | tags = { 29 | "project" = "terraform-aws-db-examples" 30 | } 31 | } 32 | 33 | 34 | ################################################### 35 | # Redis User Groups on ElastiCache 36 | ################################################### 37 | 38 | module "user_group" { 39 | source = "../../modules/elasticache-redis-user-group" 40 | # source = "tedilabs/db/aws//modules/elasticache-redis-user-group" 41 | # version = "~> 0.2.0" 42 | 43 | name = "example" 44 | default_user = module.user["example-default"].id 45 | users = [module.user["example-admin"].id] 46 | 47 | tags = { 48 | "project" = "terraform-aws-db-examples" 49 | } 50 | } 51 | 52 | 53 | ################################################### 54 | # Redis Users on ElastiCache 55 | ################################################### 56 | 57 | locals { 58 | users = [ 59 | { 60 | id = "example-default" 61 | name = "default" 62 | 63 | access_string = "on ~* -@all +@read" 64 | password_required = false 65 | }, 66 | { 67 | id = "example-admin" 68 | name = "admin" 69 | 70 | access_string = "on ~* +@all" 71 | password_required = true 72 | passwords = ["MyPassWord!Q@W#E", "MyPassW0rd!@QW#$ER"] 73 | }, 74 | ] 75 | } 76 | 77 | module "user" { 78 | source = "../../modules/elasticache-redis-user" 79 | # source = "tedilabs/db/aws//modules/elasticache-redis-user" 80 | # version = "~> 0.2.0" 81 | 82 | for_each = { 83 | for user in try(local.users, []) : 84 | user.id => user 85 | } 86 | 87 | id = each.key 88 | name = each.value.name 89 | 90 | access_string = try(each.value.access_string, null) 91 | password_required = try(each.value.password_required, true) 92 | passwords = try(each.value.passwords, []) 93 | 94 | tags = { 95 | "project" = "terraform-aws-db-examples" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /examples/elasticache-redis-with-users/outputs.tf: -------------------------------------------------------------------------------- 1 | output "cluster" { 2 | value = module.cluster 3 | } 4 | 5 | output "user_group" { 6 | value = module.user_group 7 | } 8 | 9 | output "users" { 10 | value = module.user 11 | } 12 | -------------------------------------------------------------------------------- /examples/elasticache-redis-with-users/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "~> 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~> 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/elasticache-redis-cluster/README.md: -------------------------------------------------------------------------------- 1 | # elasticache-redis-cluster 2 | 3 | This module creates following resources. 4 | 5 | - `aws_elasticache_replication_group` 6 | - `aws_elasticache_parameter_group` (optional) 7 | - `aws_security_group` (optional) 8 | - `aws_security_group_rule` (optional) 9 | 10 | 11 | ## Requirements 12 | 13 | | Name | Version | 14 | |------|---------| 15 | | [terraform](#requirement\_terraform) | >= 1.3 | 16 | | [aws](#requirement\_aws) | >= 4.36 | 17 | 18 | ## Providers 19 | 20 | | Name | Version | 21 | |------|---------| 22 | | [aws](#provider\_aws) | 4.34.0 | 23 | 24 | ## Modules 25 | 26 | | Name | Source | Version | 27 | |------|--------|---------| 28 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 29 | | [security\_group](#module\_security\_group) | tedilabs/network/aws//modules/security-group | ~> 0.26.0 | 30 | 31 | ## Resources 32 | 33 | | Name | Type | 34 | |------|------| 35 | | [aws_elasticache_parameter_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_parameter_group) | resource | 36 | | [aws_elasticache_replication_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_replication_group) | resource | 37 | 38 | ## Inputs 39 | 40 | | Name | Description | Type | Default | Required | 41 | |------|-------------|------|---------|:--------:| 42 | | [name](#input\_name) | (Required) The name of the ElastiCache Redis cluster. This parameter is stored as a lowercase string. | `string` | n/a | yes | 43 | | [node\_instance\_type](#input\_node\_instance\_type) | (Required) The instance type to be deployed for the ElastiCache Redis cluster. | `string` | n/a | yes | 44 | | [apply\_immediately](#input\_apply\_immediately) | (Optional) Whether any modifications are applied immediately, or during the next maintenance window. Default to `false`. | `bool` | `false` | no | 45 | | [auto\_failover\_enabled](#input\_auto\_failover\_enabled) | (Optional) Whether a read-only replica will be automatically promoted to read/write primary if the existing primary fails. If enabled, `node_size` must be greater than 1. Must be enabled for Redis (cluster mode enabled) cluster. Defaults to `false`. ElastiCache Auto Failover provides enhanced high availability through automatic failover to a read replica in case of a primary node failover. | `bool` | `false` | no | 46 | | [auto\_upgrade\_minor\_version\_enabled](#input\_auto\_upgrade\_minor\_version\_enabled) | (Optional) Whether automatically schedule cluster upgrade to the latest minor version, once it becomes available. Cluster upgrade will only be scheduled during the maintenance window. Defaults to `true`. Only supported if the redis version is 6 or higher. | `bool` | `true` | no | 47 | | [backup\_enabled](#input\_backup\_enabled) | (Optional) Whether to automatically create a daily backup of a set of replicas. Defaults to `false`. | `bool` | `false` | no | 48 | | [backup\_final\_snapshot\_name](#input\_backup\_final\_snapshot\_name) | (Optional) The name of your final node group (shard) snapshot. ElastiCache creates the snapshot from the primary node in the cluster. If omitted, no final snapshot will be made. | `string` | `null` | no | 49 | | [backup\_retention](#input\_backup\_retention) | (Optional) The number of days for which automated backups are retained before they are automatically deleted. Valid value is between `1` and `35`. Defaults to 1. | `number` | `1` | no | 50 | | [backup\_window](#input\_backup\_window) | (Optional) The daily time range (in UTC) during which ElastiCache will begin taking a daily snapshot of the ElastiCache Redis cluster. The minimum snapshot window is a 60 minute period. Example: 05:00-09:00. Defaults to `16:00-17:00`. | `string` | `"16:00-17:00"` | no | 51 | | [custom\_parameter\_group](#input\_custom\_parameter\_group) | (Optional) The name of the parameter group to associate with the ElastiCache Redis cluster. If this argument is omitted, the default cache parameter group for the specified engine is used. To enable `cluster mode` (sharding), use a parameter group that has the parameter `cluster-enabled` set to `true`. | `string` | `null` | no | 52 | | [default\_security\_group](#input\_default\_security\_group) | (Optional) The configuration of the default security group for the ElastiCache Redis cluster. `default_security_group` block as defined below.
(Optional) `enabled` - Whether to use the default security group. Defaults to `true`.
(Optional) `name` - The name of the default security group. If not provided, the cluster name is used for the name of security group.
(Optional) `description` - The description of the default security group.
(Optional) `ingress_rules` - A list of ingress rules in a security group. You don't need to specify `protocol`, `from_port`, `to_port`. Just specify source information. Defauls to `[{ cidr_blocks = "0.0.0.0/0" }]`. |
object({
enabled = optional(bool, true)
name = optional(string, null)
description = optional(string, "Managed by Terraform.")
ingress_rules = optional(any, [{
cidr_blocks = ["0.0.0.0/0"]
}])
})
| `{}` | no | 53 | | [description](#input\_description) | (Optional) The description of the ElastiCache Redis cluster. | `string` | `"Managed by Terraform."` | no | 54 | | [encryption\_at\_rest](#input\_encryption\_at\_rest) | The configuration for at-rest encryption of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable at-rest encryption. Defaults to `false`.
(Optional) `kms_key` - The ARN of the key to use for at-rest encryption. If not supplied, uses service managed encryption key. Can be specified only if `encryption_at_rest.enabled` is `true`. |
object({
enabled = optional(bool, false)
kms_key = optional(string, null)
})
| `{}` | no | 55 | | [encryption\_in\_transit](#input\_encryption\_in\_transit) | The configuration for in-transit encryption of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable in-transit encryption. Defaults to `false`. |
object({
enabled = optional(bool, false)
})
| `{}` | no | 56 | | [logging\_engine\_log](#input\_logging\_engine\_log) | The configuration for streaming Redis Engine Log of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable streaming Redis Engine Log. Defaults to `false`.
(Optional) `format` - The format of Redis Engine Log. Valid values are `JSON` or `TEXT`. Defaults to `JSON`.
(Optional) `destination_type` - The destination type for streaming Redis Engine Log. For CloudWatch Logs use `CLOUDWATCH_LOGS` or for Kinesis Data Firehose use `KINESIS_FIREHOSE`. Defaults to `CLOUDWATCH_LOGS`.
(Optional) `destination` - The name of either the CloudWatch Logs LogGroup or Kinesis Data Firehose resource. |
object({
enabled = optional(bool, false)
format = optional(string, "JSON")
destination_type = optional(string, "CLOUDWATCH_LOGS")
destination = optional(string, null)
})
| `{}` | no | 57 | | [logging\_slow\_log](#input\_logging\_slow\_log) | The configuration for streaming Redis Slow Log of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable streaming Redis Slow Log. Defaults to `false`.
(Optional) `format` - The format of Redis Slow Log. Valid values are `JSON` or `TEXT`. Defaults to `JSON`.
(Optional) `destination_type` - The destination type for streaming Redis Slow Log. For CloudWatch Logs use `CLOUDWATCH_LOGS` or for Kinesis Data Firehose use `KINESIS_FIREHOSE`. Defaults to `CLOUDWATCH_LOGS`.
(Optional) `destination` - The name of either the CloudWatch Logs LogGroup or Kinesis Data Firehose resource. |
object({
enabled = optional(bool, false)
format = optional(string, "JSON")
destination_type = optional(string, "CLOUDWATCH_LOGS")
destination = optional(string, null)
})
| `{}` | no | 58 | | [maintenance\_window](#input\_maintenance\_window) | (Optional) The weekly time range for when maintenance on the ElastiCache Redis cluster is performed. The format is `ddd:hh24:mi-ddd:hh24:mi` (24H Clock UTC). The minimum maintenance window is a 60 minute period. Example: `sun:05:00-sun:09:00`. Defaults to `fri:18:00-fri:20:00`. | `string` | `"fri:18:00-fri:20:00"` | no | 59 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 60 | | [multi\_az\_enabled](#input\_multi\_az\_enabled) | (Optional) Whether to enable Multi-AZ Support for the ElastiCache Redis cluster. If true, `auto_failover_enabled` must also be enabled. Defaults to `false`. | `bool` | `false` | no | 61 | | [node\_size](#input\_node\_size) | (Optional) The number of cache nodes (primary and replicas) for this ElastiCache Redis cluster will have. If Multi-AZ is enabled, this value must be at least 2. Updates will occur before other modifications. Defaults to `1`. | `number` | `1` | no | 62 | | [notification\_sns\_topic](#input\_notification\_sns\_topic) | (Optional) The ARN of an SNS topic to send ElastiCache notifications to. | `string` | `null` | no | 63 | | [parameter\_group](#input\_parameter\_group) | The configuration for parameter group of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable managed parameter group by this module.
(Optional) `name` - The name of the managed parameter group. If not provided, the name is configured with the cluster name.
(Optional) `description` - The description of the managed parameter group.
(Optional) `parameters` - The key/value set for Redis parameters of ElastiCache Redis cluster. Each key is the name of the redis parameter. Each value is the value of the redis parameter. |
object({
enabled = optional(bool, true)
name = optional(string, "")
description = optional(string, "")
parameters = optional(map(string), {})
})
| `{}` | no | 64 | | [password](#input\_password) | (Optional) Password used to access a password protected ElastiCache Redis cluster. Can be specified only if `encryption_in_transit.enabled` is `true`. | `string` | `""` | no | 65 | | [port](#input\_port) | (Optional) The port number on which each of the cache nodes will accept connections. The default port is `6379`. | `number` | `6379` | no | 66 | | [preferred\_availability\_zones](#input\_preferred\_availability\_zones) | (Optional) A list of AZs(Availability Zones) in which the ElastiCache Redis cluster nodes will be created. The order of the availability zones in the list is considered. The first item in the list will be the primary node. Ignored when updating. | `list(string)` | `[]` | no | 67 | | [redis\_version](#input\_redis\_version) | (Optional) The version number of Redis to be used for each nodes in the ElastiCache Redis cluster. If the version is 6 or higher, the major and minor version can be set, e.g., 6.2, or the minor version can be unspecified which will use the latest version at creation time, e.g., 6.x. Otherwise, specify the full version desired, e.g., 5.0.6. The actual engine version used is returned in the attribute `redis_version_actual`. | `string` | `"7.0"` | no | 68 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 69 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 70 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 71 | | [security\_groups](#input\_security\_groups) | (Optional) A list of security group IDs to assign to the instance. | `list(string)` | `[]` | no | 72 | | [sharding](#input\_sharding) | The configuration for sharding of the ElastiCache Redis cluster.
(Optional) `enabled` - Whether to enable sharding (cluster mode). It enables replication across multiple shards for enhanced scalability and availability. Defaults to `false`.
(Optional) `shard_size` - The number of shards in this cluster. Valid value is from `1` to `500`. Defaults to `3`.
(Optional) `replicas` - The number of replicas for each shard. Valid value is from `0` to `5`. Defaults to `2`. |
object({
enabled = optional(bool, false)
shard_size = optional(number, 3)
replicas = optional(number, 2)
})
| `{}` | no | 73 | | [source\_backup\_name](#input\_source\_backup\_name) | (Optional) The name of a snapshot from which to restore data into the new node group. Changing the `source_backup_name` forces a new resource. | `string` | `null` | no | 74 | | [source\_rdb\_s3\_arns](#input\_source\_rdb\_s3\_arns) | (Optional) A list of ARNs that identify Redis RDB snapshot files stored in Amazon S3. The object names cannot contain any commas. | `list(string)` | `[]` | no | 75 | | [subnet\_group](#input\_subnet\_group) | (Optional) The name of the cache subnet group to be used for the ElastiCache Redis cluster. If not provided, configured to use `default` subnet group in the default VPC. | `string` | `null` | no | 76 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 77 | | [timeouts](#input\_timeouts) | (Optional) How long to wait for the instance to be created/updated/deleted. |
object({
create = optional(string, "60m")
update = optional(string, "40m")
delete = optional(string, "40m")
})
| `{}` | no | 78 | | [user\_groups](#input\_user\_groups) | (Optional) A set of User Group IDs to associate with the ElastiCache Redis cluster. Only a maximum of one user group ID is valid. The AWS specification allows for multiple IDs, but AWS only allows a maximum size of one. | `set(string)` | `[]` | no | 79 | | [vpc\_id](#input\_vpc\_id) | (Optional) The ID of the associated VPC. You must provide the `vpc_id` when `default_security_group.enabled` is `true`. It will used to provision the default security group. | `string` | `null` | no | 80 | 81 | ## Outputs 82 | 83 | | Name | Description | 84 | |------|-------------| 85 | | [arn](#output\_arn) | The ARN of the ElastiCache Redis cluster. | 86 | | [attributes](#output\_attributes) | A set of attributes that applied to the ElastiCache Redis cluster. | 87 | | [auth](#output\_auth) | The configuration for auth of the ElastiCache Redis cluster.
`user_groups` - A set of User Group IDs to associate with the ElastiCache Redis cluster. | 88 | | [backup](#output\_backup) | The configuration for backup of the ElastiCache Redis cluster.
`enabled` - Whether to automatically create a daily backup of a set of replicas.
`window` - The daily time range (in UTC) during which ElastiCache will begin taking a daily snapshot of the ElastiCache Redis cluster.
`retention` - The number of days for which automated backups are retained before they are automatically deleted. | 89 | | [description](#output\_description) | The description of the ElastiCache Redis cluster. | 90 | | [encryption](#output\_encryption) | The configuration for encryption of the ElastiCache Redis cluster.
`at_rest` - The configuration for at-rest encryption.
`in_transit` - The configuration for in-transit encryption. | 91 | | [endpoints](#output\_endpoints) | The connection endpoints to the ElastiCache Redis cluster.
`primary` - Address of the endpoint for the primary node in the cluster, if the cluster mode is disabled.
`reader` - Address of the endpoint for the reader node in the cluster, if the cluster mode is disabled.
`configuration` - Address of the replication group configuration endpoint when cluster mode is enabled. | 92 | | [id](#output\_id) | The ID of the ElastiCache Redis cluster. | 93 | | [logging](#output\_logging) | The configuration for logging of the ElastiCache Redis cluster.
`slow_log` - The configuration for streaming Redis Slow Log.
`engine_log` - The configuration for streaming Redis Engine Log. | 94 | | [maintenance](#output\_maintenance) | The configuration for maintenance of the ElastiCache Redis cluster.
`window` - The weekly time range for when maintenance on the ElastiCache Redis cluster is performed.
`auto_upgrade_minor_version_enabled` - Whether automatically schedule cluster upgrade to the latest minor version, once it becomes available.
`notification_sns_arn` - The ARN of an SNS topic to send ElastiCache notifications to. | 95 | | [name](#output\_name) | The name of the ElastiCache Redis cluster. | 96 | | [network](#output\_network) | The configuration for network of the ElastiCache Redis cluster.
`port` - The port number on each cache nodes to accept connections.
`subnet_group` - The name of the cache subnet group used for.
`preferred_availability_zones` - The list of AZs(Availability Zones) in which the ElastiCache Redis cluster nodes will be created. | 97 | | [node\_instance\_type](#output\_node\_instance\_type) | The instance type used for the ElastiCache Redis cluster. | 98 | | [node\_size](#output\_node\_size) | The number of cache nodes (primary and replicas) for this ElastiCache Redis cluster will have. | 99 | | [nodes](#output\_nodes) | The list of all nodes are part of the ElastiCache Redis cluster. | 100 | | [parameter\_group](#output\_parameter\_group) | The name of the parameter group associated with the ElastiCache Redis cluster. | 101 | | [redis\_version](#output\_redis\_version) | The version number of Redis used for the ElastiCache Redis cluster. The actual engine version used is returned in `redis_version_actual`. | 102 | | [redis\_version\_actual](#output\_redis\_version\_actual) | The actual version number of Redis used for the ElastiCache Redis cluster. Because ElastiCache pulls the latest minor or patch for a version, this attribute returns the running version of the cache engine. | 103 | | [sharding](#output\_sharding) | The configuration for sharding of the ElastiCache Redis cluster. | 104 | | [source](#output\_source) | The configuration for source backup of the ElastiCache Redis cluster to restore from.
`backup_name` - The name of a snapshot from which to restore data into the new node group.
`rdb_s3_arns` - The list of ARNs that identify Redis RDB snapshot files stored in Amazon S3. | 105 | 106 | -------------------------------------------------------------------------------- /modules/elasticache-redis-cluster/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-db" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | locals { 18 | is_data_tiering_type = replace(var.node_instance_type, "/^cache\\.[a-z0-9]?d\\..*$/", "1") == "1" ? true : false 19 | } 20 | 21 | 22 | ################################################### 23 | # Parameter Group of ElastiCache Cluster for Redis 24 | ################################################### 25 | 26 | locals { 27 | supported_families = [ 28 | { name = "redis2.8", prefix = "2.8" }, 29 | { name = "redis3.2", prefix = "3.2" }, 30 | { name = "redis4.0", prefix = "4.0" }, 31 | { name = "redis5.0", prefix = "5.0" }, 32 | { name = "redis6.x", prefix = "6." }, 33 | { name = "redis7", prefix = "7." }, 34 | ] 35 | family = [ 36 | for f in local.supported_families : 37 | f.name 38 | if startswith(var.redis_version, f.prefix) 39 | ][0] 40 | 41 | parameters = merge( 42 | { 43 | "cluster-enabled" = var.sharding.enabled ? "yes" : "no" 44 | }, 45 | var.parameter_group.parameters 46 | ) 47 | 48 | logging_destination_types = { 49 | "CLOUDWATCH_LOGS" = "cloudwatch-logs" 50 | "KINESIS_FIREHOSE" = "kinesis-firehose" 51 | } 52 | 53 | parameger_group_default_name = "${var.name}-${replace(local.family, ".", "-")}" 54 | } 55 | 56 | resource "aws_elasticache_parameter_group" "this" { 57 | count = var.parameter_group.enabled ? 1 : 0 58 | 59 | name = coalesce(var.parameter_group.name, local.parameger_group_default_name) 60 | description = coalesce(var.parameter_group.description, "Customized Parameter Group for ${var.name} redis cluster. (v${var.redis_version})") 61 | family = local.family 62 | 63 | dynamic "parameter" { 64 | for_each = local.parameters 65 | 66 | content { 67 | name = parameter.key 68 | value = parameter.value 69 | } 70 | } 71 | 72 | tags = merge( 73 | { 74 | "Name" = local.metadata.name 75 | }, 76 | local.module_tags, 77 | var.tags, 78 | ) 79 | 80 | lifecycle { 81 | create_before_destroy = true 82 | } 83 | } 84 | 85 | 86 | ################################################### 87 | # ElastiCache Cluster for Redis 88 | ################################################### 89 | 90 | # Only need for secondary replicas 91 | # - `global_replication_group_id` 92 | resource "aws_elasticache_replication_group" "this" { 93 | replication_group_id = var.name 94 | description = var.description 95 | 96 | engine = "redis" 97 | engine_version = var.redis_version 98 | node_type = var.node_instance_type 99 | num_cache_clusters = !var.sharding.enabled ? var.node_size : null 100 | num_node_groups = var.sharding.enabled ? var.sharding.shard_size : null 101 | replicas_per_node_group = var.sharding.enabled ? var.sharding.replicas : null 102 | 103 | 104 | ## Network 105 | port = var.port 106 | subnet_group_name = var.subnet_group 107 | preferred_cache_cluster_azs = var.preferred_availability_zones 108 | security_group_ids = (var.default_security_group.enabled 109 | ? concat(module.security_group[*].id, var.security_groups) 110 | : var.security_groups 111 | ) 112 | 113 | 114 | ## Parameters 115 | parameter_group_name = (var.parameter_group.enabled 116 | ? aws_elasticache_parameter_group.this[0].name 117 | : var.custom_parameter_group 118 | ) 119 | 120 | 121 | ## Auth 122 | auth_token = length(var.password) > 0 ? var.password : null 123 | user_group_ids = length(var.user_groups) > 0 ? var.user_groups : null 124 | 125 | 126 | ## Encryption 127 | at_rest_encryption_enabled = var.encryption_at_rest.enabled 128 | kms_key_id = var.encryption_at_rest.kms_key 129 | transit_encryption_enabled = var.encryption_in_transit.enabled 130 | 131 | 132 | ## Backup 133 | snapshot_window = var.backup_window 134 | snapshot_retention_limit = var.backup_enabled ? var.backup_retention : 0 135 | final_snapshot_identifier = var.backup_final_snapshot_name 136 | 137 | 138 | ## Source 139 | snapshot_arns = var.source_rdb_s3_arns 140 | snapshot_name = var.source_backup_name 141 | 142 | 143 | ## Maintenance 144 | maintenance_window = var.maintenance_window 145 | auto_minor_version_upgrade = var.auto_upgrade_minor_version_enabled 146 | notification_topic_arn = var.notification_sns_topic 147 | 148 | 149 | ## Logging 150 | dynamic "log_delivery_configuration" { 151 | for_each = var.logging_slow_log.enabled ? [var.logging_slow_log] : [] 152 | iterator = logging 153 | 154 | content { 155 | log_type = "slow-log" 156 | log_format = lower(logging.value.format) 157 | destination_type = local.logging_destination_types[logging.value.destination_type] 158 | destination = logging.value.destination 159 | } 160 | } 161 | dynamic "log_delivery_configuration" { 162 | for_each = var.logging_engine_log.enabled ? [var.logging_engine_log] : [] 163 | iterator = logging 164 | 165 | content { 166 | log_type = "engine-log" 167 | log_format = lower(logging.value.format) 168 | destination_type = local.logging_destination_types[logging.value.destination_type] 169 | destination = logging.value.destination 170 | } 171 | } 172 | 173 | 174 | ## Attributes 175 | multi_az_enabled = var.multi_az_enabled 176 | automatic_failover_enabled = var.auto_failover_enabled 177 | data_tiering_enabled = local.is_data_tiering_type 178 | 179 | apply_immediately = var.apply_immediately 180 | 181 | timeouts { 182 | create = var.timeouts.create 183 | update = var.timeouts.update 184 | delete = var.timeouts.delete 185 | } 186 | 187 | tags = merge( 188 | { 189 | "Name" = local.metadata.name 190 | }, 191 | local.module_tags, 192 | var.tags, 193 | ) 194 | 195 | lifecycle { 196 | precondition { 197 | condition = anytrue([ 198 | !var.multi_az_enabled, 199 | var.multi_az_enabled && var.auto_failover_enabled, 200 | ]) 201 | error_message = "If Muti-AZ Support is enabled, `auto_failover_enabled` must also be enabled." 202 | } 203 | precondition { 204 | condition = (length(var.password) > 0 205 | ? var.encryption_in_transit.enabled 206 | : true 207 | ) 208 | error_message = "Password can be specified only if in-transit encryption is enabled." 209 | } 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /modules/elasticache-redis-cluster/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the ElastiCache Redis cluster." 3 | value = aws_elasticache_replication_group.this.id 4 | } 5 | 6 | output "arn" { 7 | description = "The ARN of the ElastiCache Redis cluster." 8 | value = aws_elasticache_replication_group.this.arn 9 | } 10 | 11 | output "name" { 12 | description = "The name of the ElastiCache Redis cluster." 13 | value = var.name 14 | } 15 | 16 | output "description" { 17 | description = "The description of the ElastiCache Redis cluster." 18 | value = aws_elasticache_replication_group.this.description 19 | } 20 | 21 | output "redis_version" { 22 | description = "The version number of Redis used for the ElastiCache Redis cluster. The actual engine version used is returned in `redis_version_actual`." 23 | value = aws_elasticache_replication_group.this.engine_version 24 | } 25 | 26 | output "redis_version_actual" { 27 | description = "The actual version number of Redis used for the ElastiCache Redis cluster. Because ElastiCache pulls the latest minor or patch for a version, this attribute returns the running version of the cache engine." 28 | value = aws_elasticache_replication_group.this.engine_version_actual 29 | } 30 | 31 | output "node_instance_type" { 32 | description = "The instance type used for the ElastiCache Redis cluster." 33 | value = aws_elasticache_replication_group.this.node_type 34 | } 35 | 36 | output "node_size" { 37 | description = "The number of cache nodes (primary and replicas) for this ElastiCache Redis cluster will have." 38 | value = aws_elasticache_replication_group.this.num_cache_clusters 39 | } 40 | 41 | output "nodes" { 42 | description = "The list of all nodes are part of the ElastiCache Redis cluster." 43 | value = aws_elasticache_replication_group.this.member_clusters 44 | } 45 | 46 | output "sharding" { 47 | description = "The configuration for sharding of the ElastiCache Redis cluster." 48 | value = { 49 | enabled = aws_elasticache_replication_group.this.cluster_enabled 50 | shard_size = aws_elasticache_replication_group.this.num_node_groups 51 | replicas = aws_elasticache_replication_group.this.replicas_per_node_group 52 | } 53 | } 54 | 55 | output "network" { 56 | description = <= 1 37 | ]) 38 | error_message = "`node_size` should be greater than `0`." 39 | } 40 | } 41 | 42 | variable "sharding" { 43 | description = <= 1, 60 | var.sharding.shard_size <= 500, 61 | ]) 62 | error_message = "The number of shards should be between `1` and `500`." 63 | } 64 | 65 | validation { 66 | condition = alltrue([ 67 | var.sharding.replicas >= 0, 68 | var.sharding.replicas <= 5, 69 | ]) 70 | error_message = "The number of replicas for each shard should be between `0` and `5`." 71 | } 72 | } 73 | 74 | variable "port" { 75 | description = "(Optional) The port number on which each of the cache nodes will accept connections. The default port is `6379`." 76 | type = number 77 | default = 6379 78 | nullable = false 79 | 80 | validation { 81 | condition = alltrue([ 82 | var.port >= 1, 83 | var.port <= 65535 84 | ]) 85 | error_message = "Valid values range for `port` from 1 through 65535." 86 | } 87 | } 88 | 89 | variable "vpc_id" { 90 | description = "(Optional) The ID of the associated VPC. You must provide the `vpc_id` when `default_security_group.enabled` is `true`. It will used to provision the default security group." 91 | type = string 92 | default = null 93 | } 94 | 95 | variable "subnet_group" { 96 | description = "(Optional) The name of the cache subnet group to be used for the ElastiCache Redis cluster. If not provided, configured to use `default` subnet group in the default VPC." 97 | type = string 98 | default = null 99 | } 100 | 101 | variable "preferred_availability_zones" { 102 | description = "(Optional) A list of AZs(Availability Zones) in which the ElastiCache Redis cluster nodes will be created. The order of the availability zones in the list is considered. The first item in the list will be the primary node. Ignored when updating." 103 | type = list(string) 104 | default = [] 105 | } 106 | 107 | variable "default_security_group" { 108 | description = <= 16 && length(var.password) <= 128 169 | ]) 170 | error_message = "`password` must contain from 16 to 128 alphanumeric characters or symbols (excluding @, \", and /)." 171 | } 172 | } 173 | 174 | variable "user_groups" { 175 | description = "(Optional) A set of User Group IDs to associate with the ElastiCache Redis cluster. Only a maximum of one user group ID is valid. The AWS specification allows for multiple IDs, but AWS only allows a maximum size of one." 176 | type = set(string) 177 | default = [] 178 | nullable = false 179 | } 180 | 181 | variable "encryption_at_rest" { 182 | description = <= 1, 230 | var.backup_retention <= 35, 231 | ]) 232 | error_message = "The value of `backup_retention` must be between 1 and 35." 233 | } 234 | } 235 | 236 | variable "backup_final_snapshot_name" { 237 | description = "(Optional) The name of your final node group (shard) snapshot. ElastiCache creates the snapshot from the primary node in the cluster. If omitted, no final snapshot will be made." 238 | type = string 239 | default = null 240 | } 241 | 242 | variable "source_backup_name" { 243 | description = "(Optional) The name of a snapshot from which to restore data into the new node group. Changing the `source_backup_name` forces a new resource." 244 | type = string 245 | default = null 246 | } 247 | 248 | variable "source_rdb_s3_arns" { 249 | description = "(Optional) A list of ARNs that identify Redis RDB snapshot files stored in Amazon S3. The object names cannot contain any commas." 250 | type = list(string) 251 | default = [] 252 | nullable = false 253 | } 254 | 255 | variable "maintenance_window" { 256 | description = "(Optional) The weekly time range for when maintenance on the ElastiCache Redis cluster is performed. The format is `ddd:hh24:mi-ddd:hh24:mi` (24H Clock UTC). The minimum maintenance window is a 60 minute period. Example: `sun:05:00-sun:09:00`. Defaults to `fri:18:00-fri:20:00`." 257 | type = string 258 | default = "fri:18:00-fri:20:00" 259 | nullable = false 260 | } 261 | 262 | variable "auto_upgrade_minor_version_enabled" { 263 | description = "(Optional) Whether automatically schedule cluster upgrade to the latest minor version, once it becomes available. Cluster upgrade will only be scheduled during the maintenance window. Defaults to `true`. Only supported if the redis version is 6 or higher." 264 | type = bool 265 | default = true 266 | nullable = false 267 | } 268 | 269 | variable "notification_sns_topic" { 270 | description = "(Optional) The ARN of an SNS topic to send ElastiCache notifications to." 271 | type = string 272 | default = null 273 | } 274 | 275 | variable "logging_slow_log" { 276 | description = < 9 | ## Requirements 10 | 11 | | Name | Version | 12 | |------|---------| 13 | | [terraform](#requirement\_terraform) | >= 1.3 | 14 | | [aws](#requirement\_aws) | >= 4.30 | 15 | 16 | ## Providers 17 | 18 | | Name | Version | 19 | |------|---------| 20 | | [aws](#provider\_aws) | 4.34.0 | 21 | 22 | ## Modules 23 | 24 | | Name | Source | Version | 25 | |------|--------|---------| 26 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 27 | 28 | ## Resources 29 | 30 | | Name | Type | 31 | |------|------| 32 | | [aws_elasticache_user_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_user_group) | resource | 33 | | [aws_elasticache_user_group_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_user_group_association) | resource | 34 | 35 | ## Inputs 36 | 37 | | Name | Description | Type | Default | Required | 38 | |------|-------------|------|---------|:--------:| 39 | | [default\_user](#input\_default\_user) | (Optional) The ID of default user. The user group needs to contain a user with the user name default. | `string` | n/a | yes | 40 | | [name](#input\_name) | (Required) The name of the ElastiCache user group. It can have up to 40 characters, and must begin with a letter. It should not end with a hyphen or contain two consecutive hyphens. Valid characters: A-Z, a-z, 0-9, and - (hyphen). | `string` | n/a | yes | 41 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 42 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 43 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 44 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 45 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 46 | | [users](#input\_users) | (Optional) The list of user IDs that belong to the user group. | `set(string)` | `[]` | no | 47 | 48 | ## Outputs 49 | 50 | | Name | Description | 51 | |------|-------------| 52 | | [arn](#output\_arn) | The ARN of the ElastiCache user group. | 53 | | [default\_user](#output\_default\_user) | The ID of default user. | 54 | | [id](#output\_id) | The ID of the ElastiCache user group. | 55 | | [name](#output\_name) | The name of the ElastiCache user group. | 56 | | [users](#output\_users) | The list of user IDs that belong to the user group. | 57 | 58 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user-group/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-db" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.name 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | 18 | ################################################### 19 | # User Group of ElastiCache for Redis 20 | ################################################### 21 | 22 | resource "aws_elasticache_user_group" "this" { 23 | engine = "REDIS" 24 | user_group_id = var.name 25 | user_ids = [var.default_user] 26 | 27 | tags = merge( 28 | { 29 | "Name" = local.metadata.name 30 | }, 31 | local.module_tags, 32 | var.tags, 33 | ) 34 | 35 | lifecycle { 36 | ignore_changes = [user_ids] 37 | } 38 | } 39 | 40 | resource "aws_elasticache_user_group_association" "this" { 41 | for_each = var.users 42 | 43 | user_group_id = aws_elasticache_user_group.this.user_group_id 44 | user_id = each.value 45 | } 46 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user-group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the ElastiCache user group." 3 | value = aws_elasticache_user_group.this.id 4 | } 5 | 6 | output "arn" { 7 | description = "The ARN of the ElastiCache user group." 8 | value = aws_elasticache_user_group.this.arn 9 | } 10 | 11 | output "name" { 12 | description = "The name of the ElastiCache user group." 13 | value = aws_elasticache_user_group.this.user_group_id 14 | } 15 | 16 | output "default_user" { 17 | description = "The ID of default user." 18 | value = var.default_user 19 | } 20 | 21 | output "users" { 22 | description = "The list of user IDs that belong to the user group." 23 | value = values(aws_elasticache_user_group_association.this)[*].user_id 24 | } 25 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user-group/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user-group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "(Required) The name of the ElastiCache user group. It can have up to 40 characters, and must begin with a letter. It should not end with a hyphen or contain two consecutive hyphens. Valid characters: A-Z, a-z, 0-9, and - (hyphen)." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | variable "default_user" { 8 | description = "(Optional) The ID of default user. The user group needs to contain a user with the user name default." 9 | type = string 10 | nullable = false 11 | } 12 | 13 | variable "users" { 14 | description = "(Optional) The list of user IDs that belong to the user group." 15 | type = set(string) 16 | default = [] 17 | nullable = false 18 | } 19 | 20 | variable "tags" { 21 | description = "(Optional) A map of tags to add to all resources." 22 | type = map(string) 23 | default = {} 24 | nullable = false 25 | } 26 | 27 | variable "module_tags_enabled" { 28 | description = "(Optional) Whether to create AWS Resource Tags for the module informations." 29 | type = bool 30 | default = true 31 | nullable = false 32 | } 33 | 34 | 35 | ################################################### 36 | # Resource Group 37 | ################################################### 38 | 39 | variable "resource_group_enabled" { 40 | description = "(Optional) Whether to create Resource Group to find and group AWS resources which are created by this module." 41 | type = bool 42 | default = true 43 | nullable = false 44 | } 45 | 46 | variable "resource_group_name" { 47 | description = "(Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`." 48 | type = string 49 | default = "" 50 | nullable = false 51 | } 52 | 53 | variable "resource_group_description" { 54 | description = "(Optional) The description of Resource Group." 55 | type = string 56 | default = "Managed by Terraform." 57 | nullable = false 58 | } 59 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user-group/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.0" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/README.md: -------------------------------------------------------------------------------- 1 | # elasticache-redis-user 2 | 3 | This module creates following resources. 4 | 5 | - `aws_elasticache_user` 6 | 7 | 8 | ## Requirements 9 | 10 | | Name | Version | 11 | |------|---------| 12 | | [terraform](#requirement\_terraform) | >= 1.3 | 13 | | [aws](#requirement\_aws) | >= 4.30 | 14 | 15 | ## Providers 16 | 17 | | Name | Version | 18 | |------|---------| 19 | | [aws](#provider\_aws) | 4.34.0 | 20 | 21 | ## Modules 22 | 23 | | Name | Source | Version | 24 | |------|--------|---------| 25 | | [resource\_group](#module\_resource\_group) | tedilabs/misc/aws//modules/resource-group | ~> 0.10.0 | 26 | 27 | ## Resources 28 | 29 | | Name | Type | 30 | |------|------| 31 | | [aws_elasticache_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_user) | resource | 32 | 33 | ## Inputs 34 | 35 | | Name | Description | Type | Default | Required | 36 | |------|-------------|------|---------|:--------:| 37 | | [id](#input\_id) | (Required) The ID of the ElastiCache user. | `string` | n/a | yes | 38 | | [name](#input\_name) | (Required) The username of the ElastiCache user. It can have up to 40 characters, and must begin with a letter. It should not end with a hyphen or contain two consecutive hyphens. Valid characters: A-Z, a-z, 0-9, and - (hyphen). | `string` | n/a | yes | 39 | | [access\_string](#input\_access\_string) | (Optional) Access permissions string used for this user. Defaults to `off -@all`. | `string` | `"off -@all"` | no | 40 | | [module\_tags\_enabled](#input\_module\_tags\_enabled) | (Optional) Whether to create AWS Resource Tags for the module informations. | `bool` | `true` | no | 41 | | [password\_required](#input\_password\_required) | (Optional) Whether a password is required for this user. Defaults to `false`. | `bool` | `false` | no | 42 | | [passwords](#input\_passwords) | (Optional) A set of passwords used for this user. You can create up to two passwords for each user. | `set(string)` | `[]` | no | 43 | | [resource\_group\_description](#input\_resource\_group\_description) | (Optional) The description of Resource Group. | `string` | `"Managed by Terraform."` | no | 44 | | [resource\_group\_enabled](#input\_resource\_group\_enabled) | (Optional) Whether to create Resource Group to find and group AWS resources which are created by this module. | `bool` | `true` | no | 45 | | [resource\_group\_name](#input\_resource\_group\_name) | (Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`. | `string` | `""` | no | 46 | | [tags](#input\_tags) | (Optional) A map of tags to add to all resources. | `map(string)` | `{}` | no | 47 | 48 | ## Outputs 49 | 50 | | Name | Description | 51 | |------|-------------| 52 | | [access\_string](#output\_access\_string) | Access permissions string used for this user. | 53 | | [arn](#output\_arn) | The ARN of the ElastiCache user. | 54 | | [id](#output\_id) | The ID of the ElastiCache user. | 55 | | [name](#output\_name) | The name of the ElastiCache user. | 56 | | [password\_required](#output\_password\_required) | Whether a password is required for this user. | 57 | 58 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | metadata = { 3 | package = "terraform-aws-db" 4 | version = trimspace(file("${path.module}/../../VERSION")) 5 | module = basename(path.module) 6 | name = var.id 7 | } 8 | module_tags = var.module_tags_enabled ? { 9 | "module.terraform.io/package" = local.metadata.package 10 | "module.terraform.io/version" = local.metadata.version 11 | "module.terraform.io/name" = local.metadata.module 12 | "module.terraform.io/full-name" = "${local.metadata.package}/${local.metadata.module}" 13 | "module.terraform.io/instance" = local.metadata.name 14 | } : {} 15 | } 16 | 17 | 18 | ################################################### 19 | # User of ElastiCache for Redis 20 | ################################################### 21 | 22 | resource "aws_elasticache_user" "this" { 23 | engine = "REDIS" 24 | user_id = var.id 25 | user_name = var.name 26 | 27 | access_string = var.access_string 28 | no_password_required = !var.password_required 29 | passwords = var.passwords 30 | 31 | tags = merge( 32 | { 33 | "Name" = local.metadata.name 34 | }, 35 | local.module_tags, 36 | var.tags, 37 | ) 38 | } 39 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | description = "The ID of the ElastiCache user." 3 | value = aws_elasticache_user.this.user_id 4 | } 5 | 6 | output "arn" { 7 | description = "The ARN of the ElastiCache user." 8 | value = aws_elasticache_user.this.arn 9 | } 10 | 11 | output "name" { 12 | description = "The name of the ElastiCache user." 13 | value = aws_elasticache_user.this.user_name 14 | } 15 | 16 | output "access_string" { 17 | description = "Access permissions string used for this user." 18 | value = aws_elasticache_user.this.access_string 19 | } 20 | 21 | output "password_required" { 22 | description = "Whether a password is required for this user." 23 | value = !aws_elasticache_user.this.no_password_required 24 | } 25 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/resource-group.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | resource_group_name = (var.resource_group_name != "" 3 | ? var.resource_group_name 4 | : join(".", [ 5 | local.metadata.package, 6 | local.metadata.module, 7 | replace(local.metadata.name, "/[^a-zA-Z0-9_\\.-]/", "-"), 8 | ]) 9 | ) 10 | } 11 | 12 | 13 | module "resource_group" { 14 | source = "tedilabs/misc/aws//modules/resource-group" 15 | version = "~> 0.10.0" 16 | 17 | count = (var.resource_group_enabled && var.module_tags_enabled) ? 1 : 0 18 | 19 | name = local.resource_group_name 20 | description = var.resource_group_description 21 | 22 | query = { 23 | resource_tags = local.module_tags 24 | } 25 | 26 | module_tags_enabled = false 27 | tags = merge( 28 | local.module_tags, 29 | var.tags, 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/variables.tf: -------------------------------------------------------------------------------- 1 | variable "id" { 2 | description = "(Required) The ID of the ElastiCache user." 3 | type = string 4 | nullable = false 5 | } 6 | 7 | variable "name" { 8 | description = "(Required) The username of the ElastiCache user. It can have up to 40 characters, and must begin with a letter. It should not end with a hyphen or contain two consecutive hyphens. Valid characters: A-Z, a-z, 0-9, and - (hyphen)." 9 | type = string 10 | nullable = false 11 | } 12 | 13 | # INFO: https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/Clusters.RBAC.html#Access-string 14 | variable "access_string" { 15 | description = "(Optional) Access permissions string used for this user. Defaults to `off -@all`." 16 | type = string 17 | default = "off -@all" 18 | nullable = false 19 | } 20 | 21 | variable "password_required" { 22 | description = "(Optional) Whether a password is required for this user. Defaults to `false`." 23 | type = bool 24 | default = false 25 | nullable = false 26 | } 27 | 28 | variable "passwords" { 29 | description = "(Optional) A set of passwords used for this user. You can create up to two passwords for each user." 30 | type = set(string) 31 | default = [] 32 | nullable = false 33 | } 34 | 35 | variable "tags" { 36 | description = "(Optional) A map of tags to add to all resources." 37 | type = map(string) 38 | default = {} 39 | nullable = false 40 | } 41 | 42 | variable "module_tags_enabled" { 43 | description = "(Optional) Whether to create AWS Resource Tags for the module informations." 44 | type = bool 45 | default = true 46 | nullable = false 47 | } 48 | 49 | 50 | ################################################### 51 | # Resource Group 52 | ################################################### 53 | 54 | variable "resource_group_enabled" { 55 | description = "(Optional) Whether to create Resource Group to find and group AWS resources which are created by this module." 56 | type = bool 57 | default = true 58 | nullable = false 59 | } 60 | 61 | variable "resource_group_name" { 62 | description = "(Optional) The name of Resource Group. A Resource Group name can have a maximum of 127 characters, including letters, numbers, hyphens, dots, and underscores. The name cannot start with `AWS` or `aws`." 63 | type = string 64 | default = "" 65 | nullable = false 66 | } 67 | 68 | variable "resource_group_description" { 69 | description = "(Optional) The description of Resource Group." 70 | type = string 71 | default = "Managed by Terraform." 72 | nullable = false 73 | } 74 | -------------------------------------------------------------------------------- /modules/elasticache-redis-user/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 1.5" 3 | 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = ">= 5.0" 8 | } 9 | } 10 | } 11 | --------------------------------------------------------------------------------