Skip to content

Commit 63af80b

Browse files
committed
eli-445 adding github bootstrap role permissions boundary
1 parent 53dbcbd commit 63af80b

1 file changed

Lines changed: 141 additions & 0 deletions

File tree

infrastructure/stacks/iams-developer-roles/iams_permissions_boundary.tf

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,3 +295,144 @@ resource "aws_iam_policy" "permissions_boundary" {
295295
}
296296
)
297297
}
298+
299+
data "aws_iam_policy_document" "iam_bootstrap_permissions_boundary" {
300+
# Allow IAM operations on project-scoped resources
301+
statement {
302+
sid = "AllowProjectIamOperations"
303+
effect = "Allow"
304+
actions = [
305+
"iam:GetRole*",
306+
"iam:GetPolicy*",
307+
"iam:ListRole*",
308+
"iam:ListPolicies",
309+
"iam:ListAttachedRolePolicies",
310+
"iam:ListPolicyVersions",
311+
"iam:ListPolicyTags",
312+
"iam:ListOpenIDConnectProviders",
313+
"iam:ListOpenIDConnectProviderTags",
314+
"iam:GetOpenIDConnectProvider",
315+
"iam:CreateRole",
316+
"iam:DeleteRole",
317+
"iam:UpdateRole",
318+
"iam:UpdateAssumeRolePolicy",
319+
"iam:PutRolePolicy",
320+
"iam:PutRolePermissionsBoundary",
321+
"iam:AttachRolePolicy",
322+
"iam:DetachRolePolicy",
323+
"iam:CreatePolicy*",
324+
"iam:DeletePolicy*",
325+
"iam:TagRole",
326+
"iam:TagPolicy",
327+
"iam:UntagRole",
328+
"iam:UntagPolicy",
329+
"iam:PassRole",
330+
"iam:CreateServiceLinkedRole",
331+
"iam:TagOpenIDConnectProvider",
332+
"iam:UntagOpenIDConnectProvider",
333+
"iam:CreateOpenIDConnectProvider",
334+
"iam:DeleteOpenIDConnectProvider",
335+
"iam:UpdateOpenIDConnectProviderThumbprint",
336+
"iam:AddClientIDToOpenIDConnectProvider",
337+
"iam:RemoveClientIDFromOpenIDConnectProvider",
338+
]
339+
resources = [
340+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/service-roles/github-actions-api-deployment-role",
341+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/service-roles/github-actions-iam-bootstrap-role",
342+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${var.project_name}-terraform-developer-role",
343+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/terraform-developer-role",
344+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/${upper(var.project_name)}-*",
345+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/${lower(var.project_name)}-*",
346+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/service-policies/*",
347+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/${local.stack_name}-*",
348+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com",
349+
]
350+
}
351+
352+
# Allow read-only IAM access for Terraform plan/state discovery
353+
statement {
354+
sid = "AllowIamReadAccess"
355+
effect = "Allow"
356+
actions = [
357+
"iam:Get*",
358+
"iam:List*",
359+
]
360+
resources = ["*"]
361+
}
362+
363+
# Allow Terraform state bucket access
364+
statement {
365+
sid = "AllowTerraformStateAccess"
366+
effect = "Allow"
367+
actions = [
368+
"s3:ListBucket",
369+
"s3:GetObject",
370+
"s3:PutObject",
371+
"s3:DeleteObject",
372+
]
373+
resources = [
374+
"${local.terraform_state_bucket_arn}",
375+
"${local.terraform_state_bucket_arn}/*",
376+
]
377+
}
378+
379+
# Allow Terraform state locking via DynamoDB
380+
statement {
381+
sid = "AllowTerraformStateLocking"
382+
effect = "Allow"
383+
actions = [
384+
"dynamodb:GetItem",
385+
"dynamodb:PutItem",
386+
"dynamodb:DeleteItem",
387+
]
388+
resources = [
389+
"arn:aws:dynamodb:${var.default_aws_region}:${data.aws_caller_identity.current.account_id}:table/${var.project_name}-*-terraform-lock",
390+
]
391+
}
392+
393+
# DENY: Prevent the bootstrap role from modifying its own policies
394+
statement {
395+
sid = "DenyBootstrapSelfModification"
396+
effect = "Deny"
397+
actions = [
398+
"iam:AttachRolePolicy",
399+
"iam:DetachRolePolicy",
400+
"iam:PutRolePolicy",
401+
"iam:DeleteRolePolicy",
402+
"iam:UpdateAssumeRolePolicy",
403+
"iam:PutRolePermissionsBoundary",
404+
"iam:DeleteRolePermissionsBoundary",
405+
]
406+
resources = [
407+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/service-roles/github-actions-iam-bootstrap-role",
408+
]
409+
}
410+
411+
# DENY: Prevent the bootstrap role from modifying its own permissions boundary
412+
statement {
413+
sid = "DenyBootstrapBoundaryModification"
414+
effect = "Deny"
415+
actions = [
416+
"iam:CreatePolicyVersion",
417+
"iam:DeletePolicy",
418+
"iam:DeletePolicyVersion",
419+
"iam:SetDefaultPolicyVersion",
420+
]
421+
resources = [
422+
"arn:aws:iam::${data.aws_caller_identity.current.account_id}:policy/${lower(var.project_name)}-iam-bootstrap-permissions-boundary",
423+
]
424+
}
425+
}
426+
427+
resource "aws_iam_policy" "iam_bootstrap_permissions_boundary" {
428+
name = "${lower(var.project_name)}-iam-bootstrap-permissions-boundary"
429+
description = "Permissions boundary for the GitHub Actions IAM Bootstrap role - scoped to IAM and Terraform state only"
430+
policy = data.aws_iam_policy_document.iam_bootstrap_permissions_boundary.json
431+
432+
tags = merge(
433+
local.tags,
434+
{
435+
Stack = "iams-developer-roles"
436+
}
437+
)
438+
}

0 commit comments

Comments
 (0)