Skip to content

Commit 8c5a628

Browse files
authored
Merge pull request #743 from NHSDigital/feature/kabo5-NRL-853-cloud-backup-red-line
Feature/kabo5 nrl 853 cloud backup red line
2 parents ed9fd52 + 61fad34 commit 8c5a628

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1303
-26
lines changed

scripts/bootstrap.sh

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#!/bin/bash
2+
# Setup mgmt and non-mgmt AWS accounts for NRLF
3+
set -o errexit -o nounset -o pipefail
24

35
AWS_REGION_NAME="eu-west-2"
46
PROFILE_PREFIX="nhsd-nrlf"
@@ -32,18 +34,12 @@ function _check_mgmt() {
3234
}
3335

3436
function _check_non_mgmt() {
35-
if [[ "$(aws iam list-account-aliases --query 'AccountAliases[0]' --output text)" != 'nhsd-ddc-spine-nrlf-mgmt' ]]; then
37+
if [[ "$(aws iam list-account-aliases --query 'AccountAliases[0]' --output text)" == 'nhsd-ddc-spine-nrlf-mgmt' ]]; then
3638
echo "Please log in as a non-mgmt account" >&2
3739
return 1
3840
fi
3941
}
4042

41-
function _get_mgmt_account(){
42-
if ! _check_mgmt; then return 1; fi
43-
return $(aws sts get-caller-identity --query Account --output text)
44-
}
45-
46-
4743
function _bootstrap() {
4844
local command=$1
4945
local admin_policy_arn="arn:aws:iam::aws:policy/AdministratorAccess"
@@ -55,7 +51,7 @@ function _bootstrap() {
5551
"create-mgmt")
5652
_check_mgmt || return 1
5753

58-
cd $root/terraform/bootstrap/mgmt
54+
cd terraform/bootstrap/mgmt
5955
aws s3api create-bucket --bucket "${truststore_bucket_name}" --region us-east-1 --create-bucket-configuration LocationConstraint="${AWS_REGION_NAME}"
6056
aws s3api create-bucket --bucket "${state_bucket_name}" --region us-east-1 --create-bucket-configuration LocationConstraint="${AWS_REGION_NAME}"
6157
aws s3api put-public-access-block --bucket "${state_bucket_name}" --public-access-block-configuration "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
@@ -69,7 +65,7 @@ function _bootstrap() {
6965
"delete-mgmt")
7066
_check_mgmt || return 1
7167

72-
cd $root/terraform/bootstrap/mgmt
68+
cd terraform/bootstrap/mgmt
7369
aws dynamodb delete-table --table-name "${state_lock_table_name}" || return 1
7470
local versioned_objects
7571
versioned_objects=$(aws s3api list-object-versions \
@@ -90,10 +86,20 @@ function _bootstrap() {
9086
"create-non-mgmt")
9187
_check_non_mgmt || return 1
9288

93-
cd $root/terraform/bootstrap/non-mgmt
89+
cd terraform/bootstrap/non-mgmt
9490
local tf_assume_role_policy
9591
local mgmt_account_id
96-
mgmt_account_id=$(_get_mgmt_account)
92+
93+
set +e
94+
mgmt_account_id=$(aws secretsmanager get-secret-value --secret-id "${MGMT_ACCOUNT_ID_LOCATION}" --query SecretString --output text)
95+
96+
if [ "${mgmt_account_id}" == "" ]; then
97+
aws secretsmanager create-secret --name "${MGMT_ACCOUNT_ID_LOCATION}"
98+
echo "Please set ${MGMT_ACCOUNT_ID_LOCATION} in the Secrets Manager and rerun the script"
99+
exit 1
100+
fi
101+
set -e
102+
97103
tf_assume_role_policy=$(awk "{sub(/REPLACEME/,\"${mgmt_account_id}\")}1" terraform-trust-policy.json)
98104
aws iam create-role --role-name "${TERRAFORM_ROLE_NAME}" --assume-role-policy-document "${tf_assume_role_policy}" || return 1
99105
aws iam attach-role-policy --policy-arn "${admin_policy_arn}" --role-name "${TERRAFORM_ROLE_NAME}" || return 1
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
2+
# First, we create an S3 bucket for compliance reports.
3+
resource "aws_s3_bucket" "backup_reports" {
4+
bucket_prefix = "${local.prefix}-backup-reports"
5+
}
6+
7+
resource "aws_s3_bucket_public_access_block" "backup_reports" {
8+
bucket = aws_s3_bucket.backup_reports.id
9+
10+
block_public_acls = true
11+
block_public_policy = true
12+
ignore_public_acls = true
13+
restrict_public_buckets = true
14+
}
15+
16+
resource "aws_s3_bucket_server_side_encryption_configuration" "backup_reports" {
17+
bucket = aws_s3_bucket.backup_reports.bucket
18+
19+
rule {
20+
apply_server_side_encryption_by_default {
21+
sse_algorithm = "AES256"
22+
}
23+
}
24+
}
25+
26+
resource "aws_s3_bucket_policy" "backup_reports_bucket_policy" {
27+
bucket = aws_s3_bucket.backup_reports.id
28+
29+
policy = jsonencode({
30+
Version = "2012-10-17"
31+
Id = "backup_reports_bucket_policy"
32+
Statement = [
33+
{
34+
Sid = "HTTPSOnly"
35+
Effect = "Deny"
36+
Principal = "*"
37+
Action = "s3:*"
38+
Resource = [
39+
aws_s3_bucket.backup_reports.arn,
40+
"${aws_s3_bucket.backup_reports.arn}/*",
41+
]
42+
Condition = {
43+
Bool = {
44+
"aws:SecureTransport" = "false"
45+
}
46+
}
47+
},
48+
]
49+
})
50+
}
51+
52+
53+
resource "aws_s3_bucket_ownership_controls" "backup_reports" {
54+
bucket = aws_s3_bucket.backup_reports.id
55+
rule {
56+
object_ownership = "BucketOwnerPreferred"
57+
}
58+
}
59+
60+
resource "aws_s3_bucket_acl" "backup_reports" {
61+
depends_on = [aws_s3_bucket_ownership_controls.backup_reports]
62+
63+
bucket = aws_s3_bucket.backup_reports.id
64+
acl = "private"
65+
}
66+
67+
# We need a key for the SNS topic that will be used for notifications from AWS Backup. This key
68+
# will be used to encrypt the messages sent to the topic before they are sent to the subscribers,
69+
# but isn't needed by the recipients of the messages.
70+
71+
# First we need some contextual data
72+
data "aws_caller_identity" "current" {}
73+
data "aws_region" "current" {}
74+
75+
# Now we can define the key itself
76+
resource "aws_kms_key" "backup_notifications" {
77+
description = "KMS key for AWS Backup notifications"
78+
deletion_window_in_days = 7
79+
enable_key_rotation = true
80+
policy = jsonencode({
81+
Version = "2012-10-17"
82+
Statement = [
83+
{
84+
Effect = "Allow"
85+
Sid = "Enable IAM User Permissions"
86+
Principal = {
87+
AWS = "arn:aws:iam::${var.assume_account}:root"
88+
}
89+
Action = "kms:*"
90+
Resource = "*"
91+
},
92+
{
93+
Effect = "Allow"
94+
Principal = {
95+
Service = "sns.amazonaws.com"
96+
}
97+
Action = ["kms:GenerateDataKey*", "kms:Decrypt"]
98+
Resource = "*"
99+
},
100+
]
101+
})
102+
}
103+
104+
# Now we can deploy the source and destination modules, referencing the resources we've created above.
105+
106+
module "source" {
107+
source = "../modules/backup-source"
108+
109+
backup_copy_vault_account_id = jsondecode(data.aws_secretsmanager_secret_version.backup_destination_parameters.secret_string)["account-id"]
110+
backup_copy_vault_arn = jsondecode(data.aws_secretsmanager_secret_version.backup_destination_parameters.secret_string)["vault-arn"]
111+
environment_name = local.environment
112+
bootstrap_kms_key_arn = aws_kms_key.backup_notifications.arn
113+
project_name = "${local.prefix}-"
114+
reports_bucket = aws_s3_bucket.backup_reports.bucket
115+
terraform_role_arn = "arn:aws:iam::${var.assume_account}:role/${var.assume_role}"
116+
117+
notification_target_email_addresses = local.notification_emails
118+
119+
backup_plan_config = {
120+
"compliance_resource_types" : [
121+
"S3"
122+
],
123+
"enable" = true,
124+
"rules" : [
125+
{
126+
"copy_action" : {
127+
"delete_after" : 4
128+
},
129+
"lifecycle" : {
130+
"delete_after" : 2
131+
},
132+
"name" : "daily_kept_for_2_days",
133+
"schedule" : "cron(0 0 * * ? *)"
134+
}
135+
],
136+
"selection_tag" : "NHSE-Enable-S3-Backup"
137+
}
138+
139+
backup_plan_config_dynamodb = {
140+
"compliance_resource_types" : [
141+
"DynamoDB"
142+
],
143+
"enable" : true,
144+
"rules" : [
145+
{
146+
"copy_action" : {
147+
"delete_after" : 4
148+
},
149+
"lifecycle" : {
150+
"delete_after" : 2
151+
},
152+
"name" : "daily_kept_for_2_days",
153+
"schedule" : "cron(0 0 * * ? *)"
154+
}
155+
],
156+
"selection_tag" : "NHSE-Enable-DDB-Backup"
157+
}
158+
}

terraform/account-wide-infrastructure/dev/cloudwatch.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module "lambda_errors_cloudwatch_metric_alarm_dev" {
22
source = "../modules/lambda-errors-metric-alarm"
33
name_prefix = "nhsd-nrlf--dev"
44

5+
notification_emails = local.notification_emails
6+
57
evaluation_periods = 1
68
period = 60
79
threshold = 1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,15 @@
11
data "aws_secretsmanager_secret_version" "identities_account_id" {
22
secret_id = aws_secretsmanager_secret.identities_account_id.name
33
}
4+
5+
data "aws_secretsmanager_secret_version" "backup_destination_parameters" {
6+
secret_id = aws_secretsmanager_secret.backup_destination_parameters.name
7+
}
8+
9+
data "aws_secretsmanager_secret" "emails" {
10+
name = "${local.prefix}-emails"
11+
}
12+
13+
data "aws_secretsmanager_secret_version" "emails" {
14+
secret_id = data.aws_secretsmanager_secret.emails.id
15+
}

terraform/account-wide-infrastructure/dev/dynamodb__pointers-table.tf

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module "dev-pointers-table" {
2-
source = "../modules/pointers-table"
3-
name_prefix = "nhsd-nrlf--dev"
2+
source = "../modules/pointers-table"
3+
name_prefix = "nhsd-nrlf--dev"
4+
enable_backups = true
45
}
56

67
module "dev-sandbox-pointers-table" {

terraform/account-wide-infrastructure/dev/locals.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ locals {
33
project = "nhsd-nrlf"
44
environment = terraform.workspace
55
prefix = "${local.project}--${local.environment}"
6+
7+
notification_emails = nonsensitive(toset(tolist(jsondecode(data.aws_secretsmanager_secret_version.emails.secret_string))))
68
}

terraform/account-wide-infrastructure/dev/main.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ provider "aws" {
1010
workspace = terraform.workspace
1111
}
1212
}
13+
}
14+
15+
provider "awscc" {
16+
region = local.region
1317

18+
assume_role = {
19+
role_arn = "arn:aws:iam::${var.assume_account}:role/${var.assume_role}"
20+
}
1421
}
1522

1623
terraform {

terraform/account-wide-infrastructure/dev/s3.tf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module "dev-permissions-store-bucket" {
2-
source = "../modules/permissions-store-bucket"
3-
name_prefix = "nhsd-nrlf--dev"
2+
source = "../modules/permissions-store-bucket"
3+
name_prefix = "nhsd-nrlf--dev"
4+
enable_backups = true
45
}
56

67
module "dev-sandbox-permissions-store-bucket" {
@@ -12,6 +13,7 @@ module "dev-truststore-bucket" {
1213
source = "../modules/truststore-bucket"
1314
name_prefix = "nhsd-nrlf--dev"
1415
server_certificate_file = "../../../truststore/server/dev.pem"
16+
enable_backups = true
1517
}
1618

1719
module "dev-sandbox-truststore-bucket" {

terraform/account-wide-infrastructure/dev/secrets.tf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ resource "aws_secretsmanager_secret" "identities_account_id" {
22
name = "${local.prefix}--nhs-identities-account-id"
33
}
44

5+
resource "aws_secretsmanager_secret" "backup_destination_parameters" {
6+
name = "${local.prefix}--backup-destination-parameters"
7+
description = "Parameters used to configure the backup destination"
8+
}
9+
10+
resource "aws_secretsmanager_secret" "notification_email_addresses" {
11+
name = "${local.prefix}-dev-notification-email-addresses"
12+
}
13+
514
resource "aws_secretsmanager_secret" "dev_smoke_test_apigee_app" {
615
name = "${local.prefix}--dev--apigee-app--smoke-test"
716
description = "APIGEE App used to run Smoke Tests against the DEV environment"

0 commit comments

Comments
 (0)