# Instance permissions boundary. # The scoped apply role denies iam:CreatePolicy / CreatePolicyVersion, # so later edits to this document need the hcptf-bootstrap window. data "aws_iam_policy_document" "instance_boundary" { # checkov:skip=CKV_AWS_111: SSM agent APIs require Resource=*. Secret reads are ARN-scoped. statement { sid = "SecretsRead" effect = "Allow" actions = [ "secretsmanager:GetSecretValue", ] resources = [ var.smb_password_secret_arn, var.filebrowser_password_secret_arn, ] } statement { sid = "Ec2DescribeForAgent" effect = "Allow" actions = [ "ec2:DescribeTags", "ec2:DescribeVolumes", "ec2:DescribeInstances", ] resources = ["*"] } 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:GetDeployablePatchSnapshotForInstance", "ssm:GetDocument", "ssm:DescribeDocument", "ssm:GetManifest", "ssm:ListAssociations", "ssm:ListInstanceAssociations", "ssm:PutInventory", "ssm:PutComplianceItems", "ssm:PutConfigurePackageResult", "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}:${data.aws_caller_identity.current.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" "instance_boundary" { # checkov:skip=CKV_AWS_111: SSM agent APIs require Resource=*. Secret reads are ARN-scoped. name = local.boundary_name path = "/tf-managed/" description = "EC2 permissions boundary for file-share." policy = data.aws_iam_policy_document.instance_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.instance_boundary.arn tags = { Name = local.instance_role_name } } resource "aws_iam_role_policy_attachment" "ssm" { role = aws_iam_role.instance.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } data "aws_iam_policy_document" "instance_secrets" { statement { sid = "SecretsRead" effect = "Allow" actions = [ "secretsmanager:GetSecretValue", ] resources = [ var.smb_password_secret_arn, var.filebrowser_password_secret_arn, ] } } resource "aws_iam_role_policy" "instance_secrets" { name = "file-share-secrets" role = aws_iam_role.instance.id policy = data.aws_iam_policy_document.instance_secrets.json } resource "aws_iam_instance_profile" "this" { name = local.instance_profile_name path = "/tf-managed/" role = aws_iam_role.instance.name } # DLM permissions boundary. # Intersection with AWSDataLifecycleManagerServiceRole is the snapshot API set. # Creating this policy needs the hcptf-bootstrap window. data "aws_iam_policy_document" "dlm_boundary" { # checkov:skip=CKV_AWS_111: DLM snapshot and describe APIs require Resource=*. EventBridge rules are ARN-scoped. statement { sid = "SnapshotLifecycle" effect = "Allow" actions = [ "ec2:CopySnapshot", "ec2:CreateSnapshot", "ec2:CreateSnapshots", "ec2:CreateTags", "ec2:DeleteSnapshot", "ec2:DescribeAvailabilityZones", "ec2:DescribeFastSnapshotRestores", "ec2:DescribeInstances", "ec2:DescribeSnapshotAttribute", "ec2:DescribeSnapshots", "ec2:DescribeSnapshotTierStatus", "ec2:DescribeVolumes", "ec2:DisableFastSnapshotRestores", "ec2:EnableFastSnapshotRestores", "ec2:ModifySnapshotTier", ] resources = ["*"] } statement { sid = "SnapshotSharing" effect = "Allow" actions = ["ec2:ModifySnapshotAttribute"] resources = ["arn:aws:ec2:*:*:snapshot/*"] } statement { sid = "SnapshotRules" effect = "Allow" actions = [ "events:DeleteRule", "events:DescribeRule", "events:DisableRule", "events:EnableRule", "events:ListTargetsByRule", "events:PutRule", "events:PutTargets", "events:RemoveTargets", ] resources = ["arn:aws:events:*:*:rule/AwsDataLifecycleRule.managed-cwe.*"] } } resource "aws_iam_policy" "dlm_boundary" { # checkov:skip=CKV_AWS_111: DLM snapshot and describe APIs require Resource=*. EventBridge rules are ARN-scoped. name = local.dlm_boundary_name path = "/tf-managed/" description = "Permissions boundary for the file-share DLM role." policy = data.aws_iam_policy_document.dlm_boundary.json } 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.dlm_boundary.arn tags = { Name = local.dlm_role_name } } resource "aws_iam_role_policy_attachment" "dlm" { role = aws_iam_role.dlm.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSDataLifecycleManagerServiceRole" }