# Exec-role ceiling. CreatePolicy is denied on hcptf-forgejo, so the first # apply (as hcptf-bootstrap) creates this policy and later document edits need # that same bootstrap window. data "aws_iam_policy_document" "exec_boundary" { statement { sid = "BackupBuckets" effect = "Allow" actions = [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetBucketVersioning", "s3:GetObject", "s3:GetObjectVersion", "s3:GetObjectVersionAcl", "s3:GetObjectVersionForReplication", "s3:GetObjectVersionTagging", "s3:GetReplicationConfiguration", "s3:ListBucket", "s3:PutObject", "s3:ReplicateDelete", "s3:ReplicateObject", "s3:ReplicateTags", ] resources = [ "arn:aws:s3:::${local.backup_bucket_name}", "arn:aws:s3:::${local.backup_bucket_name}/*", "arn:aws:s3:::${local.replica_bucket_name}", "arn:aws:s3:::${local.replica_bucket_name}/*", ] } statement { sid = "ForgejoSecrets" effect = "Allow" actions = ["secretsmanager:GetSecretValue"] resources = [ local.secret_arns.api_token, local.secret_arns.github_pat, local.secret_arns.gcs_sa_key, local.secret_arns.slack_webhook, ] } statement { sid = "BackupPrefix" effect = "Allow" actions = [ "ssm:GetParameter", "ssm:GetParameters", ] resources = [ "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter/forgejo/*", ] } statement { sid = "SnapshotLifecycle" effect = "Allow" actions = [ "ec2:CopySnapshot", "ec2:CreateSnapshot", "ec2:CreateSnapshots", "ec2:CreateTags", "ec2:DeleteSnapshot", "ec2:DeleteTags", "ec2:Describe*", "ec2:DisableFastSnapshotRestores", "ec2:EnableFastSnapshotRestores", "ec2:ModifySnapshotAttribute", "ec2:ResetSnapshotAttribute", ] resources = ["*"] } statement { sid = "VerificationLogs" effect = "Allow" actions = [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", ] resources = [ "arn:aws:logs:${var.aws_region}:${local.account_id}:log-group:${local.verification_log_group}", "arn:aws:logs:${var.aws_region}:${local.account_id}:log-group:${local.verification_log_group}:*", ] } statement { sid = "SsmAgentBuckets" effect = "Allow" actions = ["s3:GetObject"] resources = [ "arn:aws:s3:::aws-ssm-*/*", "arn:aws:s3:::aws-windows-downloads-*/*", "arn:aws:s3:::amazon-ssm-*/*", "arn:aws:s3:::amazon-ssm-packages-*/*", "arn:aws:s3:::patch-baseline-snapshot-*/*", ] } statement { sid = "SsmManagedInstance" effect = "Allow" actions = [ "ssm:DescribeAssociation", "ssm:DescribeDocument", "ssm:GetDeployablePatchSnapshotForInstance", "ssm:GetDocument", "ssm:GetManifest", "ssm:ListAssociations", "ssm:ListInstanceAssociations", "ssm:PutComplianceItems", "ssm:PutConfigurePackageResult", "ssm:PutInventory", "ssm:UpdateAssociationStatus", "ssm:UpdateInstanceAssociationStatus", "ssm:UpdateInstanceInformation", ] resources = ["*"] } statement { sid = "SsmAgentParameters" effect = "Allow" actions = [ "ssm:GetParameter", "ssm:GetParameters", ] resources = [ "arn:aws:ssm:${var.aws_region}::parameter/aws/service/*", "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter/aws/service/*", ] } statement { sid = "SsmMessages" effect = "Allow" actions = [ "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel", ] resources = ["*"] } statement { sid = "Ec2Messages" effect = "Allow" actions = [ "ec2messages:AcknowledgeMessage", "ec2messages:DeleteMessage", "ec2messages:FailMessage", "ec2messages:GetEndpoint", "ec2messages:GetMessages", "ec2messages:SendReply", ] resources = ["*"] } } resource "aws_iam_policy" "exec_boundary" { name = local.boundary_name path = "/tf-managed/" description = "Permissions boundary for Forgejo exec roles (PLAT-80)." policy = data.aws_iam_policy_document.exec_boundary.json } data "aws_iam_policy_document" "instance_assume" { statement { sid = "Ec2Assume" effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ec2.amazonaws.com"] } } } resource "aws_iam_role" "instance" { name = local.instance_role_name path = "/tf-managed/" assume_role_policy = data.aws_iam_policy_document.instance_assume.json permissions_boundary = aws_iam_policy.exec_boundary.arn } resource "aws_iam_role_policy_attachment" "instance_ssm" { role = aws_iam_role.instance.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } data "aws_iam_policy_document" "instance" { statement { sid = "BackupBucket" effect = "Allow" actions = [ "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:PutObject", ] resources = [ "arn:aws:s3:::${local.backup_bucket_name}", "arn:aws:s3:::${local.backup_bucket_name}/*", ] } statement { sid = "MirrorSecrets" effect = "Allow" actions = ["secretsmanager:GetSecretValue"] resources = [ local.secret_arns.api_token, local.secret_arns.github_pat, ] } statement { sid = "BackupPrefix" effect = "Allow" actions = ["ssm:GetParameter"] resources = [ "arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter/forgejo/backup-s3-prefix", ] } } resource "aws_iam_role_policy" "instance" { name = "forgejo-instance" role = aws_iam_role.instance.id policy = data.aws_iam_policy_document.instance.json } resource "aws_iam_instance_profile" "forgejo" { name = local.instance_profile_name path = "/tf-managed/" role = aws_iam_role.instance.name } data "aws_iam_policy_document" "dlm_assume" { statement { sid = "DlmAssume" effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["dlm.amazonaws.com"] } } } resource "aws_iam_role" "dlm" { name = local.dlm_role_name path = "/tf-managed/" assume_role_policy = data.aws_iam_policy_document.dlm_assume.json permissions_boundary = aws_iam_policy.exec_boundary.arn } resource "aws_iam_role_policy_attachment" "dlm" { role = aws_iam_role.dlm.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSDataLifecycleManagerServiceRole" } data "aws_iam_policy_document" "replication_assume" { statement { sid = "S3Assume" effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["s3.amazonaws.com"] } } } resource "aws_iam_role" "replication" { name = local.replication_role_name path = "/tf-managed/" assume_role_policy = data.aws_iam_policy_document.replication_assume.json permissions_boundary = aws_iam_policy.exec_boundary.arn } data "aws_iam_policy_document" "replication" { statement { sid = "ReadSource" effect = "Allow" actions = [ "s3:GetReplicationConfiguration", "s3:ListBucket", ] resources = ["arn:aws:s3:::${local.backup_bucket_name}"] } statement { sid = "ReadSourceObjects" effect = "Allow" actions = [ "s3:GetObjectVersion", "s3:GetObjectVersionAcl", "s3:GetObjectVersionForReplication", "s3:GetObjectVersionTagging", ] resources = ["arn:aws:s3:::${local.backup_bucket_name}/*"] } statement { sid = "WriteReplica" effect = "Allow" actions = [ "s3:ReplicateDelete", "s3:ReplicateObject", "s3:ReplicateTags", ] resources = ["arn:aws:s3:::${local.replica_bucket_name}/*"] } } resource "aws_iam_role_policy" "replication" { name = "forgejo-s3-replication" role = aws_iam_role.replication.id policy = data.aws_iam_policy_document.replication.json } data "aws_iam_policy_document" "lambda_assume" { statement { sid = "LambdaAssume" effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } } } resource "aws_iam_role" "lambda" { name = local.lambda_role_name path = "/tf-managed/" assume_role_policy = data.aws_iam_policy_document.lambda_assume.json permissions_boundary = aws_iam_policy.exec_boundary.arn } data "aws_iam_policy_document" "lambda" { statement { sid = "ReadBackups" effect = "Allow" actions = [ "s3:GetObject", "s3:ListBucket", ] resources = [ "arn:aws:s3:::${local.backup_bucket_name}", "arn:aws:s3:::${local.backup_bucket_name}/*", "arn:aws:s3:::${local.replica_bucket_name}", "arn:aws:s3:::${local.replica_bucket_name}/*", ] } statement { sid = "VerificationSecrets" effect = "Allow" actions = ["secretsmanager:GetSecretValue"] resources = [ local.secret_arns.gcs_sa_key, local.secret_arns.slack_webhook, ] } statement { sid = "Snapshots" effect = "Allow" actions = ["ec2:DescribeSnapshots"] resources = ["*"] } statement { sid = "Logs" effect = "Allow" actions = [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", ] resources = [ "arn:aws:logs:${var.aws_region}:${local.account_id}:log-group:${local.verification_log_group}", "arn:aws:logs:${var.aws_region}:${local.account_id}:log-group:${local.verification_log_group}:*", ] } } resource "aws_iam_role_policy" "lambda" { name = "forgejo-backup-verification" role = aws_iam_role.lambda.id policy = data.aws_iam_policy_document.lambda.json } resource "aws_iam_user" "gcs_transfer" { name = local.gcs_user_name path = "/tf-managed/" permissions_boundary = aws_iam_policy.exec_boundary.arn } data "aws_iam_policy_document" "gcs_transfer" { statement { sid = "ReadBackups" effect = "Allow" actions = [ "s3:GetObject", "s3:ListBucket", ] resources = [ "arn:aws:s3:::${local.backup_bucket_name}", "arn:aws:s3:::${local.backup_bucket_name}/*", ] } } resource "aws_iam_user_policy" "gcs_transfer" { name = "forgejo-gcs-transfer" user = aws_iam_user.gcs_transfer.name policy = data.aws_iam_policy_document.gcs_transfer.json }