Skip to content

refactor: Phase 5 - Modernize security configurations (password, MFA, advanced security) (HIGH RISK) #350

@lgallard

Description

@lgallard

Phase 5: Security Configurations

Part of: #224 (Parent Epic: Terraform Syntax Modernization)
Depends on: #349 (Phase 4)
Phase: 5 of 6
Risk Level: HIGH 🔴

Scope

Modernize lookup() functions to try() in security-critical configuration blocks within main.tf.

Files to Modify:

  • main.tf (security blocks only):
    • password_policy dynamic block
    • software_token_mfa_configuration dynamic block
    • user_pool_add_ons (advanced_security_mode) dynamic block
    • sms_configuration dynamic block

Total Changes: ~50 lookup() → try() conversions in security-critical areas

⚠️ Security Considerations

Critical Principle: Security misconfigurations should fail fast, not be silently ignored.

Risk: Using try() might mask security configuration errors that should cause deployment to fail.

Mitigation Strategy:

  1. Add comprehensive validation in variables.tf for security-critical variables
  2. Use appropriate defaults that maintain current security posture
  3. Extensive testing with security scanning tools
  4. Document expected behavior for null/missing values

Changes to Implement

1. Password Policy Block

dynamic "password_policy" {
  for_each = local.password_policy
  content {
    # All fields should use try() with null default (AWS will use defaults)
    minimum_length                   = try(password_policy.value.minimum_length, null)
    require_lowercase                = try(password_policy.value.require_lowercase, null)
    require_numbers                  = try(password_policy.value.require_numbers, null)
    require_symbols                  = try(password_policy.value.require_symbols, null)
    require_uppercase                = try(password_policy.value.require_uppercase, null)
    temporary_password_validity_days = try(password_policy.value.temporary_password_validity_days, null)
    password_history_size            = try(password_policy.value.password_history_size, null)
  }
}

Validation to Add (variables.tf):

variable "password_policy" {
  # ... existing type definition ...
  
  validation {
    condition = var.password_policy == null ? true : (
      var.password_policy.minimum_length >= 6 && 
      var.password_policy.minimum_length <= 99
    )
    error_message = "Password minimum_length must be between 6 and 99 when specified."
  }
}

2. Software Token MFA Configuration

dynamic "software_token_mfa_configuration" {
  for_each = local.software_token_mfa_configuration
  content {
    # MFA enabled flag - explicit false default (was lookup())
    enabled = try(software_token_mfa_configuration.value.enabled, false)
  }
}

Important: Default to false to maintain current behavior when not specified.

3. User Pool Add-ons (Advanced Security)

dynamic "user_pool_add_ons" {
  for_each = local.user_pool_add_ons
  content {
    # Advanced security mode - null allows AWS default
    advanced_security_mode = try(user_pool_add_ons.value.advanced_security_mode, null)

    dynamic "advanced_security_additional_flows" {
      # Use can() to check attribute existence
      for_each = can(user_pool_add_ons.value.advanced_security_additional_flows) ? [1] : []
      content {
        custom_auth_mode = try(user_pool_add_ons.value.advanced_security_additional_flows, null)
      }
    }
  }
}

4. SMS Configuration

dynamic "sms_configuration" {
  for_each = local.sms_configuration
  content {
    # SMS config requires both fields or neither
    external_id    = try(sms_configuration.value.external_id, null)
    sns_caller_arn = try(sms_configuration.value.sns_caller_arn, null)
  }
}

Validation to Add (variables.tf or locals):

# Ensure both SMS config fields are provided together
locals {
  sms_config_valid = var.sms_configuration == null ? true : (
    (var.sms_configuration.external_id != null && var.sms_configuration.sns_caller_arn != null) ||
    (var.sms_configuration.external_id == null && var.sms_configuration.sns_caller_arn == null)
  )
}

Testing Requirements

Security Validation Tests

  • Critical: Test password policy enforcement with various configurations
  • Critical: Test MFA configurations (enabled, disabled, not set)
  • Critical: Test advanced security modes (OFF, AUDIT, ENFORCED)
  • Critical: Test SMS MFA with valid and invalid configurations
  • Critical: Verify security misconfigurations fail appropriately
  • Critical: Run security compliance scans (tfsec, checkov)

Functional Tests

  • Terraform validate passes on all examples
  • Terraform plan shows no changes for existing configurations
  • Test with examples using MFA (email_mfa example)
  • Test with maximum security configuration
  • Test with minimal/no security configuration
  • Verify backward compatibility

Security Scanning

  • Run tfsec on modified files
  • Run checkov security scan
  • Verify no new security warnings introduced
  • Document any expected changes in security scan results

Acceptance Criteria

  • All ~50 lookup() calls replaced with try() in security blocks
  • Validation added for critical security parameters
  • Security defaults maintain current posture
  • No functional behavior changes (security levels unchanged)
  • All examples validate successfully
  • Security scans pass or deviations documented
  • Terraform fmt applied
  • Pre-commit hooks pass
  • CI/CD validation passes with security tests
  • Documentation updated for security configuration best practices

Security Review Checklist

  • Password policy changes reviewed
  • MFA configuration changes reviewed
  • Advanced security mode changes reviewed
  • SMS configuration changes reviewed
  • All try() defaults align with security best practices
  • Validation prevents insecure configurations
  • No silent failures for security misconfigurations

Labels

refactoring, modernization, high-priority, security, critical

Next Phase

Once this phase is validated, security-scanned, and merged, proceed to Phase 6: Core User Pool & Admin Config (CRITICAL - final phase)

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions