Enforce least-privilege bootstrap IAM user and role

This commit is contained in:
cloudneutral 2025-12-10 15:28:38 +08:00
parent b2b2807a73
commit 3d205a564e

View File

@ -27,13 +27,87 @@ resource "aws_iam_role" "terraform_deploy_role" {
)
}
# Admin full access
#
resource "aws_iam_role_policy_attachment" "attach_admin" {
resource "aws_iam_role_policy" "terraform_deploy_role_policy" {
count = var.create_role ? 1 : 0
role = aws_iam_role.terraform_deploy_role[0].name
policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
name = "${local.role_name}-bootstrap-minimal"
role = aws_iam_role.terraform_deploy_role[0].id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
# Bootstrap S3 backend (state bucket)
{
Effect = "Allow",
Action = [
"s3:CreateBucket",
"s3:GetBucketLocation",
"s3:ListBucket",
"s3:PutBucketVersioning",
"s3:PutBucketPolicy",
"s3:PutBucketTagging",
"s3:PutEncryptionConfiguration",
"s3:PutBucketPublicAccessBlock",
],
Resource = "arn:aws:s3:::${local.bootstrap.state.bucket_name}"
},
{
Effect = "Allow",
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:PutObjectTagging"
],
Resource = "arn:aws:s3:::${local.bootstrap.state.bucket_name}/*"
},
# DynamoDB state lock table
{
Effect = "Allow",
Action = [
"dynamodb:CreateTable",
"dynamodb:DescribeTable",
"dynamodb:UpdateTable",
"dynamodb:TagResource",
"dynamodb:UntagResource"
],
Resource = "arn:aws:dynamodb:${local.config_region}:${local.account.account_id}:table/${local.bootstrap.state.dynamodb_table_name}"
},
# IAM roles needed for bootstrap lifecycle
{
Effect = "Allow",
Action = [
"iam:GetRole",
"iam:CreateRole",
"iam:DeleteRole",
"iam:UpdateAssumeRolePolicy",
"iam:TagRole",
"iam:UntagRole"
],
Resource = [
"arn:aws:iam::${local.account.account_id}:role/${local.role_name}",
"arn:aws:iam::${local.account.account_id}:role/bootstrap-*",
"arn:aws:iam::${local.account.account_id}:role/terraform-*"
]
},
{
Effect = "Allow",
Action = [
"iam:PutRolePolicy",
"iam:DeleteRolePolicy",
"iam:AttachRolePolicy",
"iam:DetachRolePolicy"
],
Resource = [
"arn:aws:iam::${local.account.account_id}:role/${local.role_name}",
"arn:aws:iam::${local.account.account_id}:role/bootstrap-*",
"arn:aws:iam::${local.account.account_id}:role/terraform-*"
]
}
]
})
}
#
@ -64,37 +138,6 @@ resource "aws_iam_user_policy" "terraform_user_policy" {
"sts:AssumeRole"
],
Resource = var.create_role ? aws_iam_role.terraform_deploy_role[0].arn : var.existing_role_arn
},
# S3: Terraform state bucket
{
Effect = "Allow",
Action = [
"s3:ListBucket"
],
Resource = "arn:aws:s3:::${local.bootstrap.state.bucket_name}"
},
{
Effect = "Allow",
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
Resource = "arn:aws:s3:::${local.bootstrap.state.bucket_name}/*"
},
# DynamoDB: state lock table
{
Effect = "Allow",
Action = [
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:DeleteItem",
"dynamodb:UpdateItem",
"dynamodb:DescribeTable"
],
Resource = "arn:aws:dynamodb:${local.config_region}:${local.account.account_id}:table/${local.bootstrap.state.dynamodb_table_name}"
}
]
})