Skip to content

Commit 60ff384

Browse files
CCM-13765: Store Files for Virus Scanning (#185)
* CCM-13765: Added lambda, queue and event listener * CCM-13765: Fix terraform error * CCM-13765: Added component test * CCM-13765: Fix linting * CCM-13765: Fix linting * CCM-13765: Fix component test * CCM-13765: Updated s3 helpers * CCM-13765: Updated utils to match other PR and fix trivy * CCM-13765: Fix typecheck * CCM-13765: Fix sqs queue name * CCM-13765: Fix circular dependency check * Update infrastructure/terraform/components/dl/locals.tf Updating how unscanned_files_bucket is referenced due to it being a remote state bucket. Co-authored-by: Aiden Vaines <54067008+aidenvaines-cgi@users.noreply.github.com> * CCM-13765: Fix broken locals.tf file --------- Co-authored-by: Aiden Vaines <54067008+aidenvaines-cgi@users.noreply.github.com>
1 parent c312f06 commit 60ff384

34 files changed

Lines changed: 1957 additions & 169 deletions

infrastructure/terraform/components/dl/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ No requirements.
4242
| Name | Source | Version |
4343
|------|--------|---------|
4444
| <a name="module_core_notifier"></a> [core\_notifier](#module\_core\_notifier) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
45+
| <a name="module_file_scanner"></a> [file\_scanner](#module\_file\_scanner) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
4546
| <a name="module_kms"></a> [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-kms.zip | n/a |
4647
| <a name="module_lambda_apim_key_generation"></a> [lambda\_apim\_key\_generation](#module\_lambda\_apim\_key\_generation) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
4748
| <a name="module_lambda_lambda_apim_refresh_token"></a> [lambda\_lambda\_apim\_refresh\_token](#module\_lambda\_lambda\_apim\_refresh\_token) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
@@ -65,6 +66,7 @@ No requirements.
6566
| <a name="module_sqs_pdm_uploader"></a> [sqs\_pdm\_uploader](#module\_sqs\_pdm\_uploader) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
6667
| <a name="module_sqs_print_analyser"></a> [sqs\_print\_analyser](#module\_sqs\_print\_analyser) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.30/terraform-sqs.zip | n/a |
6768
| <a name="module_sqs_print_status_handler"></a> [sqs\_print\_status\_handler](#module\_sqs\_print\_status\_handler) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.30/terraform-sqs.zip | n/a |
69+
| <a name="module_sqs_scanner"></a> [sqs\_scanner](#module\_sqs\_scanner) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
6870
| <a name="module_sqs_ttl"></a> [sqs\_ttl](#module\_sqs\_ttl) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
6971
| <a name="module_sqs_ttl_handle_expiry_errors"></a> [sqs\_ttl\_handle\_expiry\_errors](#module\_sqs\_ttl\_handle\_expiry\_errors) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a |
7072
| <a name="module_ttl_create"></a> [ttl\_create](#module\_ttl\_create) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a |
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
resource "aws_cloudwatch_event_rule" "item_dequeued" {
2+
name = "${local.csi}-item-dequeued"
3+
description = "Queue item dequeued event rule"
4+
event_bus_name = aws_cloudwatch_event_bus.main.name
5+
6+
event_pattern = jsonencode({
7+
"detail" : {
8+
"type" : [
9+
"uk.nhs.notify.digital.letters.queue.item.dequeued.v1"
10+
]
11+
}
12+
})
13+
}
14+
15+
resource "aws_cloudwatch_event_target" "item_dequeued_scanner" {
16+
rule = aws_cloudwatch_event_rule.item_dequeued.name
17+
arn = module.sqs_scanner.sqs_queue_arn
18+
event_bus_name = aws_cloudwatch_event_bus.main.name
19+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resource "aws_lambda_event_source_mapping" "file_scanner" {
2+
event_source_arn = module.sqs_scanner.sqs_queue_arn
3+
function_name = module.file_scanner.function_name
4+
batch_size = 10
5+
maximum_batching_window_in_seconds = 5
6+
function_response_types = ["ReportBatchItemFailures"]
7+
}

infrastructure/terraform/components/dl/locals.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ locals {
55
apim_api_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/api_key"
66
apim_private_key_ssm_parameter_name = "/${var.component}/${var.environment}/apim/private_key"
77
apim_keystore_s3_bucket = "nhs-${var.aws_account_id}-${var.region}-${var.environment}-${var.component}-static-assets"
8+
unscanned_files_bucket = local.acct.additional_s3_buckets["digital-letters_unscanned-files"]["id"]
89
ssm_mesh_prefix = "/${var.component}/${var.environment}/mesh"
910
mock_mesh_endpoint = "s3://${module.s3bucket_non_pii_data.bucket}/mock-mesh"
1011
root_domain_name = "${var.environment}.${local.acct.route53_zone_names["digital-letters"]}"
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
module "file_scanner" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip"
3+
4+
function_name = "file-scanner"
5+
description = "A function for extracting PDFs from DocumentReference and storing in UnscannedFiles bucket for virus scanning"
6+
7+
aws_account_id = var.aws_account_id
8+
component = local.component
9+
environment = var.environment
10+
project = var.project
11+
region = var.region
12+
group = var.group
13+
14+
log_retention_in_days = var.log_retention_in_days
15+
kms_key_arn = module.kms.key_arn
16+
17+
iam_policy_document = {
18+
body = data.aws_iam_policy_document.file_scanner_lambda.json
19+
}
20+
21+
function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"]
22+
function_code_base_path = local.aws_lambda_functions_dir_path
23+
function_code_dir = "file-scanner-lambda/dist"
24+
function_include_common = true
25+
handler_function_name = "handler"
26+
runtime = "nodejs22.x"
27+
memory = 512
28+
timeout = 60
29+
log_level = var.log_level
30+
31+
force_lambda_code_deploy = var.force_lambda_code_deploy
32+
enable_lambda_insights = false
33+
34+
log_destination_arn = local.log_destination_arn
35+
log_subscription_role_arn = local.acct.log_subscription_role_arn
36+
37+
lambda_env_vars = {
38+
"DOCUMENT_REFERENCE_BUCKET" = module.s3bucket_pii_data.bucket
39+
"UNSCANNED_FILES_BUCKET" = local.unscanned_files_bucket
40+
"UNSCANNED_FILES_PATH_PREFIX" = var.environment
41+
"EVENT_PUBLISHER_EVENT_BUS_ARN" = aws_cloudwatch_event_bus.main.arn
42+
"EVENT_PUBLISHER_DLQ_URL" = module.sqs_event_publisher_errors.sqs_queue_url
43+
}
44+
}
45+
46+
data "aws_iam_policy_document" "file_scanner_lambda" {
47+
statement {
48+
sid = "ReadDocumentReferenceBucket"
49+
effect = "Allow"
50+
51+
actions = [
52+
"s3:GetObject",
53+
"s3:ListBucket",
54+
]
55+
56+
resources = [
57+
module.s3bucket_pii_data.arn,
58+
"${module.s3bucket_pii_data.arn}/*",
59+
]
60+
}
61+
62+
statement {
63+
sid = "WriteUnscannedFilesBucket"
64+
effect = "Allow"
65+
66+
actions = [
67+
"s3:PutObject",
68+
]
69+
70+
resources = [
71+
"arn:aws:s3:::${local.unscanned_files_bucket}/*",
72+
]
73+
}
74+
75+
statement {
76+
sid = "PutEvents"
77+
effect = "Allow"
78+
79+
actions = [
80+
"events:PutEvents",
81+
]
82+
83+
resources = [
84+
aws_cloudwatch_event_bus.main.arn,
85+
]
86+
}
87+
88+
statement {
89+
sid = "SQSPermissionsDLQs"
90+
effect = "Allow"
91+
92+
actions = [
93+
"sqs:SendMessage",
94+
"sqs:SendMessageBatch",
95+
]
96+
97+
resources = [
98+
module.sqs_event_publisher_errors.sqs_queue_arn,
99+
]
100+
}
101+
102+
statement {
103+
sid = "SQSPermissionsScannerQueue"
104+
effect = "Allow"
105+
106+
actions = [
107+
"sqs:ReceiveMessage",
108+
"sqs:DeleteMessage",
109+
"sqs:GetQueueAttributes",
110+
"sqs:GetQueueUrl",
111+
]
112+
113+
resources = [
114+
module.sqs_scanner.sqs_queue_arn,
115+
]
116+
}
117+
118+
statement {
119+
sid = "KMSPermissions"
120+
effect = "Allow"
121+
122+
actions = [
123+
"kms:Decrypt",
124+
"kms:GenerateDataKey",
125+
]
126+
127+
resources = [
128+
module.kms.key_arn,
129+
]
130+
}
131+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
module "sqs_scanner" {
2+
source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip"
3+
4+
aws_account_id = var.aws_account_id
5+
component = local.component
6+
environment = var.environment
7+
project = var.project
8+
region = var.region
9+
name = "file-scanner"
10+
sqs_kms_key_arn = module.kms.key_arn
11+
visibility_timeout_seconds = 60
12+
delay_seconds = 0
13+
create_dlq = true
14+
sqs_policy_overload = data.aws_iam_policy_document.sqs_scanner.json
15+
}
16+
17+
data "aws_iam_policy_document" "sqs_scanner" {
18+
statement {
19+
sid = "AllowEventBridgeToSendMessage"
20+
effect = "Allow"
21+
22+
principals {
23+
type = "Service"
24+
identifiers = ["events.amazonaws.com"]
25+
}
26+
27+
actions = [
28+
"sqs:SendMessage"
29+
]
30+
31+
resources = [
32+
"arn:aws:sqs:${var.region}:${var.aws_account_id}:${local.csi}-file-scanner-queue"
33+
]
34+
35+
condition {
36+
test = "ArnEquals"
37+
variable = "aws:SourceArn"
38+
values = [aws_cloudwatch_event_rule.item_dequeued.arn]
39+
}
40+
}
41+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { baseJestConfig } from '../../jest.config.base';
2+
3+
const config = baseJestConfig;
4+
5+
export default config;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"dependencies": {
3+
"@aws-sdk/client-s3": "^3.908.0",
4+
"aws-lambda": "^1.0.7",
5+
"digital-letters-events": "^0.0.1",
6+
"utils": "^0.0.1"
7+
},
8+
"devDependencies": {
9+
"@tsconfig/node22": "^22.0.2",
10+
"@types/aws-lambda": "^8.10.155",
11+
"@types/jest": "^29.5.14",
12+
"jest": "^29.7.0",
13+
"jest-mock-extended": "^3.0.7",
14+
"typescript": "^5.9.3"
15+
},
16+
"name": "nhs-notify-digital-letters-file-scanner-lambda",
17+
"private": true,
18+
"scripts": {
19+
"lambda-build": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts",
20+
"lint": "eslint .",
21+
"lint:fix": "eslint . --fix",
22+
"test:unit": "jest",
23+
"typecheck": "tsc --noEmit"
24+
},
25+
"version": "0.0.1"
26+
}

0 commit comments

Comments
 (0)