Skip to content

Commit

Permalink
Local account backup module
Browse files Browse the repository at this point in the history
  • Loading branch information
neil-sproston committed Jun 27, 2024
1 parent 55b455a commit 004483e
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 0 deletions.
48 changes: 48 additions & 0 deletions modules/backup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Terraform module: backup schedules

## Description

This is a simple module to create a AWS Backup vault, KMS keys, Plans and automatic off-account site backup.

The vault module should be ran first in the remote AWS account.

**WARNING** Once a snaphshot has been placed intothe remote locked vault it can not be removed until the
lifecycle duration has been exceeded.

## Module parameters

| Name | Description | Type | Default |
|:-----------------|:---------------------------------------------------------|:------:|:-------------------:|
| instance_name | The name of the service being served | string | - |
| remote_account | The AWS Account ID number of the remote account | string | - |
| remote_vault_arn | The vault ARN in the remote account | string | false |
| local_lifecycle | Lifecycle for local copies, in days | number | - |
| remote_lifecycle | Lifecycle for remote copies, in days | number | - |
| backup_schedule | The schedule to run backups, in AWS CRON format | string | cron(15 11 ? * * *) |
| use_env | Wether to backup by environmrnt ot ALL assets in account | bool | false |
| environment | The environment name to select assets from | string | - |


## Sample usage

This snippet creates a backup vault and plan for RSS prod. The AWS account number "123456789012" and ARN
is the locked vault created by the vault module in a seperate AWS account.

Local copies of the snapshots are held for 7 days and remote "tamper-proof" copies for 90 days. The backup
runs at 11:15 every day and backs up all assets in the prod environment (as defined by the Environment tag)
with the BackupRemote Tag set to true

```
module "rss_prod_backup_vault" {
source = "../modules/backup"
instance_name = "rss-prod"
remote_accountount = "123456789012"
remote_vault_arn = "arn:aws:backup:eu-west-2:123456789012:backup-vault:rss_prod_backup"
local_lifecycle = 7
remote_lifecycle = 90
backup_schedule = "cron(15 11 ? * * *)"
use_env = true
environment = "prod"
}
```
3 changes: 3 additions & 0 deletions modules/backup/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Data sources require dby module

data "aws_caller_identity" "current" {}
29 changes: 29 additions & 0 deletions modules/backup/iam.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Backup IAM role to use for backups

resource "aws_iam_role" "remote_backup" {
name = "${var.instance_name}-remote_backup"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["sts:AssumeRole"],
"Effect": "allow",
"Principal": {
"Service": ["backup.amazonaws.com"]
}
}
]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "remote_backup" {
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
role = aws_iam_role.remote_backup.name
}

resource "aws_iam_role_policy_attachment" "remote_backup_s3" {
policy_arn = "arn:aws:iam::aws:policy/AWSBackupServiceRolePolicyForS3Backup"
role = aws_iam_role.remote_backup.name
}
62 changes: 62 additions & 0 deletions modules/backup/kms.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Create a specific KMS key for the local backup vault and allow the remote
// AWS account access to that key.

resource "aws_kms_alias" "remote_backup_vault_key" {
name = "alias/${var.instance_name}-remote-backup-vault-key"
target_key_id = aws_kms_key.remote_backup_vault.key_id
}

resource "aws_kms_key" "remote_backup_vault" {
description = "${var.instance_name} Remote Backup vault Key"

policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "key-default-plus",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${data.aws_caller_identity.current.id}:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access from remote backup account",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${var.remote_account}:root"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistant resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::${var.remote_account}:root"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
POLICY
}
6 changes: 6 additions & 0 deletions modules/backup/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Output variable definitions

output "vault_arn" {
description = "The Local backup vault ARN"
value = aws_backup_vault.remote_backup_vault.arn
}
43 changes: 43 additions & 0 deletions modules/backup/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Input variable definitions

variable "instance_name" {
description = "The name of the service being served"
type = string
}

variable "remote_account" {
description = "The AWS accound ID number holding the remote locked vault"
type = string
}

variable "remote_vault_arn" {
description = "The ARN of the locked vault to copy snaphsots too in the remote AWS account"
type = string
}

variable "local_lifecycle" {
description = "The lifecycle used for local backup snaphots, in days"
type = string
}

variable "remote_lifecycle" {
description = "The lifecycle used for remote backup snaphots, in days"
type = string
}

variable "backup_schedule" {
description = "The schedule to run backups in, in AWS's CRON format"
type = string
default = "cron(15 11 ? * * *)"
}

variable "use_env" {
description = ""
type = bool
default = false
}

variable "environment" {
description = "The environment name to back up, if omitted then ALL assets in the AWS account will be backed up if requested."
type = string
}
96 changes: 96 additions & 0 deletions modules/backup/vault.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Create the AWS Backup Vault and plans

// The vault

resource "aws_backup_vault" "remote_backup_vault" {
name = "${var.instance_name}-remote_backup"
kms_key_arn = aws_kms_key.remote_backup_vault.arn
}

// The policy to use for the vault allowing the remote AWS account to copy snapshots
// back in case of incidents

resource "aws_backup_vault_policy" "remote_backup" {
backup_vault_name = aws_backup_vault.remote_backup_vault.name

policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "backup:CopyIntoBackupVault",
"Resource": "*",
"Principal": {
"AWS": [
"arn:aws:iam::${var.remote_account}:root"
]
}
}
]
}
POLICY
}

// The backup plan which automatically copies snapshots off-account

resource "aws_backup_plan" "remote_backup" {
name = "${var.instance_name}-remote_backup"

rule {
rule_name = "${var.instance_name}-remote_backup"
target_vault_name = aws_backup_vault.remote_backup_vault.name
schedule = var.backup_schedule

lifecycle {
delete_after = var.local_lifecycle
}
copy_action {
destination_vault_arn = var.remote_vault_arn

lifecycle {
delete_after = var.remote_lifecycle
}
}
}
}

// A selection which backs up ALL assets in the AWS account which have
// the tag BackupRemote=True

resource "aws_backup_selection" "remote_backup_account" {
count = var.use_env ? 0 : 1
iam_role_arn = aws_iam_role.remote_backup.arn
name = "${var.instance_name}-remote-backup-account"
plan_id = aws_backup_plan.remote_backup.id
resources = ["*"]

condition {
string_equals {
key = "aws:ResourceTag/BackupRemote"
value = "true"
}
}
}

// A selection which backs up assets in the AWS account which have
// the tag BackupRemote=True AND the requested Environment tag.

resource "aws_backup_selection" "remote_backup_env" {
count = var.use_env ? 1 : 0
iam_role_arn = aws_iam_role.remote_backup.arn
name = "${var.instance_name}-remote-backup-env"
plan_id = aws_backup_plan.remote_backup.id
resources = ["*"]

condition {
string_equals {
key = "aws:ResourceTag/BackupRemote"
value = "true"
}
string_equals {
key = "aws:ResourceTag/Environment"
value = var.environment
}
}
}

0 comments on commit 004483e

Please sign in to comment.