diff --git a/modules/aws-backup/README.md b/modules/aws-backup/README.md index b8e0b292c..4da76b8ae 100644 --- a/modules/aws-backup/README.md +++ b/modules/aws-backup/README.md @@ -37,6 +37,13 @@ components: iam_role_enabled: true # this will be reused vault_enabled: true # this will be reused plan_enabled: false + +## Please be careful when enabling backup_vault_lock_configuration, +# backup_vault_lock_configuration: +## `changeable_for_days` enables compliance mode and once the lock is set, the retention policy cannot be changed unless through account deletion! +# changeable_for_days: 36500 +# max_retention_days: 365 +# min_retention_days: 1 ``` Then if we would like to deploy the component into a given stacks we can import the following to deploy our backup plans. @@ -85,7 +92,12 @@ components: vars: plan_name_suffix: aws-backup-daily # https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html - schedule: cron(0 0 ? * * *) # Daily at midnight (UTC) + rules: + - name: "plan-daily" + schedule: "cron(0 5 ? * * *)" + start_window: 320 # 60 * 8 # minutes + completion_window: 10080 # 60 * 24 * 7 # minutes + delete_after: 35 # 7 * 5 # days selection_tags: - type: STRINGEQUALS key: aws-backup/efs @@ -102,7 +114,12 @@ components: vars: plan_name_suffix: aws-backup-weekly # https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html - schedule: cron(0 0 ? * 1 *) # Weekly on first day of week at midnight (UTC) + rules: + - name: "plan-weekly" + schedule: "cron(0 5 ? * SAT *)" + start_window: 320 # 60 * 8 # minutes + completion_window: 10080 # 60 * 24 * 7 # minutes + delete_after: 90 # 30 * 3 # days selection_tags: - type: STRINGEQUALS key: aws-backup/efs @@ -118,10 +135,15 @@ components: - aws-backup/plan-defaults vars: plan_name_suffix: aws-backup-monthly - # delete monthly snapshots after 60 days - delete_after: 60 # https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html - schedule: cron(0 0 1 * ? *) # Monthly on 1st day of the month (doesn't matter which) at midnight UTC + rules: + - name: "plan-monthly" + schedule: "cron(0 5 1 * ? *)" + start_window: 320 # 60 * 8 # minutes + completion_window: 10080 # 60 * 24 * 7 # minutes + delete_after: 2555 # 365 * 7 # days + cold_storage_after: 90 # 30 * 3 # days + selection_tags: - type: STRINGEQUALS key: aws-backup/efs @@ -182,13 +204,41 @@ components: copy_action_delete_after: 14 ``` +### Backup Lock Configuration + +To enable backup lock configuration, you can use the following snippet: + +* [AWS Backup Vault Lock](https://docs.aws.amazon.com/aws-backup/latest/devguide/vault-lock.html) + +#### Compliance Mode +Vaults locked in compliance mode cannot be deleted once the cooling-off period ("grace time") expires. During grace time, you can still remove the vault lock and change the lock configuration. + +To enable **Compliance Mode**, set `changeable_for_days` to a value greater than 0. Once the lock is set, the retention policy cannot be changed unless through account deletion! +```yaml +# Please be careful when enabling backup_vault_lock_configuration, + backup_vault_lock_configuration: +# `changeable_for_days` enables compliance mode and once the lock is set, the retention policy cannot be changed unless through account deletion! + changeable_for_days: 36500 + max_retention_days: 365 + min_retention_days: 1 +``` + +#### Governance Mode +Vaults locked in governance mode can have the lock removed by users with sufficient IAM permissions. + +To enable **governance mode** +```yaml + backup_vault_lock_configuration: + max_retention_days: 365 + min_retention_days: 1 +``` ## Requirements | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0.0 | +| [terraform](#requirement\_terraform) | >= 1.3.0 | | [aws](#requirement\_aws) | >= 4.9.0 | ## Providers @@ -199,7 +249,7 @@ No providers. | Name | Source | Version | |------|--------|---------| -| [backup](#module\_backup) | cloudposse/backup/aws | 0.14.0 | +| [backup](#module\_backup) | cloudposse/backup/aws | 1.0.0 | | [copy\_destination\_vault](#module\_copy\_destination\_vault) | cloudposse/stack-config/yaml//modules/remote-state | 1.5.0 | | [iam\_roles](#module\_iam\_roles) | ../account-map/modules/iam-roles | n/a | | [this](#module\_this) | cloudposse/label/null | 0.25.0 | @@ -213,8 +263,10 @@ No resources. | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [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`.
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. | `map(string)` | `{}` | no | +| [advanced\_backup\_setting](#input\_advanced\_backup\_setting) | An object that specifies backup options for each resource type. |
object({
backup_options = string
resource_type = string
})
| `null` | no | | [attributes](#input\_attributes) | 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. | `list(string)` | `[]` | no | | [backup\_resources](#input\_backup\_resources) | An array of strings that either contain Amazon Resource Names (ARNs) or match patterns of resources to assign to a backup plan | `list(string)` | `[]` | no | +| [backup\_vault\_lock\_configuration](#input\_backup\_vault\_lock\_configuration) | The backup vault lock configuration, each vault can have one vault lock in place. This will enable Backup Vault Lock on an AWS Backup vault it prevents the deletion of backup data for the specified retention period. During this time, the backup data remains immutable and cannot be deleted or modified."
`changeable_for_days` - The number of days before the lock date. If omitted creates a vault lock in `governance` mode, otherwise it will create a vault lock in `compliance` mode. |
object({
changeable_for_days = optional(number)
max_retention_days = optional(number)
min_retention_days = optional(number)
})
| `null` | no | | [cold\_storage\_after](#input\_cold\_storage\_after) | Specifies the number of days after creation that a recovery point is moved to cold storage | `number` | `null` | no | | [completion\_window](#input\_completion\_window) | The amount of time AWS Backup attempts a backup before canceling the job and returning an error. Must be at least 60 minutes greater than `start_window` | `number` | `null` | no | | [context](#input\_context) | 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. | `any` |
{
"additional_tag_map": {},
"attributes": [],
"delimiter": null,
"descriptor_formats": {},
"enabled": true,
"environment": null,
"id_length_limit": null,
"label_key_case": null,
"label_order": [],
"label_value_case": null,
"labels_as_tags": [
"unset"
],
"name": null,
"namespace": null,
"regex_replace_chars": null,
"stage": null,
"tags": {},
"tenant": null
}
| no | @@ -241,6 +293,7 @@ No resources. | [plan\_name\_suffix](#input\_plan\_name\_suffix) | The string appended to the plan name | `string` | `null` | no | | [regex\_replace\_chars](#input\_regex\_replace\_chars) | 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. | `string` | `null` | no | | [region](#input\_region) | AWS Region | `string` | n/a | yes | +| [rules](#input\_rules) | An array of rule maps used to define schedules in a backup plan |
list(object({
name = string
schedule = optional(string)
enable_continuous_backup = optional(bool)
start_window = optional(number)
completion_window = optional(number)
lifecycle = optional(object({
cold_storage_after = optional(number)
delete_after = optional(number)
opt_in_to_archive_for_supported_resources = optional(bool)
}))
copy_action = optional(object({
destination_vault_arn = optional(string)
lifecycle = optional(object({
cold_storage_after = optional(number)
delete_after = optional(number)
opt_in_to_archive_for_supported_resources = optional(bool)
}))
}))
}))
| `[]` | no | | [schedule](#input\_schedule) | A CRON expression specifying when AWS Backup initiates a backup job | `string` | `null` | no | | [selection\_tags](#input\_selection\_tags) | An array of tag condition objects used to filter resources based on tags for assigning to a backup plan | `list(map(string))` | `[]` | no | | [stage](#input\_stage) | ID element. Usually used to indicate role, e.g. 'prod', 'staging', 'source', 'build', 'test', 'deploy', 'release' | `string` | `null` | no | diff --git a/modules/aws-backup/main.tf b/modules/aws-backup/main.tf index bb371da65..f93e4717d 100644 --- a/modules/aws-backup/main.tf +++ b/modules/aws-backup/main.tf @@ -6,7 +6,7 @@ locals { module "backup" { source = "cloudposse/backup/aws" - version = "0.14.0" + version = "1.0.0" plan_name_suffix = var.plan_name_suffix vault_enabled = var.vault_enabled @@ -16,17 +16,11 @@ module "backup" { backup_resources = var.backup_resources selection_tags = var.selection_tags - schedule = var.schedule - start_window = var.start_window - completion_window = var.completion_window - cold_storage_after = var.cold_storage_after - delete_after = var.delete_after - kms_key_arn = var.kms_key_arn + kms_key_arn = var.kms_key_arn - # Copy config to new region - destination_vault_arn = local.copy_destination_arn - copy_action_cold_storage_after = var.copy_action_cold_storage_after - copy_action_delete_after = var.copy_action_delete_after + rules = var.rules + advanced_backup_setting = var.advanced_backup_setting + backup_vault_lock_configuration = var.backup_vault_lock_configuration context = module.this.context } diff --git a/modules/aws-backup/variables.tf b/modules/aws-backup/variables.tf index c43515f5a..4b8de574e 100644 --- a/modules/aws-backup/variables.tf +++ b/modules/aws-backup/variables.tf @@ -21,6 +21,19 @@ variable "start_window" { default = null } +variable "backup_vault_lock_configuration" { + type = object({ + changeable_for_days = optional(number) + max_retention_days = optional(number) + min_retention_days = optional(number) + }) + description = <<-EOT + The backup vault lock configuration, each vault can have one vault lock in place. This will enable Backup Vault Lock on an AWS Backup vault it prevents the deletion of backup data for the specified retention period. During this time, the backup data remains immutable and cannot be deleted or modified." + `changeable_for_days` - The number of days before the lock date. If omitted creates a vault lock in `governance` mode, otherwise it will create a vault lock in `compliance` mode. + EOT + default = null +} + variable "completion_window" { type = number description = "The amount of time AWS Backup attempts a backup before canceling the job and returning an error. Must be at least 60 minutes greater than `start_window`" @@ -104,3 +117,38 @@ variable "iam_role_enabled" { description = "Whether or not to create a new IAM Role and Policy Attachment" default = true } + + +variable "rules" { + type = list(object({ + name = string + schedule = optional(string) + enable_continuous_backup = optional(bool) + start_window = optional(number) + completion_window = optional(number) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + copy_action = optional(object({ + destination_vault_arn = optional(string) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + })) + })) + description = "An array of rule maps used to define schedules in a backup plan" + default = [] +} + +variable "advanced_backup_setting" { + type = object({ + backup_options = string + resource_type = string + }) + description = "An object that specifies backup options for each resource type." + default = null +} diff --git a/modules/aws-backup/versions.tf b/modules/aws-backup/versions.tf index cc73ffd35..b5920b7b1 100644 --- a/modules/aws-backup/versions.tf +++ b/modules/aws-backup/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 1.0.0" + required_version = ">= 1.3.0" required_providers { aws = { diff --git a/modules/philips-labs-github-runners/templates/userdata_post_install.sh b/modules/philips-labs-github-runners/templates/userdata_post_install.sh index b511a316b..3f810387b 100644 --- a/modules/philips-labs-github-runners/templates/userdata_post_install.sh +++ b/modules/philips-labs-github-runners/templates/userdata_post_install.sh @@ -1,3 +1,16 @@ echo "Installing Custom Packages..." yum install -y make + +# Install AWS CLI +curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" +unzip awscliv2.zip +sudo ./aws/install + +# Install `gh` CLI +type -p yum-config-manager >/dev/null || sudo yum install -y yum-utils +sudo yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo +sudo yum install -y gh + +# Install nodejs +sudo yum install -y nodejs-1:18.18.2-1.amzn2023.0.1