Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions infrastructure/modules/lambda/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ resource "aws_lambda_function" "eligibility_signposting_lambda" {
LOG_LEVEL = var.log_level
ENABLE_XRAY_PATCHING = var.enable_xray_patching
API_DOMAIN_NAME = var.api_domain_name
HASHING_SECRET_NAME = var.hashing_secret_name
}
}

Expand Down
5 changes: 5 additions & 0 deletions infrastructure/modules/lambda/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,8 @@ variable "api_domain_name" {
description = "api domain name - env variable for status endpoint response"
type = string
}

variable "hashing_secret_name" {
description = "hashing secret name"
type = string
}
8 changes: 8 additions & 0 deletions infrastructure/modules/secrets_manager/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
output "aws_hashing_secret_arn" {
value = aws_secretsmanager_secret.hashing_secret.arn
}

output "aws_hashing_secret_name" {
value = aws_secretsmanager_secret.hashing_secret.name
}

9 changes: 0 additions & 9 deletions infrastructure/modules/secrets_manager/secrets_manager.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,6 @@ resource "aws_secretsmanager_secret" "hashing_secret" {
}
}

# Initial secrets
resource "aws_secretsmanager_secret_version" "hashing_secrets_test" {
secret_id = aws_secretsmanager_secret.hashing_secret.id
secret_string = "initial_secret"
lifecycle {
ignore_changes = [secret_string]
}
}

# Resource-based policy attached to the secret
resource "aws_secretsmanager_secret_policy" "hashing_secret_policy" {
secret_arn = aws_secretsmanager_secret.hashing_secret.arn
Expand Down
4 changes: 2 additions & 2 deletions infrastructure/modules/secrets_manager/variables.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
variable "external_write_access_role_arn" {
description = "Arn of the external write access role to provide secret manager access"
type = string
description = "List of ARNs for external write access roles"
type = list(string)
}

variable "eligibility_lambda_role_arn" {
Expand Down
31 changes: 31 additions & 0 deletions infrastructure/stacks/api-layer/iam_policies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -530,3 +530,34 @@ resource "aws_iam_role_policy" "external_audit_kms_access_policy" {
role = aws_iam_role.write_access_role[count.index].id
policy = data.aws_iam_policy_document.external_role_s3_audit_kms_access_policy.json
}

# IAM policy document for Lambda secret access
data "aws_iam_policy_document" "secrets_access_policy" {
statement {
effect = "Allow"

actions = [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret",
]

resources = [
module.secrets_manager.aws_hashing_secret_arn
]
}
}

# Attach secret read policy to Lambda role
resource "aws_iam_role_policy" "lambda_secret_read_policy_attachment" {
name = "LambdaSecretReadAccess"
role = aws_iam_role.eligibility_lambda_role.id
policy = data.aws_iam_policy_document.secrets_access_policy.json
}

# Attach secret read policy to external write role
resource "aws_iam_role_policy" "external_secret_read_policy_attachment" {
count = length(aws_iam_role.write_access_role)
name = "ExternalSecretReadAccess"
role = aws_iam_role.write_access_role[count.index].id
policy = data.aws_iam_policy_document.secrets_access_policy.json
}
1 change: 1 addition & 0 deletions infrastructure/stacks/api-layer/lambda.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module "eligibility_signposting_lambda_function" {
eligibility_rules_bucket_name = module.s3_rules_bucket.storage_bucket_name
eligibility_status_table_name = module.eligibility_status_table.table_name
kinesis_audit_stream_to_s3_name = module.eligibility_audit_firehose_delivery_stream.firehose_stream_name
hashing_secret_name = module.secrets_manager.aws_hashing_secret_name
lambda_insights_extension_version = 38
log_level = "INFO"
enable_xray_patching = "true"
Expand Down
11 changes: 5 additions & 6 deletions infrastructure/stacks/api-layer/secrets_manager.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
module "secrets_manager" {
source = "../../modules/secrets_manager"
count = length(aws_iam_role.write_access_role)
external_write_access_role_arn = aws_iam_role.write_access_role[count.index].arn
environment = var.environment
stack_name = local.stack_name
workspace = terraform.workspace
eligibility_lambda_role_arn = aws_iam_role.eligibility_lambda_role.arn
external_write_access_role_arn = aws_iam_role.write_access_role[*].arn
environment = var.environment
stack_name = local.stack_name
workspace = terraform.workspace
eligibility_lambda_role_arn = aws_iam_role.eligibility_lambda_role.arn
}
28 changes: 15 additions & 13 deletions src/eligibility_signposting_api/repos/person_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,28 +55,30 @@ def get_person_record(self, nhs_hash: str | None) -> Any:
return None

def get_eligibility_data(self, nhs_number: NHSNumber) -> Person:
# AWSCURRENT secret
nhs_hash = self._hashing_service.hash_with_current_secret(nhs_number)
items = self.get_person_record(nhs_hash)
# Hash using AWSCURRENT secret and fetch items
items = None
nhs_hashed_with_current = self._hashing_service.hash_with_current_secret(nhs_number)
if nhs_hashed_with_current:
items = self.get_person_record(nhs_hashed_with_current)
if not items:
logger.warning("The AWSCURRENT secret was tried, but no person record was found")

if not items:
logger.error("No person record found for hashed nhs_number using secret AWSCURRENT")

# AWSPREVIOUS secret
nhs_hash = self._hashing_service.hash_with_previous_secret(nhs_number)

if nhs_hash is not None:
items = self.get_person_record(nhs_hash)
# Hash using AWSPREVIOUS secret and fetch items
nhs_hashed_with_previous = self._hashing_service.hash_with_previous_secret(nhs_number)
if nhs_hashed_with_previous:
items = self.get_person_record(nhs_hashed_with_previous)
if not items:
logger.error("No person record found for hashed nhs_number using secret AWSPREVIOUS")
logger.error("The AWSPREVIOUS secret was also tried, but no person record was found")
message = "Person not found after checking AWSCURRENT and AWSPREVIOUS."
raise NotFoundError(message)
else:
# fallback not hashed NHS number
# fallback : Fetch using Raw NHS number
items = self.get_person_record(nhs_number)
if not items:
logger.error("No person record found for not hashed nhs_number")
logger.error("The not hashed nhs number was also tried, but no person record was found")
message = "Person not found after checking AWSCURRENT, AWSPREVIOUS, and not hashed NHS numbers."
raise NotFoundError(message)

logger.info("Person record found")
return Person(data=items)
2 changes: 1 addition & 1 deletion src/eligibility_signposting_api/repos/secret_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def _get_secret_by_stage(self, secret_name: str, stage: str) -> dict[str, str]:
return {stage: response["SecretString"]}

except ClientError:
logger.exception("Failed to get secret %s at stage %s", secret_name, stage)
logger.warning("Failed to get secret %s at stage %s", secret_name, stage)
return {}

def get_secret_current(self, secret_name: str) -> dict[str, str]:
Expand Down
Loading