Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
3b20629
eli-238 CKV2_AWS_71 - removing wildcard domain names from AWS ACM cer…
eddalmond1 May 30, 2025
7070384
eli-238 - CKV_AWS_231 - blocking ingress from 0.0.0.0/0 to port 3389
eddalmond1 May 30, 2025
3a923d1
eli-238 CKV2_AWS_53 - Add request validation to API Gateway methods
eddalmond1 May 30, 2025
0dbb1a0
eli-238 CKV_AWS_59 - AWS API gateway methods are publicly accessible
eddalmond1 May 30, 2025
2192820
eli-238 CKV2_AWS_51 - AWS API Gateway endpoints without client certif…
eddalmond1 May 30, 2025
59bc325
eli-238 linting fix
eddalmond1 May 30, 2025
64a8d81
eli-238 amending checkov skip comments
eddalmond1 May 30, 2025
79f5d85
eli-238 adding skips for CKV_AWS_120, CKV_AWS_225 - as we're not usin…
eddalmond1 May 30, 2025
e427ccb
eli-238 changing position of Checkov skip to see if this gets picked up
eddalmond1 May 30, 2025
d57cc32
eli-238 fixing skips
eddalmond1 May 31, 2025
967b490
eli-238 CKV_AWS_338 - amending cloudwatch log group retention to 365 …
eddalmond1 May 31, 2025
e383801
eli-238 CKV_AWS_111 restricted API gateway to only be able to log in …
eddalmond1 May 31, 2025
e7a6028
eli-238 CKV_AWS_300 - s3 multipart upload failure handling
eddalmond1 Jun 2, 2025
38a34dc
eli-238 amending checkov codes used in skips
eddalmond1 Jun 2, 2025
63bf6f6
eli-238 CKV_AWS_28 - adding point in time backup of DynamoDB for Prod…
eddalmond1 Jun 2, 2025
bf14e96
eli-238 CKV_AWS_28 adding skip as we only want point in time recovery…
eddalmond1 Jun 2, 2025
496c29f
eli-238 CKV_AWS_50 adding x-ray tracing for lambda
eddalmond1 Jun 2, 2025
4be4406
eli-238 CKV_AWS_116 we've not configured a deadletter queue yet for l…
eddalmond1 Jun 2, 2025
fc945ae
eli-238 CKV_AWS_115: Concurrent execution limit will be set at APIM l…
eddalmond1 Jun 2, 2025
a1f7f65
eli-238 CKV_AWS_173: added KMS encryption of Lambda environment varia…
eddalmond1 Jun 2, 2025
9033725
eli-238 CKV_AWS_272 -0 skipping code signing for lambda, but noted on…
eddalmond1 Jun 2, 2025
a2dfe4f
eli-238 CKV_AWS_158 - adding KMS encryption using lambda cmk
eddalmond1 Jun 2, 2025
f5a8613
eli-238 CKV_AWS_144: We don't want to replicate outside our region
eddalmond1 Jun 2, 2025
18e059b
eli-238 CKV2_AWS_62: We won't enable event notifications for this buc…
eddalmond1 Jun 2, 2025
0116a2b
eli-238 CKV_AWS_145 - enabling KMS encryption for audit log buckets
eddalmond1 Jun 2, 2025
ff81010
eli-238 CKV_AWS_21: Versioning not needed given short lifecycle of logs
eddalmond1 Jun 3, 2025
f03f131
eli-238 CKV2_AWS_64 - adding KMS policies for KMS keys - specifically…
eddalmond1 Jun 3, 2025
620f1ee
eli-238 CKV2_AWS_64 - KMS key for VPC flow logs, plus additional perm…
eddalmond1 Jun 3, 2025
970189f
eli-238 skipping checks on github and developer role policies
eddalmond1 Jun 3, 2025
975bcc7
eli-238 CKV_AWS_111 - restricting IAMUserPermissions on kms keys to j…
eddalmond1 Jun 3, 2025
bdab8a5
eli-238 CKV_AWS_111 - limiting IAMS permissions to just the kms keys …
eddalmond1 Jun 3, 2025
8b7d9c1
Merge branch 'main' into feature/eja-eli-238-address-checkov-flagged-…
eddalmond1 Jun 3, 2025
de3d230
eli-238 setting checkov checks to now throw errors in CI/CD
eddalmond1 Jun 3, 2025
a6613b4
Merge branch 'main' into feature/eja-eli-238-address-checkov-flagged-…
eddalmond1 Jun 3, 2025
de084fe
eli-238 adding upload of checkov file to github
eddalmond1 Jun 3, 2025
9c04c8b
eli-238 bumping upload-artifact step to v4
eddalmond1 Jun 3, 2025
59bee59
Merge branch 'main' into feature/eja-eli-238-address-checkov-flagged-…
eddalmond1 Jun 4, 2025
b8d30c5
eli-238 adding associated rule for multipart uploads
eddalmond1 Jun 5, 2025
3faf948
Merge remote-tracking branch 'origin/main' into feature/eja-eli-238-a…
eddalmond1 Jun 5, 2025
0c63d71
eli-238 outputting kms key arns
eddalmond1 Jun 5, 2025
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
7 changes: 6 additions & 1 deletion .github/workflows/stage-1-commit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,14 @@ jobs:
uses: bridgecrewio/checkov-action@v12
with:
directory: infrastructure/
soft_fail: true
soft_fail: false
output_format: sarif
output_file_path: checkov-report.sarif
- name: Upload Checkov results to GitHub Security tab
uses: actions/upload-artifact@v4
with:
name: checkov_results
path: checkov-report.sarif
count-lines-of-code:
name: "Count lines of code"
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/modules/api_gateway/cloudwatch.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
resource "aws_cloudwatch_log_group" "api_gateway" {
name = "/aws/apigateway/${var.workspace}-${var.api_gateway_name}"
retention_in_days = 14
retention_in_days = 365
tags = var.tags
kms_key_id = aws_kms_key.api_gateway.arn

Expand Down
2 changes: 1 addition & 1 deletion infrastructure/modules/api_gateway/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ data "aws_iam_policy_document" "api_gateway_logging" {
"logs:GetLogEvents",
"logs:FilterLogEvents"
]
resources = ["*"]
resources = [aws_cloudwatch_log_group.api_gateway.arn]
}
}

Expand Down
4 changes: 4 additions & 0 deletions infrastructure/modules/api_gateway/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ output "logging_policy_attachment" {
output "iam_role_name" {
value = aws_iam_role.api_gateway.name
}

output "kms_key_arn" {
value = aws_kms_key.api_gateway.arn
}
1 change: 1 addition & 0 deletions infrastructure/modules/bootstrap/tfstate/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
18 changes: 18 additions & 0 deletions infrastructure/modules/bootstrap/tfstate/kms.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,21 @@ resource "aws_kms_alias" "terraform_state_bucket_cmk" {
name = "alias/${var.project_name}-tfstate_bucket_cmk"
target_key_id = aws_kms_key.terraform_state_bucket_cmk.key_id
}

resource "aws_kms_key_policy" "terraform_state_bucket_cmk" {
key_id = aws_kms_key.terraform_state_bucket_cmk.id
policy = data.aws_iam_policy_document.terraform_state_bucket_cmk.json
}

data "aws_iam_policy_document" "terraform_state_bucket_cmk" {
statement {
sid = "Enable IAM User Permissions for s3 buckets"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = ["kms:*"]
resources = [aws_kms_key.terraform_state_bucket_cmk.arn]
}
}
18 changes: 17 additions & 1 deletion infrastructure/modules/bootstrap/tfstate/s3.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Main state bucket
resource "aws_s3_bucket" "tfstate_bucket" {
#checkov:skip=CKV_AWS_144: We don't want to replicate outside our region
#checkov:skip=CKV2_AWS_62: We won't enable event notifications for this bucket, yet
bucket = "${var.project_name}-${var.environment}-tfstate"
tags = {
Stack = "Bootstrap"
Expand Down Expand Up @@ -95,6 +97,9 @@ resource "aws_s3_bucket_lifecycle_configuration" "tfstate_bucket" {
# Logging

resource "aws_s3_bucket" "tfstate_s3_access_logs" {
#checkov:skip=CKV_AWS_144: We don't want to replicate outside our region
#checkov:skip=CKV2_AWS_62: We won't enable event notifications for this bucket, yet
#checkov:skip=CKV_AWS_21: Versioning not needed given short lifecycle of logs
bucket = "${var.project_name}-${var.environment}-tfstate-access-logs"
}

Expand All @@ -109,7 +114,8 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "tfstate_s3_access

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.terraform_state_bucket_cmk.arn
}
}
}
Expand All @@ -131,6 +137,16 @@ resource "aws_s3_bucket_lifecycle_configuration" "tfstate_s3_access_logs_object_
noncurrent_days = var.log_retention_in_days
}
}
rule {
id = "StateBucketLogsMultipartUploadExpiration"
status = "Enabled"
filter {
prefix = ""
}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
}

resource "aws_s3_bucket_public_access_block" "s3logs" {
Expand Down
1 change: 1 addition & 0 deletions infrastructure/modules/dynamodb/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
5 changes: 5 additions & 0 deletions infrastructure/modules/dynamodb/dynamodb.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@ resource "aws_dynamodb_table" "dynamodb_table" {
kms_key_arn = aws_kms_key.dynamodb_cmk.arn
}

#checkov:skip=CKV_AWS_28: Point-in-time recovery is enabled only for production environments
point_in_time_recovery {
enabled = var.environment == "prod"
}

tags = var.tags
}
1 change: 1 addition & 0 deletions infrastructure/modules/lambda/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
18 changes: 18 additions & 0 deletions infrastructure/modules/lambda/kms.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,21 @@ resource "aws_kms_alias" "lambda_cmk" {
name = "alias/${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.lambda_func_name}-cmk"
target_key_id = aws_kms_key.lambda_cmk.key_id
}

resource "aws_kms_key_policy" "lambda_cmk" {
key_id = aws_kms_key.lambda_cmk.id
policy = data.aws_iam_policy_document.lambda_cmk.json
}

data "aws_iam_policy_document" "lambda_cmk" {
statement {
sid = "Enable IAM User Permissions for s3 buckets"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = ["kms:*"]
resources = [aws_kms_key.lambda_cmk.arn]
}
}
10 changes: 10 additions & 0 deletions infrastructure/modules/lambda/lambda.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
resource "aws_lambda_function" "eligibility_signposting_lambda" {
#checkov:skip=CKV_AWS_116: No deadletter queue is configured for this Lambda function, yet
#checkov:skip=CKV_AWS_115: Concurrent execution limit will be set at APIM level, not at Lambda level
#checkov:skip=CKV_AWS_272: Skipping code signing but flagged to create ticket to investigate on ELI-238
# If the file is not in the current working directory you will need to include a
# path.module in the filename.
filename = var.file_name
Expand All @@ -19,8 +22,15 @@ resource "aws_lambda_function" "eligibility_signposting_lambda" {
ENV = var.environment
}
}

kms_key_arn = aws_kms_key.lambda_cmk.arn

vpc_config {
subnet_ids = var.vpc_intra_subnets
security_group_ids = var.security_group_ids
}

tracing_config {
mode = "Active"
}
}
4 changes: 4 additions & 0 deletions infrastructure/modules/lambda/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ output "aws_lambda_function_name" {
output "aws_lambda_invoke_arn" {
value = aws_lambda_function.eligibility_signposting_lambda.invoke_arn
}

output "lambda_cmk_arn" {
value = aws_kms_key.lambda_cmk.arn
}
1 change: 1 addition & 0 deletions infrastructure/modules/s3/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
data "aws_caller_identity" "current" {}
18 changes: 18 additions & 0 deletions infrastructure/modules/s3/kms.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,21 @@ resource "aws_kms_alias" "storage_bucket_cmk" {
name = "alias/${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.bucket_name}-cmk"
target_key_id = aws_kms_key.storage_bucket_cmk.key_id
}

resource "aws_kms_key_policy" "storage_bucket_cmk" {
key_id = aws_kms_key.storage_bucket_cmk.id
policy = data.aws_iam_policy_document.storage_bucket_cmk.json
}

data "aws_iam_policy_document" "storage_bucket_cmk" {
statement {
sid = "Enable IAM User Permissions for s3 buckets"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = ["kms:*"]
resources = [aws_kms_key.storage_bucket_cmk.arn]
}
}
4 changes: 4 additions & 0 deletions infrastructure/modules/s3/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ output "storage_bucket_name" {
output "storage_bucket_id" {
value = aws_s3_bucket.storage_bucket.id
}

output "storage_bucket_kms_key_arn" {
value = aws_kms_key.storage_bucket_cmk.arn
}
21 changes: 18 additions & 3 deletions infrastructure/modules/s3/s3.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# s3
# Define bucket
resource "aws_s3_bucket" "storage_bucket" {
#checkov:skip=CKV_AWS_144: We don't want to replicate outside our region
#checkov:skip=CKV2_AWS_62: We won't enable event notifications for this bucket, yet
bucket = "${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.project_name}-${var.environment}-${var.bucket_name}"
}

Expand Down Expand Up @@ -63,6 +65,9 @@ resource "aws_s3_bucket_lifecycle_configuration" "storage_bucket" {

#same again for logging buckets
resource "aws_s3_bucket" "storage_bucket_access_logs" {
#checkov:skip=CKV_AWS_144: We don't want to replicate outside our region
#checkov:skip=CKV2_AWS_62: We won't enable event notifications for this bucket, yet
#checkov:skip=CKV_AWS_21: Versioning not needed given short lifecycle of logs
bucket = "${terraform.workspace == "default" ? "" : "${terraform.workspace}-"}${var.project_name}-${var.environment}-${var.bucket_name}-access-logs"
}

Expand All @@ -77,7 +82,8 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "storage_bucket_ac

rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.storage_bucket_cmk.arn
}
}
}
Expand All @@ -99,6 +105,17 @@ resource "aws_s3_bucket_lifecycle_configuration" "storage_bucket_access_logs_obj
noncurrent_days = var.log_retention_in_days
}
}
rule {
id = "StorageBucketLogsMultipartUploadExpiration"
status = "Enabled"

filter {
prefix = ""
}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
}

resource "aws_s3_bucket_public_access_block" "storage_bucket_access_logs_public_access_block" {
Expand All @@ -109,5 +126,3 @@ resource "aws_s3_bucket_public_access_block" "storage_bucket_access_logs_public_
ignore_public_acls = true
restrict_public_buckets = true
}


3 changes: 3 additions & 0 deletions infrastructure/stacks/api-layer/api_gateway.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ resource "aws_api_gateway_deployment" "eligibility_signposting_api" {
}

resource "aws_api_gateway_stage" "eligibility-signposting-api" {
#checkov:skip=CKV2_AWS_51: mTLS is enforced at the custom domain, not at the stage level
#checkov:skip=CKV_AWS_120: We're not enabling caching for this API Gateway, yet
deployment_id = aws_api_gateway_deployment.eligibility_signposting_api.id
rest_api_id = module.eligibility_signposting_api_gateway.rest_api_id
stage_name = "${local.workspace}-eligibility-signposting-api-live"
Expand All @@ -61,6 +63,7 @@ resource "aws_api_gateway_stage" "eligibility-signposting-api" {
}

resource "aws_api_gateway_method_settings" "check_eligibility" {
#checkov:skip=CKV_AWS_225: We're not enabling caching for this API Gateway, yet
rest_api_id = module.eligibility_signposting_api_gateway.rest_api_id
stage_name = aws_api_gateway_stage.eligibility-signposting-api.stage_name
method_path = "*/*"
Expand Down
3 changes: 2 additions & 1 deletion infrastructure/stacks/api-layer/cloudwatch.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# CloudWatch Log Group for lambda Flow Logs
resource "aws_cloudwatch_log_group" "lambda_logs" {
name = "/aws/lambda/${module.eligibility_signposting_lambda_function.aws_lambda_function_id}"
retention_in_days = 14
retention_in_days = 365
kms_key_id = module.eligibility_signposting_lambda_function.lambda_cmk_arn

tags = {
Name = "lambda-execution-logs"
Expand Down
2 changes: 2 additions & 0 deletions infrastructure/stacks/api-layer/healthcheck_status.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
resource "aws_api_gateway_method" "_status" {
#checkov:skip=CKV_AWS_59: API is secured via Apigee proxy with mTLS, API keys are not used
#checkov:skip=CKV2_AWS_53: No request parameters to validate for static healthcheck endpoint
rest_api_id = module.eligibility_signposting_api_gateway.rest_api_id
resource_id = aws_api_gateway_resource._status.id
http_method = "GET"
Expand Down
33 changes: 30 additions & 3 deletions infrastructure/stacks/api-layer/iam_policies.tf
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,16 @@ data "aws_iam_policy_document" "kms_key_policy" {
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"]
}
actions = ["kms:*"]
resources = ["*"]
resources = [
module.eligibility_status_table.dynamodb_kms_key_arn,
module.s3_rules_bucket.storage_bucket_kms_key_arn,
module.s3_audit_bucket.storage_bucket_kms_key_arn,
module.eligibility_signposting_api_gateway.kms_key_arn,

]
}
statement {
sid = "Allow lambda role"
sid = "Allow lambda decrypt role"
effect = "Allow"
principals {
type = "AWS"
Expand All @@ -151,7 +157,28 @@ data "aws_iam_policy_document" "kms_key_policy" {
"kms:Decrypt"
]
resources = [
module.eligibility_status_table.dynamodb_kms_key_arn
module.eligibility_status_table.dynamodb_kms_key_arn,
module.s3_rules_bucket.storage_bucket_kms_key_arn,
]
}

statement {
sid = "Allow lambda full write role"
effect = "Allow"
principals {
type = "AWS"
identifiers = [
aws_iam_role.eligibility_lambda_role.arn
]
}
actions = [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:DescribeKey"
]
resources = [
module.s3_audit_bucket.storage_bucket_kms_key_arn
]
}
}
Expand Down
15 changes: 15 additions & 0 deletions infrastructure/stacks/api-layer/patient_check.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@

resource "aws_api_gateway_request_validator" "patient_check_validator" {
rest_api_id = module.eligibility_signposting_api_gateway.rest_api_id
name = "validate-path-params"
validate_request_body = false
validate_request_parameters = true
}

resource "aws_api_gateway_method" "get_patient_check" {
#checkov:skip=CKV_AWS_59: API is secured via Apigee proxy with mTLS, API keys are not used
rest_api_id = module.eligibility_signposting_api_gateway.rest_api_id
resource_id = aws_api_gateway_resource.patient.id
http_method = "GET"
authorization = "NONE"
api_key_required = false

request_validator_id = aws_api_gateway_request_validator.patient_check_validator.id

request_parameters = {
"method.request.path.id" = true # Require the 'id' path parameter
}

depends_on = [
aws_api_gateway_resource.patient,
aws_api_gateway_resource.patient_check,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ resource "aws_iam_policy" "terraform_state" {

# API Infrastructure Management Policy
resource "aws_iam_policy" "api_infrastructure" {
#checkov:skip=CKV_AWS_287 Ensure IAM policies does not allow credentials exposure
#checkov:skip=CKV_AWS_355 Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions
#checkov:skip=CKV_AWS_288 Ensure IAM policies does not allow data exfiltration
#checkov:skip=CKV_AWS_289 Ensure IAM policies does not allow permissions management / resource exposure without constraints
#checkov:skip=CKV_AWS_286 Ensure IAM policies does not allow privilege escalation
#checkov:skip=CKV_AWS_290 Ensure IAM policies does not allow write access without constraints

name = "api-infrastructure-management"
description = "Policy granting permissions to manage API infrastructure"
path = "/service-policies/"
Expand Down
Loading