mirror of
https://github.com/Sea-Haven-Industries/forgejo.git
synced 2026-09-30 06:33:11 +00:00
The plan role only needs object reads for the verification zip. Unpacking a dump in /tmp fills the root volume.
851 lines
23 KiB
HCL
851 lines
23 KiB
HCL
# HCP plan/apply roles for forgejo-prod (PLAT-80).
|
|
# Copy of seahaven-org-baseline/examples/hcptf-workspace-iam/hcp_iam.tf.example
|
|
# with the Forgejo EC2, ALB, S3 CRR, DLM, and Lambda service set. Create, do not import.
|
|
#
|
|
# First-apply sequence:
|
|
# 1. seahaven-org-baseline scripts/create-hcptf-bootstrap-roles.sh
|
|
# --account prod --allow-workspace forgejo-prod
|
|
# 2. Point this workspace's TFC_AWS_* at hcptf-bootstrap / hcptf-bootstrap-plan
|
|
# (workspace vars, never a project set).
|
|
# 3. One Manual apply. Bootstrap can write hcptf-* and policy/tf-managed/*.
|
|
# It cannot PassRole to ec2 or create the buckets, so non-IAM resources
|
|
# error and stay out of state.
|
|
# 4. Point TFC_AWS_* at hcptf-forgejo / hcptf-forgejo-plan.
|
|
# 5. Re-run the script without --allow-workspace.
|
|
# 6. Second Manual apply creates the instance, buckets, ALB, and Lambda.
|
|
# Later edits to these hcptf-* inline policies need the same window.
|
|
# DenySelfMutation blocks PutRolePolicy on hcptf-* from the scoped role.
|
|
# Do not add StringLike on bootstrap trust. CreatePolicy stays on hcptf-bootstrap.
|
|
|
|
data "aws_iam_policy_document" "hcptf_apply_trust" {
|
|
statement {
|
|
sid = "HcpApply"
|
|
effect = "Allow"
|
|
actions = ["sts:AssumeRoleWithWebIdentity"]
|
|
|
|
principals {
|
|
type = "Federated"
|
|
identifiers = ["arn:aws:iam::${local.account_id}:oidc-provider/app.terraform.io"]
|
|
}
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "app.terraform.io:aud"
|
|
values = ["aws.workload.identity"]
|
|
}
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "app.terraform.io:sub"
|
|
values = [
|
|
"organization:seahaven:project:${local.hcp_project}:workspace:${local.hcp_workspace}:run_phase:apply",
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
data "aws_iam_policy_document" "hcptf_plan_trust" {
|
|
statement {
|
|
sid = "HcpPlan"
|
|
effect = "Allow"
|
|
actions = ["sts:AssumeRoleWithWebIdentity"]
|
|
|
|
principals {
|
|
type = "Federated"
|
|
identifiers = ["arn:aws:iam::${local.account_id}:oidc-provider/app.terraform.io"]
|
|
}
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "app.terraform.io:aud"
|
|
values = ["aws.workload.identity"]
|
|
}
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "app.terraform.io:sub"
|
|
values = [
|
|
"organization:seahaven:project:${local.hcp_project}:workspace:${local.hcp_workspace}:run_phase:plan",
|
|
]
|
|
}
|
|
}
|
|
}
|
|
|
|
data "aws_iam_policy_document" "hcptf_scoped_iam" {
|
|
statement {
|
|
sid = "DenyCreatePolicy"
|
|
effect = "Deny"
|
|
actions = [
|
|
"iam:CreatePolicy",
|
|
"iam:CreatePolicyVersion",
|
|
"iam:DeletePolicy",
|
|
"iam:DeletePolicyVersion",
|
|
"iam:SetDefaultPolicyVersion",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "CreateExecRoleWithBoundary"
|
|
effect = "Allow"
|
|
actions = ["iam:CreateRole"]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
|
|
condition {
|
|
test = "StringLike"
|
|
variable = "iam:PermissionsBoundary"
|
|
values = [
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "MutateExecRoleWithBoundary"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:AttachRolePolicy",
|
|
"iam:PutRolePolicy",
|
|
"iam:PutRolePermissionsBoundary",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
|
|
condition {
|
|
test = "StringLike"
|
|
variable = "iam:PermissionsBoundary"
|
|
values = [
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "WriteExecRoles"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:DeleteRole",
|
|
"iam:DeleteRolePolicy",
|
|
"iam:DetachRolePolicy",
|
|
"iam:TagRole",
|
|
"iam:UntagRole",
|
|
"iam:UpdateAssumeRolePolicy",
|
|
"iam:UpdateRole",
|
|
"iam:UpdateRoleDescription",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "PassInstanceRoleToEc2"
|
|
effect = "Allow"
|
|
actions = ["iam:PassRole"]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.instance_role_name}",
|
|
]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "iam:PassedToService"
|
|
values = ["ec2.amazonaws.com"]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "PassDlmRole"
|
|
effect = "Allow"
|
|
actions = ["iam:PassRole"]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.dlm_role_name}",
|
|
]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "iam:PassedToService"
|
|
values = ["dlm.amazonaws.com"]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "PassReplicationRoleToS3"
|
|
effect = "Allow"
|
|
actions = ["iam:PassRole"]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.replication_role_name}",
|
|
]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "iam:PassedToService"
|
|
values = ["s3.amazonaws.com"]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "PassLambdaRole"
|
|
effect = "Allow"
|
|
actions = ["iam:PassRole"]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.lambda_role_name}",
|
|
]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "iam:PassedToService"
|
|
values = ["lambda.amazonaws.com"]
|
|
}
|
|
}
|
|
|
|
statement {
|
|
sid = "InstanceProfiles"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:AddRoleToInstanceProfile",
|
|
"iam:CreateInstanceProfile",
|
|
"iam:DeleteInstanceProfile",
|
|
"iam:GetInstanceProfile",
|
|
"iam:ListInstanceProfileTags",
|
|
"iam:RemoveRoleFromInstanceProfile",
|
|
"iam:TagInstanceProfile",
|
|
"iam:UntagInstanceProfile",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:instance-profile/tf-managed/${local.instance_profile_name}",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "GcsTransferUser"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:CreateUser",
|
|
"iam:DeleteUser",
|
|
"iam:GetUser",
|
|
"iam:GetUserPolicy",
|
|
"iam:ListUserPolicies",
|
|
"iam:ListUserTags",
|
|
"iam:PutUserPermissionsBoundary",
|
|
"iam:PutUserPolicy",
|
|
"iam:DeleteUserPolicy",
|
|
"iam:TagUser",
|
|
"iam:UntagUser",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:user/tf-managed/${local.gcs_user_name}",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "IamReadOnly"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:GetPolicy",
|
|
"iam:GetPolicyVersion",
|
|
"iam:GetRole",
|
|
"iam:GetRolePolicy",
|
|
"iam:ListAttachedRolePolicies",
|
|
"iam:ListInstanceProfilesForRole",
|
|
"iam:ListPolicies",
|
|
"iam:ListPolicyVersions",
|
|
"iam:ListRolePolicies",
|
|
"iam:ListRoleTags",
|
|
"iam:ListRoles",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "TagExecBoundary"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:GetPolicy",
|
|
"iam:GetPolicyVersion",
|
|
"iam:ListPolicyTags",
|
|
"iam:ListPolicyVersions",
|
|
"iam:TagPolicy",
|
|
"iam:UntagPolicy",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/${local.stack_prefix}*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "DenySelfMutation"
|
|
effect = "Deny"
|
|
actions = [
|
|
"iam:AttachRolePolicy",
|
|
"iam:DeleteRole",
|
|
"iam:DeleteRolePolicy",
|
|
"iam:DeleteRolePermissionsBoundary",
|
|
"iam:DetachRolePolicy",
|
|
"iam:PutRolePolicy",
|
|
"iam:PutRolePermissionsBoundary",
|
|
"iam:UpdateAssumeRolePolicy",
|
|
"iam:UpdateRole",
|
|
"iam:UpdateRoleDescription",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/hcptf-*",
|
|
"arn:aws:iam::${local.account_id}:role/github-cfn-execution-role",
|
|
"arn:aws:iam::${local.account_id}:role/githubdeploy-*",
|
|
"arn:aws:iam::${local.account_id}:role/cdk-hnb659fds-*",
|
|
"arn:aws:iam::${local.account_id}:role/OrganizationAccountAccessRole",
|
|
"arn:aws:iam::${local.account_id}:role/seahaven-*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "DenyBoundaryTampering"
|
|
effect = "Deny"
|
|
actions = [
|
|
"iam:DeleteRolePermissionsBoundary",
|
|
"iam:DeleteUserPermissionsBoundary",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/*",
|
|
"arn:aws:iam::${local.account_id}:user/*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "DenyBoundaryPolicyEdit"
|
|
effect = "Deny"
|
|
actions = [
|
|
"iam:CreatePolicyVersion",
|
|
"iam:DeletePolicy",
|
|
"iam:DeletePolicyVersion",
|
|
"iam:SetDefaultPolicyVersion",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:policy/seahaven-*",
|
|
"arn:aws:iam::${local.account_id}:policy/tf-managed/*",
|
|
]
|
|
}
|
|
}
|
|
|
|
data "aws_iam_policy_document" "hcptf_apply_services" {
|
|
statement {
|
|
sid = "BackupAndArtifactBuckets"
|
|
effect = "Allow"
|
|
actions = ["s3:*"]
|
|
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}/*",
|
|
"arn:aws:s3:::${local.artifacts_bucket_name}",
|
|
"arn:aws:s3:::${local.artifacts_bucket_name}/*",
|
|
]
|
|
}
|
|
|
|
# RunInstances and CreateVolume do not support a useful resource ARN.
|
|
# This document is a managed policy so it is not counted against the
|
|
# apply role's 10,240-character inline quota. The plan role does not get it.
|
|
statement {
|
|
sid = "Ec2Host"
|
|
effect = "Allow"
|
|
actions = [
|
|
"ec2:AssociateIamInstanceProfile",
|
|
"ec2:AttachVolume",
|
|
"ec2:AuthorizeSecurityGroupEgress",
|
|
"ec2:AuthorizeSecurityGroupIngress",
|
|
"ec2:CreateSecurityGroup",
|
|
"ec2:CreateTags",
|
|
"ec2:CreateVolume",
|
|
"ec2:DeleteSecurityGroup",
|
|
"ec2:DeleteTags",
|
|
"ec2:DeleteVolume",
|
|
"ec2:DescribeAccountAttributes",
|
|
"ec2:DescribeAvailabilityZones",
|
|
"ec2:DescribeIamInstanceProfileAssociations",
|
|
"ec2:DescribeImages",
|
|
"ec2:DescribeInstanceAttribute",
|
|
"ec2:DescribeInstanceCreditSpecifications",
|
|
"ec2:DescribeInstanceStatus",
|
|
"ec2:DescribeInstanceTypes",
|
|
"ec2:DescribeInstances",
|
|
"ec2:DescribeNetworkInterfaces",
|
|
"ec2:DescribeSecurityGroupRules",
|
|
"ec2:DescribeSecurityGroups",
|
|
"ec2:DescribeSubnets",
|
|
"ec2:DescribeTags",
|
|
"ec2:DescribeVolumeAttribute",
|
|
"ec2:DescribeVolumeStatus",
|
|
"ec2:DescribeVolumes",
|
|
"ec2:DescribeVpcAttribute",
|
|
"ec2:DescribeVpcs",
|
|
"ec2:DetachVolume",
|
|
"ec2:DisassociateIamInstanceProfile",
|
|
"ec2:ModifyInstanceAttribute",
|
|
"ec2:ModifySecurityGroupRules",
|
|
"ec2:ModifyVolume",
|
|
"ec2:ReplaceIamInstanceProfileAssociation",
|
|
"ec2:RevokeSecurityGroupEgress",
|
|
"ec2:RevokeSecurityGroupIngress",
|
|
"ec2:RunInstances",
|
|
"ec2:StartInstances",
|
|
"ec2:StopInstances",
|
|
"ec2:TerminateInstances",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
# Listener and rule ARNs are allocated at create time.
|
|
statement {
|
|
sid = "LoadBalancer"
|
|
effect = "Allow"
|
|
actions = ["elasticloadbalancing:*"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "Certificate"
|
|
effect = "Allow"
|
|
actions = ["acm:*"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "Snapshots"
|
|
effect = "Allow"
|
|
actions = ["dlm:*"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "VerificationFunction"
|
|
effect = "Allow"
|
|
actions = ["lambda:*"]
|
|
resources = [
|
|
"arn:aws:lambda:${var.aws_region}:${local.account_id}:function:forgejo-backup-verification",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "VerificationSchedules"
|
|
effect = "Allow"
|
|
actions = ["events:*"]
|
|
resources = [
|
|
"arn:aws:events:${var.aws_region}:${local.account_id}:rule/forgejo-backup-*",
|
|
]
|
|
}
|
|
|
|
# CreateLogGroup is not reliable on the log-group ARN before the group exists.
|
|
# DescribeLogGroups is a list API. Its resource is log-group::log-stream:, not the group ARN.
|
|
statement {
|
|
sid = "CreateVerificationLogGroup"
|
|
effect = "Allow"
|
|
actions = ["logs:CreateLogGroup"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "DescribeVerificationLogGroups"
|
|
effect = "Allow"
|
|
actions = ["logs:DescribeLogGroups"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "VerificationLogs"
|
|
effect = "Allow"
|
|
actions = [
|
|
"logs:DeleteLogGroup",
|
|
"logs:DeleteRetentionPolicy",
|
|
"logs:DescribeLogGroups",
|
|
"logs:ListTagsForResource",
|
|
"logs:PutRetentionPolicy",
|
|
"logs:TagResource",
|
|
"logs:UntagResource",
|
|
]
|
|
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 = "VerificationAlarms"
|
|
effect = "Allow"
|
|
actions = [
|
|
"cloudwatch:DeleteAlarms",
|
|
"cloudwatch:DescribeAlarms",
|
|
"cloudwatch:ListTagsForResource",
|
|
"cloudwatch:PutMetricAlarm",
|
|
"cloudwatch:TagResource",
|
|
"cloudwatch:UntagResource",
|
|
]
|
|
resources = [
|
|
"arn:aws:cloudwatch:${var.aws_region}:${local.account_id}:alarm:forgejo-backup-*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "DescribeAlarms"
|
|
effect = "Allow"
|
|
actions = ["cloudwatch:DescribeAlarms"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "BackupPrefixParameter"
|
|
effect = "Allow"
|
|
actions = [
|
|
"ssm:AddTagsToResource",
|
|
"ssm:DeleteParameter",
|
|
"ssm:GetParameter",
|
|
"ssm:ListTagsForResource",
|
|
"ssm:PutParameter",
|
|
"ssm:RemoveTagsFromResource",
|
|
]
|
|
resources = [
|
|
"arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter/forgejo/*",
|
|
]
|
|
}
|
|
|
|
# DescribeParameters does not accept a parameter ARN. The provider calls it on *.
|
|
statement {
|
|
sid = "DescribeBackupParameters"
|
|
effect = "Allow"
|
|
actions = ["ssm:DescribeParameters"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "AlertTopicRead"
|
|
effect = "Allow"
|
|
actions = [
|
|
"sns:GetTopicAttributes",
|
|
"sns:ListTagsForResource",
|
|
]
|
|
resources = [local.site_alerts_arn]
|
|
}
|
|
|
|
statement {
|
|
sid = "EbsEncryption"
|
|
effect = "Allow"
|
|
actions = [
|
|
"kms:CreateGrant",
|
|
"kms:Decrypt",
|
|
"kms:DescribeKey",
|
|
"kms:GenerateDataKeyWithoutPlaintext",
|
|
"kms:ReEncryptFrom",
|
|
"kms:ReEncryptTo",
|
|
]
|
|
resources = ["*"]
|
|
|
|
condition {
|
|
test = "StringEquals"
|
|
variable = "kms:ViaService"
|
|
values = ["ec2.${var.aws_region}.amazonaws.com"]
|
|
}
|
|
}
|
|
}
|
|
|
|
data "aws_iam_policy_document" "hcptf_plan_refresh" {
|
|
statement {
|
|
sid = "RefreshIamRoles"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:GetInstanceProfile",
|
|
"iam:GetRole",
|
|
"iam:GetRolePolicy",
|
|
"iam:GetUser",
|
|
"iam:GetUserPolicy",
|
|
"iam:ListAttachedRolePolicies",
|
|
"iam:ListInstanceProfilesForRole",
|
|
"iam:ListRolePolicies",
|
|
"iam:ListRoleTags",
|
|
"iam:ListUserPolicies",
|
|
"iam:ListUserTags",
|
|
]
|
|
resources = [
|
|
"arn:aws:iam::${local.account_id}:role/tf-managed/${local.stack_prefix}*",
|
|
"arn:aws:iam::${local.account_id}:instance-profile/tf-managed/${local.stack_prefix}*",
|
|
"arn:aws:iam::${local.account_id}:user/tf-managed/${local.gcs_user_name}",
|
|
"arn:aws:iam::${local.account_id}:role/${local.apply_role}",
|
|
"arn:aws:iam::${local.account_id}:role/${local.plan_role}",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshManagedPolicies"
|
|
effect = "Allow"
|
|
actions = [
|
|
"iam:GetPolicy",
|
|
"iam:GetPolicyVersion",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshS3"
|
|
effect = "Allow"
|
|
actions = [
|
|
"s3:GetAccelerateConfiguration",
|
|
"s3:GetBucketAcl",
|
|
"s3:GetBucketCORS",
|
|
"s3:GetBucketLocation",
|
|
"s3:GetBucketLogging",
|
|
"s3:GetBucketNotification",
|
|
"s3:GetBucketObjectLockConfiguration",
|
|
"s3:GetBucketOwnershipControls",
|
|
"s3:GetBucketPolicy",
|
|
"s3:GetBucketPolicyStatus",
|
|
"s3:GetBucketPublicAccessBlock",
|
|
"s3:GetBucketRequestPayment",
|
|
"s3:GetBucketTagging",
|
|
"s3:GetBucketVersioning",
|
|
"s3:GetBucketWebsite",
|
|
"s3:GetEncryptionConfiguration",
|
|
"s3:GetLifecycleConfiguration",
|
|
"s3:GetReplicationConfiguration",
|
|
"s3:ListBucket",
|
|
]
|
|
resources = [
|
|
"arn:aws:s3:::${local.backup_bucket_name}",
|
|
"arn:aws:s3:::${local.replica_bucket_name}",
|
|
"arn:aws:s3:::${local.artifacts_bucket_name}",
|
|
]
|
|
}
|
|
|
|
# aws_s3_object refresh calls HeadObject and object metadata reads. Scope
|
|
# them to the verification package. Backup and replica objects stay unread.
|
|
statement {
|
|
sid = "RefreshLambdaPackage"
|
|
effect = "Allow"
|
|
actions = [
|
|
"s3:GetObject",
|
|
"s3:GetObjectAcl",
|
|
"s3:GetObjectAttributes",
|
|
"s3:GetObjectTagging",
|
|
]
|
|
resources = [
|
|
"arn:aws:s3:::${local.artifacts_bucket_name}/functions/forgejo-backup-verification.zip",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshEc2"
|
|
effect = "Allow"
|
|
actions = [
|
|
"ec2:DescribeAccountAttributes",
|
|
"ec2:DescribeAvailabilityZones",
|
|
"ec2:DescribeIamInstanceProfileAssociations",
|
|
"ec2:DescribeImages",
|
|
"ec2:DescribeInstanceAttribute",
|
|
"ec2:DescribeInstanceCreditSpecifications",
|
|
"ec2:DescribeInstanceStatus",
|
|
"ec2:DescribeInstanceTypes",
|
|
"ec2:DescribeInstances",
|
|
"ec2:DescribeNetworkInterfaces",
|
|
"ec2:DescribeSecurityGroupRules",
|
|
"ec2:DescribeSecurityGroups",
|
|
"ec2:DescribeSubnets",
|
|
"ec2:DescribeTags",
|
|
"ec2:DescribeVolumeAttribute",
|
|
"ec2:DescribeVolumeStatus",
|
|
"ec2:DescribeVolumes",
|
|
"ec2:DescribeVpcAttribute",
|
|
"ec2:DescribeVpcs",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshLoadBalancer"
|
|
effect = "Allow"
|
|
actions = [
|
|
"elasticloadbalancing:DescribeListenerAttributes",
|
|
"elasticloadbalancing:DescribeListeners",
|
|
"elasticloadbalancing:DescribeLoadBalancerAttributes",
|
|
"elasticloadbalancing:DescribeLoadBalancers",
|
|
"elasticloadbalancing:DescribeRules",
|
|
"elasticloadbalancing:DescribeTags",
|
|
"elasticloadbalancing:DescribeTargetGroupAttributes",
|
|
"elasticloadbalancing:DescribeTargetGroups",
|
|
"elasticloadbalancing:DescribeTargetHealth",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshCertificate"
|
|
effect = "Allow"
|
|
actions = [
|
|
"acm:DescribeCertificate",
|
|
"acm:ListCertificates",
|
|
"acm:ListTagsForCertificate",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshLambda"
|
|
effect = "Allow"
|
|
actions = [
|
|
"lambda:GetFunction",
|
|
"lambda:GetFunctionCodeSigningConfig",
|
|
"lambda:GetFunctionConfiguration",
|
|
"lambda:GetPolicy",
|
|
"lambda:GetRuntimeManagementConfig",
|
|
"lambda:ListTags",
|
|
"lambda:ListVersionsByFunction",
|
|
]
|
|
resources = [
|
|
"arn:aws:lambda:${var.aws_region}:${local.account_id}:function:forgejo-backup-verification",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshSchedules"
|
|
effect = "Allow"
|
|
actions = [
|
|
"events:DescribeRule",
|
|
"events:ListTagsForResource",
|
|
"events:ListTargetsByRule",
|
|
]
|
|
resources = [
|
|
"arn:aws:events:${var.aws_region}:${local.account_id}:rule/forgejo-backup-*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshLogs"
|
|
effect = "Allow"
|
|
actions = [
|
|
"logs:ListTagsForResource",
|
|
]
|
|
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}:*",
|
|
]
|
|
}
|
|
|
|
# DescribeLogGroups is a list API. Its resource is log-group::log-stream:, not the group ARN.
|
|
statement {
|
|
sid = "DescribeVerificationLogGroups"
|
|
effect = "Allow"
|
|
actions = ["logs:DescribeLogGroups"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshAlarms"
|
|
effect = "Allow"
|
|
actions = [
|
|
"cloudwatch:DescribeAlarms",
|
|
"cloudwatch:ListTagsForResource",
|
|
]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshParameter"
|
|
effect = "Allow"
|
|
actions = [
|
|
"ssm:GetParameter",
|
|
"ssm:ListTagsForResource",
|
|
]
|
|
resources = [
|
|
"arn:aws:ssm:${var.aws_region}:${local.account_id}:parameter/forgejo/*",
|
|
]
|
|
}
|
|
|
|
statement {
|
|
sid = "DescribeBackupParameters"
|
|
effect = "Allow"
|
|
actions = ["ssm:DescribeParameters"]
|
|
resources = ["*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshSnapshots"
|
|
effect = "Allow"
|
|
actions = [
|
|
"dlm:GetLifecyclePolicy",
|
|
"dlm:ListTagsForResource",
|
|
]
|
|
resources = ["arn:aws:dlm:${var.aws_region}:${local.account_id}:policy/*"]
|
|
}
|
|
|
|
statement {
|
|
sid = "RefreshSns"
|
|
effect = "Allow"
|
|
actions = [
|
|
"sns:GetTopicAttributes",
|
|
"sns:ListTagsForResource",
|
|
]
|
|
resources = [local.site_alerts_arn]
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role" "hcptf_apply" {
|
|
name = local.apply_role
|
|
assume_role_policy = data.aws_iam_policy_document.hcptf_apply_trust.json
|
|
max_session_duration = 3600
|
|
|
|
tags = {
|
|
Owner = "adam@seahavenind.com"
|
|
ManagedBy = "terraform"
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role" "hcptf_plan" {
|
|
name = local.plan_role
|
|
assume_role_policy = data.aws_iam_policy_document.hcptf_plan_trust.json
|
|
max_session_duration = 3600
|
|
|
|
tags = {
|
|
Owner = "adam@seahavenind.com"
|
|
ManagedBy = "terraform"
|
|
}
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "hcptf_scoped_iam" {
|
|
name = "scoped-iam-management"
|
|
role = aws_iam_role.hcptf_apply.id
|
|
policy = data.aws_iam_policy_document.hcptf_scoped_iam.json
|
|
}
|
|
|
|
# Managed, not inline: the enumerated EC2 list plus scoped-iam-management
|
|
# exceeds the 10,240-character inline quota. Bootstrap creates this on the
|
|
# first apply. Later document edits need that window (CreatePolicyVersion
|
|
# is denied on hcptf-forgejo).
|
|
resource "aws_iam_policy" "hcptf_apply_services" {
|
|
name = "forgejo-services"
|
|
path = "/tf-managed/"
|
|
description = "Forgejo HCP apply service permissions (PLAT-80)."
|
|
policy = data.aws_iam_policy_document.hcptf_apply_services.json
|
|
}
|
|
|
|
resource "aws_iam_role_policy" "hcptf_plan_refresh" {
|
|
name = "forgejo-plan-refresh"
|
|
role = aws_iam_role.hcptf_plan.id
|
|
policy = data.aws_iam_policy_document.hcptf_plan_refresh.json
|
|
}
|
|
|
|
resource "aws_iam_role_policy_attachment" "hcptf_plan_view_only" {
|
|
role = aws_iam_role.hcptf_plan.name
|
|
policy_arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess"
|
|
}
|
|
|
|
resource "aws_iam_role_policy_attachments_exclusive" "hcptf_apply" {
|
|
role_name = aws_iam_role.hcptf_apply.name
|
|
policy_arns = [
|
|
aws_iam_policy.hcptf_apply_services.arn,
|
|
]
|
|
}
|
|
|
|
resource "aws_iam_role_policy_attachments_exclusive" "hcptf_plan" {
|
|
role_name = aws_iam_role.hcptf_plan.name
|
|
policy_arns = [
|
|
"arn:aws:iam::aws:policy/job-function/ViewOnlyAccess",
|
|
]
|
|
}
|