Skip to content

Commit

Permalink
feat: manage master credentials in secrets manager (#221)
Browse files Browse the repository at this point in the history
* feat: manage master credentials in secrets manager

* fix: address PR comments

See #218

* generate README

* fix: address PR comments

* chore: update README

* fix: manage_master_user_password must be `null` or `true`

* fix: make `manage_master_user_password` logic more readable per PR request

---------

Co-authored-by: Marat Salimzianov <salemgolemugoo@users.noreply.github.com>
Co-authored-by: Lennart Goedhart <lgoedhart-ic@akiliinteractive.com>
  • Loading branch information
3 people committed Jul 24, 2024
1 parent 935ccd3 commit 69eed44
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 9 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ Available targets:
| <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 |
Expand Down Expand Up @@ -429,6 +430,7 @@ Available targets:
| <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_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 |
Expand Down
4 changes: 3 additions & 1 deletion docs/terraform.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
| <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 |
Expand Down Expand Up @@ -115,6 +116,7 @@
| <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_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 |
Expand All @@ -127,7 +129,7 @@
| <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> default: "120m"<br>`restore_type`:<br> Type of restore to be performed. Valid options are "full-copy" and "copy-on-write".<br> default: "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> default: true<br>`restore_to_time`:<br> Date and time in UTC format to restore the database cluster to. Conflicts with `use_latest_restorable_time`.<br> default: null | <pre>list(object({<br> source_cluster_identifier = string<br> restore_type = string<br> use_latest_restorable_time = bool<br> restore_to_time = string<br> }))</pre> | `[]` | 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 |
Expand Down
22 changes: 14 additions & 8 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ resource "aws_security_group_rule" "egress" {
# 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
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 ? null : var.admin_password
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
Expand Down Expand Up @@ -169,11 +172,14 @@ resource "aws_rds_cluster" "primary" {

# 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
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 ? null : var.admin_password
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
Expand Down
17 changes: 17 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ variable "db_port" {
description = "Database port"
}

variable "manage_admin_user_password" {
type = bool
default = false
nullable = false
description = "Set to true to allow RDS to manage the master user password in Secrets Manager. Cannot be set if master_password is provided"
}

variable "admin_user_secret_kms_key_id" {
type = string
default = null
description = <<-EOT
Amazon Web Services KMS key identifier is the key ARN, key ID, alias ARN, or alias name for the KMS key.
To use a KMS key in a different Amazon Web Services account, specify the key ARN or alias ARN.
If not specified, the default KMS key for your Amazon Web Services account is used.
EOT
}

variable "admin_user" {
type = string
default = "admin"
Expand Down

0 comments on commit 69eed44

Please sign in to comment.