Showing preview only (351K chars total). Download the full file or copy to clipboard to get everything.
Repository: cloudposse/terraform-aws-rds-cluster
Branch: main
Commit: 03c1ad7f1a8d
Files: 65
Total size: 331.4 KB
Directory structure:
gitextract_4dy49v9r/
├── .github/
│ ├── CODEOWNERS
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── bug_report.yml
│ │ ├── config.yml
│ │ ├── feature_request.md
│ │ ├── feature_request.yml
│ │ └── question.md
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── mergify.yml
│ ├── renovate.json
│ ├── settings.yml
│ └── workflows/
│ ├── branch.yml
│ ├── chatops.yml
│ ├── release.yml
│ └── scheduled.yml
├── .gitignore
├── LICENSE
├── README.md
├── README.yaml
├── atmos.yaml
├── context.tf
├── enhanced-monitoring.tf
├── examples/
│ ├── basic/
│ │ ├── main.tf
│ │ └── outputs.tf
│ ├── complete/
│ │ ├── context.tf
│ │ ├── fixtures.us-east-2.tfvars
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── enhanced_monitoring/
│ │ ├── main.tf
│ │ └── outputs.tf
│ ├── postgres/
│ │ ├── context.tf
│ │ ├── fixtures.us-east-2.tfvars
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ ├── serverless_mysql/
│ │ ├── main.tf
│ │ └── outputs.tf
│ ├── serverless_mysql57/
│ │ ├── main.tf
│ │ └── outputs.tf
│ ├── serverlessv2_postgres/
│ │ ├── context.tf
│ │ ├── fixtures.us-east-2.tfvars
│ │ ├── main.tf
│ │ ├── outputs.tf
│ │ ├── variables.tf
│ │ └── versions.tf
│ └── with_cluster_parameters/
│ ├── main.tf
│ └── outputs.tf
├── main.tf
├── outputs.tf
├── test/
│ ├── .gitignore
│ ├── Makefile
│ ├── Makefile.alpine
│ └── src/
│ ├── .gitignore
│ ├── Makefile
│ ├── examples_complete_test.go
│ ├── examples_postgres_test.go
│ ├── examples_serverlessv2_postgres_test.go
│ ├── go.mod
│ ├── go.sum
│ └── utils.go
├── variables.tf
└── versions.tf
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/CODEOWNERS
================================================
# Use this file to define individuals or teams that are responsible for code in a repository.
# Read more: <https://help.github.com/articles/about-codeowners/>
#
# Order is important: the last matching pattern has the highest precedence
# These owners will be the default owners for everything
* @cloudposse/engineering @cloudposse/contributors
# Cloud Posse must review any changes to Makefiles
**/Makefile @cloudposse/engineering
**/Makefile.* @cloudposse/engineering
# Cloud Posse must review any changes to GitHub actions
.github/* @cloudposse/engineering
# Cloud Posse must review any changes to standard context definition,
# but some changes can be rubber-stamped.
**/*.tf @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers
README.yaml @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers
README.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers
docs/*.md @cloudposse/engineering @cloudposse/contributors @cloudposse/approvers
# Cloud Posse Admins must review all changes to CODEOWNERS or the mergify configuration
.github/mergify.yml @cloudposse/admins
.github/CODEOWNERS @cloudposse/admins
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: 'bug'
assignees: ''
---
Found a bug? Maybe our [Slack Community](https://slack.cloudposse.com) can help.
[](https://slack.cloudposse.com)
## Describe the Bug
A clear and concise description of what the bug is.
## Expected Behavior
A clear and concise description of what you expected to happen.
## Steps to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Run '....'
3. Enter '....'
4. See error
## Screenshots
If applicable, add screenshots or logs to help explain your problem.
## Environment (please complete the following information):
Anything that will help us triage the bug will help. Here are some ideas:
- OS: [e.g. Linux, OSX, WSL, etc]
- Version [e.g. 10.15]
## Additional Context
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
---
name: Bug report
description: Create a report to help us improve
labels: ["bug"]
assignees: [""]
body:
- type: markdown
attributes:
value: |
Found a bug?
Please checkout our [Slack Community](https://slack.cloudposse.com)
or visit our [Slack Archive](https://archive.sweetops.com/).
[](https://slack.cloudposse.com)
- type: textarea
id: concise-description
attributes:
label: Describe the Bug
description: A clear and concise description of what the bug is.
placeholder: What is the bug about?
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected.
placeholder: What happened?
validations:
required: true
- type: textarea
id: reproduction-steps
attributes:
label: Steps to Reproduce
description: Steps to reproduce the behavior.
placeholder: How do we reproduce it?
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots or logs to help explain.
validations:
required: false
- type: textarea
id: environment
attributes:
label: Environment
description: Anything that will help us triage the bug.
placeholder: |
- OS: [e.g. Linux, OSX, WSL, etc]
- Version [e.g. 10.15]
- Module version
- Terraform version
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
Add any other context about the problem here.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Community Slack Team
url: https://cloudposse.com/slack/
about: |-
Please ask and answer questions here.
- name: Office Hours
url: https://cloudposse.com/office-hours/
about: |-
Join us every Wednesday for FREE Office Hours (lunch & learn).
- name: DevOps Accelerator Program
url: https://cloudposse.com/accelerate/
about: |-
Own your infrastructure in record time. We build it. You drive it.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature Request
about: Suggest an idea for this project
title: ''
labels: 'feature request'
assignees: ''
---
Have a question? Please checkout our [Slack Community](https://slack.cloudposse.com) or visit our [Slack Archive](https://archive.sweetops.com/).
[](https://slack.cloudposse.com)
## Describe the Feature
A clear and concise description of what the bug is.
## Expected Behavior
A clear and concise description of what you expected to happen.
## Use Case
Is your feature request related to a problem/challenge you are trying to solve? Please provide some additional context of why this feature or capability will be valuable.
## Describe Ideal Solution
A clear and concise description of what you want to happen. If you don't know, that's okay.
## Alternatives Considered
Explain what alternative solutions or features you've considered.
## Additional Context
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
---
name: Feature Request
description: Suggest an idea for this project
labels: ["feature request"]
assignees: [""]
body:
- type: markdown
attributes:
value: |
Have a question?
Please checkout our [Slack Community](https://slack.cloudposse.com)
or visit our [Slack Archive](https://archive.sweetops.com/).
[](https://slack.cloudposse.com)
- type: textarea
id: concise-description
attributes:
label: Describe the Feature
description: A clear and concise description of what the feature is.
placeholder: What is the feature about?
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected.
placeholder: What happened?
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case
description: |
Is your feature request related to a problem/challenge you are trying
to solve?
Please provide some additional context of why this feature or
capability will be valuable.
validations:
required: true
- type: textarea
id: ideal-solution
attributes:
label: Describe Ideal Solution
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives-considered
attributes:
label: Alternatives Considered
description: Explain alternative solutions or features considered.
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional Context
description: |
Add any other context about the problem here.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/question.md
================================================
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## what
<!--
- Describe high-level what changed as a result of these commits (i.e. in plain-english, what do these changes mean?)
- Use bullet points to be concise and to the point.
-->
## why
<!--
- Provide the justifications for the changes (e.g. business case).
- Describe why these changes were made (e.g. why do these commits fix the problem?)
- Use bullet points to be concise and to the point.
-->
## references
<!--
- Link to any supporting github issues or helpful documentation to add some context (e.g. stackoverflow).
- Use `closes #123`, if this PR closes a GitHub issue `#123`
-->
================================================
FILE: .github/mergify.yml
================================================
extends: .github
================================================
FILE: .github/renovate.json
================================================
{
"extends": [
"config:base",
":preserveSemverRanges",
":rebaseStalePrs"
],
"baseBranches": ["main"],
"labels": ["auto-update"],
"dependencyDashboardAutoclose": true,
"enabledManagers": ["terraform"],
"terraform": {
"ignorePaths": ["**/context.tf"]
}
}
================================================
FILE: .github/settings.yml
================================================
# Upstream changes from _extends are only recognized when modifications are made to this file in the default branch.
_extends: .github
repository:
name: terraform-aws-rds-cluster
description: Terraform module to provision an RDS Aurora cluster for MySQL or Postgres
homepage: https://cloudposse.com/accelerate
topics: terraform, terraform-modules, rds, rds-database, aurora, aws, mysql, cluster, hcl2, terratest
================================================
FILE: .github/workflows/branch.yml
================================================
---
name: Branch
on:
pull_request:
branches:
- main
- release/**
types: [opened, synchronize, reopened, labeled, unlabeled]
push:
branches:
- main
- release/v*
paths-ignore:
- '.github/**'
- 'docs/**'
- 'examples/**'
- 'test/**'
- 'README.md'
permissions: {}
jobs:
terraform-module:
uses: cloudposse/.github/.github/workflows/shared-terraform-module.yml@main
secrets: inherit
================================================
FILE: .github/workflows/chatops.yml
================================================
---
name: chatops
on:
issue_comment:
types: [created]
permissions:
pull-requests: write
id-token: write
contents: write
statuses: write
jobs:
test:
uses: cloudposse/.github/.github/workflows/shared-terraform-chatops.yml@main
if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/terratest') }}
secrets: inherit
================================================
FILE: .github/workflows/release.yml
================================================
---
name: release
on:
release:
types:
- published
permissions:
id-token: write
contents: write
pull-requests: write
jobs:
terraform-module:
uses: cloudposse/.github/.github/workflows/shared-release-branches.yml@main
secrets: inherit
================================================
FILE: .github/workflows/scheduled.yml
================================================
---
name: scheduled
on:
workflow_dispatch: { } # Allows manually trigger this workflow
schedule:
- cron: "0 3 * * *"
permissions:
pull-requests: write
id-token: write
contents: write
jobs:
scheduled:
uses: cloudposse/.github/.github/workflows/shared-terraform-scheduled.yml@main
secrets: inherit
================================================
FILE: .gitignore
================================================
# Compiled files
*.tfstate
*.tfstate.backup
# Module directory
.terraform
.idea
*.iml
.build-harness
build-harness
.terraform.lock.hcl
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2017-2023 Cloud Posse, LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
<!-- markdownlint-disable -->
<a href="https://cpco.io/homepage"><img src="https://github.com/cloudposse/terraform-aws-rds-cluster/blob/main/.github/banner.png?raw=true" alt="Project Banner"/></a><br/>
<p align="right"><a href="https://github.com/cloudposse/terraform-aws-rds-cluster/releases/latest"><img src="https://img.shields.io/github/release/cloudposse/terraform-aws-rds-cluster.svg?style=for-the-badge" alt="Latest Release"/></a><a href="https://github.com/cloudposse/terraform-aws-rds-cluster/commits"><img src="https://img.shields.io/github/last-commit/cloudposse/terraform-aws-rds-cluster.svg?style=for-the-badge" alt="Last Updated"/></a><a href="https://cloudposse.com/slack"><img src="https://slack.cloudposse.com/for-the-badge.svg" alt="Slack Community"/></a><a href="https://cloudposse.com/support/"><img src="https://img.shields.io/badge/Get_Support-success.svg?style=for-the-badge" alt="Get Support"/></a>
</p>
<!-- markdownlint-restore -->
<!--
** DO NOT EDIT THIS FILE
**
** This file was automatically generated by the `cloudposse/build-harness`.
** 1) Make all changes to `README.yaml`
** 2) Install [atmos](https://atmos.tools/install/) (you only need to do this once)
** 3) Run`atmos readme` to rebuild this file.
**
** (We maintain HUNDREDS of open source projects. This is how we maintain our sanity.)
**
-->
Terraform module to provision an [`RDS Aurora`](https://aws.amazon.com/rds/aurora) cluster for MySQL or Postgres.
Supports [Amazon Aurora Serverless](https://aws.amazon.com/rds/aurora/serverless/).
> [!TIP]
> #### 👽 Use Atmos with Terraform
> Cloud Posse uses [`atmos`](https://atmos.tools) to easily orchestrate multiple environments using Terraform. <br/>
> Works with [Github Actions](https://atmos.tools/integrations/github-actions/), [Atlantis](https://atmos.tools/integrations/atlantis), or [Spacelift](https://atmos.tools/integrations/spacelift).
>
> <details>
> <summary><strong>Watch demo of using Atmos with Terraform</strong></summary>
> <img src="https://github.com/cloudposse/atmos/blob/main/docs/demo.gif?raw=true"/><br/>
> <i>Example of running <a href="https://atmos.tools"><code>atmos</code></a> to manage infrastructure from our <a href="https://atmos.tools/quick-start/">Quick Start</a> tutorial.</i>
> </detalis>
## Usage
For a complete example, see [examples/complete](examples/complete).
For automated tests of the complete example using [bats](https://github.com/bats-core/bats-core) and [Terratest](https://github.com/gruntwork-io/terratest) (which tests and deploys the example on AWS), see [test](test).
[Basic example](examples/basic)
```hcl
module "rds_cluster_aurora_postgres" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
name = "postgres"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
# 1 writer, 1 reader
cluster_size = 2
# 1 writer, 3 reader
# cluster_size = 4
# 1 writer, 5 reader
# cluster_size = 6
namespace = "eg"
stage = "dev"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
}
```
[Serverless Aurora MySQL 5.6](examples/serverless_mysql)
```hcl
module "rds_cluster_aurora_mysql_serverless" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora"
engine_mode = "serverless"
cluster_family = "aurora5.6"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 256
min_capacity = 2
seconds_until_auto_pause = 300
}
]
}
```
[Serverless Aurora 2.07.1 MySQL 5.7](examples/serverless_mysql57)
```hcl
module "rds_cluster_aurora_mysql_serverless" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora-mysql"
engine_mode = "serverless"
engine_version = "5.7.mysql_aurora.2.07.1"
cluster_family = "aurora-mysql5.7"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 16
min_capacity = 1
seconds_until_auto_pause = 300
timeout_action = "ForceApplyCapacityChange"
}
]
}
```
[With cluster parameters](examples/with_cluster_parameters)
```hcl
module "rds_cluster_aurora_mysql" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
engine = "aurora"
cluster_family = "aurora-mysql5.7"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
cluster_parameters = [
{
name = "character_set_client"
value = "utf8"
},
{
name = "character_set_connection"
value = "utf8"
},
{
name = "character_set_database"
value = "utf8"
},
{
name = "character_set_results"
value = "utf8"
},
{
name = "character_set_server"
value = "utf8"
},
{
name = "collation_connection"
value = "utf8_bin"
},
{
name = "collation_server"
value = "utf8_bin"
},
{
name = "lower_case_table_names"
value = "1"
apply_method = "pending-reboot"
},
{
name = "skip-character-set-client-handshake"
value = "1"
apply_method = "pending-reboot"
}
]
}
```
[With enhanced monitoring](examples/enhanced_monitoring)
```hcl
# create IAM role for monitoring
resource "aws_iam_role" "enhanced_monitoring" {
name = "rds-cluster-example-1"
assume_role_policy = data.aws_iam_policy_document.enhanced_monitoring.json
}
# Attach Amazon's managed policy for RDS enhanced monitoring
resource "aws_iam_role_policy_attachment" "enhanced_monitoring" {
role = aws_iam_role.enhanced_monitoring.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
# allow rds to assume this role
data "aws_iam_policy_document" "enhanced_monitoring" {
statement {
actions = [
"sts:AssumeRole",
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["monitoring.rds.amazonaws.com"]
}
}
}
module "rds_cluster_aurora_postgres" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
# enable monitoring every 30 seconds
rds_monitoring_interval = 30
# reference iam role created above
rds_monitoring_role_arn = aws_iam_role.enhanced_monitoring.arn
}
```
> [!IMPORTANT]
> In Cloud Posse's examples, we avoid pinning modules to specific versions to prevent discrepancies between the documentation
> and the latest released versions. However, for your own projects, we strongly advise pinning each module to the exact version
> you're using. This practice ensures the stability of your infrastructure. Additionally, we recommend implementing a systematic
> approach for updating versions to avoid unexpected changes.
## Examples
Review the [complete example](examples/complete) to see how to use this module.
<!-- markdownlint-disable -->
## Requirements
| Name | Version |
| ---- | ------- |
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.0.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.81.0 |
| <a name="requirement_null"></a> [null](#requirement\_null) | >= 2.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | >= 2.0 |
## Providers
| Name | Version |
| ---- | ------- |
| <a name="provider_aws"></a> [aws](#provider\_aws) | >= 5.81.0 |
| <a name="provider_random"></a> [random](#provider\_random) | >= 2.0 |
## Modules
| Name | Source | Version |
| ---- | ------ | ------- |
| <a name="module_dns_master"></a> [dns\_master](#module\_dns\_master) | cloudposse/route53-cluster-hostname/aws | 0.13.0 |
| <a name="module_dns_replicas"></a> [dns\_replicas](#module\_dns\_replicas) | cloudposse/route53-cluster-hostname/aws | 0.13.0 |
| <a name="module_enhanced_monitoring_label"></a> [enhanced\_monitoring\_label](#module\_enhanced\_monitoring\_label) | cloudposse/label/null | 0.25.0 |
| <a name="module_rds_identifier"></a> [rds\_identifier](#module\_rds\_identifier) | cloudposse/label/null | 0.25.0 |
| <a name="module_this"></a> [this](#module\_this) | cloudposse/label/null | 0.25.0 |
## Resources
| Name | Type |
| ---- | ---- |
| [aws_appautoscaling_policy.replicas](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource |
| [aws_appautoscaling_target.replicas](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target) | resource |
| [aws_db_parameter_group.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_parameter_group) | resource |
| [aws_db_subnet_group.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_subnet_group) | resource |
| [aws_iam_role.enhanced_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy_attachment.enhanced_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_rds_cluster.primary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster) | resource |
| [aws_rds_cluster.secondary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster) | resource |
| [aws_rds_cluster_activity_stream.primary](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_activity_stream) | resource |
| [aws_rds_cluster_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance) | resource |
| [aws_rds_cluster_parameter_group.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_parameter_group) | resource |
| [aws_rds_reserved_instance.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_reserved_instance) | resource |
| [aws_security_group.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group_rule.egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.egress_ipv6](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.ingress_cidr_blocks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.ingress_ipv6_cidr_blocks](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.ingress_security_groups](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.traffic_inside_security_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [random_pet.instance](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource |
| [aws_iam_policy_document.enhanced_monitoring](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_rds_reserved_instance_offering.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/rds_reserved_instance_offering) | data source |
## Inputs
| Name | Description | Type | Default | Required |
| ---- | ----------- | ---- | ------- | :------: |
| <a name="input_activity_stream_enabled"></a> [activity\_stream\_enabled](#input\_activity\_stream\_enabled) | Whether to enable Activity Streams | `bool` | `false` | no |
| <a name="input_activity_stream_kms_key_id"></a> [activity\_stream\_kms\_key\_id](#input\_activity\_stream\_kms\_key\_id) | The ARN for the KMS key to encrypt Activity Stream Data data. When specifying `activity_stream_kms_key_id`, `activity_stream_enabled` needs to be set to true | `string` | `""` | no |
| <a name="input_activity_stream_mode"></a> [activity\_stream\_mode](#input\_activity\_stream\_mode) | The mode for the Activity Streams. `async` and `sync` are supported. Defaults to `async` | `string` | `"async"` | no |
| <a name="input_additional_tag_map"></a> [additional\_tag\_map](#input\_additional\_tag\_map) | Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.<br/>This is for some rare cases where resources want additional configuration of tags<br/>and therefore take a list of maps with tag key, value, and additional configuration. | `map(string)` | `{}` | no |
| <a name="input_admin_password"></a> [admin\_password](#input\_admin\_password) | Password for the master DB user. Ignored if snapshot\_identifier or replication\_source\_identifier is provided | `string` | `""` | no |
| <a name="input_admin_user"></a> [admin\_user](#input\_admin\_user) | Username for the master DB user. Ignored if snapshot\_identifier or replication\_source\_identifier is provided | `string` | `"admin"` | no |
| <a name="input_admin_user_secret_kms_key_id"></a> [admin\_user\_secret\_kms\_key\_id](#input\_admin\_user\_secret\_kms\_key\_id) | Amazon Web Services KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key.<br/>To use a KMS key in a different Amazon Web Services account, specify the key ARN or alias ARN.<br/>If not specified, the default KMS key for your Amazon Web Services account is used. | `string` | `null` | no |
| <a name="input_allocated_storage"></a> [allocated\_storage](#input\_allocated\_storage) | The allocated storage in GBs | `number` | `null` | no |
| <a name="input_allow_major_version_upgrade"></a> [allow\_major\_version\_upgrade](#input\_allow\_major\_version\_upgrade) | Enable to allow major engine version upgrades when changing engine versions. Defaults to false. | `bool` | `false` | no |
| <a name="input_allowed_cidr_blocks"></a> [allowed\_cidr\_blocks](#input\_allowed\_cidr\_blocks) | List of CIDR blocks allowed to access the cluster | `list(string)` | `[]` | no |
| <a name="input_allowed_ipv6_cidr_blocks"></a> [allowed\_ipv6\_cidr\_blocks](#input\_allowed\_ipv6\_cidr\_blocks) | List of IPv6 CIDR blocks allowed to access the cluster | `list(string)` | `[]` | no |
| <a name="input_apply_immediately"></a> [apply\_immediately](#input\_apply\_immediately) | Specifies whether any cluster modifications are applied immediately, or during the next maintenance window | `bool` | `true` | no |
| <a name="input_attributes"></a> [attributes](#input\_attributes) | ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,<br/>in the order they appear in the list. New attributes are appended to the<br/>end of the list. The elements of the list are joined by the `delimiter`<br/>and treated as a single ID element. | `list(string)` | `[]` | no |
| <a name="input_auto_minor_version_upgrade"></a> [auto\_minor\_version\_upgrade](#input\_auto\_minor\_version\_upgrade) | Indicates that minor engine upgrades will be applied automatically to the DB instance during the maintenance window | `bool` | `true` | no |
| <a name="input_autoscaling_enabled"></a> [autoscaling\_enabled](#input\_autoscaling\_enabled) | Whether to enable cluster autoscaling | `bool` | `false` | no |
| <a name="input_autoscaling_max_capacity"></a> [autoscaling\_max\_capacity](#input\_autoscaling\_max\_capacity) | Maximum number of instances to be maintained by the autoscaler | `number` | `5` | no |
| <a name="input_autoscaling_min_capacity"></a> [autoscaling\_min\_capacity](#input\_autoscaling\_min\_capacity) | Minimum number of instances to be maintained by the autoscaler | `number` | `1` | no |
| <a name="input_autoscaling_policy_type"></a> [autoscaling\_policy\_type](#input\_autoscaling\_policy\_type) | Autoscaling policy type. `TargetTrackingScaling` and `StepScaling` are supported | `string` | `"TargetTrackingScaling"` | no |
| <a name="input_autoscaling_scale_in_cooldown"></a> [autoscaling\_scale\_in\_cooldown](#input\_autoscaling\_scale\_in\_cooldown) | The amount of time, in seconds, after a scaling activity completes and before the next scaling down activity can start. Default is 300s | `number` | `300` | no |
| <a name="input_autoscaling_scale_out_cooldown"></a> [autoscaling\_scale\_out\_cooldown](#input\_autoscaling\_scale\_out\_cooldown) | The amount of time, in seconds, after a scaling activity completes and before the next scaling up activity can start. Default is 300s | `number` | `300` | no |
| <a name="input_autoscaling_target_metrics"></a> [autoscaling\_target\_metrics](#input\_autoscaling\_target\_metrics) | The metrics type to use. If this value isn't provided the default is CPU utilization | `string` | `"RDSReaderAverageCPUUtilization"` | no |
| <a name="input_autoscaling_target_value"></a> [autoscaling\_target\_value](#input\_autoscaling\_target\_value) | The target value to scale with respect to target metrics | `number` | `75` | no |
| <a name="input_backtrack_window"></a> [backtrack\_window](#input\_backtrack\_window) | The target backtrack window, in seconds. Only available for aurora engine currently. Must be between 0 and 259200 (72 hours) | `number` | `0` | no |
| <a name="input_backup_window"></a> [backup\_window](#input\_backup\_window) | Daily time range during which the backups happen | `string` | `"07:00-09:00"` | no |
| <a name="input_ca_cert_identifier"></a> [ca\_cert\_identifier](#input\_ca\_cert\_identifier) | The identifier of the CA certificate for the DB instance | `string` | `null` | no |
| <a name="input_cluster_dns_name"></a> [cluster\_dns\_name](#input\_cluster\_dns\_name) | Name of the cluster CNAME record to create in the parent DNS zone specified by `zone_id`. If left empty, the name will be auto-asigned using the format `master.var.name` | `string` | `""` | no |
| <a name="input_cluster_family"></a> [cluster\_family](#input\_cluster\_family) | The family of the DB cluster parameter group | `string` | `"aurora5.6"` | no |
| <a name="input_cluster_identifier"></a> [cluster\_identifier](#input\_cluster\_identifier) | The RDS Cluster Identifier. Will use generated label ID if not supplied | `string` | `""` | no |
| <a name="input_cluster_parameters"></a> [cluster\_parameters](#input\_cluster\_parameters) | List of DB cluster parameters to apply | <pre>list(object({<br/> apply_method = string<br/> name = string<br/> value = string<br/> }))</pre> | `[]` | no |
| <a name="input_cluster_size"></a> [cluster\_size](#input\_cluster\_size) | Number of DB instances to create in the cluster | `number` | `2` | no |
| <a name="input_cluster_type"></a> [cluster\_type](#input\_cluster\_type) | Either `regional` or `global`.<br/>If `regional` will be created as a normal, standalone DB.<br/>If `global`, will be made part of a Global cluster (requires `global_cluster_identifier`). | `string` | `"regional"` | no |
| <a name="input_context"></a> [context](#input\_context) | Single object for setting entire context at once.<br/>See description of individual variables for details.<br/>Leave string and numeric variables as `null` to use default value.<br/>Individual variable settings (non-null) override settings in context object,<br/>except for attributes, tags, and additional\_tag\_map, which are merged. | `any` | <pre>{<br/> "additional_tag_map": {},<br/> "attributes": [],<br/> "delimiter": null,<br/> "descriptor_formats": {},<br/> "enabled": true,<br/> "environment": null,<br/> "id_length_limit": null,<br/> "label_key_case": null,<br/> "label_order": [],<br/> "label_value_case": null,<br/> "labels_as_tags": [<br/> "unset"<br/> ],<br/> "name": null,<br/> "namespace": null,<br/> "regex_replace_chars": null,<br/> "stage": null,<br/> "tags": {},<br/> "tenant": null<br/>}</pre> | no |
| <a name="input_copy_tags_to_snapshot"></a> [copy\_tags\_to\_snapshot](#input\_copy\_tags\_to\_snapshot) | Copy tags to backup snapshots | `bool` | `false` | no |
| <a name="input_database_insights_mode"></a> [database\_insights\_mode](#input\_database\_insights\_mode) | The database insights mode for the RDS cluster. Valid values are `standard`, `advanced`. See https://registry.terraform.io/providers/hashicorp/aws/6.16.0/docs/resources/rds_cluster#database_insights_mode-1 | `string` | `null` | no |
| <a name="input_db_cluster_instance_class"></a> [db\_cluster\_instance\_class](#input\_db\_cluster\_instance\_class) | This setting is required to create a provisioned Multi-AZ DB cluster | `string` | `null` | no |
| <a name="input_db_name"></a> [db\_name](#input\_db\_name) | Database name (default is not to create a database) | `string` | `""` | no |
| <a name="input_db_parameter_group_name"></a> [db\_parameter\_group\_name](#input\_db\_parameter\_group\_name) | The name to give to the created `aws_db_parameter_group` resource.<br/>If omitted, the module will generate a name. | `string` | `""` | no |
| <a name="input_db_port"></a> [db\_port](#input\_db\_port) | Database port | `number` | `3306` | no |
| <a name="input_deletion_protection"></a> [deletion\_protection](#input\_deletion\_protection) | If the DB instance should have deletion protection enabled | `bool` | `false` | no |
| <a name="input_delimiter"></a> [delimiter](#input\_delimiter) | Delimiter to be used between ID elements.<br/>Defaults to `-` (hyphen). Set to `""` to use no delimiter at all. | `string` | `null` | no |
| <a name="input_descriptor_formats"></a> [descriptor\_formats](#input\_descriptor\_formats) | Describe additional descriptors to be output in the `descriptors` output map.<br/>Map of maps. Keys are names of descriptors. Values are maps of the form<br/>`{<br/> format = string<br/> labels = list(string)<br/>}`<br/>(Type is `any` so the map values can later be enhanced to provide additional options.)<br/>`format` is a Terraform format string to be passed to the `format()` function.<br/>`labels` is a list of labels, in order, to pass to `format()` function.<br/>Label values will be normalized before being passed to `format()` so they will be<br/>identical to how they appear in `id`.<br/>Default is `{}` (`descriptors` output will be empty). | `any` | `{}` | no |
| <a name="input_egress_enabled"></a> [egress\_enabled](#input\_egress\_enabled) | Whether or not to apply the egress security group rule to default security group, defaults to `true` | `bool` | `true` | no |
| <a name="input_enable_global_write_forwarding"></a> [enable\_global\_write\_forwarding](#input\_enable\_global\_write\_forwarding) | Set to `true`, to forward writes to an associated global cluster. | `bool` | `null` | no |
| <a name="input_enable_http_endpoint"></a> [enable\_http\_endpoint](#input\_enable\_http\_endpoint) | Enable HTTP endpoint (data API). | `bool` | `false` | no |
| <a name="input_enable_local_write_forwarding"></a> [enable\_local\_write\_forwarding](#input\_enable\_local\_write\_forwarding) | Set to `true`, to forward writes sent to a reader to the writer instance. | `bool` | `null` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Set to false to prevent the module from creating any resources | `bool` | `null` | no |
| <a name="input_enabled_cloudwatch_logs_exports"></a> [enabled\_cloudwatch\_logs\_exports](#input\_enabled\_cloudwatch\_logs\_exports) | List of log types to export to cloudwatch. The following log types are supported: audit, error, general, slowquery | `list(string)` | `[]` | no |
| <a name="input_engine"></a> [engine](#input\_engine) | The name of the database engine to be used for this DB cluster. Valid values: `aurora`, `aurora-mysql`, `aurora-postgresql` | `string` | `"aurora"` | no |
| <a name="input_engine_mode"></a> [engine\_mode](#input\_engine\_mode) | The database engine mode. Valid values: `parallelquery`, `provisioned`, `serverless` | `string` | `"provisioned"` | no |
| <a name="input_engine_version"></a> [engine\_version](#input\_engine\_version) | The version of the database engine to use. See `aws rds describe-db-engine-versions` | `string` | `""` | no |
| <a name="input_enhanced_monitoring_attributes"></a> [enhanced\_monitoring\_attributes](#input\_enhanced\_monitoring\_attributes) | The attributes for the enhanced monitoring IAM role | `list(string)` | <pre>[<br/> "enhanced-monitoring"<br/>]</pre> | no |
| <a name="input_enhanced_monitoring_role_enabled"></a> [enhanced\_monitoring\_role\_enabled](#input\_enhanced\_monitoring\_role\_enabled) | A boolean flag to enable/disable the creation of the enhanced monitoring IAM role. If set to `false`, the module will not create a new role and will use `rds_monitoring_role_arn` for enhanced monitoring | `bool` | `false` | no |
| <a name="input_environment"></a> [environment](#input\_environment) | ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT' | `string` | `null` | no |
| <a name="input_global_cluster_identifier"></a> [global\_cluster\_identifier](#input\_global\_cluster\_identifier) | ID of the Aurora global cluster | `string` | `""` | no |
| <a name="input_iam_database_authentication_enabled"></a> [iam\_database\_authentication\_enabled](#input\_iam\_database\_authentication\_enabled) | Specifies whether or mappings of AWS Identity and Access Management (IAM) accounts to database accounts is enabled | `bool` | `false` | no |
| <a name="input_iam_roles"></a> [iam\_roles](#input\_iam\_roles) | Iam roles for the Aurora cluster | `list(string)` | `[]` | no |
| <a name="input_id_length_limit"></a> [id\_length\_limit](#input\_id\_length\_limit) | Limit `id` to this many characters (minimum 6).<br/>Set to `0` for unlimited length.<br/>Set to `null` for keep the existing setting, which defaults to `0`.<br/>Does not affect `id_full`. | `number` | `null` | no |
| <a name="input_instance_availability_zone"></a> [instance\_availability\_zone](#input\_instance\_availability\_zone) | Optional parameter to place cluster instances in a specific availability zone. If left empty, will place randomly | `string` | `""` | no |
| <a name="input_instance_identifier_suffix"></a> [instance\_identifier\_suffix](#input\_instance\_identifier\_suffix) | The suffix to append to DB instance identifiers.<br/>If `null`, the module will generate a random suffix. If empty, no suffix will be appended. | `string` | `null` | no |
| <a name="input_instance_parameters"></a> [instance\_parameters](#input\_instance\_parameters) | List of DB instance parameters to apply | <pre>list(object({<br/> apply_method = string<br/> name = string<br/> value = string<br/> }))</pre> | `[]` | no |
| <a name="input_instance_type"></a> [instance\_type](#input\_instance\_type) | Instance type to use | `string` | `"db.t2.small"` | no |
| <a name="input_intra_security_group_traffic_enabled"></a> [intra\_security\_group\_traffic\_enabled](#input\_intra\_security\_group\_traffic\_enabled) | Whether to allow traffic between resources inside the database's security group. | `bool` | `false` | no |
| <a name="input_iops"></a> [iops](#input\_iops) | The amount of provisioned IOPS. Setting this implies a storage\_type of 'io1'. This setting is required to create a Multi-AZ DB cluster. Check TF docs for values based on db engine | `number` | `null` | no |
| <a name="input_kms_key_arn"></a> [kms\_key\_arn](#input\_kms\_key\_arn) | The ARN for the KMS encryption key. When specifying `kms_key_arn`, `storage_encrypted` needs to be set to `true` | `string` | `""` | no |
| <a name="input_label_key_case"></a> [label\_key\_case](#input\_label\_key\_case) | Controls the letter case of the `tags` keys (label names) for tags generated by this module.<br/>Does not affect keys of tags passed in via the `tags` input.<br/>Possible values: `lower`, `title`, `upper`.<br/>Default value: `title`. | `string` | `null` | no |
| <a name="input_label_order"></a> [label\_order](#input\_label\_order) | The order in which the labels (ID elements) appear in the `id`.<br/>Defaults to ["namespace", "environment", "stage", "name", "attributes"].<br/>You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present. | `list(string)` | `null` | no |
| <a name="input_label_value_case"></a> [label\_value\_case](#input\_label\_value\_case) | Controls the letter case of ID elements (labels) as included in `id`,<br/>set as tag values, and output by this module individually.<br/>Does not affect values of tags passed in via the `tags` input.<br/>Possible values: `lower`, `title`, `upper` and `none` (no transformation).<br/>Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.<br/>Default value: `lower`. | `string` | `null` | no |
| <a name="input_labels_as_tags"></a> [labels\_as\_tags](#input\_labels\_as\_tags) | Set of labels (ID elements) to include as tags in the `tags` output.<br/>Default is to include all labels.<br/>Tags with empty values will not be included in the `tags` output.<br/>Set to `[]` to suppress all generated tags.<br/>**Notes:**<br/> The value of the `name` tag, if included, will be the `id`, not the `name`.<br/> Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be<br/> changed in later chained modules. Attempts to change it will be silently ignored. | `set(string)` | <pre>[<br/> "default"<br/>]</pre> | no |
| <a name="input_maintenance_window"></a> [maintenance\_window](#input\_maintenance\_window) | Weekly time range during which system maintenance can occur, in UTC | `string` | `"wed:03:00-wed:04:00"` | no |
| <a name="input_manage_admin_user_password"></a> [manage\_admin\_user\_password](#input\_manage\_admin\_user\_password) | Set to true to allow RDS to manage the master user password in Secrets Manager. Cannot be set if master\_password is provided | `bool` | `false` | no |
| <a name="input_name"></a> [name](#input\_name) | ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.<br/>This is the only ID element not also included as a `tag`.<br/>The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input. | `string` | `null` | no |
| <a name="input_namespace"></a> [namespace](#input\_namespace) | ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique | `string` | `null` | no |
| <a name="input_network_type"></a> [network\_type](#input\_network\_type) | The network type of the cluster. Valid values: IPV4, DUAL. | `string` | `"IPV4"` | no |
| <a name="input_parameter_group_name_prefix_enabled"></a> [parameter\_group\_name\_prefix\_enabled](#input\_parameter\_group\_name\_prefix\_enabled) | Set to `true` to use `name_prefix` to name the cluster and database parameter groups. Set to `false` to use `name` instead | `bool` | `true` | no |
| <a name="input_performance_insights_enabled"></a> [performance\_insights\_enabled](#input\_performance\_insights\_enabled) | Whether to enable Performance Insights | `bool` | `false` | no |
| <a name="input_performance_insights_kms_key_id"></a> [performance\_insights\_kms\_key\_id](#input\_performance\_insights\_kms\_key\_id) | The ARN for the KMS key to encrypt Performance Insights data. When specifying `performance_insights_kms_key_id`, `performance_insights_enabled` needs to be set to true | `string` | `""` | no |
| <a name="input_performance_insights_retention_period"></a> [performance\_insights\_retention\_period](#input\_performance\_insights\_retention\_period) | Amount of time in days to retain Performance Insights data. Either 7 (7 days) or 731 (2 years) | `number` | `null` | no |
| <a name="input_promotion_tier"></a> [promotion\_tier](#input\_promotion\_tier) | Failover Priority setting on instance level. The reader who has lower tier has higher priority to get promoted to writer.<br/><br/>Readers in promotion tiers 0 and 1 scale at the same time as the writer. Readers in promotion tiers 2–15 scale independently from the writer. For more information, see: https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless-v2.how-it-works.html#aurora-serverless-v2.how-it-works.scaling | `number` | `0` | no |
| <a name="input_publicly_accessible"></a> [publicly\_accessible](#input\_publicly\_accessible) | Set to true if you want your cluster to be publicly accessible (such as via QuickSight) | `bool` | `false` | no |
| <a name="input_rds_cluster_parameter_group_name"></a> [rds\_cluster\_parameter\_group\_name](#input\_rds\_cluster\_parameter\_group\_name) | The name to give to the created `aws_rds_cluster_parameter_group` resource.<br/>If omitted, the module will generate a name. | `string` | `""` | no |
| <a name="input_rds_monitoring_interval"></a> [rds\_monitoring\_interval](#input\_rds\_monitoring\_interval) | The interval, in seconds, between points when enhanced monitoring metrics are collected for the DB instance. To disable collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid Values: 0, 1, 5, 10, 15, 30, 60 | `number` | `0` | no |
| <a name="input_rds_monitoring_role_arn"></a> [rds\_monitoring\_role\_arn](#input\_rds\_monitoring\_role\_arn) | The ARN for the IAM role that permits RDS to send enhanced monitoring metrics to CloudWatch Logs | `string` | `null` | no |
| <a name="input_rds_ri_duration"></a> [rds\_ri\_duration](#input\_rds\_ri\_duration) | The number of years to reserve the instance. Values can be 1 or 3 (or in seconds, 31536000 or 94608000) | `number` | `1` | no |
| <a name="input_rds_ri_offering_type"></a> [rds\_ri\_offering\_type](#input\_rds\_ri\_offering\_type) | Offering type of reserved DB instances. Valid values are 'No Upfront', 'Partial Upfront', 'All Upfront'. | `string` | `""` | no |
| <a name="input_rds_ri_reservation_id"></a> [rds\_ri\_reservation\_id](#input\_rds\_ri\_reservation\_id) | Customer-specified identifier to track the reservation of the reserved DB instance. | `string` | `null` | no |
| <a name="input_reader_dns_name"></a> [reader\_dns\_name](#input\_reader\_dns\_name) | Name of the reader endpoint CNAME record to create in the parent DNS zone specified by `zone_id`. If left empty, the name will be auto-asigned using the format `replicas.var.name` | `string` | `""` | no |
| <a name="input_regex_replace_chars"></a> [regex\_replace\_chars](#input\_regex\_replace\_chars) | Terraform regular expression (regex) string.<br/>Characters matching the regex will be removed from the ID elements.<br/>If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits. | `string` | `null` | no |
| <a name="input_replication_source_identifier"></a> [replication\_source\_identifier](#input\_replication\_source\_identifier) | ARN of a source DB cluster or DB instance if this DB cluster is to be created as a Read Replica | `string` | `""` | no |
| <a name="input_restore_to_point_in_time"></a> [restore\_to\_point\_in\_time](#input\_restore\_to\_point\_in\_time) | List of point-in-time recovery options. Valid parameters are:<br/><br/>`source_cluster_identifier`<br/> Identifier of the source database cluster from which to restore.<br/>`restore_type`:<br/> Type of restore to be performed. Valid options are "full-copy" and "copy-on-write".<br/>`use_latest_restorable_time`:<br/> Set to true to restore the database cluster to the latest restorable backup time. Conflicts with `restore_to_time`.<br/>`restore_to_time`:<br/> Date and time in UTC format to restore the database cluster to. Conflicts with `use_latest_restorable_time`. | <pre>list(object({<br/> source_cluster_identifier = string<br/> restore_type = optional(string, "copy-on-write")<br/> use_latest_restorable_time = optional(bool, true)<br/> restore_to_time = optional(string, null)<br/> }))</pre> | `[]` | no |
| <a name="input_retention_period"></a> [retention\_period](#input\_retention\_period) | Number of days to retain backups for | `number` | `5` | no |
| <a name="input_s3_import"></a> [s3\_import](#input\_s3\_import) | Restore from a Percona Xtrabackup in S3. The `bucket_name` is required to be in the same region as the resource. | <pre>object({<br/> bucket_name = string<br/> bucket_prefix = string<br/> ingestion_role = string<br/> source_engine = string<br/> source_engine_version = string<br/> })</pre> | `null` | no |
| <a name="input_scaling_configuration"></a> [scaling\_configuration](#input\_scaling\_configuration) | List of nested attributes with scaling properties. Only valid when `engine_mode` is set to `serverless` | <pre>list(object({<br/> auto_pause = bool<br/> max_capacity = number<br/> min_capacity = number<br/> seconds_until_auto_pause = number<br/> timeout_action = string<br/> }))</pre> | `[]` | no |
| <a name="input_security_groups"></a> [security\_groups](#input\_security\_groups) | List of security groups to be allowed to connect to the DB instance | `list(string)` | `[]` | no |
| <a name="input_serverlessv2_scaling_configuration"></a> [serverlessv2\_scaling\_configuration](#input\_serverlessv2\_scaling\_configuration) | serverlessv2 scaling properties | <pre>object({<br/> min_capacity = number<br/> max_capacity = number<br/> seconds_until_auto_pause = optional(number, null)<br/> })</pre> | `null` | no |
| <a name="input_skip_final_snapshot"></a> [skip\_final\_snapshot](#input\_skip\_final\_snapshot) | Determines whether a final DB snapshot is created before the DB cluster is deleted | `bool` | `true` | no |
| <a name="input_snapshot_identifier"></a> [snapshot\_identifier](#input\_snapshot\_identifier) | Specifies whether or not to create this cluster from a snapshot | `string` | `null` | no |
| <a name="input_source_region"></a> [source\_region](#input\_source\_region) | Source Region of primary cluster, needed when using encrypted storage and region replicas | `string` | `""` | no |
| <a name="input_stage"></a> [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no |
| <a name="input_storage_encrypted"></a> [storage\_encrypted](#input\_storage\_encrypted) | Specifies whether the DB cluster is encrypted. The default is `false` for `provisioned` `engine_mode` and `true` for `serverless` `engine_mode` | `bool` | `false` | no |
| <a name="input_storage_type"></a> [storage\_type](#input\_storage\_type) | One of 'standard' (magnetic), 'gp2' (general purpose SSD), 'io1' (provisioned IOPS SSD), 'aurora', or 'aurora-iopt1' | `string` | `null` | no |
| <a name="input_subnet_group_name"></a> [subnet\_group\_name](#input\_subnet\_group\_name) | Database subnet group name. Will use generated label ID if not supplied. | `string` | `""` | no |
| <a name="input_subnets"></a> [subnets](#input\_subnets) | List of VPC subnet IDs | `list(string)` | n/a | yes |
| <a name="input_tags"></a> [tags](#input\_tags) | Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).<br/>Neither the tag keys nor the tag values will be modified by this module. | `map(string)` | `{}` | no |
| <a name="input_tenant"></a> [tenant](#input\_tenant) | ID element \_(Rarely used, not included by default)\_. A customer identifier, indicating who this instance of a resource is for | `string` | `null` | no |
| <a name="input_timeouts_configuration"></a> [timeouts\_configuration](#input\_timeouts\_configuration) | List of timeout values per action. Only valid actions are `create`, `update` and `delete` | <pre>list(object({<br/> create = string<br/> update = string<br/> delete = string<br/> }))</pre> | `[]` | no |
| <a name="input_use_reserved_instances"></a> [use\_reserved\_instances](#input\_use\_reserved\_instances) | WARNING: Observe your plans and applies carefully when using this feature.<br/>It has potential to be very expensive if not used correctly.<br/>Also, it is not clear what happens when the reservation expires.<br/><br/>Whether to use reserved instances. | `bool` | `false` | no |
| <a name="input_vpc_id"></a> [vpc\_id](#input\_vpc\_id) | VPC ID to create the cluster in (e.g. `vpc-a22222ee`) | `string` | n/a | yes |
| <a name="input_vpc_security_group_ids"></a> [vpc\_security\_group\_ids](#input\_vpc\_security\_group\_ids) | Additional security group IDs to apply to the cluster, in addition to the provisioned default security group with ingress traffic from existing CIDR blocks and existing security groups | `list(string)` | `[]` | no |
| <a name="input_zone_id"></a> [zone\_id](#input\_zone\_id) | Route53 DNS Zone ID as list of string (0 or 1 items). If empty, no custom DNS name will be published.<br/>If the list contains a single Zone ID, a custom DNS name will be pulished in that zone.<br/>Can also be a plain string, but that use is DEPRECATED because of Terraform issues. | `any` | `[]` | no |
## Outputs
| Name | Description |
| ---- | ----------- |
| <a name="output_activity_stream_arn"></a> [activity\_stream\_arn](#output\_activity\_stream\_arn) | Activity Stream ARN |
| <a name="output_activity_stream_name"></a> [activity\_stream\_name](#output\_activity\_stream\_name) | Activity Stream Name |
| <a name="output_admin_user_secret"></a> [admin\_user\_secret](#output\_admin\_user\_secret) | The secret manager attributes for the managed admin user password (`master_user_secret`). |
| <a name="output_arn"></a> [arn](#output\_arn) | Amazon Resource Name (ARN) of the cluster |
| <a name="output_cluster_identifier"></a> [cluster\_identifier](#output\_cluster\_identifier) | Cluster Identifier |
| <a name="output_cluster_resource_id"></a> [cluster\_resource\_id](#output\_cluster\_resource\_id) | The region-unique, immutable identifie of the cluster |
| <a name="output_cluster_security_groups"></a> [cluster\_security\_groups](#output\_cluster\_security\_groups) | Default RDS cluster security groups |
| <a name="output_database_name"></a> [database\_name](#output\_database\_name) | Database name |
| <a name="output_dbi_resource_ids"></a> [dbi\_resource\_ids](#output\_dbi\_resource\_ids) | List of the region-unique, immutable identifiers for the DB instances in the cluster |
| <a name="output_endpoint"></a> [endpoint](#output\_endpoint) | The DNS address of the RDS instance |
| <a name="output_instance_arns"></a> [instance\_arns](#output\_instance\_arns) | List of ARNs of the DB instances in the cluster |
| <a name="output_instance_endpoints"></a> [instance\_endpoints](#output\_instance\_endpoints) | List of DNS addresses for the DB instances in the cluster |
| <a name="output_master_host"></a> [master\_host](#output\_master\_host) | DB Master hostname |
| <a name="output_master_username"></a> [master\_username](#output\_master\_username) | Username for the master DB user |
| <a name="output_port"></a> [port](#output\_port) | DB port |
| <a name="output_reader_endpoint"></a> [reader\_endpoint](#output\_reader\_endpoint) | A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas |
| <a name="output_replicas_host"></a> [replicas\_host](#output\_replicas\_host) | Replicas hostname |
| <a name="output_reserved_instance"></a> [reserved\_instance](#output\_reserved\_instance) | All information about the reserved instance(s) if created. |
| <a name="output_security_group_arn"></a> [security\_group\_arn](#output\_security\_group\_arn) | Security Group ARN |
| <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | Security Group ID |
| <a name="output_security_group_name"></a> [security\_group\_name](#output\_security\_group\_name) | Security Group name |
<!-- markdownlint-restore -->
## Related Projects
Check out these related projects.
- [terraform-aws-rds](https://github.com/cloudposse/terraform-aws-rds) - Terraform module to provision AWS RDS instances
- [terraform-aws-rds-cloudwatch-sns-alarms](https://github.com/cloudposse/terraform-aws-rds-cloudwatch-sns-alarms) - Terraform module that configures important RDS alerts using CloudWatch and sends them to an SNS topic
> [!TIP]
> #### Use Terraform Reference Architectures for AWS
>
> Use Cloud Posse's ready-to-go [terraform architecture blueprints](https://cloudposse.com/reference-architecture/) for AWS to get up and running quickly.
>
> ✅ We build it together with your team.<br/>
> ✅ Your team owns everything.<br/>
> ✅ 100% Open Source and backed by fanatical support.<br/>
>
> <a href="https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=commercial_support"><img alt="Request Quote" src="https://img.shields.io/badge/request%20quote-success.svg?style=for-the-badge"/></a>
> <details><summary>📚 <strong>Learn More</strong></summary>
>
> <br/>
>
> Cloud Posse is the leading [**DevOps Accelerator**](https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=commercial_support) for funded startups and enterprises.
>
> *Your team can operate like a pro today.*
>
> Ensure that your team succeeds by using Cloud Posse's proven process and turnkey blueprints. Plus, we stick around until you succeed.
> #### Day-0: Your Foundation for Success
> - **Reference Architecture.** You'll get everything you need from the ground up built using 100% infrastructure as code.
> - **Deployment Strategy.** Adopt a proven deployment strategy with GitHub Actions, enabling automated, repeatable, and reliable software releases.
> - **Site Reliability Engineering.** Gain total visibility into your applications and services with Datadog, ensuring high availability and performance.
> - **Security Baseline.** Establish a secure environment from the start, with built-in governance, accountability, and comprehensive audit logs, safeguarding your operations.
> - **GitOps.** Empower your team to manage infrastructure changes confidently and efficiently through Pull Requests, leveraging the full power of GitHub Actions.
>
> <a href="https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=commercial_support"><img alt="Request Quote" src="https://img.shields.io/badge/request%20quote-success.svg?style=for-the-badge"/></a>
>
> #### Day-2: Your Operational Mastery
> - **Training.** Equip your team with the knowledge and skills to confidently manage the infrastructure, ensuring long-term success and self-sufficiency.
> - **Support.** Benefit from a seamless communication over Slack with our experts, ensuring you have the support you need, whenever you need it.
> - **Troubleshooting.** Access expert assistance to quickly resolve any operational challenges, minimizing downtime and maintaining business continuity.
> - **Code Reviews.** Enhance your team’s code quality with our expert feedback, fostering continuous improvement and collaboration.
> - **Bug Fixes.** Rely on our team to troubleshoot and resolve any issues, ensuring your systems run smoothly.
> - **Migration Assistance.** Accelerate your migration process with our dedicated support, minimizing disruption and speeding up time-to-value.
> - **Customer Workshops.** Engage with our team in weekly workshops, gaining insights and strategies to continuously improve and innovate.
>
> <a href="https://cpco.io/commercial-support?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=commercial_support"><img alt="Request Quote" src="https://img.shields.io/badge/request%20quote-success.svg?style=for-the-badge"/></a>
>
</details>
## ✨ Contributing
This project is under active development, and we encourage contributions from our community.
Many thanks to our outstanding contributors:
<a href="https://github.com/cloudposse/terraform-aws-rds-cluster/graphs/contributors">
<img src="https://contrib.rocks/image?repo=cloudposse/terraform-aws-rds-cluster&max=24" />
</a>
For 🐛 bug reports & feature requests, please use the [issue tracker](https://github.com/cloudposse/terraform-aws-rds-cluster/issues).
In general, PRs are welcome. We follow the typical "fork-and-pull" Git workflow.
1. Review our [Code of Conduct](https://github.com/cloudposse/terraform-aws-rds-cluster/?tab=coc-ov-file#code-of-conduct) and [Contributor Guidelines](https://github.com/cloudposse/.github/blob/main/CONTRIBUTING.md).
2. **Fork** the repo on GitHub
3. **Clone** the project to your own machine
4. **Commit** changes to your own branch
5. **Push** your work back up to your fork
6. Submit a **Pull Request** so that we can review your changes
**NOTE:** Be sure to merge the latest changes from "upstream" before making a pull request!
## Running Terraform Tests
We use [Atmos](https://atmos.tools) to streamline how Terraform tests are run. It centralizes configuration and wraps common test workflows with easy-to-use commands.
All tests are located in the [`test/`](test) folder.
Under the hood, tests are powered by Terratest together with our internal [Test Helpers](https://github.com/cloudposse/test-helpers) library, providing robust infrastructure validation.
Setup dependencies:
- Install Atmos ([installation guide](https://atmos.tools/install/))
- Install Go [1.24+ or newer](https://go.dev/doc/install)
- Install Terraform or OpenTofu
To run tests:
- Run all tests:
```sh
atmos test run
```
- Clean up test artifacts:
```sh
atmos test clean
```
- Explore additional test options:
```sh
atmos test --help
```
The configuration for test commands is centrally managed. To review what's being imported, see the [`atmos.yaml`](https://raw.githubusercontent.com/cloudposse/.github/refs/heads/main/.github/atmos/terraform-module.yaml) file.
Learn more about our [automated testing in our documentation](https://docs.cloudposse.com/community/contribute/automated-testing/) or implementing [custom commands](https://atmos.tools/core-concepts/custom-commands/) with atmos.
### 🌎 Slack Community
Join our [Open Source Community](https://cpco.io/slack?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=slack) on Slack. It's **FREE** for everyone! Our "SweetOps" community is where you get to talk with others who share a similar vision for how to rollout and manage infrastructure. This is the best place to talk shop, ask questions, solicit feedback, and work together as a community to build totally *sweet* infrastructure.
### 📰 Newsletter
Sign up for [our newsletter](https://cpco.io/newsletter?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=newsletter) and join 3,000+ DevOps engineers, CTOs, and founders who get insider access to the latest DevOps trends, so you can always stay in the know.
Dropped straight into your Inbox every week — and usually a 5-minute read.
### 📆 Office Hours <a href="https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=office_hours"><img src="https://img.cloudposse.com/fit-in/200x200/https://cloudposse.com/wp-content/uploads/2019/08/Powered-by-Zoom.png" align="right" /></a>
[Join us every Wednesday via Zoom](https://cloudposse.com/office-hours?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=office_hours) for your weekly dose of insider DevOps trends, AWS news and Terraform insights, all sourced from our SweetOps community, plus a _live Q&A_ that you can’t find anywhere else.
It's **FREE** for everyone!
## License
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/License-Apache%202.0-blue.svg?style=for-the-badge" alt="License"></a>
<details>
<summary>Preamble to the Apache License, Version 2.0</summary>
<br/>
<br/>
Complete license is available in the [`LICENSE`](LICENSE) file.
```text
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
```
</details>
## Trademarks
All other trademarks referenced herein are the property of their respective owners.
---
Copyright © 2017-2026 [Cloud Posse, LLC](https://cpco.io/copyright)
<a href="https://cloudposse.com/readme/footer/link?utm_source=github&utm_medium=readme&utm_campaign=cloudposse/terraform-aws-rds-cluster&utm_content=readme_footer_link"><img alt="README footer" src="https://cloudposse.com/readme/footer/img"/></a>
<img alt="Beacon" width="0" src="https://ga-beacon.cloudposse.com/UA-76589703-4/cloudposse/terraform-aws-rds-cluster?pixel&cs=github&cm=readme&an=terraform-aws-rds-cluster"/>
================================================
FILE: README.yaml
================================================
name: terraform-aws-rds-cluster
tags:
- aws
- terraform
- terraform-modules
- databases
- rds
- rds-database
- aurora
- mysql
- cluster
categories:
- terraform-modules/databases
license: APACHE2
github_repo: cloudposse/terraform-aws-rds-cluster
badges:
- name: Latest Release
image: https://img.shields.io/github/release/cloudposse/terraform-aws-rds-cluster.svg?style=for-the-badge
url: https://github.com/cloudposse/terraform-aws-rds-cluster/releases/latest
- name: Last Updated
image: https://img.shields.io/github/last-commit/cloudposse/terraform-aws-rds-cluster.svg?style=for-the-badge
url: https://github.com/cloudposse/terraform-aws-rds-cluster/commits
- name: Slack Community
image: https://slack.cloudposse.com/for-the-badge.svg
url: https://cloudposse.com/slack
# List any related terraform modules that this module may be used with or that this module depends on.
related:
- name: terraform-aws-rds
description: Terraform module to provision AWS RDS instances
url: https://github.com/cloudposse/terraform-aws-rds
- name: terraform-aws-rds-cloudwatch-sns-alarms
description: Terraform module that configures important RDS alerts using CloudWatch and sends them to an SNS topic
url: https://github.com/cloudposse/terraform-aws-rds-cloudwatch-sns-alarms
description: |-
Terraform module to provision an [`RDS Aurora`](https://aws.amazon.com/rds/aurora) cluster for MySQL or Postgres.
Supports [Amazon Aurora Serverless](https://aws.amazon.com/rds/aurora/serverless/).
usage: |2-
For a complete example, see [examples/complete](examples/complete).
For automated tests of the complete example using [bats](https://github.com/bats-core/bats-core) and [Terratest](https://github.com/gruntwork-io/terratest) (which tests and deploys the example on AWS), see [test](test).
[Basic example](examples/basic)
```hcl
module "rds_cluster_aurora_postgres" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
name = "postgres"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
# 1 writer, 1 reader
cluster_size = 2
# 1 writer, 3 reader
# cluster_size = 4
# 1 writer, 5 reader
# cluster_size = 6
namespace = "eg"
stage = "dev"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
}
```
[Serverless Aurora MySQL 5.6](examples/serverless_mysql)
```hcl
module "rds_cluster_aurora_mysql_serverless" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora"
engine_mode = "serverless"
cluster_family = "aurora5.6"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 256
min_capacity = 2
seconds_until_auto_pause = 300
}
]
}
```
[Serverless Aurora 2.07.1 MySQL 5.7](examples/serverless_mysql57)
```hcl
module "rds_cluster_aurora_mysql_serverless" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora-mysql"
engine_mode = "serverless"
engine_version = "5.7.mysql_aurora.2.07.1"
cluster_family = "aurora-mysql5.7"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 16
min_capacity = 1
seconds_until_auto_pause = 300
timeout_action = "ForceApplyCapacityChange"
}
]
}
```
[With cluster parameters](examples/with_cluster_parameters)
```hcl
module "rds_cluster_aurora_mysql" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
engine = "aurora"
cluster_family = "aurora-mysql5.7"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
cluster_parameters = [
{
name = "character_set_client"
value = "utf8"
},
{
name = "character_set_connection"
value = "utf8"
},
{
name = "character_set_database"
value = "utf8"
},
{
name = "character_set_results"
value = "utf8"
},
{
name = "character_set_server"
value = "utf8"
},
{
name = "collation_connection"
value = "utf8_bin"
},
{
name = "collation_server"
value = "utf8_bin"
},
{
name = "lower_case_table_names"
value = "1"
apply_method = "pending-reboot"
},
{
name = "skip-character-set-client-handshake"
value = "1"
apply_method = "pending-reboot"
}
]
}
```
[With enhanced monitoring](examples/enhanced_monitoring)
```hcl
# create IAM role for monitoring
resource "aws_iam_role" "enhanced_monitoring" {
name = "rds-cluster-example-1"
assume_role_policy = data.aws_iam_policy_document.enhanced_monitoring.json
}
# Attach Amazon's managed policy for RDS enhanced monitoring
resource "aws_iam_role_policy_attachment" "enhanced_monitoring" {
role = aws_iam_role.enhanced_monitoring.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
# allow rds to assume this role
data "aws_iam_policy_document" "enhanced_monitoring" {
statement {
actions = [
"sts:AssumeRole",
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["monitoring.rds.amazonaws.com"]
}
}
}
module "rds_cluster_aurora_postgres" {
source = "cloudposse/rds-cluster/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
# enable monitoring every 30 seconds
rds_monitoring_interval = 30
# reference iam role created above
rds_monitoring_role_arn = aws_iam_role.enhanced_monitoring.arn
}
```
examples: |-
Review the [complete example](examples/complete) to see how to use this module.
include: []
contributors: []
================================================
FILE: atmos.yaml
================================================
# Atmos Configuration — powered by https://atmos.tools
#
# This configuration enables centralized, DRY, and consistent project scaffolding using Atmos.
#
# Included features:
# - Organizational custom commands: https://atmos.tools/core-concepts/custom-commands
# - Automated README generation: https://atmos.tools/cli/commands/docs/generate
#
# Import shared configuration used by all modules
import:
- https://raw.githubusercontent.com/cloudposse/.github/refs/heads/main/.github/atmos/terraform-module.yaml
================================================
FILE: context.tf
================================================
#
# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label
# All other instances of this file should be a copy of that one
#
#
# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf
# and then place it in your Terraform module to automatically get
# Cloud Posse's standard configuration inputs suitable for passing
# to Cloud Posse modules.
#
# curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf
#
# Modules should access the whole context as `module.this.context`
# to get the input variables with nulls for defaults,
# for example `context = module.this.context`,
# and access individual variables as `module.this.<var>`,
# with final values filled in.
#
# For example, when using defaults, `module.this.context.delimiter`
# will be null, and `module.this.delimiter` will be `-` (hyphen).
#
module "this" {
source = "cloudposse/label/null"
version = "0.25.0" # requires Terraform >= 0.13.0
enabled = var.enabled
namespace = var.namespace
tenant = var.tenant
environment = var.environment
stage = var.stage
name = var.name
delimiter = var.delimiter
attributes = var.attributes
tags = var.tags
additional_tag_map = var.additional_tag_map
label_order = var.label_order
regex_replace_chars = var.regex_replace_chars
id_length_limit = var.id_length_limit
label_key_case = var.label_key_case
label_value_case = var.label_value_case
descriptor_formats = var.descriptor_formats
labels_as_tags = var.labels_as_tags
context = var.context
}
# Copy contents of cloudposse/terraform-null-label/variables.tf here
variable "context" {
type = any
default = {
enabled = true
namespace = null
tenant = null
environment = null
stage = null
name = null
delimiter = null
attributes = []
tags = {}
additional_tag_map = {}
regex_replace_chars = null
label_order = []
id_length_limit = null
label_key_case = null
label_value_case = null
descriptor_formats = {}
# Note: we have to use [] instead of null for unset lists due to
# https://github.com/hashicorp/terraform/issues/28137
# which was not fixed until Terraform 1.0.0,
# but we want the default to be all the labels in `label_order`
# and we want users to be able to prevent all tag generation
# by setting `labels_as_tags` to `[]`, so we need
# a different sentinel to indicate "default"
labels_as_tags = ["unset"]
}
description = <<-EOT
Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.
EOT
validation {
condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"])
error_message = "Allowed values: `lower`, `title`, `upper`."
}
validation {
condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"])
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "enabled" {
type = bool
default = null
description = "Set to false to prevent the module from creating any resources"
}
variable "namespace" {
type = string
default = null
description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique"
}
variable "tenant" {
type = string
default = null
description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for"
}
variable "environment" {
type = string
default = null
description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'"
}
variable "stage" {
type = string
default = null
description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'"
}
variable "name" {
type = string
default = null
description = <<-EOT
ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input.
EOT
}
variable "delimiter" {
type = string
default = null
description = <<-EOT
Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all.
EOT
}
variable "attributes" {
type = list(string)
default = []
description = <<-EOT
ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element.
EOT
}
variable "labels_as_tags" {
type = set(string)
default = ["default"]
description = <<-EOT
Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored.
EOT
}
variable "tags" {
type = map(string)
default = {}
description = <<-EOT
Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module.
EOT
}
variable "additional_tag_map" {
type = map(string)
default = {}
description = <<-EOT
Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration.
EOT
}
variable "label_order" {
type = list(string)
default = null
description = <<-EOT
The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present.
EOT
}
variable "regex_replace_chars" {
type = string
default = null
description = <<-EOT
Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits.
EOT
}
variable "id_length_limit" {
type = number
default = null
description = <<-EOT
Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`.
EOT
validation {
condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0
error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length."
}
}
variable "label_key_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`.
EOT
validation {
condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case)
error_message = "Allowed values: `lower`, `title`, `upper`."
}
}
variable "label_value_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`.
EOT
validation {
condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case)
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "descriptor_formats" {
type = any
default = {}
description = <<-EOT
Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty).
EOT
}
#### End of copy of cloudposse/terraform-null-label/variables.tf
================================================
FILE: enhanced-monitoring.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance#monitoring_role_arn
module "enhanced_monitoring_label" {
source = "cloudposse/label/null"
version = "0.25.0"
enabled = module.this.enabled && var.enhanced_monitoring_role_enabled
attributes = var.enhanced_monitoring_attributes
context = module.this.context
}
# Create IAM role for enhanced monitoring
resource "aws_iam_role" "enhanced_monitoring" {
count = module.this.enabled && var.enhanced_monitoring_role_enabled ? 1 : 0
name = module.enhanced_monitoring_label.id
assume_role_policy = join("", data.aws_iam_policy_document.enhanced_monitoring[*].json)
tags = module.enhanced_monitoring_label.tags
}
# Attach Amazon's managed policy for RDS enhanced monitoring
resource "aws_iam_role_policy_attachment" "enhanced_monitoring" {
count = module.this.enabled && var.enhanced_monitoring_role_enabled ? 1 : 0
role = join("", aws_iam_role.enhanced_monitoring[*].name)
policy_arn = "arn:${local.partition}:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
# Allow RDS monitoring to assume the enhanced monitoring role
data "aws_iam_policy_document" "enhanced_monitoring" {
count = module.this.enabled && var.enhanced_monitoring_role_enabled ? 1 : 0
statement {
actions = [
"sts:AssumeRole"
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["monitoring.rds.amazonaws.com"]
}
}
}
================================================
FILE: examples/basic/main.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html
provider "aws" {
region = "us-west-1"
}
module "rds_cluster_aurora_postgres" {
source = "../../"
name = "postgres"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
cluster_size = 2
namespace = "eg"
stage = "dev"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
}
================================================
FILE: examples/basic/outputs.tf
================================================
output "name" {
value = module.rds_cluster_aurora_postgres.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_postgres.master_username
description = "Username for the master DB user"
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_postgres.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_postgres.arn
description = "Amazon Resource Name (ARN) of cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_postgres.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_postgres.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_postgres.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_postgres.replicas_host
description = "Replicas hostname"
}
================================================
FILE: examples/complete/context.tf
================================================
#
# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label
# All other instances of this file should be a copy of that one
#
#
# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf
# and then place it in your Terraform module to automatically get
# Cloud Posse's standard configuration inputs suitable for passing
# to Cloud Posse modules.
#
# curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf
#
# Modules should access the whole context as `module.this.context`
# to get the input variables with nulls for defaults,
# for example `context = module.this.context`,
# and access individual variables as `module.this.<var>`,
# with final values filled in.
#
# For example, when using defaults, `module.this.context.delimiter`
# will be null, and `module.this.delimiter` will be `-` (hyphen).
#
module "this" {
source = "cloudposse/label/null"
version = "0.25.0" # requires Terraform >= 0.13.0
enabled = var.enabled
namespace = var.namespace
tenant = var.tenant
environment = var.environment
stage = var.stage
name = var.name
delimiter = var.delimiter
attributes = var.attributes
tags = var.tags
additional_tag_map = var.additional_tag_map
label_order = var.label_order
regex_replace_chars = var.regex_replace_chars
id_length_limit = var.id_length_limit
label_key_case = var.label_key_case
label_value_case = var.label_value_case
descriptor_formats = var.descriptor_formats
labels_as_tags = var.labels_as_tags
context = var.context
}
# Copy contents of cloudposse/terraform-null-label/variables.tf here
variable "context" {
type = any
default = {
enabled = true
namespace = null
tenant = null
environment = null
stage = null
name = null
delimiter = null
attributes = []
tags = {}
additional_tag_map = {}
regex_replace_chars = null
label_order = []
id_length_limit = null
label_key_case = null
label_value_case = null
descriptor_formats = {}
# Note: we have to use [] instead of null for unset lists due to
# https://github.com/hashicorp/terraform/issues/28137
# which was not fixed until Terraform 1.0.0,
# but we want the default to be all the labels in `label_order`
# and we want users to be able to prevent all tag generation
# by setting `labels_as_tags` to `[]`, so we need
# a different sentinel to indicate "default"
labels_as_tags = ["unset"]
}
description = <<-EOT
Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.
EOT
validation {
condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"])
error_message = "Allowed values: `lower`, `title`, `upper`."
}
validation {
condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"])
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "enabled" {
type = bool
default = null
description = "Set to false to prevent the module from creating any resources"
}
variable "namespace" {
type = string
default = null
description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique"
}
variable "tenant" {
type = string
default = null
description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for"
}
variable "environment" {
type = string
default = null
description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'"
}
variable "stage" {
type = string
default = null
description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'"
}
variable "name" {
type = string
default = null
description = <<-EOT
ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input.
EOT
}
variable "delimiter" {
type = string
default = null
description = <<-EOT
Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all.
EOT
}
variable "attributes" {
type = list(string)
default = []
description = <<-EOT
ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element.
EOT
}
variable "labels_as_tags" {
type = set(string)
default = ["default"]
description = <<-EOT
Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored.
EOT
}
variable "tags" {
type = map(string)
default = {}
description = <<-EOT
Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module.
EOT
}
variable "additional_tag_map" {
type = map(string)
default = {}
description = <<-EOT
Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration.
EOT
}
variable "label_order" {
type = list(string)
default = null
description = <<-EOT
The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present.
EOT
}
variable "regex_replace_chars" {
type = string
default = null
description = <<-EOT
Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits.
EOT
}
variable "id_length_limit" {
type = number
default = null
description = <<-EOT
Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`.
EOT
validation {
condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0
error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length."
}
}
variable "label_key_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`.
EOT
validation {
condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case)
error_message = "Allowed values: `lower`, `title`, `upper`."
}
}
variable "label_value_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`.
EOT
validation {
condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case)
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "descriptor_formats" {
type = any
default = {}
description = <<-EOT
Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty).
EOT
}
#### End of copy of cloudposse/terraform-null-label/variables.tf
================================================
FILE: examples/complete/fixtures.us-east-2.tfvars
================================================
region = "us-east-2"
availability_zones = ["us-east-2a", "us-east-2b"]
namespace = "eg"
stage = "test"
name = "rds-cluster"
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Concepts.DBInstanceClass.html#Concepts.DBInstanceClass.SupportAurora
instance_type = "db.t3.medium"
cluster_family = "aurora-mysql8.0"
engine = "aurora-mysql"
engine_mode = "provisioned"
cluster_size = 1
deletion_protection = false
autoscaling_enabled = false
db_name = "test_db"
admin_user = "admin"
admin_password = "admin_password"
enhanced_monitoring_role_enabled = true
rds_monitoring_interval = 30
intra_security_group_traffic_enabled = true
================================================
FILE: examples/complete/main.tf
================================================
provider "aws" {
region = var.region
}
module "vpc" {
source = "cloudposse/vpc/aws"
version = "2.2.0"
ipv4_primary_cidr_block = "172.16.0.0/16"
context = module.this.context
}
module "subnets" {
source = "cloudposse/dynamic-subnets/aws"
version = "2.4.2"
availability_zones = var.availability_zones
vpc_id = module.vpc.vpc_id
igw_id = [module.vpc.igw_id]
ipv4_cidr_block = [module.vpc.vpc_cidr_block]
nat_gateway_enabled = false
nat_instance_enabled = false
context = module.this.context
}
module "rds_cluster" {
source = "../../"
engine = var.engine
engine_mode = var.engine_mode
cluster_family = var.cluster_family
cluster_size = var.cluster_size
admin_user = var.admin_user
admin_password = var.admin_password
db_name = var.db_name
instance_type = var.instance_type
vpc_id = module.vpc.vpc_id
subnets = module.subnets.private_subnet_ids
security_groups = [module.vpc.vpc_default_security_group_id]
deletion_protection = var.deletion_protection
autoscaling_enabled = var.autoscaling_enabled
storage_type = var.storage_type
iops = var.iops
allocated_storage = var.allocated_storage
intra_security_group_traffic_enabled = var.intra_security_group_traffic_enabled
cluster_parameters = [
{
name = "character_set_client"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_connection"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_database"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_results"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_server"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "collation_connection"
value = "utf8_bin"
apply_method = "pending-reboot"
},
{
name = "collation_server"
value = "utf8_bin"
apply_method = "pending-reboot"
},
{
name = "lower_case_table_names"
value = "1"
apply_method = "pending-reboot"
},
{
name = "skip-character-set-client-handshake"
value = "1"
apply_method = "pending-reboot"
}
]
context = module.this.context
}
================================================
FILE: examples/complete/outputs.tf
================================================
output "database_name" {
value = module.rds_cluster.database_name
description = "Database name"
}
output "cluster_identifier" {
value = module.rds_cluster.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster.arn
description = "Amazon Resource Name (ARN) of the cluster"
}
output "endpoint" {
value = module.rds_cluster.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster.replicas_host
description = "Replicas hostname"
}
output "dbi_resource_ids" {
value = module.rds_cluster.dbi_resource_ids
description = "List of the region-unique, immutable identifiers for the DB instances in the cluster"
}
output "cluster_resource_id" {
value = module.rds_cluster.cluster_resource_id
description = "The region-unique, immutable identifie of the cluster"
}
output "public_subnet_cidrs" {
value = module.subnets.public_subnet_cidrs
description = "Public subnet CIDR blocks"
}
output "private_subnet_cidrs" {
value = module.subnets.private_subnet_cidrs
description = "Private subnet CIDR blocks"
}
output "vpc_cidr" {
value = module.vpc.vpc_cidr_block
description = "VPC CIDR"
}
output "security_group_id" {
value = module.rds_cluster.security_group_id
description = "Security Group ID"
}
output "security_group_arn" {
value = module.rds_cluster.security_group_arn
description = "Security Group ARN"
}
output "security_group_name" {
value = module.rds_cluster.security_group_name
description = "Security Group name"
}
================================================
FILE: examples/complete/variables.tf
================================================
variable "region" {
type = string
description = "AWS region"
}
variable "availability_zones" {
type = list(string)
description = "Availability zones"
}
variable "instance_type" {
type = string
description = "Instance type to use"
}
variable "cluster_size" {
type = number
description = "Number of DB instances to create in the cluster"
}
variable "db_name" {
type = string
description = "Database name"
}
variable "admin_user" {
type = string
description = "(Required unless a snapshot_identifier is provided) Username for the master DB user"
}
variable "admin_password" {
type = string
description = "(Required unless a snapshot_identifier is provided) Password for the master DB user"
}
variable "cluster_family" {
type = string
description = "The family of the DB cluster parameter group"
}
variable "engine" {
type = string
description = "The name of the database engine to be used for this DB cluster. Valid values: `aurora`, `aurora-mysql`, `aurora-postgresql`"
}
variable "engine_mode" {
type = string
description = "The database engine mode. Valid values: `parallelquery`, `provisioned`, `serverless`"
}
variable "deletion_protection" {
type = bool
description = "If the DB instance should have deletion protection enabled"
}
variable "autoscaling_enabled" {
type = bool
description = "Whether to enable cluster autoscaling"
}
variable "enhanced_monitoring_role_enabled" {
type = bool
description = "A boolean flag to enable/disable the creation of the enhanced monitoring IAM role. If set to `false`, the module will not create a new role and will use `rds_monitoring_role_arn` for enhanced monitoring"
}
variable "rds_monitoring_interval" {
type = number
description = "The interval, in seconds, between points when enhanced monitoring metrics are collected for the DB instance. To disable collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid Values: 0, 1, 5, 10, 15, 30, 60"
}
variable "storage_type" {
type = string
description = "One of 'standard' (magnetic), 'gp2' (general purpose SSD), or 'io1' (provisioned IOPS SSD)"
default = null
}
variable "iops" {
type = number
description = "The amount of provisioned IOPS. Setting this implies a storage_type of 'io1'. This setting is required to create a Multi-AZ DB cluster. Check TF docs for values based on db engine"
default = null
}
variable "allocated_storage" {
type = number
description = "The allocated storage in GBs"
default = null
}
variable "intra_security_group_traffic_enabled" {
type = bool
default = false
description = "Whether to allow traffic between resources inside the database's security group."
}
================================================
FILE: examples/complete/versions.tf
================================================
terraform {
required_version = ">= 1.1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.17.0"
}
null = {
source = "hashicorp/null"
version = ">= 2.0"
}
}
}
================================================
FILE: examples/enhanced_monitoring/main.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html
provider "aws" {
region = "us-west-1"
}
# create IAM role for monitoring
resource "aws_iam_role" "enhanced_monitoring" {
name = "rds-cluster-example-1"
assume_role_policy = data.aws_iam_policy_document.enhanced_monitoring.json
}
# Attach Amazon's managed policy for RDS enhanced monitoring
resource "aws_iam_role_policy_attachment" "enhanced_monitoring" {
role = aws_iam_role.enhanced_monitoring.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
# allow rds to assume this role
data "aws_iam_policy_document" "enhanced_monitoring" {
statement {
actions = [
"sts:AssumeRole",
]
effect = "Allow"
principals {
type = "Service"
identifiers = ["monitoring.rds.amazonaws.com"]
}
}
}
module "rds_cluster_aurora_postgres" {
source = "../../"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql9.6"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 5432
instance_type = "db.r4.large"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
# enable monitoring every 30 seconds
rds_monitoring_interval = 30
# reference iam role created above
rds_monitoring_role_arn = aws_iam_role.enhanced_monitoring.arn
}
================================================
FILE: examples/enhanced_monitoring/outputs.tf
================================================
output "name" {
value = module.rds_cluster_aurora_postgres.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_postgres.master_username
description = "Username for the master DB user"
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_postgres.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_postgres.arn
description = "Amazon Resource Name (ARN) of cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_postgres.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_postgres.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_postgres.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_postgres.replicas_host
description = "Replicas hostname"
}
================================================
FILE: examples/postgres/context.tf
================================================
#
# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label
# All other instances of this file should be a copy of that one
#
#
# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf
# and then place it in your Terraform module to automatically get
# Cloud Posse's standard configuration inputs suitable for passing
# to Cloud Posse modules.
#
# curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf
#
# Modules should access the whole context as `module.this.context`
# to get the input variables with nulls for defaults,
# for example `context = module.this.context`,
# and access individual variables as `module.this.<var>`,
# with final values filled in.
#
# For example, when using defaults, `module.this.context.delimiter`
# will be null, and `module.this.delimiter` will be `-` (hyphen).
#
module "this" {
source = "cloudposse/label/null"
version = "0.25.0" # requires Terraform >= 0.13.0
enabled = var.enabled
namespace = var.namespace
tenant = var.tenant
environment = var.environment
stage = var.stage
name = var.name
delimiter = var.delimiter
attributes = var.attributes
tags = var.tags
additional_tag_map = var.additional_tag_map
label_order = var.label_order
regex_replace_chars = var.regex_replace_chars
id_length_limit = var.id_length_limit
label_key_case = var.label_key_case
label_value_case = var.label_value_case
descriptor_formats = var.descriptor_formats
labels_as_tags = var.labels_as_tags
context = var.context
}
# Copy contents of cloudposse/terraform-null-label/variables.tf here
variable "context" {
type = any
default = {
enabled = true
namespace = null
tenant = null
environment = null
stage = null
name = null
delimiter = null
attributes = []
tags = {}
additional_tag_map = {}
regex_replace_chars = null
label_order = []
id_length_limit = null
label_key_case = null
label_value_case = null
descriptor_formats = {}
# Note: we have to use [] instead of null for unset lists due to
# https://github.com/hashicorp/terraform/issues/28137
# which was not fixed until Terraform 1.0.0,
# but we want the default to be all the labels in `label_order`
# and we want users to be able to prevent all tag generation
# by setting `labels_as_tags` to `[]`, so we need
# a different sentinel to indicate "default"
labels_as_tags = ["unset"]
}
description = <<-EOT
Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.
EOT
validation {
condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"])
error_message = "Allowed values: `lower`, `title`, `upper`."
}
validation {
condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"])
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "enabled" {
type = bool
default = null
description = "Set to false to prevent the module from creating any resources"
}
variable "namespace" {
type = string
default = null
description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique"
}
variable "tenant" {
type = string
default = null
description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for"
}
variable "environment" {
type = string
default = null
description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'"
}
variable "stage" {
type = string
default = null
description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'"
}
variable "name" {
type = string
default = null
description = <<-EOT
ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input.
EOT
}
variable "delimiter" {
type = string
default = null
description = <<-EOT
Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all.
EOT
}
variable "attributes" {
type = list(string)
default = []
description = <<-EOT
ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element.
EOT
}
variable "labels_as_tags" {
type = set(string)
default = ["default"]
description = <<-EOT
Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored.
EOT
}
variable "tags" {
type = map(string)
default = {}
description = <<-EOT
Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module.
EOT
}
variable "additional_tag_map" {
type = map(string)
default = {}
description = <<-EOT
Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration.
EOT
}
variable "label_order" {
type = list(string)
default = null
description = <<-EOT
The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present.
EOT
}
variable "regex_replace_chars" {
type = string
default = null
description = <<-EOT
Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits.
EOT
}
variable "id_length_limit" {
type = number
default = null
description = <<-EOT
Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`.
EOT
validation {
condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0
error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length."
}
}
variable "label_key_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`.
EOT
validation {
condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case)
error_message = "Allowed values: `lower`, `title`, `upper`."
}
}
variable "label_value_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`.
EOT
validation {
condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case)
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "descriptor_formats" {
type = any
default = {}
description = <<-EOT
Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty).
EOT
}
#### End of copy of cloudposse/terraform-null-label/variables.tf
================================================
FILE: examples/postgres/fixtures.us-east-2.tfvars
================================================
region = "us-east-2"
availability_zones = ["us-east-2a", "us-east-2b", "us-east-2c"]
namespace = "eg"
stage = "test"
name = "rds-cluster"
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Concepts.DBInstanceClass.html#Concepts.DBInstanceClass.SupportAurora
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster_instance
instance_type = "db.t3.large"
cluster_family = "aurora-postgresql15"
engine_version = "15.13"
engine = "aurora-postgresql"
engine_mode = "provisioned"
cluster_size = 1
deletion_protection = false
autoscaling_enabled = false
db_name = "test_db"
admin_user = "admin_test"
admin_password = "admin_password"
enhanced_monitoring_role_enabled = true
rds_monitoring_interval = 30
================================================
FILE: examples/postgres/main.tf
================================================
provider "aws" {
region = var.region
}
module "vpc" {
source = "cloudposse/vpc/aws"
version = "2.2.0"
ipv4_primary_cidr_block = "172.16.0.0/16"
context = module.this.context
}
module "subnets" {
source = "cloudposse/dynamic-subnets/aws"
version = "2.4.2"
availability_zones = var.availability_zones
vpc_id = module.vpc.vpc_id
igw_id = [module.vpc.igw_id]
ipv4_cidr_block = [module.vpc.vpc_cidr_block]
nat_gateway_enabled = false
nat_instance_enabled = false
context = module.this.context
}
module "rds_cluster" {
source = "../../"
engine = var.engine
engine_mode = var.engine_mode
engine_version = var.engine_version
cluster_family = var.cluster_family
cluster_size = contains(regex("^(?:.*(aurora))?.*$", var.engine), "aurora") ? var.cluster_size : 0
admin_user = var.admin_user
admin_password = var.admin_password
db_name = var.db_name
instance_type = var.instance_type
db_cluster_instance_class = var.db_cluster_instance_class
vpc_id = module.vpc.vpc_id
subnets = module.subnets.private_subnet_ids
security_groups = [module.vpc.vpc_default_security_group_id]
deletion_protection = var.deletion_protection
autoscaling_enabled = var.autoscaling_enabled
storage_type = var.storage_type
iops = var.iops
allocated_storage = var.allocated_storage
context = module.this.context
}
================================================
FILE: examples/postgres/outputs.tf
================================================
output "database_name" {
value = module.rds_cluster.database_name
description = "Database name"
}
output "cluster_identifier" {
value = module.rds_cluster.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster.arn
description = "Amazon Resource Name (ARN) of the cluster"
}
output "endpoint" {
value = module.rds_cluster.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster.replicas_host
description = "Replicas hostname"
}
output "dbi_resource_ids" {
value = module.rds_cluster.dbi_resource_ids
description = "List of the region-unique, immutable identifiers for the DB instances in the cluster"
}
output "cluster_resource_id" {
value = module.rds_cluster.cluster_resource_id
description = "The region-unique, immutable identifie of the cluster"
}
output "public_subnet_cidrs" {
value = module.subnets.public_subnet_cidrs
description = "Public subnet CIDR blocks"
}
output "private_subnet_cidrs" {
value = module.subnets.private_subnet_cidrs
description = "Private subnet CIDR blocks"
}
output "vpc_cidr" {
value = module.vpc.vpc_cidr_block
description = "VPC CIDR"
}
output "security_group_id" {
value = module.rds_cluster.security_group_id
description = "Security Group ID"
}
output "security_group_arn" {
value = module.rds_cluster.security_group_arn
description = "Security Group ARN"
}
output "security_group_name" {
value = module.rds_cluster.security_group_name
description = "Security Group name"
}
================================================
FILE: examples/postgres/variables.tf
================================================
variable "region" {
type = string
description = "AWS region"
}
variable "availability_zones" {
type = list(string)
description = "Availability Zones for the instance"
}
variable "instance_type" {
type = string
description = "Instance type to use"
}
variable "cluster_size" {
type = number
description = "Number of DB instances to create in the cluster"
}
variable "db_name" {
type = string
description = "Database name"
}
variable "admin_user" {
type = string
description = "(Required unless a snapshot_identifier is provided) Username for the master DB user"
}
variable "admin_password" {
type = string
description = "(Required unless a snapshot_identifier is provided) Password for the master DB user"
}
variable "cluster_family" {
type = string
description = "The family of the DB cluster parameter group"
}
variable "engine" {
type = string
description = "The name of the database engine to be used for this DB cluster. Valid values: `aurora`, `aurora-mysql`, `aurora-postgresql`"
}
variable "engine_mode" {
type = string
description = "The database engine mode. Valid values: `parallelquery`, `provisioned`, `serverless`"
}
variable "engine_version" {
type = string
default = ""
description = "The version of the database engine to use. See `aws rds describe-db-engine-versions` "
}
variable "deletion_protection" {
type = bool
description = "If the DB instance should have deletion protection enabled"
}
variable "autoscaling_enabled" {
type = bool
description = "Whether to enable cluster autoscaling"
}
variable "enhanced_monitoring_role_enabled" {
type = bool
description = "A boolean flag to enable/disable the creation of the enhanced monitoring IAM role. If set to `false`, the module will not create a new role and will use `rds_monitoring_role_arn` for enhanced monitoring"
}
variable "rds_monitoring_interval" {
type = number
description = "The interval, in seconds, between points when enhanced monitoring metrics are collected for the DB instance. To disable collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid Values: 0, 1, 5, 10, 15, 30, 60"
}
variable "storage_type" {
type = string
description = "One of 'standard' (magnetic), 'gp2' (general purpose SSD), or 'io1' (provisioned IOPS SSD)"
default = null
}
variable "iops" {
type = number
description = "The amount of provisioned IOPS. Setting this implies a storage_type of 'io1'. This setting is required to create a Multi-AZ DB cluster. Check TF docs for values based on db engine"
default = null
}
variable "allocated_storage" {
type = number
description = "The allocated storage in GBs"
default = null
}
variable "db_cluster_instance_class" {
type = string
default = null
description = "This setting is required to create a Multi-AZ RDS cluster (not Aurora)"
}
================================================
FILE: examples/postgres/versions.tf
================================================
terraform {
required_version = ">= 1.1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.17.0"
}
null = {
source = "hashicorp/null"
version = ">= 2.0"
}
}
}
================================================
FILE: examples/serverless_mysql/main.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Updates.20180206.html
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html
provider "aws" {
region = "us-west-1"
}
module "rds_cluster_aurora_mysql_serverless" {
source = "../../"
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora"
engine_mode = "serverless"
cluster_family = "aurora5.6"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 256
min_capacity = 2
seconds_until_auto_pause = 300
}
]
}
================================================
FILE: examples/serverless_mysql/outputs.tf
================================================
output "name" {
value = module.rds_cluster_aurora_mysql_serverless.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_mysql_serverless.master_username
description = "Username for the master DB user"
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_mysql_serverless.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_mysql_serverless.arn
description = "Amazon Resource Name (ARN) of cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_mysql_serverless.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_mysql_serverless.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_mysql_serverless.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_mysql_serverless.replicas_host
description = "Replicas hostname"
}
================================================
FILE: examples/serverless_mysql57/main.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Updates.serverless_2_07_01.html
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/aurora-serverless.html
provider "aws" {
region = "us-west-1"
}
module "rds_cluster_aurora_mysql_serverless" {
source = "../.."
namespace = "eg"
stage = "dev"
name = "db"
engine = "aurora-mysql"
engine_mode = "serverless"
engine_version = "5.7.mysql_aurora.2.07.1"
cluster_family = "aurora-mysql5.7"
cluster_size = 0
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
db_port = 3306
vpc_id = "vpc-xxxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
enable_http_endpoint = true
scaling_configuration = [
{
auto_pause = true
max_capacity = 16
min_capacity = 1
seconds_until_auto_pause = 300
timeout_action = "ForceApplyCapacityChange"
}
]
}
================================================
FILE: examples/serverless_mysql57/outputs.tf
================================================
output "name" {
value = module.rds_cluster_aurora_mysql_serverless.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_mysql_serverless.master_username
description = "Username for the master DB user"
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_mysql_serverless.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_mysql_serverless.arn
description = "Amazon Resource Name (ARN) of cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_mysql_serverless.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_mysql_serverless.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_mysql_serverless.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_mysql_serverless.replicas_host
description = "Replicas hostname"
}
================================================
FILE: examples/serverlessv2_postgres/context.tf
================================================
#
# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label
# All other instances of this file should be a copy of that one
#
#
# Copy this file from https://github.com/cloudposse/terraform-null-label/blob/master/exports/context.tf
# and then place it in your Terraform module to automatically get
# Cloud Posse's standard configuration inputs suitable for passing
# to Cloud Posse modules.
#
# curl -sL https://raw.githubusercontent.com/cloudposse/terraform-null-label/master/exports/context.tf -o context.tf
#
# Modules should access the whole context as `module.this.context`
# to get the input variables with nulls for defaults,
# for example `context = module.this.context`,
# and access individual variables as `module.this.<var>`,
# with final values filled in.
#
# For example, when using defaults, `module.this.context.delimiter`
# will be null, and `module.this.delimiter` will be `-` (hyphen).
#
module "this" {
source = "cloudposse/label/null"
version = "0.25.0" # requires Terraform >= 0.13.0
enabled = var.enabled
namespace = var.namespace
tenant = var.tenant
environment = var.environment
stage = var.stage
name = var.name
delimiter = var.delimiter
attributes = var.attributes
tags = var.tags
additional_tag_map = var.additional_tag_map
label_order = var.label_order
regex_replace_chars = var.regex_replace_chars
id_length_limit = var.id_length_limit
label_key_case = var.label_key_case
label_value_case = var.label_value_case
descriptor_formats = var.descriptor_formats
labels_as_tags = var.labels_as_tags
context = var.context
}
# Copy contents of cloudposse/terraform-null-label/variables.tf here
variable "context" {
type = any
default = {
enabled = true
namespace = null
tenant = null
environment = null
stage = null
name = null
delimiter = null
attributes = []
tags = {}
additional_tag_map = {}
regex_replace_chars = null
label_order = []
id_length_limit = null
label_key_case = null
label_value_case = null
descriptor_formats = {}
# Note: we have to use [] instead of null for unset lists due to
# https://github.com/hashicorp/terraform/issues/28137
# which was not fixed until Terraform 1.0.0,
# but we want the default to be all the labels in `label_order`
# and we want users to be able to prevent all tag generation
# by setting `labels_as_tags` to `[]`, so we need
# a different sentinel to indicate "default"
labels_as_tags = ["unset"]
}
description = <<-EOT
Single object for setting entire context at once.
See description of individual variables for details.
Leave string and numeric variables as `null` to use default value.
Individual variable settings (non-null) override settings in context object,
except for attributes, tags, and additional_tag_map, which are merged.
EOT
validation {
condition = lookup(var.context, "label_key_case", null) == null ? true : contains(["lower", "title", "upper"], var.context["label_key_case"])
error_message = "Allowed values: `lower`, `title`, `upper`."
}
validation {
condition = lookup(var.context, "label_value_case", null) == null ? true : contains(["lower", "title", "upper", "none"], var.context["label_value_case"])
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "enabled" {
type = bool
default = null
description = "Set to false to prevent the module from creating any resources"
}
variable "namespace" {
type = string
default = null
description = "ID element. Usually an abbreviation of your organization name, e.g. 'eg' or 'cp', to help ensure generated IDs are globally unique"
}
variable "tenant" {
type = string
default = null
description = "ID element _(Rarely used, not included by default)_. A customer identifier, indicating who this instance of a resource is for"
}
variable "environment" {
type = string
default = null
description = "ID element. Usually used for region e.g. 'uw2', 'us-west-2', OR role 'prod', 'staging', 'dev', 'UAT'"
}
variable "stage" {
type = string
default = null
description = "ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release'"
}
variable "name" {
type = string
default = null
description = <<-EOT
ID element. Usually the component or solution name, e.g. 'app' or 'jenkins'.
This is the only ID element not also included as a `tag`.
The "name" tag is set to the full `id` string. There is no tag with the value of the `name` input.
EOT
}
variable "delimiter" {
type = string
default = null
description = <<-EOT
Delimiter to be used between ID elements.
Defaults to `-` (hyphen). Set to `""` to use no delimiter at all.
EOT
}
variable "attributes" {
type = list(string)
default = []
description = <<-EOT
ID element. Additional attributes (e.g. `workers` or `cluster`) to add to `id`,
in the order they appear in the list. New attributes are appended to the
end of the list. The elements of the list are joined by the `delimiter`
and treated as a single ID element.
EOT
}
variable "labels_as_tags" {
type = set(string)
default = ["default"]
description = <<-EOT
Set of labels (ID elements) to include as tags in the `tags` output.
Default is to include all labels.
Tags with empty values will not be included in the `tags` output.
Set to `[]` to suppress all generated tags.
**Notes:**
The value of the `name` tag, if included, will be the `id`, not the `name`.
Unlike other `null-label` inputs, the initial setting of `labels_as_tags` cannot be
changed in later chained modules. Attempts to change it will be silently ignored.
EOT
}
variable "tags" {
type = map(string)
default = {}
description = <<-EOT
Additional tags (e.g. `{'BusinessUnit': 'XYZ'}`).
Neither the tag keys nor the tag values will be modified by this module.
EOT
}
variable "additional_tag_map" {
type = map(string)
default = {}
description = <<-EOT
Additional key-value pairs to add to each map in `tags_as_list_of_maps`. Not added to `tags` or `id`.
This is for some rare cases where resources want additional configuration of tags
and therefore take a list of maps with tag key, value, and additional configuration.
EOT
}
variable "label_order" {
type = list(string)
default = null
description = <<-EOT
The order in which the labels (ID elements) appear in the `id`.
Defaults to ["namespace", "environment", "stage", "name", "attributes"].
You can omit any of the 6 labels ("tenant" is the 6th), but at least one must be present.
EOT
}
variable "regex_replace_chars" {
type = string
default = null
description = <<-EOT
Terraform regular expression (regex) string.
Characters matching the regex will be removed from the ID elements.
If not set, `"/[^a-zA-Z0-9-]/"` is used to remove all characters other than hyphens, letters and digits.
EOT
}
variable "id_length_limit" {
type = number
default = null
description = <<-EOT
Limit `id` to this many characters (minimum 6).
Set to `0` for unlimited length.
Set to `null` for keep the existing setting, which defaults to `0`.
Does not affect `id_full`.
EOT
validation {
condition = var.id_length_limit == null ? true : var.id_length_limit >= 6 || var.id_length_limit == 0
error_message = "The id_length_limit must be >= 6 if supplied (not null), or 0 for unlimited length."
}
}
variable "label_key_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of the `tags` keys (label names) for tags generated by this module.
Does not affect keys of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper`.
Default value: `title`.
EOT
validation {
condition = var.label_key_case == null ? true : contains(["lower", "title", "upper"], var.label_key_case)
error_message = "Allowed values: `lower`, `title`, `upper`."
}
}
variable "label_value_case" {
type = string
default = null
description = <<-EOT
Controls the letter case of ID elements (labels) as included in `id`,
set as tag values, and output by this module individually.
Does not affect values of tags passed in via the `tags` input.
Possible values: `lower`, `title`, `upper` and `none` (no transformation).
Set this to `title` and set `delimiter` to `""` to yield Pascal Case IDs.
Default value: `lower`.
EOT
validation {
condition = var.label_value_case == null ? true : contains(["lower", "title", "upper", "none"], var.label_value_case)
error_message = "Allowed values: `lower`, `title`, `upper`, `none`."
}
}
variable "descriptor_formats" {
type = any
default = {}
description = <<-EOT
Describe additional descriptors to be output in the `descriptors` output map.
Map of maps. Keys are names of descriptors. Values are maps of the form
`{
format = string
labels = list(string)
}`
(Type is `any` so the map values can later be enhanced to provide additional options.)
`format` is a Terraform format string to be passed to the `format()` function.
`labels` is a list of labels, in order, to pass to `format()` function.
Label values will be normalized before being passed to `format()` so they will be
identical to how they appear in `id`.
Default is `{}` (`descriptors` output will be empty).
EOT
}
#### End of copy of cloudposse/terraform-null-label/variables.tf
================================================
FILE: examples/serverlessv2_postgres/fixtures.us-east-2.tfvars
================================================
region = "us-east-2"
availability_zones = ["us-east-2a", "us-east-2b"]
namespace = "eg"
stage = "test"
name = "rds-cluster"
engine = "aurora-postgresql"
cluster_family = "aurora-postgresql15"
engine_version = "15.13"
instance_type = "db.serverless"
cluster_size = 1
deletion_protection = false
autoscaling_enabled = false
db_name = "test_db"
admin_user = "postgres"
admin_password = "admin_password"
enhanced_monitoring_role_enabled = true
rds_monitoring_interval = 30
max_capacity = 16
min_capacity = 0.5
================================================
FILE: examples/serverlessv2_postgres/main.tf
================================================
provider "aws" {
region = var.region
}
module "vpc" {
source = "cloudposse/vpc/aws"
version = "2.2.0"
ipv4_primary_cidr_block = "172.16.0.0/16"
context = module.this.context
}
module "subnets" {
source = "cloudposse/dynamic-subnets/aws"
version = "2.4.2"
availability_zones = var.availability_zones
vpc_id = module.vpc.vpc_id
igw_id = [module.vpc.igw_id]
ipv4_cidr_block = [module.vpc.vpc_cidr_block]
nat_gateway_enabled = false
nat_instance_enabled = false
context = module.this.context
}
module "rds_cluster_aurora_serverlessv2_postgres_13" {
source = "../../"
instance_type = var.instance_type
engine = var.engine
cluster_family = var.cluster_family
engine_version = var.engine_version
cluster_size = var.cluster_size
admin_user = var.admin_user
admin_password = var.admin_password
db_name = var.db_name
vpc_id = module.vpc.vpc_id
subnets = module.subnets.private_subnet_ids
security_groups = [module.vpc.vpc_default_security_group_id]
deletion_protection = var.deletion_protection
serverlessv2_scaling_configuration = {
max_capacity = var.max_capacity
min_capacity = var.min_capacity
}
context = module.this.context
}
================================================
FILE: examples/serverlessv2_postgres/outputs.tf
================================================
output "database_name" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.master_username
description = "Username for the master DB user"
sensitive = true
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.arn
description = "Amazon Resource Name (ARN) of the cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.replicas_host
description = "Replicas hostname"
}
output "dbi_resource_ids" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.dbi_resource_ids
description = "List of the region-unique, immutable identifiers for the DB instances in the cluster"
}
output "cluster_resource_id" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.cluster_resource_id
description = "The region-unique, immutable identifie of the cluster"
}
output "public_subnet_cidrs" {
value = module.subnets.public_subnet_cidrs
description = "Public subnet CIDR blocks"
}
output "private_subnet_cidrs" {
value = module.subnets.private_subnet_cidrs
description = "Private subnet CIDR blocks"
}
output "vpc_cidr" {
value = module.vpc.vpc_cidr_block
description = "VPC CIDR"
}
output "security_group_id" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.security_group_id
description = "Security Group ID"
}
output "security_group_arn" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.security_group_arn
description = "Security Group ARN"
}
output "security_group_name" {
value = module.rds_cluster_aurora_serverlessv2_postgres_13.security_group_name
description = "Security Group name"
}
================================================
FILE: examples/serverlessv2_postgres/variables.tf
================================================
variable "region" {
type = string
description = "AWS region"
}
variable "availability_zones" {
type = list(string)
description = "Availability zones"
}
variable "cluster_family" {
type = string
description = "The family of the DB cluster parameter group"
}
variable "engine" {
type = string
description = "The name of the database engine to be used for this DB cluster. Valid values: `aurora`, `aurora-mysql`, `aurora-postgresql`"
}
variable "engine_version" {
type = string
default = ""
description = "The version of the database engine to use. See `aws rds describe-db-engine-versions` "
}
variable "instance_type" {
type = string
description = "Instance type to use"
}
variable "cluster_size" {
type = number
description = "Number of DB instances to create in the cluster"
}
variable "db_name" {
type = string
description = "Database name"
}
variable "admin_user" {
type = string
description = "(Required unless a snapshot_identifier is provided) Username for the master DB user"
}
variable "admin_password" {
type = string
description = "(Required unless a snapshot_identifier is provided) Password for the master DB user"
}
variable "max_capacity" {
type = number
description = "The maximum capacity for an Aurora DB cluster in provisioned DB engine mode"
}
variable "min_capacity" {
type = number
description = "The minimum capacity for an Aurora DB cluster in provisioned DB engine mode"
}
variable "deletion_protection" {
type = bool
description = "If the DB instance should have deletion protection enabled"
}
variable "autoscaling_enabled" {
type = bool
description = "Whether to enable cluster autoscaling"
}
variable "enhanced_monitoring_role_enabled" {
type = bool
description = "A boolean flag to enable/disable the creation of the enhanced monitoring IAM role. If set to `false`, the module will not create a new role and will use `rds_monitoring_role_arn` for enhanced monitoring"
}
variable "rds_monitoring_interval" {
type = number
description = "The interval, in seconds, between points when enhanced monitoring metrics are collected for the DB instance. To disable collecting Enhanced Monitoring metrics, specify 0. The default is 0. Valid Values: 0, 1, 5, 10, 15, 30, 60"
}
================================================
FILE: examples/serverlessv2_postgres/versions.tf
================================================
terraform {
required_version = ">= 1.1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.12"
}
null = {
source = "hashicorp/null"
version = ">= 2.0"
}
}
}
================================================
FILE: examples/with_cluster_parameters/main.tf
================================================
# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html
provider "aws" {
region = "us-west-1"
}
module "rds_cluster_aurora_mysql" {
source = "../../"
engine = "aurora-mysql"
cluster_family = "aurora-mysql5.7"
cluster_size = 2
namespace = "eg"
stage = "dev"
name = "db"
admin_user = "admin1"
admin_password = "Test123456789"
db_name = "dbname"
instance_type = "db.t2.small"
vpc_id = "vpc-xxxxxxx"
security_groups = ["sg-xxxxxxxx"]
subnets = ["subnet-xxxxxxxx", "subnet-xxxxxxxx"]
zone_id = "Zxxxxxxxx"
cluster_parameters = [
{
name = "character_set_client"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_connection"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_database"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_results"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "character_set_server"
value = "utf8"
apply_method = "pending-reboot"
},
{
name = "collation_connection"
value = "utf8_bin"
apply_method = "pending-reboot"
},
{
name = "collation_server"
value = "utf8_bin"
apply_method = "pending-reboot"
},
{
name = "lower_case_table_names"
value = "1"
apply_method = "pending-reboot"
},
{
name = "skip-character-set-client-handshake"
value = "1"
apply_method = "pending-reboot"
}
]
}
================================================
FILE: examples/with_cluster_parameters/outputs.tf
================================================
output "name" {
value = module.rds_cluster_aurora_mysql.database_name
description = "Database name"
}
output "master_username" {
value = module.rds_cluster_aurora_mysql.master_username
description = "Username for the master DB user"
}
output "cluster_identifier" {
value = module.rds_cluster_aurora_mysql.cluster_identifier
description = "Cluster Identifier"
}
output "arn" {
value = module.rds_cluster_aurora_mysql.arn
description = "Amazon Resource Name (ARN) of cluster"
}
output "endpoint" {
value = module.rds_cluster_aurora_mysql.endpoint
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = module.rds_cluster_aurora_mysql.reader_endpoint
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "master_host" {
value = module.rds_cluster_aurora_mysql.master_host
description = "DB Master hostname"
}
output "replicas_host" {
value = module.rds_cluster_aurora_mysql.replicas_host
description = "Replicas hostname"
}
================================================
FILE: main.tf
================================================
locals {
enabled = module.this.enabled
partition = one(data.aws_partition.current[*].partition)
deployed_cluster_identifier = local.enabled ? coalesce(one(aws_rds_cluster.primary[*].id), one(aws_rds_cluster.secondary[*].id)) : ""
db_subnet_group_name = one(aws_db_subnet_group.default[*].name)
instance_class = var.serverlessv2_scaling_configuration != null ? "db.serverless" : var.instance_type
instance_identifier_prefix = var.cluster_identifier == "" ? module.this.id : var.cluster_identifier
instance_identifier_suffix_fragment = var.instance_identifier_suffix == null ? null : (
var.instance_identifier_suffix == "" ? "" : "${module.this.delimiter}${var.instance_identifier_suffix}"
)
instance_identifier = !local.enabled ? "" : (
var.instance_identifier_suffix == null ? random_pet.instance[0].id : "${local.instance_identifier_prefix}${local.instance_identifier_suffix_fragment}"
)
cluster_instance_count = local.enabled ? var.cluster_size : 0
is_regional_cluster = var.cluster_type == "regional"
is_serverless = var.engine_mode == "serverless"
ignore_admin_credentials = var.replication_source_identifier != "" || var.snapshot_identifier != null
reserved_instance_engine = var.engine
use_reserved_instances = var.use_reserved_instances && !local.is_serverless
}
data "aws_partition" "current" {
count = local.enabled ? 1 : 0
}
# TODO: Use cloudposse/security-group module
resource "aws_security_group" "default" {
count = local.enabled ? 1 : 0
name = module.this.id
description = "Allow inbound traffic from Security Groups and CIDRs"
vpc_id = var.vpc_id
tags = module.this.tags
}
resource "aws_security_group_rule" "ingress_security_groups" {
count = local.enabled ? length(var.security_groups) : 0
description = "Allow inbound traffic from existing security groups"
type = "ingress"
from_port = var.db_port
to_port = var.db_port
protocol = "tcp"
source_security_group_id = var.security_groups[count.index]
security_group_id = join("", aws_security_group.default[*].id)
}
resource "aws_security_group_rule" "traffic_inside_security_group" {
count = local.enabled && var.intra_security_group_traffic_enabled ? 1 : 0
description = "Allow traffic between members of the database security group"
type = "ingress"
from_port = var.db_port
to_port = var.db_port
protocol = "tcp"
self = true
security_group_id = join("", aws_security_group.default[*].id)
}
resource "aws_security_group_rule" "ingress_cidr_blocks" {
count = local.enabled && length(var.allowed_cidr_blocks) > 0 ? 1 : 0
description = "Allow inbound traffic from existing CIDR blocks"
type = "ingress"
from_port = var.db_port
to_port = var.db_port
protocol = "tcp"
cidr_blocks = var.allowed_cidr_blocks
security_group_id = join("", aws_security_group.default[*].id)
}
resource "aws_security_group_rule" "ingress_ipv6_cidr_blocks" {
count = local.enabled && length(var.allowed_ipv6_cidr_blocks) > 0 ? 1 : 0
description = "Allow inbound traffic from existing CIDR blocks"
type = "ingress"
from_port = var.db_port
to_port = var.db_port
protocol = "tcp"
ipv6_cidr_blocks = var.allowed_ipv6_cidr_blocks
security_group_id = join("", aws_security_group.default[*].id)
}
resource "aws_security_group_rule" "egress" {
count = local.enabled && var.egress_enabled ? 1 : 0
description = "Allow outbound traffic"
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = join("", aws_security_group.default[*].id)
}
resource "aws_security_group_rule" "egress_ipv6" {
count = local.enabled && var.egress_enabled ? 1 : 0
description = "Allow outbound ipv6 traffic"
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
ipv6_cidr_blocks = ["::/0"]
security_group_id = join("", aws_security_group.default[*].id)
}
data "aws_rds_reserved_instance_offering" "default" {
count = local.use_reserved_instances ? 1 : 0
db_instance_class = var.instance_type
duration = var.rds_ri_duration
multi_az = startswith(local.reserved_instance_engine, "aurora") ? false : local.cluster_instance_count > 1 # Aurora options never available for multi AZ for Reserved Instances. Single Reserved Instances rates still apply. https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/USER_WorkingWithReservedDBInstances.html
offering_type = var.rds_ri_offering_type
product_description = local.reserved_instance_engine
}
# Note: I'm not sure what will happen when the db reservation expires, and this is not easy to test.
# It will either be recreated or will require manual intervention to recreate.
resource "aws_rds_reserved_instance" "default" {
count = local.use_reserved_instances ? 1 : 0
offering_id = data.aws_rds_reserved_instance_offering.default[0].id
instance_count = local.cluster_instance_count
reservation_id = var.rds_ri_reservation_id
lifecycle {
# Once created, we want to avoid any case of accidentally re-creating.
prevent_destroy = true
}
}
# The name "primary" is poorly chosen. We actually mean standalone or regional.
# The primary cluster of a global database is actually created with the "secondary" cluster resource below.
resource "aws_rds_cluster" "primary" {
count = local.enabled && local.is_regional_cluster ? 1 : 0
cluster_identifier = var.cluster_identifier == "" ? module.this.id : var.cluster_identifier
database_name = var.db_name
# manage_master_user_password must be `null` or `true`. If it is `false`, and `master_password` is not `null`, a conflict occurs.
manage_master_user_password = var.manage_admin_user_password ? var.manage_admin_user_password : null
master_user_secret_kms_key_id = var.admin_user_secret_kms_key_id
master_username = local.ignore_admin_credentials ? null : var.admin_user
master_password = local.ignore_admin_credentials || var.manage_admin_user_password ? null : var.admin_password
backup_retention_period = var.retention_period
preferred_backup_window = var.backup_window
copy_tags_to_snapshot = var.copy_tags_to_snapshot
final_snapshot_identifier = var.cluster_identifier == "" ? lower(module.this.id) : lower(var.cluster_identifier)
skip_final_snapshot = var.skip_final_snapshot
apply_immediately = var.apply_immediately
db_cluster_instance_class = local.is_serverless ? null : var.db_cluster_instance_class
storage_encrypted = local.is_serverless ? null : var.storage_encrypted
storage_type = var.storage_type
iops = var.iops
allocated_storage = var.allocated_storage
kms_key_id = var.kms_key_arn
source_region = var.source_region
snapshot_identifier = var.snapshot_identifier
vpc_security_group_ids = compact(flatten([join("", aws_security_group.default[*].id), var.vpc_security_group_ids]))
preferred_maintenance_window = var.maintenance_window
network_type = var.network_type
db_subnet_group_name = join("", aws_db_subnet_group.default[*].name)
db_cluster_parameter_group_name = join("", aws_rds_cluster_parameter_group.default[*].name)
iam_database_authentication_enabled = var.iam_database_authentication_enabled
tags = module.this.tags
engine = var.engine
engine_version = var.engine_version
allow_major_version_upgrade = var.allow_major_version_upgrade
db_instance_parameter_group_name = var.allow_major_version_upgrade ? join("", aws_db_parameter_group.default[*].name) : null
engine_mode = var.engine_mode
iam_roles = var.iam_roles
backtrack_window = var.backtrack_window
enable_http_endpoint = var.enable_http_endpoint
port = var.db_port
enable_global_write_forwarding = var.enable_global_write_forwarding
enable_local_write_forwarding = var.enable_local_write_forwarding
performance_insights_enabled = var.performance_insights_enabled
performance_insights_kms_key_id = var.performance_insights_kms_key_id
performance_insights_retention_period = var.performance_insights_retention_period
database_insights_mode = var.database_insights_mode
depends_on = [
aws_db_subnet_group.default,
aws_rds_cluster_parameter_group.default,
aws_security_group.default,
]
dynamic "s3_import" {
for_each = var.s3_import[*]
content {
bucket_name = lookup(s3_import.value, "bucket_name", null)
bucket_prefix = lookup(s3_import.value, "bucket_prefix", null)
ingestion_role = lookup(s3_import.value, "ingestion_role", null)
source_engine = lookup(s3_import.value, "source_engine", null)
source_engine_version = lookup(s3_import.value, "source_engine_version", null)
}
}
dynamic "scaling_configuration" {
for_each = var.scaling_configuration
content {
auto_pause = lookup(scaling_configuration.value, "auto_pause", null)
max_capacity = lookup(scaling_configuration.value, "max_capacity", null)
min_capacity = lookup(scaling_configuration.value, "min_capacity", null)
seconds_until_auto_pause = lookup(scaling_configuration.value, "seconds_until_auto_pause", null)
timeout_action = lookup(scaling_configuration.value, "timeout_action", null)
}
}
dynamic "serverlessv2_scaling_configuration" {
for_each = var.serverlessv2_scaling_configuration[*]
content {
max_capacity = serverlessv2_scaling_configuration.value.max_capacity
min_capacity = serverlessv2_scaling_configuration.value.min_capacity
seconds_until_auto_pause = serverlessv2_scaling_configuration.value.seconds_until_auto_pause
}
}
dynamic "timeouts" {
for_each = var.timeouts_configuration
content {
create = lookup(timeouts.value, "create", "120m")
update = lookup(timeouts.value, "update", "120m")
delete = lookup(timeouts.value, "delete", "120m")
}
}
dynamic "restore_to_point_in_time" {
for_each = var.restore_to_point_in_time
content {
source_cluster_identifier = restore_to_point_in_time.value.source_cluster_identifier
restore_type = restore_to_point_in_time.value.restore_type
# use_latest_restorable_time and restore_to_time are mutually exclusive.
# If restore_to_time is given, then we ignore use_latest_restorable_time
use_latest_restorable_time = restore_to_point_in_time.value.restore_to_time != null ? null : restore_to_point_in_time.value.use_latest_restorable_time
restore_to_time = restore_to_point_in_time.value.restore_to_time
}
}
enabled_cloudwatch_logs_exports = var.enabled_cloudwatch_logs_exports
deletion_protection = var.deletion_protection
replication_source_identifier = var.replication_source_identifier
}
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#replication_source_identifier
resource "aws_rds_cluster" "secondary" {
count = local.enabled && !local.is_regional_cluster ? 1 : 0
cluster_identifier = var.cluster_identifier == "" ? module.this.id : var.cluster_identifier
database_name = var.db_name
# manage_master_user_password must be `null` or `true`. If it is `false`, and `master_password` is not `null`, a conflict occurs.
manage_master_user_password = var.manage_admin_user_password ? var.manage_admin_user_password : null
master_user_secret_kms_key_id = var.admin_user_secret_kms_key_id
master_username = local.ignore_admin_credentials ? null : var.admin_user
master_password = local.ignore_admin_credentials || var.manage_admin_user_password ? null : var.admin_password
backup_retention_period = var.retention_period
preferred_backup_window = var.backup_window
copy_tags_to_snapshot = var.copy_tags_to_snapshot
final_snapshot_identifier = var.cluster_identifier == "" ? lower(module.this.id) : lower(var.cluster_identifier)
skip_final_snapshot = var.skip_final_snapshot
apply_immediately = var.apply_immediately
db_cluster_instance_class = local.is_serverless ? null : var.db_cluster_instance_class
storage_encrypted = var.storage_encrypted
storage_type = var.storage_type
kms_key_id = var.kms_key_arn
source_region = var.source_region
snapshot_identifier = var.snapshot_identifier
vpc_security_group_ids = compact(flatten([join("", aws_security_group.default[*].id), var.vpc_security_group_ids]))
preferred_maintenance_window = var.maintenance_window
network_type = var.network_type
db_subnet_group_name = join("", aws_db_subnet_group.default[*].name)
db_cluster_parameter_group_name = join("", aws_rds_cluster_parameter_group.default[*].name)
iam_database_authentication_enabled = var.iam_database_authentication_enabled
tags = module.this.tags
engine = var.engine
engine_version = var.engine_version
allow_major_version_upgrade = var.allow_major_version_upgrade
engine_mode = var.engine_mode
iam_roles = var.iam_roles
backtrack_window = var.backtrack_window
enable_http_endpoint = var.enable_http_endpoint
port = var.db_port
enable_global_write_forwarding = var.enable_global_write_forwarding
enable_local_write_forwarding = var.enable_local_write_forwarding
database_insights_mode = var.database_insights_mode
depends_on = [
aws_db_subnet_group.default,
aws_db_parameter_group.default,
aws_rds_cluster_parameter_group.default,
aws_security_group.default,
]
dynamic "scaling_configuration" {
for_each = var.scaling_configuration
content {
auto_pause = lookup(scaling_configuration.value, "auto_pause", null)
max_capacity = lookup(scaling_configuration.value, "max_capacity", null)
min_capacity = lookup(scaling_configuration.value, "min_capacity", null)
seconds_until_auto_pause = lookup(scaling_configuration.value, "seconds_until_auto_pause", null)
timeout_action = lookup(scaling_configuration.value, "timeout_action", null)
}
}
dynamic "serverlessv2_scaling_configuration" {
for_each = var.serverlessv2_scaling_configuration[*]
content {
max_capacity = serverlessv2_scaling_configuration.value.max_capacity
min_capacity = serverlessv2_scaling_configuration.value.min_capacity
}
}
dynamic "timeouts" {
for_each = var.timeouts_configuration
content {
create = lookup(timeouts.value, "create", "120m")
update = lookup(timeouts.value, "update", "120m")
delete = lookup(timeouts.value, "delete", "120m")
}
}
enabled_cloudwatch_logs_exports = var.enabled_cloudwatch_logs_exports
deletion_protection = var.deletion_protection
global_cluster_identifier = var.global_cluster_identifier
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster#replication_source_identifier
# ARN of a source DB cluster or DB instance if this DB cluster is to be created as a Read Replica.
# If DB Cluster is part of a Global Cluster, use the lifecycle configuration block ignore_changes argument
# to prevent Terraform from showing differences for this argument instead of configuring this value.
lifecycle {
ignore_changes = [
replication_source_identifier, # will be set/managed by Global Cluster
snapshot_identifier, # if created from a snapshot, will be non-null at creation, but null afterwards
]
}
}
resource "random_pet" "instance" {
count = local.enabled && var.instance_identifier_suffix == null ? 1 : 0
prefix = local.instance_identifier_prefix
keepers = {
cluster_family = var.cluster_family
instance_class = var.serverlessv2_scaling_configuration != null ? "db.serverless" : var.instance_type
}
}
module "rds_identifier" {
count = local.enabled ? 1 : 0
source = "cloudposse/label/null"
version = "0.25.0"
name = local.instance_identifier
# Max length of RDS identifier is 63 characters, but in `aws_rds_cluster_instance`
# we append the instance index to the identifier
# Setting the limit to 60 allow to use up to 99 instances, when only 16 is allowed
# (1 writer + 15 readers)
# https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/Aurora.Replication.html
id_length_limit = 60
}
resource "aws_rds_cluster_instance" "default" {
count = local.cluster_instance_count
identifier = "${module.rds_identifier[0].id}-${count.index + 1}"
cluster_identifier = local.deployed_cluster_identifier
instance_class = local.instance_class
db_subnet_group_name = local.db_subnet_group_name
db_parameter_group_name = join("", aws_db_parameter_group.default[*].name)
publicly_accessible = var.publicly_accessible
tags = module.this.tags
engine = var.engine
engine_version = var.engine_version
auto_minor_version_upgrade = var.auto_minor_version_upgrade
monitoring_interval = var.rds_monitoring_interval
monitoring_role_arn = var.enhanced_monitoring_role_enabled ? join("", aws_iam_role.enhanced_monitoring[*].arn) : var.rds_monitoring_role_arn
performance_insights_enabled = var.performance_insights_enabled
performance_insights_kms_key_id = var.performance_insights_kms_key_id
performance_insights_retention_period = var.performance_insights_retention_period
availability_zone = var.instance_availability_zone
apply_immediately = var.apply_immediately
preferred_maintenance_window = var.maintenance_window
copy_tags_to_snapshot = var.copy_tags_to_snapshot
ca_cert_identifier = var.ca_cert_identifier
promotion_tier = var.promotion_tier
dynamic "timeouts" {
for_each = var.timeouts_configuration
content {
create = lookup(timeouts.value, "create", "120m")
update = lookup(timeouts.value, "update", "120m")
delete = lookup(timeouts.value, "delete", "120m")
}
}
depends_on = [
aws_db_subnet_group.default,
aws_db_parameter_group.default,
aws_iam_role.enhanced_monitoring,
aws_rds_cluster.secondary,
aws_rds_cluster_parameter_group.default,
]
lifecycle {
ignore_changes = [engine_version]
create_before_destroy = true
}
}
resource "aws_db_subnet_group" "default" {
count = local.enabled ? 1 : 0
name = try(length(var.subnet_group_name), 0) == 0 ? module.this.id : var.subnet_group_name
description = "Allowed subnets for DB cluster instances"
subnet_ids = var.subnets
tags = module.this.tags
}
resource "aws_rds_cluster_parameter_group" "default" {
count = local.enabled ? 1 : 0
name_prefix = var.parameter_group_name_prefix_enabled ? "${coalesce(var.rds_cluster_parameter_group_name, module.this.id)}${module.this.delimiter}" : null
name = !var.parameter_group_name_prefix_enabled ? coalesce(var.rds_cluster_parameter_group_name, module.this.id) : null
description = "DB cluster parameter group"
family = var.cluster_family
dynamic "parameter" {
for_each = var.cluster_parameters
content {
apply_method = lookup(parameter.value, "apply_method", null)
name = parameter.value.name
value = parameter.value.value
}
}
tags = module.this.tags
lifecycle {
create_before_destroy = true
}
}
resource "aws_db_parameter_group" "default" {
count = local.enabled ? 1 : 0
name_prefix = var.parameter_group_name_prefix_enabled ? "${coalesce(var.db_parameter_group_name, module.this.id)}${module.this.delimiter}" : null
name = !var.parameter_group_name_prefix_enabled ? coalesce(var.db_parameter_group_name, module.this.id) : null
description = "DB instance parameter group"
family = var.cluster_family
dynamic "parameter" {
for_each = var.instance_parameters
content {
apply_method = lookup(parameter.value, "apply_method", null)
name = parameter.value.name
value = parameter.value.value
}
}
tags = module.this.tags
lifecycle {
create_before_destroy = true
}
}
locals {
cluster_dns_name_default = "master.${module.this.name}"
cluster_dns_name = var.cluster_dns_name != "" ? var.cluster_dns_name : local.cluster_dns_name_default
reader_dns_name_default = "replicas.${module.this.name}"
reader_dns_name = var.reader_dns_name != "" ? var.reader_dns_name : local.reader_dns_name_default
}
module "dns_master" {
source = "cloudposse/route53-cluster-hostname/aws"
version = "0.13.0"
enabled = local.enabled && length(var.zone_id) > 0
dns_name = local.cluster_dns_name
zone_id = try(var.zone_id[0], tostring(var.zone_id), "")
records = coalescelist(aws_rds_cluster.primary[*].endpoint, aws_rds_cluster.secondary[*].endpoint, [""])
context = module.this.context
}
module "dns_replicas" {
source = "cloudposse/route53-cluster-hostname/aws"
version = "0.13.0"
enabled = local.enabled && length(var.zone_id) > 0 && !local.is_serverless && local.cluster_instance_count > 0
dns_name = local.reader_dns_name
zone_id = try(var.zone_id[0], tostring(var.zone_id), "")
records = coalescelist(aws_rds_cluster.primary[*].reader_endpoint, aws_rds_cluster.secondary[*].reader_endpoint, [""])
context = module.this.context
}
resource "aws_appautoscaling_target" "replicas" {
count = local.enabled && var.autoscaling_enabled ? 1 : 0
service_namespace = "rds"
scalable_dimension = "rds:cluster:ReadReplicaCount"
resource_id = "cluster:${local.deployed_cluster_identifier}"
min_capacity = var.autoscaling_min_capacity
max_capacity = var.autoscaling_max_capacity
}
resource "aws_appautoscaling_policy" "replicas" {
count = local.enabled && var.autoscaling_enabled ? 1 : 0
name = module.this.id
service_namespace = join("", aws_appautoscaling_target.replicas[*].service_namespace)
scalable_dimension = join("", aws_appautoscaling_target.replicas[*].scalable_dimension)
resource_id = join("", aws_appautoscaling_target.replicas[*].resource_id)
policy_type = var.autoscaling_policy_type
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = var.autoscaling_target_metrics
}
disable_scale_in = false
target_value = var.autoscaling_target_value
scale_in_cooldown = var.autoscaling_scale_in_cooldown
scale_out_cooldown = var.autoscaling_scale_out_cooldown
}
}
resource "aws_rds_cluster_activity_stream" "primary" {
count = local.enabled && var.activity_stream_enabled ? 1 : 0
resource_arn = join("", aws_rds_cluster.primary[*].arn)
mode = var.activity_stream_mode
kms_key_id = var.activity_stream_kms_key_id
}
================================================
FILE: outputs.tf
================================================
output "database_name" {
value = var.db_name
description = "Database name"
}
output "master_username" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].master_username) : join("", aws_rds_cluster.secondary[*].master_username)
description = "Username for the master DB user"
sensitive = true
}
output "cluster_identifier" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].cluster_identifier) : join("", aws_rds_cluster.secondary[*].cluster_identifier)
description = "Cluster Identifier"
}
output "arn" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].arn) : join("", aws_rds_cluster.secondary[*].arn)
description = "Amazon Resource Name (ARN) of the cluster"
}
output "endpoint" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].endpoint) : join("", aws_rds_cluster.secondary[*].endpoint)
description = "The DNS address of the RDS instance"
}
output "reader_endpoint" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].reader_endpoint) : join("", aws_rds_cluster.secondary[*].reader_endpoint)
description = "A read-only endpoint for the Aurora cluster, automatically load-balanced across replicas"
}
output "port" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].port) : join("", aws_rds_cluster.secondary[*].port)
description = "DB port"
}
# See: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/rds_cluster.html#master_user_secret
output "admin_user_secret" {
value = var.manage_admin_user_password ? concat(aws_rds_cluster.primary[*].master_user_secret) : []
description = "The secret manager attributes for the managed admin user password (`master_user_secret`)."
}
output "master_host" {
value = module.dns_master.hostname
description = "DB Master hostname"
}
output "replicas_host" {
value = module.dns_replicas.hostname
description = "Replicas hostname"
}
output "dbi_resource_ids" {
value = aws_rds_cluster_instance.default[*].dbi_resource_id
description = "List of the region-unique, immutable identifiers for the DB instances in the cluster"
}
output "instance_endpoints" {
value = aws_rds_cluster_instance.default[*].endpoint
description = "List of DNS addresses for the DB instances in the cluster"
}
output "instance_arns" {
value = aws_rds_cluster_instance.default[*].arn
description = "List of ARNs of the DB instances in the cluster"
}
output "cluster_resource_id" {
value = local.is_regional_cluster ? join("", aws_rds_cluster.primary[*].cluster_resource_id) : join("", aws_rds_cluster.secondary[*].cluster_resource_id)
description = "The region-unique, immutable identifie of the cluster"
}
output "cluster_security_groups" {
value = coalescelist(aws_rds_cluster.primary[*].vpc_security_group_ids, aws_rds_cluster.secondary[*].vpc_security_group_ids, [""])
description = "Default RDS cluster security groups"
}
output "security_group_id" {
value = join("", aws_security_group.default[*].id)
description = "Security Group ID"
}
output "security_group_arn" {
value = join("", aws_security_group.default[*].arn)
description = "Security Group ARN"
}
output "security_group_name" {
value = join("", aws_security_group.default[*].name)
description = "Security Group name"
}
output "activity_stream_arn" {
value = join("", aws_rds_cluster_activity_stream.primary[*].id)
description = "Activity Stream ARN"
}
output "activity_stream_name" {
value = join("", aws_rds_clu
gitextract_4dy49v9r/ ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── feature_request.md │ │ ├── feature_request.yml │ │ └── question.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── mergify.yml │ ├── renovate.json │ ├── settings.yml │ └── workflows/ │ ├── branch.yml │ ├── chatops.yml │ ├── release.yml │ └── scheduled.yml ├── .gitignore ├── LICENSE ├── README.md ├── README.yaml ├── atmos.yaml ├── context.tf ├── enhanced-monitoring.tf ├── examples/ │ ├── basic/ │ │ ├── main.tf │ │ └── outputs.tf │ ├── complete/ │ │ ├── context.tf │ │ ├── fixtures.us-east-2.tfvars │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── variables.tf │ │ └── versions.tf │ ├── enhanced_monitoring/ │ │ ├── main.tf │ │ └── outputs.tf │ ├── postgres/ │ │ ├── context.tf │ │ ├── fixtures.us-east-2.tfvars │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── variables.tf │ │ └── versions.tf │ ├── serverless_mysql/ │ │ ├── main.tf │ │ └── outputs.tf │ ├── serverless_mysql57/ │ │ ├── main.tf │ │ └── outputs.tf │ ├── serverlessv2_postgres/ │ │ ├── context.tf │ │ ├── fixtures.us-east-2.tfvars │ │ ├── main.tf │ │ ├── outputs.tf │ │ ├── variables.tf │ │ └── versions.tf │ └── with_cluster_parameters/ │ ├── main.tf │ └── outputs.tf ├── main.tf ├── outputs.tf ├── test/ │ ├── .gitignore │ ├── Makefile │ ├── Makefile.alpine │ └── src/ │ ├── .gitignore │ ├── Makefile │ ├── examples_complete_test.go │ ├── examples_postgres_test.go │ ├── examples_serverlessv2_postgres_test.go │ ├── go.mod │ ├── go.sum │ └── utils.go ├── variables.tf └── versions.tf
SYMBOL INDEX (7 symbols across 4 files)
FILE: test/src/examples_complete_test.go
function TestExamplesComplete (line 15) | func TestExamplesComplete(t *testing.T) {
function TestExamplesCompleteDisabled (line 70) | func TestExamplesCompleteDisabled(t *testing.T) {
FILE: test/src/examples_postgres_test.go
function TestExamplesPostgres (line 15) | func TestExamplesPostgres(t *testing.T) {
function TestExamplesPostgresDisabled (line 70) | func TestExamplesPostgresDisabled(t *testing.T) {
FILE: test/src/examples_serverlessv2_postgres_test.go
function TestExamplesServerlessV2Postgres (line 15) | func TestExamplesServerlessV2Postgres(t *testing.T) {
function TestExamplesServerlessV2PostgresDisabled (line 70) | func TestExamplesServerlessV2PostgresDisabled(t *testing.T) {
FILE: test/src/utils.go
function cleanup (line 10) | func cleanup(t *testing.T, terraformOptions *terraform.Options, tempTest...
Condensed preview — 65 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (355K chars).
[
{
"path": ".github/CODEOWNERS",
"chars": 1201,
"preview": "# Use this file to define individuals or teams that are responsible for code in a repository.\n# Read more: <https://help"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 902,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: 'bug'\nassignees: ''\n\n---\n\nFound a bug? "
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 1859,
"preview": "---\nname: Bug report\ndescription: Create a report to help us improve\nlabels: [\"bug\"]\nassignees: [\"\"]\nbody:\n - type: mar"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 496,
"preview": "blank_issues_enabled: false\n\ncontact_links:\n\n - name: Community Slack Team\n url: https://cloudposse.com/slack/\n a"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 1021,
"preview": "---\nname: Feature Request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: 'feature request'\nassignees: ''\n\n---"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.yml",
"chars": 1914,
"preview": "---\nname: Feature Request\ndescription: Suggest an idea for this project\nlabels: [\"feature request\"]\nassignees: [\"\"]\nbody"
},
{
"path": ".github/ISSUE_TEMPLATE/question.md",
"chars": 0,
"preview": ""
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 602,
"preview": "## what\n\n<!--\n- Describe high-level what changed as a result of these commits (i.e. in plain-english, what do these chan"
},
{
"path": ".github/mergify.yml",
"chars": 17,
"preview": "extends: .github\n"
},
{
"path": ".github/renovate.json",
"chars": 285,
"preview": "{\n \"extends\": [\n \"config:base\",\n \":preserveSemverRanges\",\n \":rebaseStalePrs\"\n ],\n \"baseBranches\": [\"main\"],\n"
},
{
"path": ".github/settings.yml",
"chars": 423,
"preview": "# Upstream changes from _extends are only recognized when modifications are made to this file in the default branch.\n_ex"
},
{
"path": ".github/workflows/branch.yml",
"chars": 462,
"preview": "---\nname: Branch\non:\n pull_request:\n branches:\n - main\n - release/**\n types: [opened, synchronize, reop"
},
{
"path": ".github/workflows/chatops.yml",
"chars": 368,
"preview": "---\nname: chatops\non:\n issue_comment:\n types: [created]\n\npermissions:\n pull-requests: write\n id-token: write\n con"
},
{
"path": ".github/workflows/release.yml",
"chars": 263,
"preview": "---\nname: release\non:\n release:\n types:\n - published\n\npermissions:\n id-token: write\n contents: write\n pull-r"
},
{
"path": ".github/workflows/scheduled.yml",
"chars": 323,
"preview": "---\nname: scheduled\non:\n workflow_dispatch: { } # Allows manually trigger this workflow\n schedule:\n - cron: \"0 3 *"
},
{
"path": ".gitignore",
"chars": 137,
"preview": "# Compiled files\n*.tfstate\n*.tfstate.backup\n\n# Module directory\n.terraform\n.idea\n*.iml\n\n.build-harness\nbuild-harness\n.te"
},
{
"path": "LICENSE",
"chars": 11351,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 56191,
"preview": "\n\n<!-- markdownlint-disable -->\n<a href=\"https://cpco.io/homepage\"><img src=\"https://github.com/cloudposse/terraform-aws"
},
{
"path": "README.yaml",
"chars": 8639,
"preview": "name: terraform-aws-rds-cluster\n\ntags:\n - aws\n - terraform\n - terraform-modules\n - databases\n - rds\n - rds-databas"
},
{
"path": "atmos.yaml",
"chars": 511,
"preview": "# Atmos Configuration — powered by https://atmos.tools\n#\n# This configuration enables centralized, DRY, and consistent p"
},
{
"path": "context.tf",
"chars": 10101,
"preview": "#\n# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label\n# All other instances of this file should be a cop"
},
{
"path": "enhanced-monitoring.tf",
"chars": 1621,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_Monitoring.OS.html\n# https://registry.terraform.io/provide"
},
{
"path": "examples/basic/main.tf",
"chars": 715,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html\n\nprovider \"aws\" {\n r"
},
{
"path": "examples/basic/outputs.tf",
"chars": 1127,
"preview": "output \"name\" {\n value = module.rds_cluster_aurora_postgres.database_name\n description = \"Database name\"\n}\n\noutp"
},
{
"path": "examples/complete/context.tf",
"chars": 10101,
"preview": "#\n# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label\n# All other instances of this file should be a cop"
},
{
"path": "examples/complete/fixtures.us-east-2.tfvars",
"chars": 652,
"preview": "region = \"us-east-2\"\n\navailability_zones = [\"us-east-2a\", \"us-east-2b\"]\n\nnamespace = \"eg\"\n\nstage = \"test\"\n\nname = \"rds-c"
},
{
"path": "examples/complete/main.tf",
"chars": 2856,
"preview": "provider \"aws\" {\n region = var.region\n}\n\nmodule \"vpc\" {\n source = \"cloudposse/vpc/aws\"\n version = \"2.2.0\"\n\n ipv4_pr"
},
{
"path": "examples/complete/outputs.tf",
"chars": 1953,
"preview": "output \"database_name\" {\n value = module.rds_cluster.database_name\n description = \"Database name\"\n}\n\noutput \"clu"
},
{
"path": "examples/complete/variables.tf",
"chars": 2842,
"preview": "variable \"region\" {\n type = string\n description = \"AWS region\"\n}\n\nvariable \"availability_zones\" {\n type "
},
{
"path": "examples/complete/versions.tf",
"chars": 229,
"preview": "terraform {\n required_version = \">= 1.1.0\"\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n ve"
},
{
"path": "examples/enhanced_monitoring/main.tf",
"chars": 1642,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html\n\nprovider \"aws\" {\n r"
},
{
"path": "examples/enhanced_monitoring/outputs.tf",
"chars": 1127,
"preview": "output \"name\" {\n value = module.rds_cluster_aurora_postgres.database_name\n description = \"Database name\"\n}\n\noutp"
},
{
"path": "examples/postgres/context.tf",
"chars": 10101,
"preview": "#\n# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label\n# All other instances of this file should be a cop"
},
{
"path": "examples/postgres/fixtures.us-east-2.tfvars",
"chars": 759,
"preview": "region = \"us-east-2\"\n\navailability_zones = [\"us-east-2a\", \"us-east-2b\", \"us-east-2c\"]\n\nnamespace = \"eg\"\n\nstage = \"test\"\n"
},
{
"path": "examples/postgres/main.tf",
"chars": 1616,
"preview": "provider \"aws\" {\n region = var.region\n}\n\nmodule \"vpc\" {\n source = \"cloudposse/vpc/aws\"\n version = \"2.2.0\"\n\n ipv4_pr"
},
{
"path": "examples/postgres/outputs.tf",
"chars": 1953,
"preview": "output \"database_name\" {\n value = module.rds_cluster.database_name\n description = \"Database name\"\n}\n\noutput \"clu"
},
{
"path": "examples/postgres/variables.tf",
"chars": 3016,
"preview": "variable \"region\" {\n type = string\n description = \"AWS region\"\n}\n\nvariable \"availability_zones\" {\n type "
},
{
"path": "examples/postgres/versions.tf",
"chars": 229,
"preview": "terraform {\n required_version = \">= 1.1.0\"\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n ve"
},
{
"path": "examples/serverless_mysql/main.tf",
"chars": 1218,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html\n# https://docs.aws.am"
},
{
"path": "examples/serverless_mysql/outputs.tf",
"chars": 1191,
"preview": "output \"name\" {\n value = module.rds_cluster_aurora_mysql_serverless.database_name\n description = \"Database name\""
},
{
"path": "examples/serverless_mysql57/main.tf",
"chars": 1310,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html\n# https://docs.aws.am"
},
{
"path": "examples/serverless_mysql57/outputs.tf",
"chars": 1191,
"preview": "output \"name\" {\n value = module.rds_cluster_aurora_mysql_serverless.database_name\n description = \"Database name\""
},
{
"path": "examples/serverlessv2_postgres/context.tf",
"chars": 10101,
"preview": "#\n# ONLY EDIT THIS FILE IN github.com/cloudposse/terraform-null-label\n# All other instances of this file should be a cop"
},
{
"path": "examples/serverlessv2_postgres/fixtures.us-east-2.tfvars",
"chars": 524,
"preview": "region = \"us-east-2\"\n\navailability_zones = [\"us-east-2a\", \"us-east-2b\"]\n\nnamespace = \"eg\"\n\nstage = \"test\"\n\nname = \"rds-c"
},
{
"path": "examples/serverlessv2_postgres/main.tf",
"chars": 1328,
"preview": "provider \"aws\" {\n region = var.region\n}\n\nmodule \"vpc\" {\n source = \"cloudposse/vpc/aws\"\n version = \"2.2.0\"\n\n ipv4_pr"
},
{
"path": "examples/serverlessv2_postgres/outputs.tf",
"chars": 2521,
"preview": "output \"database_name\" {\n value = module.rds_cluster_aurora_serverlessv2_postgres_13.database_name\n description "
},
{
"path": "examples/serverlessv2_postgres/variables.tf",
"chars": 2392,
"preview": "variable \"region\" {\n type = string\n description = \"AWS region\"\n}\n\nvariable \"availability_zones\" {\n type "
},
{
"path": "examples/serverlessv2_postgres/versions.tf",
"chars": 227,
"preview": "terraform {\n required_version = \">= 1.1.0\"\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n ve"
},
{
"path": "examples/with_cluster_parameters/main.tf",
"chars": 1828,
"preview": "# https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBClusterParameterGroup.html\n\nprovider \"aws\" {\n r"
},
{
"path": "examples/with_cluster_parameters/outputs.tf",
"chars": 1103,
"preview": "output \"name\" {\n value = module.rds_cluster_aurora_mysql.database_name\n description = \"Database name\"\n}\n\noutput "
},
{
"path": "main.tf",
"chars": 24708,
"preview": "locals {\n enabled = module.this.enabled\n\n partition = one(data.aws_partition.current[*].partition)\n\n deployed_cluster"
},
{
"path": "outputs.tf",
"chars": 3924,
"preview": "output \"database_name\" {\n value = var.db_name\n description = \"Database name\"\n}\n\noutput \"master_username\" {\n val"
},
{
"path": "test/.gitignore",
"chars": 14,
"preview": ".test-harness\n"
},
{
"path": "test/Makefile",
"chars": 1155,
"preview": "TEST_HARNESS ?= https://github.com/cloudposse/test-harness.git\nTEST_HARNESS_BRANCH ?= master\nTEST_HARNESS_PATH = $(realp"
},
{
"path": "test/Makefile.alpine",
"chars": 153,
"preview": "ifneq (,$(wildcard /sbin/apk))\n## Install all dependencies for alpine\ndeps:: init\n\t@apk add --update terraform-docs@clou"
},
{
"path": "test/src/.gitignore",
"chars": 16,
"preview": ".gopath\nvendor/\n"
},
{
"path": "test/src/Makefile",
"chars": 1046,
"preview": "export TERRAFORM_VERSION ?= $(shell curl -s https://checkpoint-api.hashicorp.com/v1/check/terraform | jq -r -M '.current"
},
{
"path": "test/src/examples_complete_test.go",
"chars": 4089,
"preview": "package test\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gruntwork-io/terratest/modules/random\"\n\t\"github.com"
},
{
"path": "test/src/examples_postgres_test.go",
"chars": 4126,
"preview": "package test\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gruntwork-io/terratest/modules/random\"\n\t\"github.com"
},
{
"path": "test/src/examples_serverlessv2_postgres_test.go",
"chars": 4152,
"preview": "package test\n\nimport (\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/gruntwork-io/terratest/modules/random\"\n\t\"github.com"
},
{
"path": "test/src/go.mod",
"chars": 4610,
"preview": "module github.com/cloudposse/terraform-aws-rds-cluster\n\ngo 1.24\n\ntoolchain go1.24.0\n\nrequire (\n\tgithub.com/gruntwork-io/"
},
{
"path": "test/src/go.sum",
"chars": 106257,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
},
{
"path": "test/src/utils.go",
"chars": 264,
"preview": "package test\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/gruntwork-io/terratest/modules/terraform\"\n)\n\nfunc cleanup(t *testi"
},
{
"path": "variables.tf",
"chars": 20015,
"preview": "variable \"zone_id\" {\n type = any\n default = []\n description = <<-EOT\n Route53 DNS Zone ID as list of st"
},
{
"path": "versions.tf",
"chars": 310,
"preview": "terraform {\n required_version = \">= 1.0.0\"\n\n required_providers {\n aws = {\n source = \"hashicorp/aws\"\n ve"
}
]
About this extraction
This page contains the full source code of the cloudposse/terraform-aws-rds-cluster GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 65 files (331.4 KB), approximately 117.8k tokens, and a symbol index with 7 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.