Skip to content

microsoftexpert/tf-mod-aws-rbin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🗑️ AWS Recycle Bin (RBin) Retention Rule Terraform Module

Creates one AWS Recycle Bin retention rule (aws_rbin_rule) — an account/Region-wide, retroactive-going-forward safety net that intercepts deletes of matching EBS snapshots or AMIs and retains them for a set period, with an optional tamper-resistant lock. Built for the AWS provider v6.x.

Terraform aws module type resources


🧩 Overview

  • 🗑️ Creates one Recycle Bin retention rule that protects EBS_SNAPSHOT or EC2_IMAGE (AMI) resources from accidental or malicious permanent deletion — a deleted matching resource is moved into the Recycle Bin instead of destroyed outright.
  • 🎯 Two rule shapes, both supported: a tag-level rule (resource_tags set — protects only tagged resources) or a Region-level rule (resource_tags empty, optional exclude_resource_tags — protects everything of that type in the Region except explicit exclusions).
  • 🔒 Tamper-resistant locking (lock_configuration) — once locked, the retention period cannot be shortened and the rule cannot be deleted by anyone, including a fully-privileged rbin:* principal, until an explicit unlock and a 7–30 day unlock-delay period elapse. This module validates the real AWS constraint that only a bare Region-level rule can be locked at plan time, before it can fail at apply.
  • Acts retroactively going forward, not retroactively backward — from the moment the rule reaches available, every subsequent matching delete is intercepted account/Region-wide; it has no effect on anything already deleted.
  • 🔗 Emits id, status, lock_state, lock_end_time, and tags_all for wiring into runbooks, compliance reporting, and EventBridge-based alerting on lock-state changes.

💡 Why it matters: For a regulated FI, the ability to make a retention rule's protection itself tamper-resistant — immune even to a compromised or over-privileged IAM principal — is the single strongest control available against accidental or malicious deletion of snapshots and AMIs that may back PII-bearing volumes.


❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


🗺️ Where this fits in the family

tf-mod-aws-rbin is a leaf/consumer control — per SCOPE.md it consumes nothing from other tf-mod-aws-* modules; it matches EBS snapshots / AMIs by resource_type + tag (not by id/ARN) and stands alongside those modules as an account-level safety net.

flowchart LR
 EBS["tf-mod-aws-ebs-volume<br/>(snapshot lifecycle, matched by tag)"]
 AMI["tf-mod-aws-ami<br/>(matched by tag)"]
 THIS["tf-mod-aws-rbin<br/>(THIS MODULE)"]
 EB["tf-mod-aws-eventbridge<br/>(lock-state events, out of suite)"]

 EBS -.->|"resource_type=EBS_SNAPSHOT + tag match"| THIS
 AMI -.->|"resource_type=EC2_IMAGE + tag match"| THIS
 THIS -.->|"RuleLocked / RuleUnlocked events"| EB

 style THIS fill:#FF9900,color:#fff,stroke:#cc7a00,stroke-width:2px
Loading

This module consumes no direct outputs from other tf-mod-* modules (it matches resources by resource_type + tag rather than by reference); it emits id / lock_state for runbook and EventBridge correlation — see the Typical wiring table.


🧬 What this module builds

A single aws_rbin_rule.this keystone with dynamic blocks for the two mutually-exclusive rule shapes and the optional tamper-resistant lock.

flowchart TD
 subgraph mod["tf-mod-aws-rbin"]
 THIS["aws_rbin_rule.this<br/>(keystone)<br/>resource_type + retention_period"]
 RT["resource_tags<br/>(dynamic) — tag-level rule"]
 ERT["exclude_resource_tags<br/>(dynamic) — Region-level rule"]
 LOCK["lock_configuration<br/>(dynamic, 0 or 1) — tamper-resistant lock"]
 end

 THIS --> RT
 THIS --> ERT
 THIS --> LOCK

 style THIS fill:#FF9900,color:#fff,stroke:#cc7a00,stroke-width:2px
 style LOCK stroke-dasharray: 5 5
Loading
Resource / block Count Created when
aws_rbin_rule.this 1 always (keystone)
resource_tags 0..n caller sets non-empty var.resource_tags (tag-level rule)
exclude_resource_tags 0..n caller sets non-empty var.exclude_resource_tags (Region-level rule)
lock_configuration 0 or 1 var.lock_configuration != null — only valid on a bare Region-level rule

📁 Module Structure

tf-mod-aws-rbin/
├── providers.tf # terraform >= 1.12, aws >= 6.0 < 7.0 (no provider{} block)
├── variables.tf # description, resource_type, resource_tags, retention_period,
│ # lock_configuration, exclude_resource_tags, tags, timeouts
├── main.tf # aws_rbin_rule.this
├── outputs.tf # id, status, lock_state, lock_end_time, tags_all
├── README.md
└── SCOPE.md

⚙️ Quick Start

Smallest working call — a tag-level rule retaining tagged EBS snapshots for 30 days:

module "snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Retain deleted prod EBS snapshots for 30 days"
  resource_type = "EBS_SNAPSHOT"

  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" }
  ]

  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }

  tags = {
    Environment = "prod"
    CostCenter  = "platform"
  }
}

Wire it alongside the resources it protects:

module "app_data_volume" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-ebs-volume?ref=v1.0.0"
  tags   = { Environment = "prod" } # matches snapshot_retention.resource_tags above
  #...
}

⚠️ Pin the source to a tag (?ref=v1.0.0) — never a branch.


🔑 Required IAM Permissions

Least-privilege actions the executing Terraform identity needs (verified against the AWS "Control access to Recycle Bin with IAM" guide).

Action Required for Notes
rbin:CreateRule Rule creation (apply) Core create action.
rbin:GetRule Read / refresh state (plan)
rbin:ListRules Import / drift detection
rbin:UpdateRule In-place updates (description, retention period, tags) Rejected by the API while the rule is locked.
rbin:DeleteRule Destroy Rejected by the API while the rule is locked.
rbin:LockRule Applying a non-null lock_configuration Only valid on a bare Region-level rule (see Architecture Notes).
rbin:UnlockRule Removing/lowering lock_configuration Starts the unlock-delay clock; does not immediately unlock.
rbin:TagResource tags at create/update
rbin:UntagResource Tag removal
rbin:ListTagsForResource Tag read-back

Not ARN-scopable at create time — the rule id doesn't exist yet when CreateRule runs. Narrow beyond Resource: "*" using the rbin:Request/ResourceType (on CreateRule/ListRules) or rbin:Attribute/ResourceType condition keys instead.

ℹ️ No service-linked role, no iam:PassRole — Recycle Bin creates no SLR, and a retention rule is not an IAM principal.


📋 AWS Prerequisites

  • Service-linked roles: none required.
  • Account opt-ins: none — Recycle Bin is on by default in every active Region.
  • Scope is account + Region + resource-type wide, not per-resource — a rule matches by resource_type (+ tags for a tag-level rule), never by naming a specific snapshot/AMI id. It acts retroactively going forward only: it has no effect on resources deleted before it existed.
  • Two mutually exclusive rule shapes (see Architecture Notes for the full detail): tag-level (resource_tags set) and Region-level (resource_tags empty, optional exclude_resource_tags). Only a bare Region-level rule (both tag lists empty) is eligible for lock_configuration.
  • Region constraints: none — no us-east-1 global-service coupling. Rules are Region-scoped; the module inherits the caller's provider Region.
  • Service quotas: default 100 retention rules per Region per account (adjustable via Service Quotas).

🔌 Typical wiring

This module output Feeds into
id Runbooks / terraform import key; correlate against GetRule/EventBridge events, which reference the rule by this id.
status Post-apply health checks — confirm "available" before relying on the rule.
lock_state Compliance reporting; alerting on unexpected pending_unlock transitions (pairs with an EventBridge rule on RuleUnlockScheduled in a future tf-mod-aws-eventbridge wiring).
lock_end_time Runbooks during an active unlock window — when the rule becomes modifiable/deletable again.
tags_all Governance / audit of effective tags (incl. provider default_tags).

ℹ️ There is no arn outputaws_rbin_rule exposes no ARN attribute. See Architecture Notes.


🧠 Architecture Notes

ID formatid is the RBin-assigned rule identifier (e.g. rule-0123456789abcdef0). This is what the RBin API (GetRule / UpdateRule / DeleteRule) and terraform import use to reference the rule.

No ARN — a documented gap, not an oversight. The aws_rbin_rule resource (verified against hashicorp/aws v6.54.0) exports only id, status, lock_state, and lock_end_time. Recycle Bin references rules by id, and IAM scopes rbin:* actions via the rbin:Request/ResourceType / rbin:Attribute/ResourceType condition keys rather than a resource ARN. Primary outputs for this module are id + tags_all, not id + arn — adding an arn output here would reference a nonexistent attribute and fail terraform validate.

Two rule shapes, not composable filters:

  • Tag-level ruleresource_tags non-empty. Protects only resources carrying the matching tag(s). Narrow blast radius.
  • Region-level ruleresource_tags empty; exclude_resource_tags optionally non-empty. Protects every resource of resource_type in the Region except excluded tags. Broader — and, for a regulated FI, often the more protective default.

Setting both resource_tags and exclude_resource_tags non-empty is rejected by a validation {} block — the AWS API's own Basic-Usage vs Region-Level examples show these as two distinct modes, not a combinable filter.

lock_configuration eligibility (the key gotcha): per AWS, "You can't lock tag-level retention rules, or Region-level retention rules that have exclusion tags." Only a bare Region-level rule — resource_tags empty and exclude_resource_tags empty — can be locked. This module enforces that with cross-variable validation {} blocks so a misconfigured lock attempt fails at terraform plan, not at apply against the live RBin API.

Locking tradeoffs:

  • Once locked, UpdateRule and DeleteRule are rejected by the API for any principal until the rule is explicitly unlocked and the unlock-delay period elapses.
  • The unlock-delay value (7–30 days) cannot be changed once locked — only re-locked, which resets the clock. Choose it deliberately; it should exceed your realistic incident-detection-and-response window.
  • Unlocking does not immediately unlock — it starts the delay clock (lock_state transitions to pending_unlock, lock_end_time is populated).

tagstags_alldefault_tagsvar.tags flows to aws_rbin_rule.this.tags. The computed tags_all output is the merge of resource tags over the provider's default_tags; resource tags win on key conflict. default_tags is the caller's provider-block concern, never set inside this module.

Eventual consistency — a freshly created rule starts in status = "pending" and transitions to "available" shortly after; only "available" rules actively retain deletions.

Destroy ordering / lock interaction — destroying a locked rule fails outright; unlock it first (a lock_configuration update to null) and wait out the unlock-delay period before the destroy will succeed.

Region — retention rules are Region-scoped, not global; there is no us-east-1 constraint. Multi-Region coverage requires one module call per Region (provider aliases).


📚 Example Library (copy-paste)

1 · Minimal — tag-level EBS snapshot rule
module "snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" }
  ]
  retention_period = {
    retention_period_value = 14
    retention_period_unit  = "DAYS"
  }
}
2 · With tags
module "snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Retain tagged prod EBS snapshots"
  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" }
  ]
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }

  tags = {
    Environment = "prod"
    Application = "core-banking"
    Owner       = "platform-team"
  }
}

tags merge with provider default_tags; resource tags win on key conflict. Inspect the effective set via the tags_all output.

3 · EC2_IMAGE (AMI) variant — tag-level rule
module "ami_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Retain deleted golden-image AMIs for 90 days"
  resource_type = "EC2_IMAGE"
  resource_tags = [
    { resource_tag_key = "ImageClass", resource_tag_value = "golden" }
  ]
  retention_period = {
    retention_period_value = 90
    retention_period_unit  = "DAYS"
  }
}
4 · Region-level rule — protect every EBS snapshot in the Region
module "region_wide_snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Region-wide safety net for all deleted EBS snapshots"
  resource_type = "EBS_SNAPSHOT"
  # resource_tags left empty (default []) -> Region-level rule

  retention_period = {
    retention_period_value = 7
    retention_period_unit  = "DAYS"
  }
}

Broader than a tag-level rule by design — every EBS snapshot deleted in the Region is retained for 7 days, no tag required. This is also the only shape eligible for lock_configuration (Example 5).

5 · Locked Region-level rule (recommended for production)
module "locked_snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Locked, tamper-resistant retention for all prod-account EBS snapshots"
  resource_type = "EBS_SNAPSHOT"
  # resource_tags and exclude_resource_tags both empty -- required for locking

  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }

  lock_configuration = {
    unlock_delay = {
      unlock_delay_value = 14
      unlock_delay_unit  = "DAYS"
    }
  }

  tags = { Environment = "prod", Compliance = "locked-retention" }
}

⚠️ Once applied, this rule's 30-day retention cannot be shortened and the rule cannot be deleted by anyone until it is explicitly unlocked and the 14-day unlock delay elapses. Choose the unlock delay based on your realistic incident-response window — it cannot be changed later without re-locking.

6 · Region-level rule with exclusions
module "region_wide_with_exclusions" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Protect all AMIs except those explicitly marked ephemeral"
  resource_type = "EC2_IMAGE"
  exclude_resource_tags = [
    { resource_tag_key = "Lifecycle", resource_tag_value = "ephemeral" }
  ]

  retention_period = {
    retention_period_value = 14
    retention_period_unit  = "DAYS"
  }
}

⚠️ A Region-level rule with exclusion tags is not eligible for lock_configuration — only a bare Region-level rule (no resource_tags, no exclude_resource_tags) can be locked (see Example 5). Setting lock_configuration here fails terraform plan with a clear error.

7 · Custom description and short retention (dev/test)
module "dev_snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Short-window safety net for dev EBS snapshots"
  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "dev" }
  ]
  retention_period = {
    retention_period_value = 1
    retention_period_unit  = "DAYS"
  }
}
8 · Multiple tag conditions on one tag-level rule
module "multi_tag_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" },
    { resource_tag_key = "DataClass", resource_tag_value = "npi" }
  ]
  retention_period = {
    retention_period_value = 45
    retention_period_unit  = "DAYS"
  }
}

Multiple resource_tags entries are OR'd by the RBin API — a snapshot matching any listed tag is retained, not only one matching all.

9 · Customer-managed KMS — N/A for this resource

A Recycle Bin retention rule is a control-plane policy object — it holds no data of its own (the underlying EBS snapshots/AMIs it protects carry their own encryption, configured in tf-mod-aws-ebs-volume / tf-mod-aws-ami). This module therefore exposes no kms_key_arn variable: there is nothing here for a CMK to encrypt.

# No kms_key_arn here -- intentionally. Encrypt the protected snapshots/AMIs
# themselves in tf-mod-aws-ebs-volume / tf-mod-aws-ami, not the retention rule.
module "snapshot_retention" {
  source        = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"
  resource_type = "EBS_SNAPSHOT"
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }
}
10 · Secure-by-default opt-out — deliberately unlocked production rule

The secure-default recommendation is to lock production retention rules (Example 5). An explicit, documented exception to leave a production rule unlocked:

module "prod_unlocked_by_exception" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Unlocked by exception -- team needs to tune retention during rollout"
  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" }
  ]
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }
  # lock_configuration intentionally omitted (null) -- revisit once retention is finalized

  tags = { Exception = "unlocked-retention-rollout-tuning" }
}

Revisit and lock once the retention value is finalized — locking is cheap to add later, but the unlock-delay value cannot be changed after the fact.

11 · `for_each` pattern — one rule per resource type
locals {
  retention_rules = {
    snapshots = {
      resource_type = "EBS_SNAPSHOT"
      tag_value     = "prod"
      days          = 30
    }
    amis = {
      resource_type = "EC2_IMAGE"
      tag_value     = "prod"
      days          = 90
    }
  }
}

module "retention" {
  source   = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"
  for_each = local.retention_rules

  description   = "Retention for ${each.value.resource_type}"
  resource_type = each.value.resource_type
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = each.value.tag_value }
  ]
  retention_period = {
    retention_period_value = each.value.days
    retention_period_unit  = "DAYS"
  }

  tags = { Environment = "prod" }
}

One aws_rbin_rule protects exactly one resource_typefor_each is the pattern for standing up the full set (snapshots + AMIs) from one module block.

12 · Import an existing retention rule
import {
  to = module.existing_rule.aws_rbin_rule.this
  id = "rule-0123456789abcdef0"
}

module "existing_rule" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  resource_type = "EBS_SNAPSHOT"
  resource_tags = [
    { resource_tag_key = "Environment", resource_tag_value = "prod" }
  ]
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }
}

Match resource_type, resource_tags / exclude_resource_tags, and retention_period to the real rule's configuration before import, or the next plan shows a diff.

13 · Verify rule status and lock state post-apply
module "snapshot_retention" {
  source        = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"
  resource_type = "EBS_SNAPSHOT"
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }
  lock_configuration = {
    unlock_delay = { unlock_delay_value = 7, unlock_delay_unit = "DAYS" }
  }
}

output "rule_status" {
  value = module.snapshot_retention.status
}

output "rule_lock_state" {
  value = module.snapshot_retention.lock_state
}
14 · Multi-Region — same rule in two Regions (provider aliases)
provider "aws" {
  alias  = "use1"
  region = "us-east-1"
}
provider "aws" {
  alias  = "usw2"
  region = "us-west-2"
}

module "retention_use1" {
  source    = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"
  providers = { aws = aws.use1 }

  resource_type    = "EBS_SNAPSHOT"
  resource_tags    = [{ resource_tag_key = "Environment", resource_tag_value = "prod" }]
  retention_period = { retention_period_value = 30, retention_period_unit = "DAYS" }
}

module "retention_usw2" {
  source    = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"
  providers = { aws = aws.usw2 }

  resource_type    = "EBS_SNAPSHOT"
  resource_tags    = [{ resource_tag_key = "Environment", resource_tag_value = "prod" }]
  retention_period = { retention_period_value = 30, retention_period_unit = "DAYS" }
}

Retention rules are Region-scoped — register one per Region you provision snapshots/AMIs in.

15 · End-to-end composition — locked Region-level rules wired alongside protected resources
module "app_data_volume" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-ebs-volume?ref=v1.0.0"

  tags = { Environment = "prod", DataClass = "npi" }
  #... size, availability_zone, kms_key_arn (from tf-mod-aws-kms)...
}

module "golden_ami" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-ami?ref=v1.0.0"

  tags = { ImageClass = "golden" }
  #... image build details...
}

# One locked, Region-wide rule protecting every EBS snapshot in the account/Region
module "snapshot_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Locked account-wide safety net for all EBS snapshots"
  resource_type = "EBS_SNAPSHOT"
  retention_period = {
    retention_period_value = 30
    retention_period_unit  = "DAYS"
  }
  lock_configuration = {
    unlock_delay = { unlock_delay_value = 14, unlock_delay_unit = "DAYS" }
  }
  tags = { Environment = "prod" }
}

# A narrower, tag-scoped rule for golden AMIs -- kept unlocked so the image
# pipeline can retune retention during rollout (Example 10 pattern)
module "ami_retention" {
  source = "git::https://github.com/microsoftexpert/tf-mod-aws-rbin?ref=v1.0.0"

  description   = "Golden AMI retention (unlocked during pipeline rollout)"
  resource_type = "EC2_IMAGE"
  resource_tags = [
    { resource_tag_key = "ImageClass", resource_tag_value = "golden" }
  ]
  retention_period = {
    retention_period_value = 90
    retention_period_unit  = "DAYS"
  }
}

The Region-level snapshot rule protects app_data_volume's snapshots (and every other EBS snapshot in the Region) without needing to reference it by id or ARN — Recycle Bin matches by resource_type (+ tags), not by resource reference, which is why this module consumes nothing from tf-mod-aws-ebs-volume/tf-mod-aws-ami directly.


📥 Inputs (high-level)

Core

  • description (string, default null) — human-readable description; the closest thing to a "name" this resource has.
  • resource_type (string, required) — "EBS_SNAPSHOT" or "EC2_IMAGE".
  • retention_period (object, required) — { retention_period_value = number, retention_period_unit = optional(string, "DAYS") }.

Rule scope

  • resource_tags (list(object), default []) — tag-level rule scope; each { resource_tag_key, resource_tag_value = optional }.
  • exclude_resource_tags (list(object), default []) — Region-level rule exclusions; same shape. Mutually exclusive with a non-empty resource_tags.

Locking

  • lock_configuration (object, default null) — { unlock_delay = { unlock_delay_value = number (7-30), unlock_delay_unit = optional(string, "DAYS") } }. Only valid when both tag lists above are empty.

Universal

  • tags (map(string), default {}).
  • timeouts (object, default {} — provider defaults 30m create/update/delete apply).

🧾 Outputs

  • id — the rule identifier (rule-...); the RBin API and terraform import reference key.
  • status"pending" or "available".
  • lock_state"locked" / "pending_unlock" / "unlocked".
  • lock_end_time — unlock-delay expiry timestamp (populated only while pending_unlock).
  • tags_all — merged tags incl. provider default_tags.

No sensitive outputs — this resource holds no secret material. No arn output — the resource exposes none (see Architecture Notes).


🧱 Design Principles

Posture Default Opt-out / opt-in
Rule scope resource_tags empty (no forced tag filter) Set resource_tags for a narrow tag-level rule, or deliberately choose the broader Region-level shape (often the more protective choice for a regulated FI) by leaving it empty
Tamper-resistant retention (lock_configuration) null (unlocked) Recommended for production — set a non-null lock_configuration on a bare Region-level rule; the friction of an immutable retention period is deliberate
Unlock delay No implicit default; validated to AWS's enforced 7-30 day range Choose the longest delay your incident-response process can tolerate — it cannot be shortened after locking

Additional principles:

  • Single resource named this — exactly four files; no provider {} block; no credential or region variable.
  • Real API constraints enforced at plan time, not apply time — the lock/tag-shape mutual exclusions are validated in variables.tf so a misconfiguration fails terraform plan instead of the live RBin API.
  • Primary outputs id + tags_all (not id + arn — this resource exposes no ARN, documented rather than fabricated).

🚀 Runbook

cd C:\GitHubCode\newawsmodules\tf-mod-aws-rbin

terraform init -backend=false
terraform validate
terraform fmt -check

plan / apply require valid AWS credentials (profile / SSO / OIDC) and a configured provider Region. This module declares only required_providers and inherits the caller's provider.

⚠️ Pin the source with ?ref=v1.0.0, never a branch.


🔍 Troubleshooting

Symptom Likely cause Fix
lock_configuration cannot be set on a tag-level rule (plan-time validation error) lock_configuration set together with non-empty resource_tags Locking only applies to a bare Region-level rule — clear resource_tags or drop lock_configuration.
lock_configuration cannot be set on a Region-level rule that has exclusion tags lock_configuration set together with non-empty exclude_resource_tags Clear exclude_resource_tags or drop lock_configuration — only a rule with both tag lists empty can be locked.
Set resource_tags... or exclude_resource_tags..., not both Both tag lists non-empty These are two different rule shapes (tag-level vs Region-level) — populate only one.
apply fails updating/deleting a rule that plans cleanly The rule is currently locked Expected — UpdateRule/DeleteRule are rejected by AWS while locked. Unlock first and wait out the unlock-delay period.
Rule appears created but isn't retaining deletions yet status is still "pending", not "available" Check the status output; newly created rules transition shortly after apply.
apply fails UnauthorizedOperation / AccessDenied Missing IAM action (e.g. rbin:CreateRule, rbin:LockRule) Grant the least-privilege action from Required IAM Permissions; don't broaden to *.
Tag drift on every plan Same key in both provider default_tags and module tags Resource tags win — remove the duplicate from one side; inspect tags_all.
Confusion looking for an arn output This resource exports no ARN attribute Reference the rule by its id output instead — that's what the RBin API itself uses.
Unlock delay can't be changed Rule was already locked with a different unlock_delay_value Expected — AWS fixes the unlock delay once locked. Re-lock (which resets the clock) if you must change it.

🔗 Related Docs


🧡 "Infrastructure as Code should be standardized, consistent, and secure."

About

No description or website provided.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages