feat(feature-flags): centralized tenant-wide feature toggles

Add feature-flags module for organization-wide security controls:
- Environment presets (production/staging/development)
- Security toggles (GuardDuty, Security Hub, Config, CloudTrail)
- Compliance toggles (CIS, PCI, HIPAA, NIST, SOC2)
- IAM toggles (password policy, MFA enforcement)
- Alerting toggles (severity routing, thresholds)
- Cost management toggles (budgets, thresholds)
- Networking toggles (VPC, endpoints, NAT)
- Backup toggles (schedules, retention)

All features are OPT-IN by default. User input overrides presets.
Includes example wiring into security-baseline and alerting modules.
This commit is contained in:
Greg Hendrickson
2026-02-03 20:02:59 +00:00
parent 6136cde9bb
commit a4e07796b8
3 changed files with 827 additions and 0 deletions

View File

@@ -0,0 +1,232 @@
# Feature Flags Module
Centralized feature toggles for organization-wide security, compliance, and operational controls. Define once, propagate everywhere.
## Philosophy
- **Everything OPT-IN**: All features default to `false` or minimal settings
- **Environment Presets**: Quick setup via `production`, `staging`, or `development` presets
- **User Override Wins**: Explicit settings always override preset defaults
- **Single Source of Truth**: Define features once, reference everywhere
## Usage
### Basic - Custom Settings
```hcl
module "feature_flags" {
source = "../modules/feature-flags"
security = {
guardduty_enabled = true
securityhub_enabled = true
config_enabled = true
cloudtrail_enabled = true
}
compliance = {
cis_benchmark_enabled = true
}
iam = {
mfa_enforcement_enabled = true
}
}
```
### Quick Start - Environment Presets
```hcl
# Production: Maximum security (all security services enabled)
module "feature_flags" {
source = "../modules/feature-flags"
environment_preset = "production"
}
# Staging: Security with cost awareness
module "feature_flags" {
source = "../modules/feature-flags"
environment_preset = "staging"
}
# Development: Minimal security, maximum flexibility
module "feature_flags" {
source = "../modules/feature-flags"
environment_preset = "development"
}
```
### Preset with Overrides
```hcl
module "feature_flags" {
source = "../modules/feature-flags"
environment_preset = "production"
# Override: Disable Macie even in production
security = {
macie_enabled = false
}
# Override: Enable PCI compliance
compliance = {
pci_dss_enabled = true
}
}
```
### Consuming in Other Modules
```hcl
module "security_baseline" {
source = "../modules/security-baseline"
name = "org-security"
# Reference feature flags
enable_guardduty = module.feature_flags.security.guardduty_enabled
enable_securityhub = module.feature_flags.security.securityhub_enabled
enable_config = module.feature_flags.security.config_enabled
enable_access_analyzer = module.feature_flags.security.access_analyzer_enabled
config_bucket_name = module.s3_bucket.id
}
module "alerting" {
source = "../modules/alerting"
name = "org-alerts"
enable_guardduty_events = module.feature_flags.alerting.guardduty_alerts_enabled
enable_securityhub_events = module.feature_flags.alerting.securityhub_alerts_enabled
enable_aws_health_events = module.feature_flags.alerting.health_alerts_enabled
}
```
## Environment Presets Comparison
| Feature | Production | Staging | Development |
|---------|------------|---------|-------------|
| GuardDuty | ✅ | ✅ | ❌ |
| Security Hub | ✅ | ✅ | ❌ |
| AWS Config | ✅ | ✅ | ❌ |
| CloudTrail | ✅ | ✅ | ❌ |
| Access Analyzer | ✅ | ❌ | ❌ |
| CIS Benchmark | ✅ | ❌ | ❌ |
| MFA Enforcement | ✅ | ❌ | ❌ |
| Permissions Boundary | ✅ | ✅ | ❌ |
| EBS Encryption | ✅ | ✅ | ✅ |
| S3 Block Public | ✅ | ✅ | ❌ |
## Feature Categories
### Security (`var.security`)
Threat detection and data protection services.
| Flag | Default | Description |
|------|---------|-------------|
| `guardduty_enabled` | `false` | Enable GuardDuty threat detection |
| `guardduty_s3_protection` | `true` | GuardDuty S3 data source |
| `guardduty_eks_protection` | `true` | GuardDuty EKS audit logs |
| `guardduty_malware_protection` | `true` | GuardDuty malware scanning |
| `securityhub_enabled` | `false` | Enable Security Hub |
| `config_enabled` | `false` | Enable AWS Config |
| `cloudtrail_enabled` | `false` | Enable CloudTrail |
| `access_analyzer_enabled` | `false` | Enable IAM Access Analyzer |
| `ebs_encryption_default` | `true` | Default EBS encryption |
| `s3_block_public_access` | `true` | Account-level S3 public block |
### Compliance (`var.compliance`)
Compliance frameworks and Config rules.
| Flag | Default | Description |
|------|---------|-------------|
| `cis_benchmark_enabled` | `false` | CIS AWS Foundations Benchmark |
| `aws_foundational_enabled` | `true` | AWS Foundational Security Best Practices |
| `pci_dss_enabled` | `false` | PCI DSS compliance rules |
| `hipaa_enabled` | `false` | HIPAA compliance rules |
| `config_rules_enabled` | `false` | Enable managed Config rules |
| `config_auto_remediation` | `false` | Auto-remediate Config findings |
### IAM (`var.iam`)
Identity and access management policies.
| Flag | Default | Description |
|------|---------|-------------|
| `password_policy_enabled` | `true` | Enable account password policy |
| `password_minimum_length` | `14` | Minimum password length |
| `password_max_age_days` | `90` | Password rotation period |
| `mfa_enforcement_enabled` | `false` | Require MFA for all actions |
| `mfa_grace_period_days` | `0` | Grace period for new users |
| `require_imdsv2` | `true` | Require EC2 IMDSv2 |
### Alerting (`var.alerting`)
Security event notifications.
| Flag | Default | Description |
|------|---------|-------------|
| `guardduty_alerts_enabled` | `true` | Alert on GuardDuty findings |
| `securityhub_alerts_enabled` | `true` | Alert on Security Hub findings |
| `health_alerts_enabled` | `true` | Alert on AWS Health events |
| `guardduty_min_severity` | `4.0` | Minimum GuardDuty severity (0-10) |
| `securityhub_min_severity` | `70` | Minimum Security Hub severity (0-100) |
### Cost (`var.cost`)
Budget and cost management.
| Flag | Default | Description |
|------|---------|-------------|
| `budgets_enabled` | `true` | Enable AWS Budgets |
| `budget_default_limit` | `1000` | Default monthly budget |
| `budget_alert_thresholds` | `[50,80,100]` | Alert threshold percentages |
| `cost_allocation_tags_enabled` | `true` | Enable cost allocation tags |
### Networking (`var.networking`)
VPC and network configuration.
| Flag | Default | Description |
|------|---------|-------------|
| `create_vpc` | `true` | Create tenant VPC |
| `vpc_endpoints_enabled` | `true` | Create VPC endpoints |
| `nat_gateway_enabled` | `true` | Create NAT Gateway |
| `nat_gateway_ha` | `false` | Multi-AZ NAT Gateways |
### Backup (`var.backup`)
AWS Backup configuration.
| Flag | Default | Description |
|------|---------|-------------|
| `backup_enabled` | `false` | Enable AWS Backup |
| `daily_backup_enabled` | `true` | Daily backup schedule |
| `daily_retention_days` | `7` | Daily backup retention |
## Outputs
| Output | Description |
|--------|-------------|
| `security` | Merged security feature flags |
| `compliance` | Merged compliance feature flags |
| `iam` | Merged IAM feature flags |
| `alerting` | Merged alerting feature flags |
| `cost` | Cost management feature flags |
| `networking` | Networking feature flags |
| `backup` | Backup feature flags |
| `environment_preset` | Active preset name |
| `is_production` | Boolean: true if production preset |
| `encryption_required` | Boolean: true if encryption defaults enabled |
| `compliance_strict` | Boolean: true if strict compliance enabled |
## Best Practices
1. **Define Once**: Create feature flags in your root/organization module
2. **Reference Everywhere**: Pass flags to child modules via outputs
3. **Use Presets**: Start with a preset, override as needed
4. **Document Deviations**: Comment why you override preset defaults
5. **Review Regularly**: Periodically review which features are enabled

View File

@@ -0,0 +1,170 @@
################################################################################
# Example: Organization Baseline with Feature Flags
#
# Demonstrates wiring feature flags into security and compliance modules.
# Copy and adapt for your organization's needs.
################################################################################
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
################################################################################
# Feature Flags - Single Source of Truth
################################################################################
module "feature_flags" {
source = "../../"
# Use production preset with customizations
environment_preset = "production"
# Override: Also enable PCI compliance
compliance = {
pci_dss_enabled = true
}
# Override: Configure alerting thresholds
alerting = {
guardduty_min_severity = 7.0 # Only alert on HIGH+ findings
critical_to_pagerduty = true # Page for critical issues
}
}
################################################################################
# Security Baseline - Consumes Feature Flags
################################################################################
resource "aws_s3_bucket" "config" {
bucket_prefix = "org-config-"
force_destroy = true
}
resource "aws_s3_bucket_versioning" "config" {
bucket = aws_s3_bucket.config.id
versioning_configuration {
status = "Enabled"
}
}
module "security_baseline" {
source = "../../../security-baseline"
name = "org-security"
# Wire feature flags
enable_guardduty = module.feature_flags.security.guardduty_enabled
enable_securityhub = module.feature_flags.security.securityhub_enabled
enable_config = module.feature_flags.security.config_enabled
enable_access_analyzer = module.feature_flags.security.access_analyzer_enabled
config_bucket_name = aws_s3_bucket.config.id
# Security Hub standards based on compliance flags
securityhub_standards = concat(
module.feature_flags.compliance.aws_foundational_enabled ? ["aws-foundational-security-best-practices/v/1.0.0"] : [],
module.feature_flags.compliance.cis_benchmark_enabled ? ["cis-aws-foundations-benchmark/v/1.4.0"] : [],
module.feature_flags.compliance.pci_dss_enabled ? ["pci-dss/v/3.2.1"] : []
)
tags = {
Environment = module.feature_flags.environment_preset
ManagedBy = "terraform"
}
}
################################################################################
# Alerting - Consumes Feature Flags
################################################################################
module "alerting" {
source = "../../../alerting"
name = "org-alerts"
email_endpoints = ["security@example.com"]
# Wire feature flags
enable_guardduty_events = module.feature_flags.alerting.guardduty_alerts_enabled
enable_securityhub_events = module.feature_flags.alerting.securityhub_alerts_enabled
enable_aws_health_events = module.feature_flags.alerting.health_alerts_enabled
tags = {
Environment = module.feature_flags.environment_preset
}
}
################################################################################
# IAM Account Settings - Consumes Feature Flags
################################################################################
module "iam_settings" {
source = "../../../iam-account-settings"
account_alias = "my-org-prod"
enable_password_policy = module.feature_flags.iam.password_policy_enabled
enforce_mfa = module.feature_flags.iam.mfa_enforcement_enabled
password_policy = {
minimum_length = module.feature_flags.iam.password_minimum_length
require_symbols = module.feature_flags.iam.password_require_symbols
require_numbers = module.feature_flags.iam.password_require_numbers
require_uppercase_characters = module.feature_flags.iam.password_require_uppercase
require_lowercase_characters = module.feature_flags.iam.password_require_lowercase
max_password_age = module.feature_flags.iam.password_max_age_days
password_reuse_prevention = module.feature_flags.iam.password_reuse_prevention
}
tags = {
Environment = module.feature_flags.environment_preset
}
}
################################################################################
# CloudTrail - Consumes Feature Flags
################################################################################
module "cloudtrail" {
source = "../../../cloudtrail"
count = module.feature_flags.security.cloudtrail_enabled ? 1 : 0
name = "org-trail"
is_multi_region = module.feature_flags.security.cloudtrail_multi_region
enable_log_file_validation = module.feature_flags.security.cloudtrail_log_validation
enable_insights = module.feature_flags.security.cloudtrail_insights
enable_data_events = module.feature_flags.security.cloudtrail_data_events
tags = {
Environment = module.feature_flags.environment_preset
}
}
################################################################################
# Outputs
################################################################################
output "feature_flags" {
value = {
preset = module.feature_flags.environment_preset
is_production = module.feature_flags.is_production
encryption_required = module.feature_flags.encryption_required
compliance_strict = module.feature_flags.compliance_strict
}
description = "Active feature flags summary"
}
output "enabled_services" {
value = module.security_baseline.enabled_services
}

View File

@@ -0,0 +1,425 @@
################################################################################
# Feature Flags Module
#
# Centralized feature toggles for organization-wide security controls.
# Define once, propagate everywhere. All features are OPT-IN by default.
#
# Usage:
# module "feature_flags" {
# source = "../modules/feature-flags"
#
# security = {
# guardduty_enabled = true
# securityhub_enabled = true
# config_enabled = true
# cloudtrail_enabled = true
# }
#
# compliance = {
# cis_benchmark_enabled = true
# pci_dss_enabled = false
# hipaa_enabled = false
# }
# }
#
# Then reference in other modules:
# enable_guardduty = module.feature_flags.security.guardduty_enabled
#
################################################################################
terraform {
required_version = ">= 1.5.0"
}
################################################################################
# Security Feature Flags
################################################################################
variable "security" {
type = object({
# Threat Detection
guardduty_enabled = optional(bool, false)
guardduty_s3_protection = optional(bool, true)
guardduty_eks_protection = optional(bool, true)
guardduty_malware_protection = optional(bool, true)
guardduty_rds_protection = optional(bool, false)
guardduty_lambda_protection = optional(bool, false)
guardduty_runtime_monitoring = optional(bool, false)
# Security Posture
securityhub_enabled = optional(bool, false)
securityhub_auto_enable = optional(bool, true)
# Configuration Compliance
config_enabled = optional(bool, false)
config_all_resources = optional(bool, true)
config_include_global = optional(bool, true)
# Audit Logging
cloudtrail_enabled = optional(bool, false)
cloudtrail_multi_region = optional(bool, true)
cloudtrail_log_validation = optional(bool, true)
cloudtrail_insights = optional(bool, false)
cloudtrail_data_events = optional(bool, false)
# Identity
access_analyzer_enabled = optional(bool, false)
access_analyzer_type = optional(string, "ACCOUNT")
macie_enabled = optional(bool, false)
inspector_enabled = optional(bool, false)
# Network Security
vpc_flow_logs_enabled = optional(bool, false)
network_firewall_enabled = optional(bool, false)
# Data Protection
ebs_encryption_default = optional(bool, true)
s3_block_public_access = optional(bool, true)
rds_encryption_default = optional(bool, true)
})
default = {}
description = "Security service feature flags"
}
################################################################################
# Compliance Feature Flags
################################################################################
variable "compliance" {
type = object({
# Standards
cis_benchmark_enabled = optional(bool, false)
cis_benchmark_version = optional(string, "1.4.0")
aws_foundational_enabled = optional(bool, true)
pci_dss_enabled = optional(bool, false)
hipaa_enabled = optional(bool, false)
nist_800_53_enabled = optional(bool, false)
soc2_enabled = optional(bool, false)
# Config Rules
config_rules_enabled = optional(bool, false)
config_auto_remediation = optional(bool, false)
# Custom Rules
custom_config_rules = optional(list(string), [])
})
default = {}
description = "Compliance framework feature flags"
}
################################################################################
# IAM Feature Flags
################################################################################
variable "iam" {
type = object({
# Password Policy
password_policy_enabled = optional(bool, true)
password_minimum_length = optional(number, 14)
password_require_symbols = optional(bool, true)
password_require_numbers = optional(bool, true)
password_require_uppercase = optional(bool, true)
password_require_lowercase = optional(bool, true)
password_max_age_days = optional(number, 90)
password_reuse_prevention = optional(number, 24)
password_hard_expiry = optional(bool, false)
# MFA
mfa_enforcement_enabled = optional(bool, false)
mfa_hardware_required = optional(bool, false)
mfa_grace_period_days = optional(number, 0)
# Roles
create_admin_role = optional(bool, true)
create_developer_role = optional(bool, true)
create_readonly_role = optional(bool, true)
create_permissions_boundary = optional(bool, true)
# Service Control
require_imdsv2 = optional(bool, true)
})
default = {}
description = "IAM feature flags"
}
################################################################################
# Alerting Feature Flags
################################################################################
variable "alerting" {
type = object({
# Event Sources
guardduty_alerts_enabled = optional(bool, true)
securityhub_alerts_enabled = optional(bool, true)
config_alerts_enabled = optional(bool, true)
health_alerts_enabled = optional(bool, true)
cloudtrail_alerts_enabled = optional(bool, false)
# Severity Routing
critical_to_pagerduty = optional(bool, false)
high_to_slack = optional(bool, true)
medium_to_email = optional(bool, true)
low_to_cloudwatch = optional(bool, true)
# Thresholds
guardduty_min_severity = optional(number, 4.0)
securityhub_min_severity = optional(number, 70)
})
default = {}
description = "Alerting feature flags"
}
################################################################################
# Cost Management Feature Flags
################################################################################
variable "cost" {
type = object({
# Budgets
budgets_enabled = optional(bool, true)
budget_forecasted_alerts = optional(bool, true)
budget_default_limit = optional(number, 1000)
budget_alert_thresholds = optional(list(number), [50, 80, 100])
# Cost Allocation
cost_allocation_tags_enabled = optional(bool, true)
cost_explorer_enabled = optional(bool, true)
})
default = {}
description = "Cost management feature flags"
}
################################################################################
# Networking Feature Flags
################################################################################
variable "networking" {
type = object({
# VPC
create_vpc = optional(bool, true)
vpc_endpoints_enabled = optional(bool, true)
nat_gateway_enabled = optional(bool, true)
nat_gateway_ha = optional(bool, false)
# DNS
route53_enabled = optional(bool, false)
private_dns_enabled = optional(bool, true)
# Transit
transit_gateway_enabled = optional(bool, false)
ram_sharing_enabled = optional(bool, false)
})
default = {}
description = "Networking feature flags"
}
################################################################################
# Backup Feature Flags
################################################################################
variable "backup" {
type = object({
# AWS Backup
backup_enabled = optional(bool, false)
backup_vault_encryption = optional(bool, true)
backup_cross_region = optional(bool, false)
backup_cross_account = optional(bool, false)
# Default Schedules
daily_backup_enabled = optional(bool, true)
weekly_backup_enabled = optional(bool, true)
monthly_backup_enabled = optional(bool, false)
# Retention
daily_retention_days = optional(number, 7)
weekly_retention_days = optional(number, 30)
monthly_retention_days = optional(number, 365)
})
default = {}
description = "Backup feature flags"
}
################################################################################
# Environment Presets
################################################################################
variable "environment_preset" {
type = string
default = "custom"
description = "Environment preset (production, staging, development, custom)"
validation {
condition = contains(["production", "staging", "development", "custom"], var.environment_preset)
error_message = "Must be production, staging, development, or custom"
}
}
locals {
# Production preset - maximum security
production_overrides = {
security = {
guardduty_enabled = true
securityhub_enabled = true
config_enabled = true
cloudtrail_enabled = true
access_analyzer_enabled = true
ebs_encryption_default = true
s3_block_public_access = true
}
compliance = {
cis_benchmark_enabled = true
aws_foundational_enabled = true
config_rules_enabled = true
}
iam = {
password_policy_enabled = true
mfa_enforcement_enabled = true
create_permissions_boundary = true
}
alerting = {
guardduty_alerts_enabled = true
securityhub_alerts_enabled = true
health_alerts_enabled = true
}
}
# Staging preset - security with cost awareness
staging_overrides = {
security = {
guardduty_enabled = true
securityhub_enabled = true
config_enabled = true
cloudtrail_enabled = true
access_analyzer_enabled = false
ebs_encryption_default = true
s3_block_public_access = true
}
compliance = {
cis_benchmark_enabled = false
aws_foundational_enabled = true
config_rules_enabled = true
}
iam = {
password_policy_enabled = true
mfa_enforcement_enabled = false
create_permissions_boundary = true
}
alerting = {
guardduty_alerts_enabled = true
securityhub_alerts_enabled = false
health_alerts_enabled = true
}
}
# Development preset - minimal security, maximum flexibility
development_overrides = {
security = {
guardduty_enabled = false
securityhub_enabled = false
config_enabled = false
cloudtrail_enabled = false
access_analyzer_enabled = false
ebs_encryption_default = true
s3_block_public_access = false
}
compliance = {
cis_benchmark_enabled = false
aws_foundational_enabled = false
config_rules_enabled = false
}
iam = {
password_policy_enabled = true
mfa_enforcement_enabled = false
create_permissions_boundary = false
}
alerting = {
guardduty_alerts_enabled = false
securityhub_alerts_enabled = false
health_alerts_enabled = true
}
}
# Select preset or use custom
preset_map = {
production = local.production_overrides
staging = local.staging_overrides
development = local.development_overrides
custom = {}
}
selected_preset = local.preset_map[var.environment_preset]
}
################################################################################
# Merged Outputs
#
# Merge user input with preset defaults. User input always wins.
################################################################################
output "security" {
value = merge(
var.security,
try(local.selected_preset.security, {})
)
description = "Merged security feature flags"
}
output "compliance" {
value = merge(
var.compliance,
try(local.selected_preset.compliance, {})
)
description = "Merged compliance feature flags"
}
output "iam" {
value = merge(
var.iam,
try(local.selected_preset.iam, {})
)
description = "Merged IAM feature flags"
}
output "alerting" {
value = merge(
var.alerting,
try(local.selected_preset.alerting, {})
)
description = "Merged alerting feature flags"
}
output "cost" {
value = var.cost
description = "Cost management feature flags"
}
output "networking" {
value = var.networking
description = "Networking feature flags"
}
output "backup" {
value = var.backup
description = "Backup feature flags"
}
output "environment_preset" {
value = var.environment_preset
description = "Active environment preset"
}
# Convenience outputs for common checks
output "is_production" {
value = var.environment_preset == "production"
description = "True if production preset is active"
}
output "encryption_required" {
value = var.security.ebs_encryption_default && var.security.s3_block_public_access
description = "True if encryption defaults are enabled"
}
output "compliance_strict" {
value = var.compliance.cis_benchmark_enabled || var.compliance.pci_dss_enabled || var.compliance.hipaa_enabled
description = "True if any strict compliance standard is enabled"
}