Skip to content

Commit 06522b3

Browse files
authored
Merge branch 'main' into PRMP-627
2 parents 1c4f394 + 67c7fec commit 06522b3

Some content is hidden

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

50 files changed

+678
-415
lines changed

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!-- markdownlint-disable-next-line first-line-heading -->
2+
## Overview
3+
4+
**Jira ticket**: [TBC](https://nhsd-jira.digital.nhs.uk/browse/XXX)
5+
6+
### Description
7+
8+
<!-- Describe your changes in detail. -->
9+
10+
### Context
11+
12+
<!-- Why is this change required? What problem does it solve? -->
13+
14+
## Checklist
15+
16+
<!--
17+
18+
Put an `x` in the completed tasks.
19+
20+
If a task is not relevant, `x` it, then strike through the text e.g.:
21+
- [x] ~~This task is not relevant.~~
22+
23+
-->
24+
25+
Tasks for all changes:
26+
27+
- [ ] 1. I have linked this PR to its Jira ticket.
28+
- [ ] 2. I have run git pre-commits.
29+
- [ ] 3. I have updated relevant documentation.
30+
- [ ] 4. I have considered the cross-team impact (and have PR approval from both Core & Demographics if necessary).
31+
- [ ] 5. I have successfully [deployed this change to a sandbox](https://github.com/NHSDigital/national-document-repository-infrastructure/actions/workflows/deploy-sandbox.yml) and witnessed it build: [Workflow run: TBC](https://github.com/NHSDigital/national-document-repository-infrastructure/actions/runs/XXX)
32+
- [ ] 6. I have checked the Terraform Plan from this PR against `ndr-dev`.

.github/workflows/automated-pr-validator.yml

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ name: "Z-AUTOMATED: PR Validator"
22

33
on:
44
pull_request:
5-
types: [opened, synchronize, reopened]
5+
types: [opened, synchronize, reopened, edited]
6+
7+
permissions: {}
68

79
jobs:
810
sbom_scan:
@@ -120,3 +122,23 @@ jobs:
120122
BRANCH_NAME=${{ github.event.repository.default_branch }}
121123
chmod +x scripts/markdown-validator.sh
122124
scripts/markdown-validator.sh
125+
126+
checklist_validator:
127+
name: Checklist Validation
128+
runs-on: ubuntu-latest
129+
permissions:
130+
contents: read
131+
steps:
132+
- name: Checkout repository
133+
uses: actions/checkout@v5
134+
135+
- name: Set up Python 3.11
136+
uses: actions/setup-python@v6
137+
with:
138+
python-version: 3.11
139+
140+
- name: Run checklist validator
141+
run: |
142+
python3 scripts/github/checklist_validator/main.py
143+
env:
144+
PR_BODY: ${{ github.event.pull_request.body }}

.github/workflows/cron-daily-health-check.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ jobs:
119119
runTests: false
120120
build: npm run build
121121
working-directory: ./app
122+
123+
- name: Copy main.html to index.html for serve compatibility
124+
run: cp ./dist/main.html ./dist/index.html
125+
working-directory: ./app
122126

123127
- name: npm install serve -g
124128
run: npm install serve -g

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@ tfplan
3636
.idea/
3737
.vscode/
3838
venv/
39+
40+
#Ignore certificates
41+
scripts/csrs
42+
scripts/keys

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ As this repository is a standalone infrastructure there is no python/node based
2929
git config core.hooksPath .githooks
3030
```
3131

32-
Pre-commits will run on any commit. This will build docs and format the terraform.
32+
Pre-commits will run on all commits. This will build docs and format the terraform.

infrastructure/backup-cross-account.tf

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ resource "aws_backup_selection" "cross_account_backup_selection" {
6060
module.bulk_upload_report_dynamodb_table.dynamodb_table_arn,
6161
module.statistical-reports-store.bucket_arn,
6262
module.pdm_dynamodb_table.dynamodb_table_arn,
63-
module.pdm-document-store.bucket_arn
63+
module.pdm-document-store.bucket_arn,
64+
module.core_dynamodb_table.dynamodb_table_arn,
6465
]
6566
}
6667

infrastructure/buckets.tf

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ module "ndr-lloyd-george-store" {
5151
access_logs_enabled = local.is_production
5252
access_logs_bucket_id = local.access_logs_bucket_id
5353
cloudfront_enabled = true
54-
cloudfront_arn = module.cloudfront-distribution-lg.cloudfront_arn
54+
cloudfront_arn = aws_cloudfront_distribution.s3_presign_mask.arn
5555
bucket_name = var.lloyd_george_bucket_name
5656
enable_bucket_versioning = true
5757
environment = var.environment
@@ -122,6 +122,8 @@ module "ndr-bulk-staging-store" {
122122
bucket_name = var.staging_store_bucket_name
123123
enable_cors_configuration = true
124124
enable_bucket_versioning = true
125+
cloudfront_arn = aws_cloudfront_distribution.s3_presign_mask.arn
126+
cloudfront_enabled = true
125127
environment = var.environment
126128
owner = var.owner
127129
force_destroy = local.is_force_destroy
@@ -167,7 +169,7 @@ module "ndr-document-pending-review-store" {
167169
enable_bucket_versioning = true
168170
force_destroy = local.is_force_destroy
169171
cloudfront_enabled = true
170-
cloudfront_arn = module.cloudfront-distribution-lg.cloudfront_arn
172+
cloudfront_arn = aws_cloudfront_distribution.s3_presign_mask.arn
171173
enable_cors_configuration = true
172174
cors_rules = [
173175
{
@@ -233,6 +235,18 @@ resource "aws_s3_bucket_lifecycle_configuration" "staging-store-lifecycle-rules"
233235
prefix = "user_upload/"
234236
}
235237
}
238+
rule {
239+
id = "Delete objects in review folder that have existed for 24 hours"
240+
status = "Enabled"
241+
242+
expiration {
243+
days = 1
244+
}
245+
246+
filter {
247+
prefix = "review/"
248+
}
249+
}
236250
rule {
237251
id = "default-to-intelligent-tiering"
238252
status = "Enabled"
@@ -281,6 +295,17 @@ resource "aws_s3_bucket_lifecycle_configuration" "ndr_document_pending_review_st
281295
}
282296
filter {}
283297
}
298+
rule {
299+
id = "remove-delete-markers-after-42-days"
300+
status = "Enabled"
301+
expiration {
302+
expired_object_delete_marker = true
303+
}
304+
noncurrent_version_expiration {
305+
noncurrent_days = 42
306+
}
307+
filter {}
308+
}
284309
}
285310

286311
# Logging Buckets

infrastructure/cloudfront.tf

Lines changed: 146 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
locals {
2+
# required by USA-based CI pipeline runners to run smoke tests
3+
allow_us_comms = !local.is_production
4+
}
5+
6+
resource "aws_cloudfront_origin_access_control" "s3" {
7+
name = "${terraform.workspace}_cloudfront_s3_oac_policy"
8+
description = "CloudFront S3 OAC"
9+
origin_access_control_origin_type = "s3"
10+
signing_behavior = "never"
11+
signing_protocol = "sigv4"
12+
}
13+
114
module "cloudfront_firewall_waf_v2" {
215
source = "./modules/firewall_waf_v2"
316
cloudfront_acl = true
@@ -8,16 +21,136 @@ module "cloudfront_firewall_waf_v2" {
821
providers = { aws = aws.us_east_1 }
922
}
1023

11-
module "cloudfront-distribution-lg" {
12-
source = "./modules/cloudfront"
13-
bucket_domain_name = module.ndr-lloyd-george-store.bucket_regional_domain_name
14-
bucket_id = module.ndr-lloyd-george-store.bucket_id
15-
qualifed_arn = module.edge-presign-lambda.qualified_arn
16-
depends_on = [module.edge-presign-lambda.qualified_arn, module.ndr-lloyd-george-store.bucket_id, module.ndr-lloyd-george-store.bucket_domain_name, module.ndr-document-pending-review-store.bucket_id, module.ndr-document-pending-review-store.bucket_domain_name]
17-
web_acl_id = try(module.cloudfront_firewall_waf_v2[0].arn, "")
18-
has_secondary_bucket = local.is_production ? false : true
19-
secondary_bucket_domain_name = module.ndr-document-pending-review-store.bucket_regional_domain_name
20-
secondary_bucket_id = module.ndr-document-pending-review-store.bucket_id
21-
secondary_bucket_path_pattern = "/review/*"
22-
log_bucket_id = local.access_logs_bucket_id
23-
}
24+
resource "aws_cloudfront_distribution" "s3_presign_mask" {
25+
price_class = "PriceClass_100"
26+
27+
origin {
28+
domain_name = module.ndr-lloyd-george-store.bucket_regional_domain_name
29+
origin_id = module.ndr-lloyd-george-store.bucket_id
30+
origin_access_control_id = aws_cloudfront_origin_access_control.s3.id
31+
}
32+
enabled = true
33+
is_ipv6_enabled = true
34+
35+
default_cache_behavior {
36+
allowed_methods = ["HEAD", "GET", "OPTIONS"]
37+
cached_methods = ["HEAD", "GET", "OPTIONS"]
38+
target_origin_id = module.ndr-lloyd-george-store.bucket_id
39+
viewer_protocol_policy = "redirect-to-https"
40+
cache_policy_id = aws_cloudfront_cache_policy.nocache.id
41+
origin_request_policy_id = aws_cloudfront_origin_request_policy.viewer.id
42+
43+
lambda_function_association {
44+
event_type = "origin-request"
45+
lambda_arn = module.edge-presign-lambda.qualified_arn
46+
}
47+
}
48+
49+
origin {
50+
domain_name = module.ndr-document-pending-review-store.bucket_regional_domain_name
51+
origin_id = module.ndr-document-pending-review-store.bucket_id
52+
origin_access_control_id = aws_cloudfront_origin_access_control.s3.id
53+
}
54+
55+
ordered_cache_behavior {
56+
allowed_methods = ["HEAD", "GET", "OPTIONS"]
57+
cached_methods = ["HEAD", "GET", "OPTIONS"]
58+
path_pattern = "/review/*"
59+
target_origin_id = module.ndr-document-pending-review-store.bucket_id
60+
viewer_protocol_policy = "redirect-to-https"
61+
cache_policy_id = aws_cloudfront_cache_policy.nocache.id
62+
origin_request_policy_id = aws_cloudfront_origin_request_policy.viewer.id
63+
64+
lambda_function_association {
65+
event_type = "origin-request"
66+
lambda_arn = module.edge-presign-lambda.qualified_arn
67+
}
68+
}
69+
70+
origin {
71+
domain_name = module.ndr-bulk-staging-store.bucket_regional_domain_name
72+
origin_id = module.ndr-bulk-staging-store.bucket_id
73+
origin_access_control_id = aws_cloudfront_origin_access_control.s3.id
74+
}
75+
76+
ordered_cache_behavior {
77+
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
78+
cached_methods = ["HEAD", "GET", "OPTIONS"]
79+
path_pattern = "/upload/*"
80+
target_origin_id = module.ndr-bulk-staging-store.bucket_id
81+
viewer_protocol_policy = "redirect-to-https"
82+
cache_policy_id = aws_cloudfront_cache_policy.nocache.id
83+
origin_request_policy_id = aws_cloudfront_origin_request_policy.viewer.id
84+
85+
lambda_function_association {
86+
event_type = "origin-request"
87+
lambda_arn = module.edge-presign-lambda.qualified_arn
88+
}
89+
}
90+
91+
viewer_certificate {
92+
cloudfront_default_certificate = true
93+
}
94+
95+
restrictions {
96+
geo_restriction {
97+
restriction_type = "whitelist"
98+
locations = local.allow_us_comms ? ["GB", "US"] : ["GB"]
99+
}
100+
}
101+
102+
web_acl_id = try(module.cloudfront_firewall_waf_v2[0].arn, "")
103+
}
104+
105+
resource "aws_cloudfront_origin_request_policy" "viewer" {
106+
name = "${terraform.workspace}_BlockQueriesAndAllowViewer"
107+
108+
query_strings_config {
109+
query_string_behavior = "whitelist"
110+
query_strings {
111+
items = [
112+
"X-Amz-Algorithm",
113+
"X-Amz-Credential",
114+
"X-Amz-Date",
115+
"X-Amz-Expires",
116+
"X-Amz-SignedHeaders",
117+
"X-Amz-Signature",
118+
"X-Amz-Security-Token"
119+
]
120+
}
121+
}
122+
123+
headers_config {
124+
header_behavior = "whitelist"
125+
headers {
126+
items = [
127+
"Host",
128+
"CloudFront-Viewer-Country",
129+
"X-Forwarded-For"
130+
]
131+
}
132+
}
133+
134+
cookies_config {
135+
cookie_behavior = "none"
136+
}
137+
}
138+
139+
resource "aws_cloudfront_cache_policy" "nocache" {
140+
name = "${terraform.workspace}_nocache_policy"
141+
default_ttl = 0
142+
max_ttl = 0
143+
min_ttl = 0
144+
145+
parameters_in_cache_key_and_forwarded_to_origin {
146+
cookies_config {
147+
cookie_behavior = "none"
148+
}
149+
headers_config {
150+
header_behavior = "none"
151+
}
152+
query_strings_config {
153+
query_string_behavior = "none"
154+
}
155+
}
156+
}

infrastructure/dev.tfvars

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@ cloud_security_email_param_environment = "dev"
1212
apim_environment = "internal-dev."
1313

1414
kms_deletion_window = 7
15+
16+
ssh_key_management_dry_run = true

infrastructure/dynamo_db_review.tf

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
module "document_review_dynamodb_table" {
2-
count = local.is_production ? 0 : 1
1+
module "document_upload_review_dynamodb_table" {
32
source = "./modules/dynamo_db"
43
table_name = var.document_review_table_name
54
hash_key = "ID"
5+
sort_key = "Version"
66
deletion_protection_enabled = local.is_production
77
stream_enabled = false
8-
ttl_enabled = true
9-
ttl_attribute_name = "TTL"
8+
ttl_enabled = false
109
point_in_time_recovery_enabled = !local.is_sandbox
1110

1211
attributes = [
@@ -36,11 +35,15 @@ module "document_review_dynamodb_table" {
3635
},
3736
{
3837
name = "ReviewDate"
39-
type = "S"
38+
type = "N"
4039
},
4140
{
4241
name = "UploadDate"
4342
type = "N"
43+
},
44+
{
45+
name = "Version"
46+
type = "N"
4447
}
4548

4649
]

0 commit comments

Comments
 (0)