Security group: known Terraform limitations
Some things people ask the terraform-aws-modules/security-group/aws module for
cannot be implemented by any module, in any registry. They are limits of
Terraform itself. This page collects the recurring ones for this module, says
plainly what causes each, gives the native workaround in full, and - where one
exists - shows the Operational Rule that removes the need for a fork.
This module is downloaded ~3M times a month, so these come up often.
Read the native option first
Every problem below names the workaround you can apply today without compliance.tf. Several of them are the right answer on their own. The rule is an alternative to maintaining a fork, not a replacement for a control AWS already offers you.
Terraform cannot replace a security group that is still attached to something
A change that forces replacement - a new name, or a name_prefix change - makes Terraform destroy the group before creating its replacement. AWS refuses to delete a security group that any ENI still references, so the apply fails part-way through with DependencyViolation and leaves the change half-applied.
Why Terraform cannot fix this
lifecycle is a meta-argument block, and Terraform evaluates it before it evaluates the rest of the configuration. Its arguments therefore cannot reference a variable, a local, or anything else that is computed. That is the whole reason no module can expose prevent_destroy, ignore_changes, or create_before_destroy as an input: there is no expression a module author could put there that Terraform would accept.
This is a property of Terraform, not of this module. The request to lift the restriction has been open since 2015, it is one of the most-supported requests in the tracker, and OpenTofu carries the same request. Until one of them ships a way to set a meta-argument from outside the resource block, every module in every registry has the same limitation.
| Repository | Issue | Title |
|---|---|---|
| hashicorp/terraform | #3116 | Cannot use interpolations in lifecycle attributes |
| hashicorp/terraform | #18367 | Feature request: support prevent_destroy for modules |
| hashicorp/terraform | #21546 | Passing ignore_changes into a module |
| hashicorp/terraform | #24188 | Support for dynamic blocks and meta-arguments |
| hashicorp/terraform | #27360 | A method to override configuration and meta arguments within a module |
| opentofu/opentofu | #1329 | Support variables in lifecycle blocks |
The native workaround
The fix is create_before_destroy = true on the security group, which is a lifecycle argument and so cannot be passed in. Fork this module and add the lifecycle block to the resource yourself. That works, and it is the honest answer - it is what module maintainers do when they need it. The cost is ongoing rather than one-off: the fork has to be re-synced with every upstream release, and each sync needs a review to confirm the block still lands on the resource it was meant for. A wrapper module does not avoid this, because the lifecycle block still has to sit inside the resource block, which is inside the module you did not write.
Where replacement is not actually required, the other native option is to avoid forcing it: keep name_prefix stable and change rules in place rather than recreating the group.
Managed fix
Native option only, today. compliance.tf has no rule for this yet, so the
workaround above is the whole answer. create_before_destroy is not yet available as a rule.
Using the maintained alternative
compliance.tf serves this module from a registry that applies the rules above
during terraform init. The change is the source line; the inputs and outputs are the upstream module's.
module "security_group" {
source = "https://cis.compliance.tf/terraform-aws-modules/security-group/aws"
# ... the same inputs you pass today ...
}None of the limitations above has a rule yet, so this module is served with
compliance controls only. The ?add_rules= parameter takes the ids of rules that
do exist - see Operational Rule Definitions.
Related
- Operational Rules - what rules are, and how they differ from compliance controls
- Operational Rule Definitions - the HCL of every selectable rule
- Stop paying the Terraform fork tax - why forking a module to add a
lifecycleblock costs more than it looks