Skip to content

Commit 14d6a5e

Browse files
authored
ELI-331: Mask PII/GDPR info (#239)
* ELI-331: Mask PII/GDPR info * ELI-331: Fix formatting * ELI-331: Fix format and lint
1 parent 5889dcd commit 14d6a5e

3 files changed

Lines changed: 100 additions & 4 deletions

File tree

infrastructure/modules/api_gateway/cloudwatch.tf

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,96 @@ resource "aws_cloudwatch_log_group" "api_gateway" {
88
prevent_destroy = false
99
}
1010
}
11+
12+
resource "aws_cloudwatch_log_data_protection_policy" "api_gateway_data_protection" {
13+
log_group_name = aws_cloudwatch_log_group.api_gateway.name
14+
policy_document = jsonencode({
15+
Name = "data-protection-policy"
16+
Version = "2021-06-01"
17+
Statement = [
18+
{
19+
Sid = "MaskSensitiveData"
20+
Effect = "Deny"
21+
Principal = { "AWS" : "*" }
22+
Action = "cloudwatch:PutLogEvents"
23+
Resource = "*"
24+
DataIdentifier = [
25+
"arn:aws:dataprotection::aws:data-identifier/DateOfBirth",
26+
"arn:aws:dataprotection::aws:data-identifier/UkPostcode",
27+
"arn:aws:dataprotection::aws:data-identifier/Custom:UkPostcodeSector",
28+
"arn:aws:dataprotection::aws:data-identifier/Custom:GpPracticeCode",
29+
"arn:aws:dataprotection::aws:data-identifier/Custom:13QFlag",
30+
"arn:aws:dataprotection::aws:data-identifier/Custom:CareHomeFlag",
31+
"arn:aws:dataprotection::aws:data-identifier/Custom:DEFlag",
32+
"arn:aws:dataprotection::aws:data-identifier/Custom:RemovalReasonCode",
33+
"arn:aws:dataprotection::aws:data-identifier/Custom:ValidDosesCount",
34+
"arn:aws:dataprotection::aws:data-identifier/Custom:InvalidDosesCount",
35+
"arn:aws:dataprotection::aws:data-identifier/Custom:LastSuccessfulDate",
36+
"arn:aws:dataprotection::aws:data-identifier/Custom:LastValidDoseDate",
37+
"arn:aws:dataprotection::aws:data-identifier/Custom:CohortLabel"
38+
39+
]
40+
Operation = {
41+
"cloudwatch:Mask" = {}
42+
}
43+
},
44+
]
45+
CustomDataIdentifier = [
46+
{
47+
Name = "UkPostcodeSector"
48+
Regex = "[A-Z]{1,2}[0-9R-9][0A-Z]? ?[0-9]"
49+
Severity = "High"
50+
},
51+
{
52+
Name = "GpPracticeCode"
53+
Regex = "GP_PRACTICE[\\s\\\"':=]*([A-Z][0-9]{5})"
54+
Severity = "High"
55+
},
56+
{
57+
Name = "13QFlag"
58+
Regex = "13Q_FLAG[\\s\\\"':=]*[YN]"
59+
Severity = "High"
60+
},
61+
{
62+
Name = "CareHomeFlag"
63+
Regex = "CARE_HOME_FLAG[\\s\\\"':=]*[YN]"
64+
Severity = "High"
65+
},
66+
{
67+
Name = "DEFlag"
68+
Regex = "DE_FLAG[\\s\\\"':=]*[YN]"
69+
Severity = "High"
70+
},
71+
{
72+
Name = "RemovalReasonCode"
73+
Regex = "REMOVAL_REASON_CODE[\\s\\\"':=]*([A-Z]{3})"
74+
Severity = "High"
75+
},
76+
{
77+
Name = "ValidDosesCount"
78+
Regex = "VALID_DOSES_COUNT[\\s\\\"':=]*([0-9]{1,2}|100)"
79+
Severity = "High"
80+
},
81+
{
82+
Name = "InvalidDosesCount"
83+
Regex = "INVALID_DOSES_COUNT[\\s\\\"':=]*([0-9]{1,2}|100)"
84+
Severity = "High"
85+
},
86+
{
87+
Name = "LastSuccessfulDate"
88+
Regex = "LAST_SUCCESSFUL_DATE[\\s\\\"':=]*([0-9]{8})"
89+
Severity = "High"
90+
},
91+
{
92+
Name = "LastValidDoseDate"
93+
Regex = "LAST_VALID_DOSE_DATE[\\s\\\"':=]*([0-9]{8})"
94+
Severity = "High"
95+
},
96+
{
97+
Name = "CohortLabel"
98+
Regex = "COHORT_LABEL[\\s\\\"':=]*([A-Za-z0-9_ -]{1,100})"
99+
Severity = "High"
100+
}
101+
]
102+
})
103+
}

src/eligibility_signposting_api/services/eligibility_services.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ def get_eligibility_status(
5151
"nhs_number": nhs_number,
5252
},
5353
)
54+
55+
if person_data and person_data[0] and campaign_configs and campaign_configs[0]:
56+
logger.info("Test data masking person data: %r", person_data[0])
57+
logger.info(
58+
"Test data masking campaign config data: %r", campaign_configs[0].model_dump(by_alias=True)
59+
)
60+
5461
except NotFoundError as e:
5562
raise UnknownPersonError from e
5663
else:

tests/integration/lambda/test_app_running_as_lambda.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import base64
21
import json
32
import logging
43
from http import HTTPStatus
@@ -69,7 +68,6 @@ def test_install_and_call_lambda_flask(
6968
Payload=json.dumps(request_payload),
7069
LogType="Tail",
7170
)
72-
log_output = base64.b64decode(response["LogResult"]).decode("utf-8")
7371

7472
# Then
7573
assert_that(response, has_entries(StatusCode=HTTPStatus.OK))
@@ -80,8 +78,6 @@ def test_install_and_call_lambda_flask(
8078
has_entries(statusCode=HTTPStatus.OK, body=is_json_that(has_key("processedSuggestions"))),
8179
)
8280

83-
assert_that(log_output, contains_string("person_data"))
84-
8581

8682
def test_install_and_call_flask_lambda_over_http(
8783
persisted_person: NHSNumber,

0 commit comments

Comments
 (0)