From 62979f7f2d18bb8b8a1f97e1cf7a22a7136f81e6 Mon Sep 17 00:00:00 2001 From: Catalina Garcia Date: Tue, 19 May 2026 15:50:04 +0100 Subject: [PATCH 1/6] wip: add permissive boundary --- .../permissions-boundary-policy.tf | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 infra/modules/deployer-access/permissions-boundary-policy.tf diff --git a/infra/modules/deployer-access/permissions-boundary-policy.tf b/infra/modules/deployer-access/permissions-boundary-policy.tf new file mode 100644 index 000000000..e068e54e6 --- /dev/null +++ b/infra/modules/deployer-access/permissions-boundary-policy.tf @@ -0,0 +1,53 @@ +resource "aws_iam_policy" "permissions_boundary" { + policy = data.aws_iam_policy_document.permissions_boundary.json + description = "Permissions boundary for non-human role" + path = "/permissions_boundaries/" +} + +data "aws_iam_policy_document" "permissions_boundary" { + #checkov:skip=CKV2_AWS_40:addressing in future commit + #checkov:skip=CKV_AWS_107:addressing in future commit + #checkov:skip=CKV_AWS_108:addressing in future commit + #checkov:skip=CKV_AWS_109:addressing in future commit + #checkov:skip=CKV_AWS_110:addressing in future commit + #checkov:skip=CKV_AWS_111:addressing in future commit + #checkov:skip=CKV_AWS_356:addressing in future commit + statement { + resources = ["*"] + effect = "Allow" + actions = [ + "acm:*", + "application-autoscaling:*", + "application-signals:*", + "cloudformation:*", + "cloudfront:*", + "cloudwatch:*", + "codebuild:*", + "codecommit:*", + "codepipeline:*", + "codestar-connections:*", + "ec2:*", + "ecr:*", + "ecs:*", + "elasticache:*", + "elasticloadbalancing:*", + "events:*", + "guardduty:*", + "iam:*", + "kms:*", + "lambda:*", + "logs:*", + "rds:*", + "route53:*", + "s3:*", + "secretsmanager:*", + "ses:*", + "shield:*", + "sns:*", + "sqs:*", + "ssm:*", + "wafv2:*", + ] + + } +} From 10a3fb1f351a6972b074ec48b92ed1c61505d31c Mon Sep 17 00:00:00 2001 From: Catalina Garcia Date: Wed, 20 May 2026 09:27:05 +0100 Subject: [PATCH 2/6] Prevent boundary policy removal/modification When we assign this policy to a role we want to make sure it's not able to change the boundaries --- .../permissions-boundary-policy.tf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/infra/modules/deployer-access/permissions-boundary-policy.tf b/infra/modules/deployer-access/permissions-boundary-policy.tf index e068e54e6..52530f51a 100644 --- a/infra/modules/deployer-access/permissions-boundary-policy.tf +++ b/infra/modules/deployer-access/permissions-boundary-policy.tf @@ -1,4 +1,5 @@ resource "aws_iam_policy" "permissions_boundary" { + name = "deployer-${var.environment_name}-boundary" policy = data.aws_iam_policy_document.permissions_boundary.json description = "Permissions boundary for non-human role" path = "/permissions_boundaries/" @@ -50,4 +51,27 @@ data "aws_iam_policy_document" "permissions_boundary" { ] } + + statement { + sid = "DenyBoundaryPolicyModification" + effect = "Deny" + actions = [ + "iam:CreatePolicyVersion", + "iam:DeletePolicy", + "iam:DeletePolicyVersion", + "iam:SetDefaultPolicyVersion" + ] + resources = [ + "arn:aws:iam::${var.account_id}:policy/permissions_boundaries/deployer-${var.environment_name}-boundary"] + } + + statement { + sid = "DenyBoundaryRemoval" + effect = "Deny" + actions = [ + "iam:DeleteRolePermissionsBoundary", + "iam:DeleteUserPermissionBoundary" + ] + resources = ["*"] + } } From df3d4c5eb143b2bb256f411b416e2aeb853ed38d Mon Sep 17 00:00:00 2001 From: Catalina Garcia Date: Thu, 21 May 2026 08:24:30 +0100 Subject: [PATCH 3/6] tmp: add assume role --- .../deployer-access/permissions-boundary-policy.tf | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/infra/modules/deployer-access/permissions-boundary-policy.tf b/infra/modules/deployer-access/permissions-boundary-policy.tf index 52530f51a..290062f36 100644 --- a/infra/modules/deployer-access/permissions-boundary-policy.tf +++ b/infra/modules/deployer-access/permissions-boundary-policy.tf @@ -52,6 +52,19 @@ data "aws_iam_policy_document" "permissions_boundary" { } + statement { + sid = "AllowAssumeRoleOnSpecificRoles" + effect = "Allow" + actions = [ + "sts:AssumeRole" + ] + resources = [ + // Include only specific roles - do we just hardcode these? either way, we should make sure the roles themselves have a permissions boundary + // does this include human roles and the end-to-end-test role? + //specific roles in own account. Other accounts * + ] + } + statement { sid = "DenyBoundaryPolicyModification" effect = "Deny" From 6f614a7c50f73de9530604752096d95ecde099b8 Mon Sep 17 00:00:00 2001 From: Catalina Garcia Date: Tue, 26 May 2026 15:53:54 +0100 Subject: [PATCH 4/6] The deployer role can only create roles with the same boundary We want to prevent priviledge escalation of the deployer role. Any role created by the deployer role should have at least the same permissions boundary as the deployer --- infra/modules/deployer-access/policy.tf | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/infra/modules/deployer-access/policy.tf b/infra/modules/deployer-access/policy.tf index 87f76d876..736fc653a 100644 --- a/infra/modules/deployer-access/policy.tf +++ b/infra/modules/deployer-access/policy.tf @@ -489,6 +489,11 @@ data "aws_iam_policy_document" "iam" { "iam:PutRolePolicy", "iam:TagRole" ] + condition { + variable = "iam:PermissionsBoundary" + test = "StringEquals" + values = [aws_iam_policy.permissions_boundary.arn] + } effect = "Allow" resources = [ "arn:aws:iam::${var.account_id}:policy/codebuild-*", @@ -514,6 +519,11 @@ data "aws_iam_policy_document" "iam" { "iam:UpdateAssumeRolePolicy", "iam:TagRole" ] + condition { + variable = "iam:PermissionsBoundary" + test = "StringEquals" + values = [aws_iam_policy.permissions_boundary.arn] + } effect = "Allow" resources = [ "arn:aws:iam::${var.account_id}:role/${var.environment_name}-forms-admin-ecs-task", @@ -540,6 +550,11 @@ data "aws_iam_policy_document" "iam" { "iam:TagRole", "iam:UpdateRole" ] + condition { + variable = "iam:PermissionsBoundary" + test = "StringEquals" + values = [aws_iam_policy.permissions_boundary.arn] + } effect = "Allow" resources = [ "arn:aws:iam::${var.account_id}:role/shield-response-team", @@ -561,6 +576,11 @@ data "aws_iam_policy_document" "iam" { "iam:UpdateAssumeRolePolicy", "iam:UpdateRole" ] + condition { + variable = "iam:PermissionsBoundary" + test = "StringEquals" + values = [aws_iam_policy.permissions_boundary.arn] + } effect = "Allow" resources = [ "arn:aws:iam::${var.account_id}:role/govuk-forms-submissions-to-s3-${var.environment_name}", From 3692550f427ffbe97ff15c2eacae7977e94cf4f4 Mon Sep 17 00:00:00 2001 From: Catalina Garcia Date: Tue, 26 May 2026 16:00:26 +0100 Subject: [PATCH 5/6] Add the permissions boundary to the deployer role --- infra/modules/deployer-access/roles.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/infra/modules/deployer-access/roles.tf b/infra/modules/deployer-access/roles.tf index 8469fdb35..9b46243bd 100644 --- a/infra/modules/deployer-access/roles.tf +++ b/infra/modules/deployer-access/roles.tf @@ -24,4 +24,6 @@ data "aws_iam_policy_document" "assume_role" { resource "aws_iam_role" "deployer" { name = "deployer-${var.environment_name}" assume_role_policy = data.aws_iam_policy_document.assume_role.json + + permissions_boundary = aws_iam_policy.permissions_boundary.arn } From 9c78a8cc0122f77aac2f4fc54ec4c5fa87b8ddc5 Mon Sep 17 00:00:00 2001 From: Tom Whitwell Date: Wed, 1 Jul 2026 10:40:31 +0100 Subject: [PATCH 6/6] Add xray permissions and fix sts:AssumeRole resources in boundary The ADOT collector sidecar on ECS task roles requires xray:* actions; without it in the boundary, distributed tracing breaks at runtime. The sts:AssumeRole statement previously had empty resources (invalid policy). Scoped it to the two roles that boundary-carrying roles need to assume: submissions-to-s3 and s3-end-to-end-test. --- .../modules/deployer-access/permissions-boundary-policy.tf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/infra/modules/deployer-access/permissions-boundary-policy.tf b/infra/modules/deployer-access/permissions-boundary-policy.tf index 290062f36..0bbc6cf02 100644 --- a/infra/modules/deployer-access/permissions-boundary-policy.tf +++ b/infra/modules/deployer-access/permissions-boundary-policy.tf @@ -48,6 +48,7 @@ data "aws_iam_policy_document" "permissions_boundary" { "sqs:*", "ssm:*", "wafv2:*", + "xray:*", ] } @@ -58,10 +59,10 @@ data "aws_iam_policy_document" "permissions_boundary" { actions = [ "sts:AssumeRole" ] + # forms-runner-ecs-task assumes submissions-to-s3; codebuild-e2e-tests assumes s3-end-to-end-test resources = [ - // Include only specific roles - do we just hardcode these? either way, we should make sure the roles themselves have a permissions boundary - // does this include human roles and the end-to-end-test role? - //specific roles in own account. Other accounts * + "arn:aws:iam::${var.account_id}:role/govuk-forms-submissions-to-s3-*", + "arn:aws:iam::${var.account_id}:role/govuk-s3-end-to-end-test-*", ] }