mirror of
https://github.com/Sea-Haven-Industries/file-share.git
synced 2026-10-03 12:43:16 +00:00
fix(infra): run nightly snapshots as a stack-local DLM role (PLAT-77)
The lifecycle policy assumed a service-linked role AWS does not provide, so it stayed in ERROR and never snapshotted the data volume.
This commit is contained in:
parent
bbbdacd01c
commit
1a3c3d72a2
5 changed files with 90 additions and 21 deletions
|
|
@ -23,7 +23,7 @@ The data volume is not created by Terraform. Set `data_volume_id` on the workspa
|
||||||
|
|
||||||
Workspace `file-share-prod` is manual apply. Auto-apply stays off until the share has soaked. `user_data_replace_on_change` is false, so an AMI or user-data change does not replace the instance by itself. Snapshot the data volume and confirm before any apply that would replace the instance.
|
Workspace `file-share-prod` is manual apply. Auto-apply stays off until the share has soaked. `user_data_replace_on_change` is false, so an AMI or user-data change does not replace the instance by itself. Snapshot the data volume and confirm before any apply that would replace the instance.
|
||||||
|
|
||||||
The nightly DLM policy targets volumes tagged `file-share-backup=true` and keeps 30 snapshots.
|
The nightly DLM policy targets volumes tagged `file-share-backup=true` and keeps 30 snapshots. The policy runs as `/tf-managed/file-share-dlm`.
|
||||||
|
|
||||||
## Secrets
|
## Secrets
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
resource "aws_dlm_lifecycle_policy" "nightly" {
|
resource "aws_dlm_lifecycle_policy" "nightly" {
|
||||||
description = "Nightly EBS snapshots for file share"
|
description = "Nightly EBS snapshots for file share"
|
||||||
execution_role_arn = local.dlm_service_role_arn
|
execution_role_arn = aws_iam_role.dlm.arn
|
||||||
state = "ENABLED"
|
state = "ENABLED"
|
||||||
|
|
||||||
policy_details {
|
policy_details {
|
||||||
|
|
|
||||||
|
|
@ -156,10 +156,10 @@ data "aws_iam_policy_document" "hcptf_scoped_iam" {
|
||||||
}
|
}
|
||||||
|
|
||||||
statement {
|
statement {
|
||||||
sid = "PassDlmServiceRole"
|
sid = "PassDlmRole"
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
actions = ["iam:PassRole"]
|
actions = ["iam:PassRole"]
|
||||||
resources = [local.dlm_service_role_arn]
|
resources = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/tf-managed/${local.dlm_role_name}"]
|
||||||
|
|
||||||
condition {
|
condition {
|
||||||
test = "StringEquals"
|
test = "StringEquals"
|
||||||
|
|
@ -168,21 +168,6 @@ data "aws_iam_policy_document" "hcptf_scoped_iam" {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
statement {
|
|
||||||
sid = "CreateDlmServiceLinkedRole"
|
|
||||||
effect = "Allow"
|
|
||||||
actions = [
|
|
||||||
"iam:CreateServiceLinkedRole",
|
|
||||||
]
|
|
||||||
resources = [local.dlm_service_role_arn]
|
|
||||||
|
|
||||||
condition {
|
|
||||||
test = "StringEquals"
|
|
||||||
variable = "iam:AWSServiceName"
|
|
||||||
values = ["dlm.amazonaws.com"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
statement {
|
statement {
|
||||||
sid = "InstanceProfiles"
|
sid = "InstanceProfiles"
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
|
|
|
||||||
|
|
@ -165,3 +165,87 @@ resource "aws_iam_instance_profile" "this" {
|
||||||
path = "/tf-managed/"
|
path = "/tf-managed/"
|
||||||
role = aws_iam_role.instance.name
|
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:ModifySnapshotAttribute",
|
||||||
|
"ec2:ModifySnapshotTier",
|
||||||
|
]
|
||||||
|
resources = ["*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ locals {
|
||||||
instance_role_name = "file-share-role"
|
instance_role_name = "file-share-role"
|
||||||
instance_profile_name = "file-share-profile"
|
instance_profile_name = "file-share-profile"
|
||||||
boundary_name = "file-share-instance-boundary"
|
boundary_name = "file-share-instance-boundary"
|
||||||
|
dlm_role_name = "file-share-dlm"
|
||||||
|
dlm_boundary_name = "file-share-dlm-boundary"
|
||||||
|
|
||||||
office_lan_cidrs = ["10.10.0.0/16", "10.30.0.0/16"]
|
office_lan_cidrs = ["10.10.0.0/16", "10.30.0.0/16"]
|
||||||
subnet_cidr = "10.40.20.0/24"
|
subnet_cidr = "10.40.20.0/24"
|
||||||
|
|
@ -19,8 +21,6 @@ locals {
|
||||||
|
|
||||||
create_instance = var.data_volume_id != ""
|
create_instance = var.data_volume_id != ""
|
||||||
|
|
||||||
dlm_service_role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/dlm.amazonaws.com/AWSServiceRoleForDataLifecycleManager"
|
|
||||||
|
|
||||||
user_data = templatefile("${path.module}/user_data.sh.tftpl", {
|
user_data = templatefile("${path.module}/user_data.sh.tftpl", {
|
||||||
aws_region = var.aws_region
|
aws_region = var.aws_region
|
||||||
filebrowser_version = var.filebrowser_version
|
filebrowser_version = var.filebrowser_version
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue