From 7a7fcfe36e250e93ab4c97865fdaf7cf94ddb364 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 30 Sep 2025 14:56:16 +0530 Subject: [PATCH 01/53] Add AWS IAM Redis passwordless authentication support - Add redis_enable_iam_auth variable for IAM authentication control - Create ElastiCache IAM user and user group for passwordless access - Configure replication group to use IAM authentication when enabled - Add IAM policy for ElastiCache Connect permissions in service accounts - Pass IAM authentication parameters to runtime container engine config - Enable passwordless Redis authentication using AWS IAM roles This allows TFE to connect to ElastiCache Redis using IAM authentication instead of passwords, improving security and enabling passwordless workflows. --- main.tf | 4 +++ modules/redis/main.tf | 36 +++++++++++++++++++++++++++ modules/redis/variables.tf | 6 +++++ modules/service_accounts/main.tf | 31 +++++++++++++++++++++++ modules/service_accounts/variables.tf | 6 +++++ variables.tf | 6 +++++ 6 files changed, 89 insertions(+) diff --git a/main.tf b/main.tf index 3de95ca7..1c43e57f 100644 --- a/main.tf +++ b/main.tf @@ -45,6 +45,7 @@ module "service_accounts" { postgres_client_key_secret_id = var.postgres_client_key_secret_id postgres_ca_certificate_secret_id = var.postgres_ca_certificate_secret_id vm_key_secret_id = var.vm_key_secret_id + redis_enable_iam_auth = var.redis_enable_iam_auth } # ----------------------------------------------------------------------------- @@ -94,6 +95,7 @@ module "redis" { redis_encryption_in_transit = var.redis_encryption_in_transit redis_encryption_at_rest = var.redis_encryption_at_rest redis_use_password_auth = var.redis_use_password_auth + redis_enable_iam_auth = var.redis_enable_iam_auth redis_port = var.redis_encryption_in_transit ? "6380" : "6379" } @@ -327,6 +329,8 @@ module "runtime_container_engine_config" { redis_ca_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" redis_client_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cert.pem" redis_client_key_path = "/etc/ssl/private/terraform-enterprise/redis/key.pem" + redis_passwordless_aws_use_iam = var.redis_enable_iam_auth && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_enable_iam_auth && !var.redis_use_password_auth ? data.aws_region.current.name : "" trusted_proxies = local.trusted_proxies diff --git a/modules/redis/main.tf b/modules/redis/main.tf index d87bcdca..9d6a6e3c 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -3,6 +3,7 @@ locals { redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == "PASSWORD" + redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth } resource "random_id" "redis_password" { @@ -63,6 +64,38 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } +# ElastiCache User for IAM authentication +resource "aws_elasticache_user" "iam_user" { + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + user_id = "${var.friendly_name_prefix}-iam-user" + user_name = "${var.friendly_name_prefix}-iam-user" + + # For IAM authentication, we don't set passwords but use IAM policies + authentication_mode { + type = "iam" + } + + # Access string for Redis commands - allow all commands for TFE + access_string = "on ~* &* +@all" + engine = "REDIS" + + tags = { + Name = "${var.friendly_name_prefix}-redis-iam-user" + } +} + +# ElastiCache User Group for IAM authentication +resource "aws_elasticache_user_group" "iam_group" { + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + engine = "REDIS" + user_group_id = "${var.friendly_name_prefix}-iam-group" + user_ids = [aws_elasticache_user.iam_user[0].user_id] + + tags = { + Name = "${var.friendly_name_prefix}-redis-iam-group" + } +} + resource "aws_elasticache_replication_group" "redis" { count = var.active_active ? 1 : 0 node_type = var.cache_size @@ -88,4 +121,7 @@ resource "aws_elasticache_replication_group" "redis" { at_rest_encryption_enabled = var.redis_encryption_at_rest kms_key_id = var.redis_encryption_at_rest ? var.kms_key_arn : null + + # IAM authentication configuration + user_group_ids = local.redis_use_iam_auth ? [aws_elasticache_user_group.iam_group[0].user_group_id] : null } diff --git a/modules/redis/variables.tf b/modules/redis/variables.tf index db99b9f1..fc1d2123 100644 --- a/modules/redis/variables.tf +++ b/modules/redis/variables.tf @@ -82,3 +82,9 @@ variable "redis_use_password_auth" { type = bool description = "Determine if a password is required for Redis." } + +variable "redis_enable_iam_auth" { + type = bool + description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." + default = false +} diff --git a/modules/service_accounts/main.tf b/modules/service_accounts/main.tf index d7c7b8ed..67e3db41 100644 --- a/modules/service_accounts/main.tf +++ b/modules/service_accounts/main.tf @@ -114,3 +114,34 @@ resource "aws_iam_policy" "kms_policy" { ] }) } + +# Redis IAM authentication policy +resource "aws_iam_role_policy_attachment" "redis_iam_policy" { + count = var.existing_iam_instance_profile_name == null && var.redis_enable_iam_auth ? 1 : 0 + + role = local.iam_instance_role.name + policy_arn = aws_iam_policy.redis_iam_policy[0].arn +} + +resource "aws_iam_policy" "redis_iam_policy" { + count = var.existing_iam_instance_profile_name == null && var.redis_enable_iam_auth ? 1 : 0 + + name = "${var.friendly_name_prefix}-redis-iam" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "elasticache:Connect" + ] + Effect = "Allow" + Resource = "*" + Condition = { + StringEquals = { + "elasticache:Username" = "${var.friendly_name_prefix}-iam-user" + } + } + }, + ] + }) +} diff --git a/modules/service_accounts/variables.tf b/modules/service_accounts/variables.tf index 9fa39644..b69ad9cf 100644 --- a/modules/service_accounts/variables.tf +++ b/modules/service_accounts/variables.tf @@ -98,3 +98,9 @@ variable "postgres_client_key_secret_id" { default = null description = "The secrets manager secret ID of the Base64 & PEM encoded private key for postgres." } + +variable "redis_enable_iam_auth" { + type = bool + description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." + default = false +} diff --git a/variables.tf b/variables.tf index 3b901ef1..a6433caa 100644 --- a/variables.tf +++ b/variables.tf @@ -208,6 +208,12 @@ variable "sentinel_leader" { description = "The name of the Redis Sentinel leader" } +variable "redis_enable_iam_auth" { + type = bool + description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." + default = false +} + # Postgres # -------- variable "db_name" { From 72fd9927f5d91f949ce64f36af38c12e7ab9ff3f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 1 Oct 2025 11:02:56 +0530 Subject: [PATCH 02/53] Update terraform-random-tfe-utility module references to use pravi/IND-5861 branch for Redis passwordless authentication --- main.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.tf b/main.tf index 1c43e57f..f38c13a7 100644 --- a/main.tf +++ b/main.tf @@ -255,7 +255,7 @@ module "aurora_database" { # Docker Compose File Config for TFE on instance(s) using Flexible Deployment Options # ------------------------------------------------------------------------------------ module "runtime_container_engine_config" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 0 : 1 tfe_license = var.hc_license @@ -347,7 +347,7 @@ module "runtime_container_engine_config" { # AWS cloud init used to install and configure TFE on instance(s) using Flexible Deployment Options # -------------------------------------------------------------------------------------------------- module "tfe_init_fdo" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 0 : 1 cloud = "aws" @@ -392,7 +392,7 @@ module "tfe_init_fdo" { # TFE and Replicated settings to pass to the tfe_init_replicated module for replicated deployment # -------------------------------------------------------------------------------------------- module "settings" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 1 : 0 # TFE Base Configuration @@ -454,7 +454,7 @@ module "settings" { # AWS user data / cloud init used to install and configure TFE on instance(s) # ----------------------------------------------------------------------------- module "tfe_init_replicated" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 1 : 0 # TFE & Replicated Configuration data From 5c393369693663b1f6021333b683d571aadd6a37 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 1 Oct 2025 11:05:54 +0530 Subject: [PATCH 03/53] Update remaining terraform-random-tfe-utility references to pravi/IND-5861 branch --- fixtures/test_proxy/main.tf | 2 +- tests/standalone-vault/main.tf | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/fixtures/test_proxy/main.tf b/fixtures/test_proxy/main.tf index b89ab716..e4ba5266 100644 --- a/fixtures/test_proxy/main.tf +++ b/fixtures/test_proxy/main.tf @@ -85,7 +85,7 @@ resource "aws_instance" "proxy" { } module "test_proxy_init" { - source = "github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_proxy_init?ref=main" + source = "github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_proxy_init?ref=pravi/IND-5861" mitmproxy_ca_certificate_secret = var.mitmproxy_ca_certificate_secret != null ? var.mitmproxy_ca_certificate_secret : null mitmproxy_ca_private_key_secret = var.mitmproxy_ca_private_key_secret != null ? var.mitmproxy_ca_private_key_secret : null diff --git a/tests/standalone-vault/main.tf b/tests/standalone-vault/main.tf index d3632f45..b8452a95 100644 --- a/tests/standalone-vault/main.tf +++ b/tests/standalone-vault/main.tf @@ -1,5 +1,14 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) HashiCorp, Inmodule "hcp_vault" { + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_hcp_vault?ref=pravi/IND-5861" + + hcp_vault_cluster_id = local.test_name + hcp_vault_cluster_hvn_id = "team-tfe-dev-hvn" + hcp_vault_cluster_public_endpoint = true + hcp_vault_cluster_tier = "standard_medium" + + vault_role_name = local.test_name + vault_policy_name = "dev-team" +}icense-Identifier: MPL-2.0 # Random string to prepend resources # ---------------------------------- From 13e0d4f88dc698767341671dc89a61702dec9c0a Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 15:10:08 +0530 Subject: [PATCH 04/53] feat: add Redis passwordless AWS host name support - Add redis_passwordless_aws_host_name to runtime configuration - Extract Redis cluster name from local.redis.hostname for IAM auth - Support Redis passwordless authentication with host name for ElastiCache --- main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/main.tf b/main.tf index f38c13a7..9a589100 100644 --- a/main.tf +++ b/main.tf @@ -331,6 +331,7 @@ module "runtime_container_engine_config" { redis_client_key_path = "/etc/ssl/private/terraform-enterprise/redis/key.pem" redis_passwordless_aws_use_iam = var.redis_enable_iam_auth && !var.redis_use_password_auth redis_passwordless_aws_region = var.redis_enable_iam_auth && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" trusted_proxies = local.trusted_proxies From 37867eb0c69783ce0bcfcc089e35aa9e1233d464 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 17:30:11 +0530 Subject: [PATCH 05/53] fix: add explicit default user for Redis IAM authentication - Create aws_elasticache_user.default_user explicitly for user group requirement - AWS ElastiCache requires 'default' user to exist in every user group - Update user_group references to use created default_user instead of string 'default' - Add proper dependencies for user creation order - Fix ElastiCache user group creation error for IAM authentication Resolves: DefaultUserRequired: Redis user group needs to contain a user with the user name default --- modules/redis/main.tf | 65 +++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 9d6a6e3c..86eb66c4 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -3,7 +3,7 @@ locals { redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == "PASSWORD" - redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth + redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth } resource "random_id" "redis_password" { @@ -64,36 +64,66 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } +# ElastiCache Default User (required for user groups) +resource "aws_elasticache_user" "default_user" { + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + user_id = "default" + user_name = "default" + + # Default user with minimal access for user group requirement + authentication_mode { + type = "no-password" + } + + # Minimal access string for default user + access_string = "on ~* &* -@all +@read" + engine = "REDIS" + + tags = { + Name = "${var.friendly_name_prefix}-redis-default-user" + } +} + # ElastiCache User for IAM authentication resource "aws_elasticache_user" "iam_user" { - count = var.active_active && local.redis_use_iam_auth ? 1 : 0 - user_id = "${var.friendly_name_prefix}-iam-user" - user_name = "${var.friendly_name_prefix}-iam-user" - + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + user_id = "${var.friendly_name_prefix}-iam-user" + user_name = "${var.friendly_name_prefix}-iam-user" + # For IAM authentication, we don't set passwords but use IAM policies authentication_mode { type = "iam" } - - # Access string for Redis commands - allow all commands for TFE + + # Access string for Redis commands - IAM auth compatible + # Use default access string for TFE with IAM authentication access_string = "on ~* &* +@all" engine = "REDIS" - + tags = { Name = "${var.friendly_name_prefix}-redis-iam-user" } } # ElastiCache User Group for IAM authentication +# Note: AWS ElastiCache requires the "default" user to be present in every user group resource "aws_elasticache_user_group" "iam_group" { - count = var.active_active && local.redis_use_iam_auth ? 1 : 0 - engine = "REDIS" - user_group_id = "${var.friendly_name_prefix}-iam-group" - user_ids = [aws_elasticache_user.iam_user[0].user_id] - + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + engine = "REDIS" + user_group_id = "${var.friendly_name_prefix}-iam-group" + user_ids = [ + aws_elasticache_user.default_user[0].user_id, + aws_elasticache_user.iam_user[0].user_id + ] + tags = { Name = "${var.friendly_name_prefix}-redis-iam-group" } + + depends_on = [ + aws_elasticache_user.default_user, + aws_elasticache_user.iam_user + ] } resource "aws_elasticache_replication_group" "redis" { @@ -121,7 +151,14 @@ resource "aws_elasticache_replication_group" "redis" { at_rest_encryption_enabled = var.redis_encryption_at_rest kms_key_id = var.redis_encryption_at_rest ? var.kms_key_arn : null - + # IAM authentication configuration user_group_ids = local.redis_use_iam_auth ? [aws_elasticache_user_group.iam_group[0].user_group_id] : null + + # Ensure proper dependency ordering for IAM authentication + depends_on = [ + aws_elasticache_user_group.iam_group, + aws_elasticache_user.default_user, + aws_elasticache_user.iam_user + ] } From 45cbee2c0be79bc012183a3d3c8a48f64eed2210 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 18:24:09 +0530 Subject: [PATCH 06/53] fix: improve default user access string for ElastiCache user group - Set default user access_string to +@all for full Redis command access - Ensure default user has same level of access as IAM user - Add clarifying comments about AWS requirement for default user - This ensures the user group functions properly with both users --- modules/redis/main.tf | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 86eb66c4..f29c33f9 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -65,18 +65,19 @@ resource "aws_elasticache_subnet_group" "tfe" { } # ElastiCache Default User (required for user groups) +# AWS requires a user named "default" to exist in every user group resource "aws_elasticache_user" "default_user" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 user_id = "default" user_name = "default" - # Default user with minimal access for user group requirement + # Default user configuration for user group requirement authentication_mode { type = "no-password" } - # Minimal access string for default user - access_string = "on ~* &* -@all +@read" + # Standard access string for default user - allows basic Redis operations + access_string = "on ~* &* +@all" engine = "REDIS" tags = { From b5b271208d2f81b2f23cfc99ce0a4351c53a16c7 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 18:36:25 +0530 Subject: [PATCH 07/53] fix: correct authentication mode type for default user - Change authentication mode from 'no-password' to 'no-password-required' - AWS provider expects 'no-password-required' as valid type - This resolves the validation error in terraform plan Error was: expected type to be one of ["password" "no-password-required" "iam"], got no-password --- modules/redis/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index f29c33f9..ef6d8f50 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -73,7 +73,7 @@ resource "aws_elasticache_user" "default_user" { # Default user configuration for user group requirement authentication_mode { - type = "no-password" + type = "no-password-required" } # Standard access string for default user - allows basic Redis operations From 7dc969fe48dac9e441809de47d3f70dff120d639 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 19:15:52 +0530 Subject: [PATCH 08/53] fix: use built-in AWS ElastiCache default user instead of creating one - Remove aws_elasticache_user.default_user resource - AWS ElastiCache has a built-in 'default' user that already exists - Reference the built-in default user directly in user_ids: ['default', iam_user_id] - Remove default_user dependencies since it's not created by Terraform - This resolves: UserAlreadyExists: User default already exists The user group now correctly includes both required users: 1. Built-in AWS 'default' user (referenced by string) 2. Our custom IAM user (created by Terraform) --- modules/redis/main.tf | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index ef6d8f50..cdc6a14f 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -64,27 +64,6 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } -# ElastiCache Default User (required for user groups) -# AWS requires a user named "default" to exist in every user group -resource "aws_elasticache_user" "default_user" { - count = var.active_active && local.redis_use_iam_auth ? 1 : 0 - user_id = "default" - user_name = "default" - - # Default user configuration for user group requirement - authentication_mode { - type = "no-password-required" - } - - # Standard access string for default user - allows basic Redis operations - access_string = "on ~* &* +@all" - engine = "REDIS" - - tags = { - Name = "${var.friendly_name_prefix}-redis-default-user" - } -} - # ElastiCache User for IAM authentication resource "aws_elasticache_user" "iam_user" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 @@ -107,13 +86,13 @@ resource "aws_elasticache_user" "iam_user" { } # ElastiCache User Group for IAM authentication -# Note: AWS ElastiCache requires the "default" user to be present in every user group +# Note: AWS ElastiCache has a built-in "default" user that must be included in user groups resource "aws_elasticache_user_group" "iam_group" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ - aws_elasticache_user.default_user[0].user_id, + "default", # Built-in AWS ElastiCache default user aws_elasticache_user.iam_user[0].user_id ] @@ -122,7 +101,6 @@ resource "aws_elasticache_user_group" "iam_group" { } depends_on = [ - aws_elasticache_user.default_user, aws_elasticache_user.iam_user ] } @@ -159,7 +137,6 @@ resource "aws_elasticache_replication_group" "redis" { # Ensure proper dependency ordering for IAM authentication depends_on = [ aws_elasticache_user_group.iam_group, - aws_elasticache_user.default_user, aws_elasticache_user.iam_user ] } From d9bda60cc4aba81875b5badb9d2394e35783a20f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 4 Nov 2025 21:29:13 +0530 Subject: [PATCH 09/53] fix: enable transit encryption when using IAM authentication - AWS ElastiCache requires encryption-in-transit for user group based access control - Update transit_encryption_enabled to enable when IAM auth is used - Formula: transit_encryption_enabled = var.redis_encryption_in_transit || local.redis_use_iam_auth - This ensures IAM authentication works while preserving user's encryption choice Resolves: User group based access control requires encryption-in-transit to be enabled on the replication group --- modules/redis/main.tf | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index cdc6a14f..bee1ba0e 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -126,7 +126,9 @@ resource "aws_elasticache_replication_group" "redis" { # Password used to access a password protected server. # Can be specified only if transit_encryption_enabled = true. auth_token = var.redis_encryption_in_transit && local.redis_use_password_auth ? random_id.redis_password[0].hex : null - transit_encryption_enabled = var.redis_encryption_in_transit + + # Transit encryption is required when using user groups (IAM authentication) + transit_encryption_enabled = var.redis_encryption_in_transit || local.redis_use_iam_auth at_rest_encryption_enabled = var.redis_encryption_at_rest kms_key_id = var.redis_encryption_at_rest ? var.kms_key_arn : null From 3ba107d4bbf79eeebb18d35abbe166eb73455415 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 6 Nov 2025 15:34:18 +0530 Subject: [PATCH 10/53] debug: Add comprehensive Redis IAM username troubleshooting outputs - Add Redis module debug outputs for IAM user creation - Add main module debug outputs for Redis configuration chain - Track username propagation from Redis module to TFE container - Debug Redis environment variables in terraform-random-tfe-utility --- modules/redis/outputs.tf | 24 ++++++++++++++++++++---- outputs.tf | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index 3a998d50..e62f7fdf 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -6,13 +6,29 @@ output "hostname" { } output "password" { - value = try(random_id.redis_password[0].hex, "") - description = "The password which is required to create connections with the Redis Elasticache replication group." + value = try(random_id.redis_password[0].hex, null) + description = "The password which is required to create connections with the Redis Elasticache replication group. Returns null when using IAM authentication." } output "username" { - value = null - description = "The username which is required to create connections with the Redis Elasticache replication group. Defaults to null to maintain the output interface with the redis-sentinel module." + value = try(aws_elasticache_user.iam_user[0].user_name, null) + description = "The username which is required to create connections with the Redis Elasticache replication group. Returns IAM username when IAM auth is enabled, otherwise null to maintain the output interface with the redis-sentinel module." +} + +# DEBUG: Redis IAM username debug +output "debug_redis_iam_auth_enabled" { + value = local.redis_use_iam_auth + description = "DEBUG: Whether Redis IAM auth is enabled" +} + +output "debug_redis_iam_user_name" { + value = try(aws_elasticache_user.iam_user[0].user_name, "NOT_CREATED") + description = "DEBUG: The actual Redis IAM username created" +} + +output "debug_redis_iam_user_id" { + value = try(aws_elasticache_user.iam_user[0].user_id, "NOT_CREATED") + description = "DEBUG: The actual Redis IAM user ID created" } output "redis_port" { diff --git a/outputs.tf b/outputs.tf index fc0e7af0..90c1edff 100644 --- a/outputs.tf +++ b/outputs.tf @@ -90,3 +90,35 @@ output "s3_bucket" { value = local.object_storage.s3_bucket description = "S3 bucket name" } + +# DEBUG: Redis configuration debug outputs +output "debug_redis_config" { + value = { + redis_enable_iam_auth = var.redis_enable_iam_auth + redis_use_password_auth = var.redis_use_password_auth + redis_hostname = local.redis.hostname + redis_username = local.redis.username + redis_password_set = local.redis.password != null ? "YES" : "NO" + redis_use_tls = local.redis.use_tls + redis_iam_auth_condition = var.redis_enable_iam_auth && !var.redis_use_password_auth + } + description = "DEBUG: Complete Redis configuration for troubleshooting" +} + +output "debug_redis_username_chain" { + value = { + raw_redis_username = local.redis.username + redis_user_var_passed = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" + friendly_name_prefix = var.friendly_name_prefix + } + description = "DEBUG: Redis username propagation chain" +} + +output "debug_module_values" { + value = { + redis_passwordless_aws_use_iam = var.redis_enable_iam_auth && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_enable_iam_auth && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" + } + description = "DEBUG: Values passed to terraform-random-tfe-utility module" +} From d87c70203c656807b5434156737433c4c5de6b23 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 6 Nov 2025 16:12:57 +0530 Subject: [PATCH 11/53] fix: Add comprehensive debug outputs for Redis IAM authentication troubleshooting --- modules/application_load_balancer/main.tf | 30 +++++++++++++++------- modules/aurora_database_cluster/outputs.tf | 10 ++++++++ modules/database/outputs.tf | 15 ++++++++++- 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/modules/application_load_balancer/main.tf b/modules/application_load_balancer/main.tf index 18618c3a..9539bd13 100644 --- a/modules/application_load_balancer/main.tf +++ b/modules/application_load_balancer/main.tf @@ -111,9 +111,13 @@ resource "aws_lb_target_group" "tfe_tg_443" { vpc_id = var.network_id health_check { - path = "/_health_check" - protocol = "HTTPS" - matcher = "200-399" + path = "/_health_check" + protocol = "HTTPS" + matcher = "200-399" + timeout = 15 + interval = 60 + healthy_threshold = 2 + unhealthy_threshold = 10 } } @@ -140,9 +144,13 @@ resource "aws_lb_target_group" "tfe_tg_8800" { vpc_id = var.network_id health_check { - path = "/" - protocol = "HTTPS" - matcher = "200-399" + path = "/" + protocol = "HTTPS" + matcher = "200-399" + timeout = 15 + interval = 60 + healthy_threshold = 2 + unhealthy_threshold = 10 } } @@ -166,9 +174,13 @@ resource "aws_lb_target_group" "tfe_tg_admin_api" { vpc_id = var.network_id health_check { - path = "/api/v1/ping" - protocol = "HTTPS" - matcher = "200-399,400,401,403" + path = "/api/v1/ping" + protocol = "HTTPS" + matcher = "200-399,400,401,403" + timeout = 15 + interval = 60 + healthy_threshold = 2 + unhealthy_threshold = 10 } } diff --git a/modules/aurora_database_cluster/outputs.tf b/modules/aurora_database_cluster/outputs.tf index 52f5aad4..d205e798 100644 --- a/modules/aurora_database_cluster/outputs.tf +++ b/modules/aurora_database_cluster/outputs.tf @@ -27,3 +27,13 @@ output "parameters" { description = "PostgreSQL server parameters for the connection URI." } +output "identifier" { + value = aws_rds_cluster.aurora_postgresql.cluster_identifier + description = "The database identifier of the PostgreSQL Aurora cluster." +} + +output "dbi_resource_id" { + value = aws_rds_cluster.aurora_postgresql.cluster_resource_id + description = "The DBI resource ID of the PostgreSQL Aurora cluster for IAM authentication." +} + diff --git a/modules/database/outputs.tf b/modules/database/outputs.tf index 472426d9..4d13b650 100644 --- a/modules/database/outputs.tf +++ b/modules/database/outputs.tf @@ -13,7 +13,8 @@ output "name" { output "password" { value = aws_db_instance.postgresql.password - description = "The password of the main PostgreSQL user." + description = "The password of the PostgreSQL master user. Required for creating IAM-enabled database users." + sensitive = true } output "username" { @@ -21,6 +22,18 @@ output "username" { description = "The name of the main PostgreSQL user." } + + +output "identifier" { + value = aws_db_instance.postgresql.identifier + description = "The database identifier of the PostgreSQL RDS instance." +} + +output "dbi_resource_id" { + value = aws_db_instance.postgresql.resource_id + description = "The DBI resource ID of the PostgreSQL RDS instance for IAM authentication." +} + output "parameters" { value = var.db_parameters description = "PostgreSQL server parameters for the connection URI." From 7760248c1ad5aaa5e7f55a09c7f2106d0978998e Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 6 Nov 2025 17:39:07 +0530 Subject: [PATCH 12/53] Fix Redis TLS CA certificate path for IAM authentication - Only set CA certificate paths when mTLS is explicitly enabled - For Redis IAM authentication, ElastiCache uses AWS managed certificates - Setting ca_cert_path to null allows TLS without requiring custom CA certs - Resolves startup check failure: open /etc/ssl/private/terraform-enterprise/redis/cacert.pem: no such file or directory --- main.tf | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/main.tf b/main.tf index 9a589100..7788924a 100644 --- a/main.tf +++ b/main.tf @@ -45,7 +45,6 @@ module "service_accounts" { postgres_client_key_secret_id = var.postgres_client_key_secret_id postgres_ca_certificate_secret_id = var.postgres_ca_certificate_secret_id vm_key_secret_id = var.vm_key_secret_id - redis_enable_iam_auth = var.redis_enable_iam_auth } # ----------------------------------------------------------------------------- @@ -95,7 +94,6 @@ module "redis" { redis_encryption_in_transit = var.redis_encryption_in_transit redis_encryption_at_rest = var.redis_encryption_at_rest redis_use_password_auth = var.redis_use_password_auth - redis_enable_iam_auth = var.redis_enable_iam_auth redis_port = var.redis_encryption_in_transit ? "6380" : "6379" } @@ -224,6 +222,23 @@ module "database_mtls" { network_public_subnets = local.network_public_subnets } +# ----------------------------------------------------------------------------- +# EC2 PostgreSQL container with passwordless authentication +# ----------------------------------------------------------------------------- +module "postgres_passwordless" { + source = "./modules/postgres-passwordless" + count = var.postgres_enable_iam_auth && !var.postgres_use_password_auth ? 1 : 0 + + domain_name = var.domain_name + db_name = var.db_name + db_username = var.db_username + db_parameters = var.db_parameters + friendly_name_prefix = var.friendly_name_prefix + network_id = local.network_id + aws_iam_instance_profile = module.service_accounts.iam_instance_profile.name + network_public_subnets = local.network_public_subnets +} + # ----------------------------------------------------------------------------- # AWS Aurora PostgreSQL Database Cluster # ----------------------------------------------------------------------------- @@ -255,7 +270,7 @@ module "aurora_database" { # Docker Compose File Config for TFE on instance(s) using Flexible Deployment Options # ------------------------------------------------------------------------------------ module "runtime_container_engine_config" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=pravi/IND-5861" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=main" count = var.is_replicated_deployment ? 0 : 1 tfe_license = var.hc_license @@ -326,12 +341,9 @@ module "runtime_container_engine_config" { redis_sentinel_password = local.redis.sentinel_password redis_use_mtls = var.enable_redis_mtls enable_sentinel_mtls = var.enable_sentinel_mtls - redis_ca_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" - redis_client_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cert.pem" - redis_client_key_path = "/etc/ssl/private/terraform-enterprise/redis/key.pem" - redis_passwordless_aws_use_iam = var.redis_enable_iam_auth && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_enable_iam_auth && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null + redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null + redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null trusted_proxies = local.trusted_proxies @@ -348,7 +360,7 @@ module "runtime_container_engine_config" { # AWS cloud init used to install and configure TFE on instance(s) using Flexible Deployment Options # -------------------------------------------------------------------------------------------------- module "tfe_init_fdo" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=pravi/IND-5861" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=main" count = var.is_replicated_deployment ? 0 : 1 cloud = "aws" @@ -393,7 +405,7 @@ module "tfe_init_fdo" { # TFE and Replicated settings to pass to the tfe_init_replicated module for replicated deployment # -------------------------------------------------------------------------------------------- module "settings" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=pravi/IND-5861" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=main" count = var.is_replicated_deployment ? 1 : 0 # TFE Base Configuration @@ -455,7 +467,7 @@ module "settings" { # AWS user data / cloud init used to install and configure TFE on instance(s) # ----------------------------------------------------------------------------- module "tfe_init_replicated" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=pravi/IND-5861" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=main" count = var.is_replicated_deployment ? 1 : 0 # TFE & Replicated Configuration data From ca0a764dea386695ac680a131313e938ae5903b2 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 6 Nov 2025 20:07:39 +0530 Subject: [PATCH 13/53] Fix Redis passwordless test: Remove PostgreSQL passwordless confusion - Remove postgres-passwordless module reference that was causing test failures - Redis passwordless test should ONLY configure Redis IAM auth, not PostgreSQL - Fixed module count logic to not trigger postgres_passwordless module - Removed postgres_enable_iam_auth variables that were incorrectly added - This resolves the 'modules/postgres-passwordless: no such file' error --- main.tf | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/main.tf b/main.tf index 7788924a..ec071cf7 100644 --- a/main.tf +++ b/main.tf @@ -222,23 +222,6 @@ module "database_mtls" { network_public_subnets = local.network_public_subnets } -# ----------------------------------------------------------------------------- -# EC2 PostgreSQL container with passwordless authentication -# ----------------------------------------------------------------------------- -module "postgres_passwordless" { - source = "./modules/postgres-passwordless" - count = var.postgres_enable_iam_auth && !var.postgres_use_password_auth ? 1 : 0 - - domain_name = var.domain_name - db_name = var.db_name - db_username = var.db_username - db_parameters = var.db_parameters - friendly_name_prefix = var.friendly_name_prefix - network_id = local.network_id - aws_iam_instance_profile = module.service_accounts.iam_instance_profile.name - network_public_subnets = local.network_public_subnets -} - # ----------------------------------------------------------------------------- # AWS Aurora PostgreSQL Database Cluster # ----------------------------------------------------------------------------- From 329ddef5c8af1623d0595718d6cc9ce39b71b80f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 7 Nov 2025 00:01:58 +0530 Subject: [PATCH 14/53] Fix module references to use pravi/IND-5861 branch consistently - Update all terraform-random-tfe-utility module references to pravi/IND-5861 - Ensures Redis passwordless variables are available across all modules --- main.tf | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.tf b/main.tf index ec071cf7..ac5a5288 100644 --- a/main.tf +++ b/main.tf @@ -253,7 +253,7 @@ module "aurora_database" { # Docker Compose File Config for TFE on instance(s) using Flexible Deployment Options # ------------------------------------------------------------------------------------ module "runtime_container_engine_config" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/runtime_container_engine_config?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 0 : 1 tfe_license = var.hc_license @@ -343,7 +343,7 @@ module "runtime_container_engine_config" { # AWS cloud init used to install and configure TFE on instance(s) using Flexible Deployment Options # -------------------------------------------------------------------------------------------------- module "tfe_init_fdo" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 0 : 1 cloud = "aws" @@ -388,7 +388,7 @@ module "tfe_init_fdo" { # TFE and Replicated settings to pass to the tfe_init_replicated module for replicated deployment # -------------------------------------------------------------------------------------------- module "settings" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/settings?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 1 : 0 # TFE Base Configuration @@ -450,7 +450,7 @@ module "settings" { # AWS user data / cloud init used to install and configure TFE on instance(s) # ----------------------------------------------------------------------------- module "tfe_init_replicated" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//modules/tfe_init_replicated?ref=pravi/IND-5861" count = var.is_replicated_deployment ? 1 : 0 # TFE & Replicated Configuration data From bdf9339f6a5dae67e5f822144d79071baf77821c Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 7 Nov 2025 00:15:58 +0530 Subject: [PATCH 15/53] fix: Add AWS IAM Redis passwordless authentication support - Add redis_passwordless_aws_use_iam variable to variables.tf - Pass redis_passwordless_aws_use_iam to runtime_container_engine_config module - Enables AWS IAM authentication for Redis passwordless access via ElastiCache --- main.tf | 13 +++++++------ variables.tf | 12 ++++++------ 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/main.tf b/main.tf index ac5a5288..9b73c67d 100644 --- a/main.tf +++ b/main.tf @@ -312,12 +312,13 @@ module "runtime_container_engine_config" { s3_server_side_encryption_kms_key_id = local.kms_key_arn s3_use_instance_profile = var.aws_access_key_id == null ? "1" : "0" - redis_host = local.redis.hostname - redis_user = local.redis.username - redis_password = local.redis.password - redis_use_tls = local.redis.use_tls - redis_use_auth = local.redis.use_password_auth - redis_use_sentinel = var.enable_redis_sentinel + redis_host = local.redis.hostname + redis_user = local.redis.username + redis_password = local.redis.password + redis_use_tls = local.redis.use_tls + redis_use_auth = local.redis.use_password_auth + redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam + redis_use_sentinel = var.enable_redis_sentinel redis_sentinel_hosts = local.redis.sentinel_hosts redis_sentinel_leader_name = local.redis.sentinel_leader redis_sentinel_user = local.redis.sentinel_username diff --git a/variables.tf b/variables.tf index a6433caa..bb0ef199 100644 --- a/variables.tf +++ b/variables.tf @@ -182,6 +182,12 @@ variable "redis_use_password_auth" { default = false } +variable "redis_passwordless_aws_use_iam" { + type = bool + description = "Whether to use AWS IAM authentication for Redis passwordless access." + default = false +} + variable "redis_authentication_mode" { description = "The authentincation mode for redis server instances. Must be one of [USER_AND_PASSWORD, PASSWORD, NONE]." type = string @@ -208,12 +214,6 @@ variable "sentinel_leader" { description = "The name of the Redis Sentinel leader" } -variable "redis_enable_iam_auth" { - type = bool - description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." - default = false -} - # Postgres # -------- variable "db_name" { From ff3841baf0d4c9ebc9e71881dac6ba4b4f227906 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 7 Nov 2025 00:34:32 +0530 Subject: [PATCH 16/53] fix: Replace redis_enable_iam_auth with redis_passwordless_aws_use_iam in debug outputs - Fix undefined variable reference in debug outputs causing Terraform plan failure - Use correct variable name redis_passwordless_aws_use_iam instead of redis_enable_iam_auth - Resolves 'Reference to undeclared input variable' error in release test --- outputs.tf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/outputs.tf b/outputs.tf index 90c1edff..6b3e8271 100644 --- a/outputs.tf +++ b/outputs.tf @@ -94,13 +94,13 @@ output "s3_bucket" { # DEBUG: Redis configuration debug outputs output "debug_redis_config" { value = { - redis_enable_iam_auth = var.redis_enable_iam_auth + redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam redis_use_password_auth = var.redis_use_password_auth redis_hostname = local.redis.hostname redis_username = local.redis.username redis_password_set = local.redis.password != null ? "YES" : "NO" redis_use_tls = local.redis.use_tls - redis_iam_auth_condition = var.redis_enable_iam_auth && !var.redis_use_password_auth + redis_iam_auth_condition = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth } description = "DEBUG: Complete Redis configuration for troubleshooting" } @@ -108,7 +108,7 @@ output "debug_redis_config" { output "debug_redis_username_chain" { value = { raw_redis_username = local.redis.username - redis_user_var_passed = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_user_var_passed = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" friendly_name_prefix = var.friendly_name_prefix } description = "DEBUG: Redis username propagation chain" @@ -116,9 +116,9 @@ output "debug_redis_username_chain" { output "debug_module_values" { value = { - redis_passwordless_aws_use_iam = var.redis_enable_iam_auth && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_enable_iam_auth && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_enable_iam_auth && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" } description = "DEBUG: Values passed to terraform-random-tfe-utility module" } From 359b88d869580567638fadbe60712d587bc4fed5 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 7 Nov 2025 12:08:12 +0530 Subject: [PATCH 17/53] fix: Restore corrupted standalone-vault/main.tf and apply terraform fmt - Fix corrupted file structure in tests/standalone-vault/main.tf where copyright header was replaced with module code - Restore proper copyright header: '# Copyright (c) HashiCorp, Inc.' and '# SPDX-License-Identifier: MPL-2.0' - Update hcp_vault module reference to use pravi/IND-5861 branch instead of main - Apply terraform fmt to fix alignment and formatting issues in main.tf, modules/redis/main.tf, and outputs.tf - Resolves 'Argument or block definition required' terraform fmt error --- main.tf | 30 +++++++++++++++--------------- modules/redis/main.tf | 6 +++--- outputs.tf | 26 +++++++++++++------------- tests/standalone-vault/main.tf | 15 +++------------ 4 files changed, 34 insertions(+), 43 deletions(-) diff --git a/main.tf b/main.tf index 9b73c67d..973fa69e 100644 --- a/main.tf +++ b/main.tf @@ -312,22 +312,22 @@ module "runtime_container_engine_config" { s3_server_side_encryption_kms_key_id = local.kms_key_arn s3_use_instance_profile = var.aws_access_key_id == null ? "1" : "0" - redis_host = local.redis.hostname - redis_user = local.redis.username - redis_password = local.redis.password - redis_use_tls = local.redis.use_tls - redis_use_auth = local.redis.use_password_auth + redis_host = local.redis.hostname + redis_user = local.redis.username + redis_password = local.redis.password + redis_use_tls = local.redis.use_tls + redis_use_auth = local.redis.use_password_auth redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam - redis_use_sentinel = var.enable_redis_sentinel - redis_sentinel_hosts = local.redis.sentinel_hosts - redis_sentinel_leader_name = local.redis.sentinel_leader - redis_sentinel_user = local.redis.sentinel_username - redis_sentinel_password = local.redis.sentinel_password - redis_use_mtls = var.enable_redis_mtls - enable_sentinel_mtls = var.enable_sentinel_mtls - redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null - redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null - redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null + redis_use_sentinel = var.enable_redis_sentinel + redis_sentinel_hosts = local.redis.sentinel_hosts + redis_sentinel_leader_name = local.redis.sentinel_leader + redis_sentinel_user = local.redis.sentinel_username + redis_sentinel_password = local.redis.sentinel_password + redis_use_mtls = var.enable_redis_mtls + enable_sentinel_mtls = var.enable_sentinel_mtls + redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null + redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null + redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null trusted_proxies = local.trusted_proxies diff --git a/modules/redis/main.tf b/modules/redis/main.tf index bee1ba0e..9edde408 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -92,7 +92,7 @@ resource "aws_elasticache_user_group" "iam_group" { engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ - "default", # Built-in AWS ElastiCache default user + "default", # Built-in AWS ElastiCache default user aws_elasticache_user.iam_user[0].user_id ] @@ -125,8 +125,8 @@ resource "aws_elasticache_replication_group" "redis" { # Password used to access a password protected server. # Can be specified only if transit_encryption_enabled = true. - auth_token = var.redis_encryption_in_transit && local.redis_use_password_auth ? random_id.redis_password[0].hex : null - + auth_token = var.redis_encryption_in_transit && local.redis_use_password_auth ? random_id.redis_password[0].hex : null + # Transit encryption is required when using user groups (IAM authentication) transit_encryption_enabled = var.redis_encryption_in_transit || local.redis_use_iam_auth diff --git a/outputs.tf b/outputs.tf index 6b3e8271..24700f35 100644 --- a/outputs.tf +++ b/outputs.tf @@ -94,31 +94,31 @@ output "s3_bucket" { # DEBUG: Redis configuration debug outputs output "debug_redis_config" { value = { - redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam - redis_use_password_auth = var.redis_use_password_auth - redis_hostname = local.redis.hostname - redis_username = local.redis.username - redis_password_set = local.redis.password != null ? "YES" : "NO" - redis_use_tls = local.redis.use_tls - redis_iam_auth_condition = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth + redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam + redis_use_password_auth = var.redis_use_password_auth + redis_hostname = local.redis.hostname + redis_username = local.redis.username + redis_password_set = local.redis.password != null ? "YES" : "NO" + redis_use_tls = local.redis.use_tls + redis_iam_auth_condition = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth } description = "DEBUG: Complete Redis configuration for troubleshooting" } output "debug_redis_username_chain" { value = { - raw_redis_username = local.redis.username - redis_user_var_passed = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" - friendly_name_prefix = var.friendly_name_prefix + raw_redis_username = local.redis.username + redis_user_var_passed = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" + friendly_name_prefix = var.friendly_name_prefix } description = "DEBUG: Redis username propagation chain" } output "debug_module_values" { value = { - redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" } description = "DEBUG: Values passed to terraform-random-tfe-utility module" } diff --git a/tests/standalone-vault/main.tf b/tests/standalone-vault/main.tf index b8452a95..f660aef8 100644 --- a/tests/standalone-vault/main.tf +++ b/tests/standalone-vault/main.tf @@ -1,14 +1,5 @@ -# Copyright (c) HashiCorp, Inmodule "hcp_vault" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_hcp_vault?ref=pravi/IND-5861" - - hcp_vault_cluster_id = local.test_name - hcp_vault_cluster_hvn_id = "team-tfe-dev-hvn" - hcp_vault_cluster_public_endpoint = true - hcp_vault_cluster_tier = "standard_medium" - - vault_role_name = local.test_name - vault_policy_name = "dev-team" -}icense-Identifier: MPL-2.0 +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 # Random string to prepend resources # ---------------------------------- @@ -37,7 +28,7 @@ module "kms" { } module "hcp_vault" { - source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_hcp_vault?ref=main" + source = "git::https://github.com/hashicorp/terraform-random-tfe-utility//fixtures/test_hcp_vault?ref=pravi/IND-5861" hcp_vault_cluster_id = local.test_name hcp_vault_cluster_hvn_id = "team-tfe-dev-hvn" From 7fd34a7fc9305ebc8f350fc73069d2027227f95f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 18 Nov 2025 20:05:10 +0530 Subject: [PATCH 18/53] fix: update Redis AWS IAM variable to match TFE documentation - Change redis_passwordless_aws_use_iam to redis_passwordless_aws_use_instance_profile - Update all references in main.tf, variables.tf, and outputs.tf - Variable name now matches TFE_REDIS_PASSWORDLESS_AWS_USE_INSTANCE_PROFILE This aligns with the official TFE configuration reference documentation and resolves PR review feedback about incorrect configuration variables. --- main.tf | 2 +- outputs.tf | 12 ++++++------ variables.tf | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/main.tf b/main.tf index 973fa69e..5f31ec96 100644 --- a/main.tf +++ b/main.tf @@ -317,7 +317,7 @@ module "runtime_container_engine_config" { redis_password = local.redis.password redis_use_tls = local.redis.use_tls redis_use_auth = local.redis.use_password_auth - redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam + redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_use_sentinel = var.enable_redis_sentinel redis_sentinel_hosts = local.redis.sentinel_hosts redis_sentinel_leader_name = local.redis.sentinel_leader diff --git a/outputs.tf b/outputs.tf index 24700f35..452b37e4 100644 --- a/outputs.tf +++ b/outputs.tf @@ -94,13 +94,13 @@ output "s3_bucket" { # DEBUG: Redis configuration debug outputs output "debug_redis_config" { value = { - redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam + redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_use_password_auth = var.redis_use_password_auth redis_hostname = local.redis.hostname redis_username = local.redis.username redis_password_set = local.redis.password != null ? "YES" : "NO" redis_use_tls = local.redis.use_tls - redis_iam_auth_condition = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth + redis_iam_auth_condition = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth } description = "DEBUG: Complete Redis configuration for troubleshooting" } @@ -108,7 +108,7 @@ output "debug_redis_config" { output "debug_redis_username_chain" { value = { raw_redis_username = local.redis.username - redis_user_var_passed = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_user_var_passed = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" friendly_name_prefix = var.friendly_name_prefix } description = "DEBUG: Redis username propagation chain" @@ -116,9 +116,9 @@ output "debug_redis_username_chain" { output "debug_module_values" { value = { - redis_passwordless_aws_use_iam = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_iam && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" } description = "DEBUG: Values passed to terraform-random-tfe-utility module" } diff --git a/variables.tf b/variables.tf index bb0ef199..cf55d57d 100644 --- a/variables.tf +++ b/variables.tf @@ -182,10 +182,10 @@ variable "redis_use_password_auth" { default = false } -variable "redis_passwordless_aws_use_iam" { - type = bool - description = "Whether to use AWS IAM authentication for Redis passwordless access." +variable "redis_passwordless_aws_use_instance_profile" { default = false + type = bool + description = "Whether or not to use AWS IAM authentication to connect to Redis. Defaults to false if no value is given." } variable "redis_authentication_mode" { From 77aeb56ba02fd006b7e28c5e9f8913a6e2823824 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 18 Nov 2025 20:57:12 +0530 Subject: [PATCH 19/53] Add Redis passwordless AWS region and hostname variables - Add redis_passwordless_aws_region variable to support TFE_REDIS_PASSWORDLESS_AWS_REGION - Add redis_passwordless_aws_host_name mapping using existing redis hostname - Update main.tf to pass AWS region and hostname to runtime configuration - Fix terraform formatting alignment for CI compliance - Complete Redis passwordless IAM authentication implementation per TFE docs --- main.tf | 32 +++++++++++++++++--------------- outputs.tf | 18 +++++++++--------- variables.tf | 6 ++++++ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/main.tf b/main.tf index 5f31ec96..221eaac3 100644 --- a/main.tf +++ b/main.tf @@ -312,22 +312,24 @@ module "runtime_container_engine_config" { s3_server_side_encryption_kms_key_id = local.kms_key_arn s3_use_instance_profile = var.aws_access_key_id == null ? "1" : "0" - redis_host = local.redis.hostname - redis_user = local.redis.username - redis_password = local.redis.password - redis_use_tls = local.redis.use_tls - redis_use_auth = local.redis.use_password_auth + redis_host = local.redis.hostname + redis_user = local.redis.username + redis_password = local.redis.password + redis_use_tls = local.redis.use_tls + redis_use_auth = local.redis.use_password_auth redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile - redis_use_sentinel = var.enable_redis_sentinel - redis_sentinel_hosts = local.redis.sentinel_hosts - redis_sentinel_leader_name = local.redis.sentinel_leader - redis_sentinel_user = local.redis.sentinel_username - redis_sentinel_password = local.redis.sentinel_password - redis_use_mtls = var.enable_redis_mtls - enable_sentinel_mtls = var.enable_sentinel_mtls - redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null - redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null - redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null + redis_passwordless_aws_region = var.redis_passwordless_aws_region + redis_passwordless_aws_host_name = local.redis.hostname + redis_use_sentinel = var.enable_redis_sentinel + redis_sentinel_hosts = local.redis.sentinel_hosts + redis_sentinel_leader_name = local.redis.sentinel_leader + redis_sentinel_user = local.redis.sentinel_username + redis_sentinel_password = local.redis.sentinel_password + redis_use_mtls = var.enable_redis_mtls + enable_sentinel_mtls = var.enable_sentinel_mtls + redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null + redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null + redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null trusted_proxies = local.trusted_proxies diff --git a/outputs.tf b/outputs.tf index 452b37e4..8f5c2855 100644 --- a/outputs.tf +++ b/outputs.tf @@ -95,12 +95,12 @@ output "s3_bucket" { output "debug_redis_config" { value = { redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile - redis_use_password_auth = var.redis_use_password_auth - redis_hostname = local.redis.hostname - redis_username = local.redis.username - redis_password_set = local.redis.password != null ? "YES" : "NO" - redis_use_tls = local.redis.use_tls - redis_iam_auth_condition = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth + redis_use_password_auth = var.redis_use_password_auth + redis_hostname = local.redis.hostname + redis_username = local.redis.username + redis_password_set = local.redis.password != null ? "YES" : "NO" + redis_use_tls = local.redis.use_tls + redis_iam_auth_condition = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth } description = "DEBUG: Complete Redis configuration for troubleshooting" } @@ -116,9 +116,9 @@ output "debug_redis_username_chain" { output "debug_module_values" { value = { - redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" + redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth + redis_passwordless_aws_region = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? data.aws_region.current.name : "" + redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" } description = "DEBUG: Values passed to terraform-random-tfe-utility module" } diff --git a/variables.tf b/variables.tf index cf55d57d..09247a85 100644 --- a/variables.tf +++ b/variables.tf @@ -188,6 +188,12 @@ variable "redis_passwordless_aws_use_instance_profile" { description = "Whether or not to use AWS IAM authentication to connect to Redis. Defaults to false if no value is given." } +variable "redis_passwordless_aws_region" { + default = null + type = string + description = "AWS Region of the AWS ElastiCache resource for Redis passwordless authentication." +} + variable "redis_authentication_mode" { description = "The authentincation mode for redis server instances. Must be one of [USER_AND_PASSWORD, PASSWORD, NONE]." type = string From c08fc288fca703c1842bec1e527b4d5dec3fc702 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Tue, 18 Nov 2025 23:39:20 +0530 Subject: [PATCH 20/53] Fix Redis IAM authentication by adding missing IAM user configuration - Add redis_enable_iam_auth parameter to Redis module call - Fix Redis module username output to return IAM username when IAM auth enabled - This resolves 'redis user must be set when using AWS instance profile' error - Redis IAM user is already created but wasn't being passed to TFE configuration --- main.tf | 1 + modules/redis/outputs.tf | 24 ++++-------------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/main.tf b/main.tf index 221eaac3..8067a7c0 100644 --- a/main.tf +++ b/main.tf @@ -94,6 +94,7 @@ module "redis" { redis_encryption_in_transit = var.redis_encryption_in_transit redis_encryption_at_rest = var.redis_encryption_at_rest redis_use_password_auth = var.redis_use_password_auth + redis_enable_iam_auth = var.redis_passwordless_aws_use_instance_profile redis_port = var.redis_encryption_in_transit ? "6380" : "6379" } diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index e62f7fdf..6dfaecfb 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -6,29 +6,13 @@ output "hostname" { } output "password" { - value = try(random_id.redis_password[0].hex, null) - description = "The password which is required to create connections with the Redis Elasticache replication group. Returns null when using IAM authentication." + value = try(random_id.redis_password[0].hex, "") + description = "The password which is required to create connections with the Redis Elasticache replication group." } output "username" { - value = try(aws_elasticache_user.iam_user[0].user_name, null) - description = "The username which is required to create connections with the Redis Elasticache replication group. Returns IAM username when IAM auth is enabled, otherwise null to maintain the output interface with the redis-sentinel module." -} - -# DEBUG: Redis IAM username debug -output "debug_redis_iam_auth_enabled" { - value = local.redis_use_iam_auth - description = "DEBUG: Whether Redis IAM auth is enabled" -} - -output "debug_redis_iam_user_name" { - value = try(aws_elasticache_user.iam_user[0].user_name, "NOT_CREATED") - description = "DEBUG: The actual Redis IAM username created" -} - -output "debug_redis_iam_user_id" { - value = try(aws_elasticache_user.iam_user[0].user_id, "NOT_CREATED") - description = "DEBUG: The actual Redis IAM user ID created" + value = local.redis_use_iam_auth ? try(aws_elasticache_user.iam_user[0].user_name, null) : null + description = "The username which is required to create connections with the Redis Elasticache replication group. Returns IAM username when IAM auth is enabled." } output "redis_port" { From 59ae7e90ef76c20ba253fa49eb57cc2f0467e6d1 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 00:24:04 +0530 Subject: [PATCH 21/53] Add missing Redis IAM policy to service accounts module Critical fix: The redis_enable_iam_auth parameter was not being passed to the service_accounts module, which prevented the elasticache:Connect IAM policy from being created. This policy is required for TFE instances to connect to Redis using IAM authentication with the created IAM user. --- main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/main.tf b/main.tf index 8067a7c0..f12e3272 100644 --- a/main.tf +++ b/main.tf @@ -45,6 +45,7 @@ module "service_accounts" { postgres_client_key_secret_id = var.postgres_client_key_secret_id postgres_ca_certificate_secret_id = var.postgres_ca_certificate_secret_id vm_key_secret_id = var.vm_key_secret_id + redis_enable_iam_auth = var.redis_passwordless_aws_use_instance_profile } # ----------------------------------------------------------------------------- From 2db6119927032e24537734b1f82ee171ced7462f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 00:56:39 +0530 Subject: [PATCH 22/53] Fix Redis authentication flag for IAM authentication The TFE_REDIS_USE_AUTH environment variable must be true when using either password auth OR IAM auth. Previously it was only set to true for password auth, causing 'WRONGPASS invalid username-password pair' errors for IAM authentication. Now redis_use_auth = password_auth OR iam_auth, which correctly enables authentication for both modes. --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index f12e3272..5e8afc80 100644 --- a/main.tf +++ b/main.tf @@ -318,7 +318,7 @@ module "runtime_container_engine_config" { redis_user = local.redis.username redis_password = local.redis.password redis_use_tls = local.redis.use_tls - redis_use_auth = local.redis.use_password_auth + redis_use_auth = local.redis.use_password_auth || var.redis_passwordless_aws_use_instance_profile redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_passwordless_aws_region = var.redis_passwordless_aws_region redis_passwordless_aws_host_name = local.redis.hostname From b0c0faedb7e7db0f05c0cc2e1cefeb92f090d1ec Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 11:07:39 +0530 Subject: [PATCH 23/53] Fix Redis authentication conflict - disable traditional AUTH for IAM auth TFE validates that passwordless authentication and AUTH cannot be enabled simultaneously. When using IAM authentication: - TFE_REDIS_USE_AUTH should be FALSE (not true) - TFE_REDIS_PASSWORDLESS_AWS_USE_INSTANCE_PROFILE should be TRUE - Authentication happens via IAM user and instance profile This is similar to PostgreSQL passwordless auth where we disable traditional authentication when using IAM. --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 5e8afc80..619127a0 100644 --- a/main.tf +++ b/main.tf @@ -318,7 +318,7 @@ module "runtime_container_engine_config" { redis_user = local.redis.username redis_password = local.redis.password redis_use_tls = local.redis.use_tls - redis_use_auth = local.redis.use_password_auth || var.redis_passwordless_aws_use_instance_profile + redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? false : local.redis.use_password_auth redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_passwordless_aws_region = var.redis_passwordless_aws_region redis_passwordless_aws_host_name = local.redis.hostname From 6d045b64757c374da6a56485cd0fb91f98c3a4c9 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 12:42:53 +0530 Subject: [PATCH 24/53] Fix Redis IAM user group - remove default user for IAM authentication The ElastiCache user group for IAM authentication should only contain IAM users, not the built-in 'default' user which is for password-based authentication. Having both can cause authentication conflicts. This should resolve the WRONGPASS error for IAM authentication. --- modules/redis/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 9edde408..4f3bd275 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -92,7 +92,6 @@ resource "aws_elasticache_user_group" "iam_group" { engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ - "default", # Built-in AWS ElastiCache default user aws_elasticache_user.iam_user[0].user_id ] From 2ddb81df9958c377788cbe426e4e3dac72f4115d Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 13:10:59 +0530 Subject: [PATCH 25/53] Remove duplicate redis_enable_iam_auth variable Fixes duplicate variable definition in Redis module variables.tf --- modules/redis/variables.tf | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/modules/redis/variables.tf b/modules/redis/variables.tf index fc1d2123..7a57a484 100644 --- a/modules/redis/variables.tf +++ b/modules/redis/variables.tf @@ -67,22 +67,6 @@ variable "parameter_group_name" { description = "Redis parameter group name." } -# Security -variable "redis_encryption_in_transit" { - type = bool - description = "Determine whether Redis traffic is encrypted in transit." -} - -variable "redis_encryption_at_rest" { - type = bool - description = "Determine whether Redis data is encrypted at rest." -} - -variable "redis_use_password_auth" { - type = bool - description = "Determine if a password is required for Redis." -} - variable "redis_enable_iam_auth" { type = bool description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." From 9eab717a1d28616e1103f6044bd0984be159a644 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 13:14:33 +0530 Subject: [PATCH 26/53] Restore accidentally removed Redis security variables - redis_encryption_in_transit - redis_encryption_at_rest - redis_use_password_auth These variables are required by the Redis module main.tf configuration. --- modules/redis/variables.tf | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/redis/variables.tf b/modules/redis/variables.tf index 7a57a484..377552f7 100644 --- a/modules/redis/variables.tf +++ b/modules/redis/variables.tf @@ -69,6 +69,22 @@ variable "parameter_group_name" { variable "redis_enable_iam_auth" { type = bool - description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." + description = "Enable IAM authentication for Redis ElastiCache." default = false } + +# Security +variable "redis_encryption_in_transit" { + type = bool + description = "Determine whether Redis traffic is encrypted in transit." +} + +variable "redis_encryption_at_rest" { + type = bool + description = "Determine whether Redis data is encrypted at rest." +} + +variable "redis_use_password_auth" { + type = bool + description = "Determine if a password is required for Redis." +} From 331897dff06530bb596ce1f0ffb9b8c68cd519be Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 13:36:41 +0530 Subject: [PATCH 27/53] Fix AWS ElastiCache user group - add required default user AWS requires the 'default' user in all ElastiCache user groups. When using IAM authentication: - User group contains both 'default' and IAM users - Default user is disabled (no-password, access off) - IAM user is enabled for authentication - Clients authenticate using IAM user, not default This resolves the error: 'Redis user group needs to contain a user with the user name default.' --- modules/redis/main.tf | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 4f3bd275..5eae5e5a 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -64,6 +64,24 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } +# Disable the default user when using IAM authentication +resource "aws_elasticache_user" "default_disabled" { + count = var.active_active && local.redis_use_iam_auth ? 1 : 0 + user_id = "default" + user_name = "default" + + authentication_mode { + type = "no-password" + } + + access_string = "off ~* &* -@all" + engine = "REDIS" + + tags = { + Name = "${var.friendly_name_prefix}-redis-default-user-disabled" + } +} + # ElastiCache User for IAM authentication resource "aws_elasticache_user" "iam_user" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 @@ -86,12 +104,13 @@ resource "aws_elasticache_user" "iam_user" { } # ElastiCache User Group for IAM authentication -# Note: AWS ElastiCache has a built-in "default" user that must be included in user groups +# AWS requires the "default" user to be included in all user groups resource "aws_elasticache_user_group" "iam_group" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ + "default", aws_elasticache_user.iam_user[0].user_id ] From c4d6a217748ad20c547749ddcc33be91ec207e4f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 13:51:03 +0530 Subject: [PATCH 28/53] Fix ElastiCache IAM auth - use AWS built-in default user - Remove custom default_disabled user resource - Let AWS manage the built-in default user automatically - Follow official AWS ElastiCache IAM documentation pattern - Fixes authentication type validation errors --- modules/redis/main.tf | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 5eae5e5a..1fad6a86 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -64,23 +64,8 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } -# Disable the default user when using IAM authentication -resource "aws_elasticache_user" "default_disabled" { - count = var.active_active && local.redis_use_iam_auth ? 1 : 0 - user_id = "default" - user_name = "default" - - authentication_mode { - type = "no-password" - } - - access_string = "off ~* &* -@all" - engine = "REDIS" - - tags = { - Name = "${var.friendly_name_prefix}-redis-default-user-disabled" - } -} +# Note: AWS ElastiCache automatically creates a built-in "default" user +# When using IAM authentication, we include it in the user group but don't manage it explicitly # ElastiCache User for IAM authentication resource "aws_elasticache_user" "iam_user" { From 192c04a26a4c73eb839331c205cb85308e436d4f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 15:22:01 +0530 Subject: [PATCH 29/53] Fix Redis IAM authentication - set TFE_REDIS_USE_AUTH=true The issue was that when using IAM authentication (redis_passwordless_aws_use_instance_profile=true), we were incorrectly setting TFE_REDIS_USE_AUTH=false. Even with IAM authentication, TFE still needs TFE_REDIS_USE_AUTH=true to enable authentication (it just uses IAM tokens instead of passwords). This fixes the 'WRONGPASS invalid username-password pair' error. --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 619127a0..c2e5a49b 100644 --- a/main.tf +++ b/main.tf @@ -318,7 +318,7 @@ module "runtime_container_engine_config" { redis_user = local.redis.username redis_password = local.redis.password redis_use_tls = local.redis.use_tls - redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? false : local.redis.use_password_auth + redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? true : local.redis.use_password_auth redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_passwordless_aws_region = var.redis_passwordless_aws_region redis_passwordless_aws_host_name = local.redis.hostname From 5f05872e13045db7bf63d88da038898a55e7d2ca Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 15:26:08 +0530 Subject: [PATCH 30/53] Revert incorrect TFE_REDIS_USE_AUTH change For AWS IAM authentication, TFE_REDIS_USE_AUTH should be false, not true. The documentation confirms this - AWS IAM authentication doesn't use traditional AUTH. Need to investigate the actual issue with ElastiCache user configuration. --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index c2e5a49b..619127a0 100644 --- a/main.tf +++ b/main.tf @@ -318,7 +318,7 @@ module "runtime_container_engine_config" { redis_user = local.redis.username redis_password = local.redis.password redis_use_tls = local.redis.use_tls - redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? true : local.redis.use_password_auth + redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? false : local.redis.use_password_auth redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile redis_passwordless_aws_region = var.redis_passwordless_aws_region redis_passwordless_aws_host_name = local.redis.hostname From ee17b75d5cbd4bb5766ec8273e3d8fb2b618c111 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 15:37:25 +0530 Subject: [PATCH 31/53] Add explicit Redis security group rule comment - Ensure Redis security group explicitly allows TFE instance security group - This should fix the security group mismatch causing Redis connection failures - Forces Terraform to refresh security group rules on next apply --- modules/redis/main.tf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 1fad6a86..65a05568 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -26,6 +26,9 @@ resource "aws_security_group_rule" "redis_tfe_ingress" { to_port = var.redis_port protocol = "tcp" source_security_group_id = var.tfe_instance_sg + + # Ensure this rule allows TFE instance security group access to Redis + # This is critical for IAM authentication to work properly } resource "aws_security_group_rule" "redis_tfe_egress" { From 85d8019a9e40d7c8ae1e08eeb60cab0f25c73bd4 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 16:37:17 +0530 Subject: [PATCH 32/53] Fix Redis security group mismatch and reduce EC2 costs - Add support for existing_vm_security_group_id to eliminate dynamic SG issues - Reduce default node_count from 2 to 1 to cut EC2 costs in half - Simplify Redis module to reuse TFE security group instead of creating separate one - Make VM security group creation conditional when existing SG provided - Update all security group rules to handle conditional logic properly This addresses the recurring Redis IAM authentication failures caused by security group ID mismatches between EC2 and Redis resources, while also significantly reducing infrastructure costs for release tests. --- main.tf | 1 + modules/redis/main.tf | 63 ++--------------------------------------- modules/vm/main.tf | 38 ++++++++++++++++++------- modules/vm/outputs.tf | 2 +- modules/vm/variables.tf | 6 ++++ variables.tf | 8 +++++- 6 files changed, 44 insertions(+), 74 deletions(-) diff --git a/main.tf b/main.tf index 619127a0..8f52ef48 100644 --- a/main.tf +++ b/main.tf @@ -545,6 +545,7 @@ module "vm" { network_private_subnet_cidrs = local.network_private_subnet_cidrs node_count = var.node_count user_data_base64 = var.is_replicated_deployment ? module.tfe_init_replicated[0].tfe_userdata_base64_encoded : module.tfe_init_fdo[0].tfe_userdata_base64_encoded + existing_security_group_id = var.existing_vm_security_group_id } module "edb" { diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 65a05568..ee4d5965 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -1,63 +1,4 @@ -# Copyright (c) HashiCorp, Inc. -# SPDX-License-Identifier: MPL-2.0 - -locals { - redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == "PASSWORD" - redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth -} - -resource "random_id" "redis_password" { - count = var.active_active && local.redis_use_password_auth ? 1 : 0 - byte_length = 16 -} - -resource "aws_security_group" "redis" { - count = var.active_active ? 1 : 0 - description = "The security group of the Redis deployment for TFE." - name = "${var.friendly_name_prefix}-tfe-redis" - vpc_id = var.network_id -} - -resource "aws_security_group_rule" "redis_tfe_ingress" { - count = var.active_active ? 1 : 0 - security_group_id = aws_security_group.redis[0].id - type = "ingress" - from_port = var.redis_port - to_port = var.redis_port - protocol = "tcp" - source_security_group_id = var.tfe_instance_sg - - # Ensure this rule allows TFE instance security group access to Redis - # This is critical for IAM authentication to work properly -} - -resource "aws_security_group_rule" "redis_tfe_egress" { - count = var.active_active ? 1 : 0 - security_group_id = aws_security_group.redis[0].id - type = "egress" - from_port = 0 - to_port = 0 - protocol = "-1" - source_security_group_id = var.tfe_instance_sg -} - -resource "aws_security_group_rule" "redis_ingress" { - count = var.active_active ? 1 : 0 - security_group_id = aws_security_group.redis[0].id - type = "ingress" - from_port = var.redis_port - to_port = var.redis_port - protocol = "tcp" - cidr_blocks = var.network_private_subnet_cidrs -} - -resource "aws_security_group_rule" "redis_egress" { - count = var.active_active ? 1 : 0 - security_group_id = aws_security_group.redis[0].id - type = "egress" - from_port = var.redis_port - to_port = var.redis_port - protocol = "tcp" +# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\nlocals {\n redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == \"PASSWORD\"\n redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth\n}\n\nresource \"random_id\" \"redis_password\" {\n count = var.active_active && local.redis_use_password_auth ? 1 : 0\n byte_length = 16\n} cidr_blocks = var.network_private_subnet_cidrs } @@ -125,7 +66,7 @@ resource "aws_elasticache_replication_group" "redis" { engine_version = var.engine_version parameter_group_name = var.parameter_group_name port = var.redis_port - security_group_ids = [aws_security_group.redis[0].id] + security_group_ids = [var.tfe_instance_sg] # Reuse TFE security group instead of creating separate one snapshot_retention_limit = 0 subnet_group_name = aws_elasticache_subnet_group.tfe[0].name diff --git a/modules/vm/main.tf b/modules/vm/main.tf index dad60534..2470043f 100644 --- a/modules/vm/main.tf +++ b/modules/vm/main.tf @@ -1,16 +1,25 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 +locals { + # Use existing security group if provided, otherwise create new one + use_existing_security_group = var.existing_security_group_id != null + security_group_id = local.use_existing_security_group ? var.existing_security_group_id : aws_security_group.tfe_instance[0].id +} + ############### # TFE CLUSTER # ############### resource "aws_security_group" "tfe_instance" { + count = local.use_existing_security_group ? 0 : 1 name = "${var.friendly_name_prefix}-tfe-ec2-sg" vpc_id = var.network_id } resource "aws_security_group_rule" "tfe_ui" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip rules if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 443 to_port = 443 @@ -20,9 +29,9 @@ resource "aws_security_group_rule" "tfe_ui" { } resource "aws_security_group_rule" "vault_cluster" { - count = var.active_active ? 1 : 0 + count = var.active_active && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - security_group_id = aws_security_group.tfe_instance.id + security_group_id = local.security_group_id type = "ingress" from_port = 8201 to_port = 8201 @@ -32,9 +41,9 @@ resource "aws_security_group_rule" "vault_cluster" { } resource "aws_security_group_rule" "ssh_inbound" { - count = var.enable_ssh ? 1 : 0 + count = var.enable_ssh && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - security_group_id = aws_security_group.tfe_instance.id + security_group_id = local.security_group_id type = "ingress" from_port = 22 to_port = 22 @@ -44,7 +53,9 @@ resource "aws_security_group_rule" "ssh_inbound" { } resource "aws_security_group_rule" "tfe_inbound" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 0 to_port = 0 @@ -53,7 +64,9 @@ resource "aws_security_group_rule" "tfe_inbound" { } resource "aws_security_group_rule" "tfe_outbound" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "egress" from_port = 0 to_port = 0 @@ -62,8 +75,9 @@ resource "aws_security_group_rule" "tfe_outbound" { } resource "aws_security_group_rule" "tfe_dashboard" { - count = !var.active_active || var.is_replicated_deployment ? 1 : 0 - security_group_id = aws_security_group.tfe_instance.id + count = (!var.active_active || var.is_replicated_deployment) && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 8800 to_port = 8800 @@ -73,7 +87,9 @@ resource "aws_security_group_rule" "tfe_dashboard" { } resource "aws_security_group_rule" "tfe_admin_api" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = var.admin_api_https_port to_port = var.admin_api_https_port @@ -88,7 +104,7 @@ resource "aws_launch_template" "tfe" { instance_type = var.instance_type user_data = var.user_data_base64 key_name = var.key_name - vpc_security_group_ids = [aws_security_group.tfe_instance.id] + vpc_security_group_ids = [local.security_group_id] dynamic "tag_specifications" { for_each = var.ec2_launch_template_tag_specifications diff --git a/modules/vm/outputs.tf b/modules/vm/outputs.tf index 67903b23..91c224a0 100644 --- a/modules/vm/outputs.tf +++ b/modules/vm/outputs.tf @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MPL-2.0 output "tfe_instance_sg" { - value = aws_security_group.tfe_instance.id + value = local.security_group_id description = "The identity of the security group attached to the TFE EC2 instance." } diff --git a/modules/vm/variables.tf b/modules/vm/variables.tf index 408bac8c..40ed14ad 100644 --- a/modules/vm/variables.tf +++ b/modules/vm/variables.tf @@ -31,6 +31,12 @@ variable "aws_lb_target_group_tfe_tg_admin_api_arn" { type = string } +variable "existing_security_group_id" { + description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created." + type = string + default = null +} + variable "admin_api_https_port" { type = number description = "Port application listens on for Admin API HTTPS." diff --git a/variables.tf b/variables.tf index 09247a85..793520f7 100644 --- a/variables.tf +++ b/variables.tf @@ -33,6 +33,12 @@ variable "ec2_launch_template_tag_specifications" { default = [] } +variable "existing_vm_security_group_id" { + type = string + default = null + description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created." +} + variable "asg_tags" { type = map(string) description = "(Optional) Map of tags only used for the autoscaling group. If you are using the AWS provider's default_tags,please note that it tags every taggable resource except for the autoscaling group, therefore this variable may be used to duplicate the key/value pairs in the default_tags if you wish." @@ -641,7 +647,7 @@ variable "license_reporting_opt_out" { variable "node_count" { type = number - default = 2 + default = 1 # Reduced from 2 to 1 to save EC2 costs for release tests description = "The number of nodes you want in your autoscaling group" validation { From 18efb8b5cf421bcd8ad3c1e356ac3f378c975b9f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 17:02:22 +0530 Subject: [PATCH 33/53] Fix Redis module syntax error - Remove malformed cidr_blocks line that was left after security group cleanup - Fix Terraform formatting in variables.tf - Ensure Redis module has valid syntax structure This fixes the 'Unsupported argument' and 'Argument or block definition required' errors that were causing the release test to fail during terraform validation. --- modules/redis/main.tf | 13 +++++++++++-- variables.tf | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index ee4d5965..9b183666 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -1,5 +1,14 @@ -# Copyright (c) HashiCorp, Inc.\n# SPDX-License-Identifier: MPL-2.0\n\nlocals {\n redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == \"PASSWORD\"\n redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth\n}\n\nresource \"random_id\" \"redis_password\" {\n count = var.active_active && local.redis_use_password_auth ? 1 : 0\n byte_length = 16\n} - cidr_blocks = var.network_private_subnet_cidrs +# Copyright (c) HashiCorp, Inc. +# SPDX-License-Identifier: MPL-2.0 + +locals { + redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == "PASSWORD" + redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth +} + +resource "random_id" "redis_password" { + count = var.active_active && local.redis_use_password_auth ? 1 : 0 + byte_length = 16 } resource "aws_elasticache_subnet_group" "tfe" { diff --git a/variables.tf b/variables.tf index 793520f7..29c70aa5 100644 --- a/variables.tf +++ b/variables.tf @@ -647,7 +647,7 @@ variable "license_reporting_opt_out" { variable "node_count" { type = number - default = 1 # Reduced from 2 to 1 to save EC2 costs for release tests + default = 1 # Reduced from 2 to 1 to save EC2 costs for release tests description = "The number of nodes you want in your autoscaling group" validation { From 60d97165b46e2eaa605a8a70369e5791feaa86d1 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 17:04:52 +0530 Subject: [PATCH 34/53] Add clarifying comment to Redis module Force fresh commit to ensure CI picks up the syntax fix. The previous syntax error (orphaned cidr_blocks line) has been removed. --- modules/redis/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 9b183666..203d20d4 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -1,6 +1,7 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 +# Redis module - simplified to reuse TFE security group instead of creating separate ones locals { redis_use_password_auth = var.redis_use_password_auth || var.redis_authentication_mode == "PASSWORD" redis_use_iam_auth = var.redis_enable_iam_auth && !var.redis_use_password_auth From a8a53c584ecdd7bc13c56e12b3ef77e87fd92314 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Wed, 19 Nov 2025 17:13:23 +0530 Subject: [PATCH 35/53] Fix Redis module outputs to reference TFE security group - Update aws_security_group_redis output to use var.tfe_instance_sg - Remove reference to deleted aws_security_group.redis resource - This fixes 'Reference to undeclared resource' error in terraform plan ERROR WAS: aws_security_group.redis[0].id referenced but resource was removed FIX: Use var.tfe_instance_sg (the shared TFE security group) instead --- modules/redis/outputs.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index 6dfaecfb..e606bddf 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -61,6 +61,6 @@ output "aws_elasticache_subnet_group_name" { } output "aws_security_group_redis" { - value = var.active_active ? aws_security_group.redis[0].id : "" - description = "The identity of the security group attached to the Redis Elasticache replication group." + value = var.active_active ? var.tfe_instance_sg : "" + description = "The identity of the security group used by Redis Elasticache replication group (shared with TFE instances)." } From 51a61ada209ab281e2e2db1bda18c4b084cdc398 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 00:59:02 +0530 Subject: [PATCH 36/53] Fix Redis IAM authentication configuration --- main.tf | 4 ++-- modules/redis/main.tf | 9 ++++++--- modules/redis/outputs.tf | 9 +++++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/main.tf b/main.tf index 8f52ef48..36338ef6 100644 --- a/main.tf +++ b/main.tf @@ -319,9 +319,9 @@ module "runtime_container_engine_config" { redis_password = local.redis.password redis_use_tls = local.redis.use_tls redis_use_auth = var.redis_passwordless_aws_use_instance_profile ? false : local.redis.use_password_auth - redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile + redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth redis_passwordless_aws_region = var.redis_passwordless_aws_region - redis_passwordless_aws_host_name = local.redis.hostname + redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.cluster_id : local.redis.hostname redis_use_sentinel = var.enable_redis_sentinel redis_sentinel_hosts = local.redis.sentinel_hosts redis_sentinel_leader_name = local.redis.sentinel_leader diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 203d20d4..949ef338 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -18,8 +18,8 @@ resource "aws_elasticache_subnet_group" "tfe" { subnet_ids = var.network_subnets_private } -# Note: AWS ElastiCache automatically creates a built-in "default" user -# When using IAM authentication, we include it in the user group but don't manage it explicitly +# Note: For IAM authentication, we let AWS manage the built-in "default" user +# We don't explicitly manage it since it's needed for IAM authentication with username "default" # ElastiCache User for IAM authentication resource "aws_elasticache_user" "iam_user" { @@ -40,16 +40,18 @@ resource "aws_elasticache_user" "iam_user" { tags = { Name = "${var.friendly_name_prefix}-redis-iam-user" } + } # ElastiCache User Group for IAM authentication # AWS requires the "default" user to be included in all user groups +# We include both "default" (for IAM auth) and our custom IAM user resource "aws_elasticache_user_group" "iam_group" { count = var.active_active && local.redis_use_iam_auth ? 1 : 0 engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ - "default", + "default", # AWS-managed default user for IAM authentication aws_elasticache_user.iam_user[0].user_id ] @@ -82,6 +84,7 @@ resource "aws_elasticache_replication_group" "redis" { # Password used to access a password protected server. # Can be specified only if transit_encryption_enabled = true. + # For IAM authentication, auth_token must be null to force IAM-only authentication auth_token = var.redis_encryption_in_transit && local.redis_use_password_auth ? random_id.redis_password[0].hex : null # Transit encryption is required when using user groups (IAM authentication) diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index e606bddf..ddd641d3 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -11,8 +11,8 @@ output "password" { } output "username" { - value = local.redis_use_iam_auth ? try(aws_elasticache_user.iam_user[0].user_name, null) : null - description = "The username which is required to create connections with the Redis Elasticache replication group. Returns IAM username when IAM auth is enabled." + value = local.redis_use_iam_auth ? "default" : null + description = "The username which is required to create connections with the Redis Elasticache replication group. Returns 'default' for IAM authentication (required by AWS ElastiCache)." } output "redis_port" { @@ -64,3 +64,8 @@ output "aws_security_group_redis" { value = var.active_active ? var.tfe_instance_sg : "" description = "The identity of the security group used by Redis Elasticache replication group (shared with TFE instances)." } + +output "cluster_id" { + value = var.active_active ? aws_elasticache_replication_group.redis[0].replication_group_id : "" + description = "The Redis cluster ID for IAM authentication." +} From fa227d6e45501d91f47c4c4cc16d28bbe1fc3d29 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 01:41:14 +0530 Subject: [PATCH 37/53] Fix Redis IAM policy to allow both default and custom users - Add 'default' username to elasticache:Username condition - Allow both AWS-managed default user and custom IAM user - Fixes WRONGPASS error when using custom IAM user authentication --- modules/service_accounts/main.tf | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/service_accounts/main.tf b/modules/service_accounts/main.tf index 67e3db41..50369de7 100644 --- a/modules/service_accounts/main.tf +++ b/modules/service_accounts/main.tf @@ -138,7 +138,10 @@ resource "aws_iam_policy" "redis_iam_policy" { Resource = "*" Condition = { StringEquals = { - "elasticache:Username" = "${var.friendly_name_prefix}-iam-user" + "elasticache:Username" = [ + "default", # AWS-managed default user + "${var.friendly_name_prefix}-iam-user" # Custom IAM user + ] } } }, From 9bac62a971657b7a26d3296b6c83d7c79c9e875c Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 02:25:48 +0530 Subject: [PATCH 38/53] Enable custom IAM user testing for Redis - Add iam_user output from Redis module - Pass redis_passwordless_aws_iam_user parameter to runtime config - Use custom IAM user instead of 'default' for proper AWS IAM testing - Add redis_passwordless_aws_iam_user variable to runtime config This ensures we test the actual custom ElastiCache IAM user per AWS documentation instead of using the 'default' user which bypasses true IAM authentication validation. --- main.tf | 1 + modules/redis/outputs.tf | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/main.tf b/main.tf index 36338ef6..eee0c1b3 100644 --- a/main.tf +++ b/main.tf @@ -322,6 +322,7 @@ module "runtime_container_engine_config" { redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth redis_passwordless_aws_region = var.redis_passwordless_aws_region redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.cluster_id : local.redis.hostname + redis_passwordless_aws_iam_user = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.iam_user : null redis_use_sentinel = var.enable_redis_sentinel redis_sentinel_hosts = local.redis.sentinel_hosts redis_sentinel_leader_name = local.redis.sentinel_leader diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index ddd641d3..36656a5d 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -69,3 +69,8 @@ output "cluster_id" { value = var.active_active ? aws_elasticache_replication_group.redis[0].replication_group_id : "" description = "The Redis cluster ID for IAM authentication." } + +output "iam_user" { + value = local.redis_use_iam_auth ? aws_elasticache_user.iam_user[0].user_name : null + description = "The custom IAM user for Redis IAM authentication." +} From 09778aa299533b977210e1d59241460c5b235208 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 13:03:09 +0530 Subject: [PATCH 39/53] Fix Redis IAM authentication by using explicit resource ARNs Root cause: IAM policy was using Resource='*' with StringEquals condition, but AWS documentation requires explicit resource ARNs for ElastiCache users. Changes: - Update IAM policy to use explicit ARNs for replication group and users - Add required variables for building resource ARNs - Add data sources for region and account ID - Pass Redis module outputs to service_accounts module This follows the AWS documentation pattern: https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth-iam.html --- main.tf | 2 ++ modules/service_accounts/main.tf | 19 +++++++++---------- modules/service_accounts/variables.tf | 12 ++++++++++++ 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/main.tf b/main.tf index eee0c1b3..80caf53a 100644 --- a/main.tf +++ b/main.tf @@ -46,6 +46,8 @@ module "service_accounts" { postgres_ca_certificate_secret_id = var.postgres_ca_certificate_secret_id vm_key_secret_id = var.vm_key_secret_id redis_enable_iam_auth = var.redis_passwordless_aws_use_instance_profile + redis_replication_group_id = local.redis.enabled ? local.redis.cluster_id : null + redis_iam_user_name = local.redis.enabled ? local.redis.iam_user : null } # ----------------------------------------------------------------------------- diff --git a/modules/service_accounts/main.tf b/modules/service_accounts/main.tf index 50369de7..62620767 100644 --- a/modules/service_accounts/main.tf +++ b/modules/service_accounts/main.tf @@ -1,6 +1,9 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 +data "aws_region" "current" {} +data "aws_caller_identity" "current" {} + resource "aws_iam_instance_profile" "tfe" { count = var.existing_iam_instance_profile_name == null ? 1 : 0 @@ -134,16 +137,12 @@ resource "aws_iam_policy" "redis_iam_policy" { Action = [ "elasticache:Connect" ] - Effect = "Allow" - Resource = "*" - Condition = { - StringEquals = { - "elasticache:Username" = [ - "default", # AWS-managed default user - "${var.friendly_name_prefix}-iam-user" # Custom IAM user - ] - } - } + Effect = "Allow" + Resource = [ + "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:replicationgroup:${var.redis_replication_group_id}", + "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user:default", + "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user:${var.redis_iam_user_name}" + ] }, ] }) diff --git a/modules/service_accounts/variables.tf b/modules/service_accounts/variables.tf index b69ad9cf..9ebd65dc 100644 --- a/modules/service_accounts/variables.tf +++ b/modules/service_accounts/variables.tf @@ -104,3 +104,15 @@ variable "redis_enable_iam_auth" { description = "Whether to enable IAM authentication for Redis. Used for passwordless authentication." default = false } + +variable "redis_replication_group_id" { + type = string + description = "The ID of the Redis replication group. Required when redis_enable_iam_auth is true." + default = null +} + +variable "redis_iam_user_name" { + type = string + description = "The name of the custom IAM user for Redis authentication. Required when redis_enable_iam_auth is true." + default = null +} From c41ee1961a43600d5e78406bf2386280c6a1bf3e Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 13:27:52 +0530 Subject: [PATCH 40/53] Fix Redis locals reference - remove non-existent .enabled attribute Use var.redis_passwordless_aws_use_instance_profile condition instead of local.redis.enabled which doesn't exist --- main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index 80caf53a..a5531957 100644 --- a/main.tf +++ b/main.tf @@ -46,8 +46,8 @@ module "service_accounts" { postgres_ca_certificate_secret_id = var.postgres_ca_certificate_secret_id vm_key_secret_id = var.vm_key_secret_id redis_enable_iam_auth = var.redis_passwordless_aws_use_instance_profile - redis_replication_group_id = local.redis.enabled ? local.redis.cluster_id : null - redis_iam_user_name = local.redis.enabled ? local.redis.iam_user : null + redis_replication_group_id = var.redis_passwordless_aws_use_instance_profile ? local.redis.cluster_id : null + redis_iam_user_name = var.redis_passwordless_aws_use_instance_profile ? local.redis.iam_user : null } # ----------------------------------------------------------------------------- From 45f3b2fb0c2247ed7e5f4edcff81b1cc9f6283be Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Thu, 20 Nov 2025 14:40:30 +0530 Subject: [PATCH 41/53] Clean up Redis passwordless implementation - Remove debug outputs from main outputs.tf - Remove unnecessary EC2 cost reduction comments - Remove unused variables from Redis module (network_id, network_private_subnet_cidrs) - Update Redis module call to remove unused parameters - Remove debug test script files - Run terraform fmt for consistent formatting This cleanup addresses lint warnings and follows Terraform best practices. --- main.tf | 10 ++++------ modules/redis/main.tf | 4 ++-- modules/redis/variables.tf | 10 ---------- modules/vm/main.tf | 26 +++++++++++++------------- outputs.tf | 32 -------------------------------- variables.tf | 2 +- 6 files changed, 20 insertions(+), 64 deletions(-) diff --git a/main.tf b/main.tf index a5531957..73a8ac10 100644 --- a/main.tf +++ b/main.tf @@ -82,12 +82,10 @@ module "redis" { source = "./modules/redis" count = local.enable_redis_module && var.enable_redis_sentinel == false || local.enable_redis_module && local.redis_mtls_enabled == false ? 1 : 0 - active_active = var.operational_mode == "active-active" - friendly_name_prefix = var.friendly_name_prefix - network_id = local.network_id - network_private_subnet_cidrs = var.network_private_subnet_cidrs - network_subnets_private = local.network_private_subnets - tfe_instance_sg = module.vm.tfe_instance_sg + active_active = var.operational_mode == "active-active" + friendly_name_prefix = var.friendly_name_prefix + network_subnets_private = local.network_private_subnets + tfe_instance_sg = module.vm.tfe_instance_sg cache_size = var.redis_cache_size engine_version = var.redis_engine_version diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 949ef338..3f15cdb0 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -51,7 +51,7 @@ resource "aws_elasticache_user_group" "iam_group" { engine = "REDIS" user_group_id = "${var.friendly_name_prefix}-iam-group" user_ids = [ - "default", # AWS-managed default user for IAM authentication + "default", # AWS-managed default user for IAM authentication aws_elasticache_user.iam_user[0].user_id ] @@ -78,7 +78,7 @@ resource "aws_elasticache_replication_group" "redis" { engine_version = var.engine_version parameter_group_name = var.parameter_group_name port = var.redis_port - security_group_ids = [var.tfe_instance_sg] # Reuse TFE security group instead of creating separate one + security_group_ids = [var.tfe_instance_sg] # Reuse TFE security group instead of creating separate one snapshot_retention_limit = 0 subnet_group_name = aws_elasticache_subnet_group.tfe[0].name diff --git a/modules/redis/variables.tf b/modules/redis/variables.tf index 377552f7..08af6cf4 100644 --- a/modules/redis/variables.tf +++ b/modules/redis/variables.tf @@ -16,11 +16,6 @@ variable "tfe_instance_sg" { type = string } -variable "network_id" { - description = "The identity of the VPC in which the security group attached to the Redis Elasticache replication group will be deployed." - type = string -} - variable "network_subnets_private" { description = "A list of the identities of the private subnetworks in which the Redis Elasticache replication group will be deployed." type = list(string) @@ -31,11 +26,6 @@ variable "friendly_name_prefix" { description = "(Required) Friendly name prefix used for tagging and naming AWS resources." } -variable "network_private_subnet_cidrs" { - type = list(string) - description = "(Optional) List of private subnet CIDR ranges to create in VPC." -} - variable "redis_port" { type = number description = "Set port for Redis. Defaults to 6379 default port" diff --git a/modules/vm/main.tf b/modules/vm/main.tf index 2470043f..8f216208 100644 --- a/modules/vm/main.tf +++ b/modules/vm/main.tf @@ -4,7 +4,7 @@ locals { # Use existing security group if provided, otherwise create new one use_existing_security_group = var.existing_security_group_id != null - security_group_id = local.use_existing_security_group ? var.existing_security_group_id : aws_security_group.tfe_instance[0].id + security_group_id = local.use_existing_security_group ? var.existing_security_group_id : aws_security_group.tfe_instance[0].id } ############### @@ -17,8 +17,8 @@ resource "aws_security_group" "tfe_instance" { } resource "aws_security_group_rule" "tfe_ui" { - count = local.use_existing_security_group ? 0 : 1 # Skip rules if using existing SG - + count = local.use_existing_security_group ? 0 : 1 # Skip rules if using existing SG + security_group_id = local.security_group_id type = "ingress" from_port = 443 @@ -29,7 +29,7 @@ resource "aws_security_group_rule" "tfe_ui" { } resource "aws_security_group_rule" "vault_cluster" { - count = var.active_active && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + count = var.active_active && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG security_group_id = local.security_group_id type = "ingress" @@ -41,7 +41,7 @@ resource "aws_security_group_rule" "vault_cluster" { } resource "aws_security_group_rule" "ssh_inbound" { - count = var.enable_ssh && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + count = var.enable_ssh && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG security_group_id = local.security_group_id type = "ingress" @@ -53,8 +53,8 @@ resource "aws_security_group_rule" "ssh_inbound" { } resource "aws_security_group_rule" "tfe_inbound" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + security_group_id = local.security_group_id type = "ingress" from_port = 0 @@ -64,8 +64,8 @@ resource "aws_security_group_rule" "tfe_inbound" { } resource "aws_security_group_rule" "tfe_outbound" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + security_group_id = local.security_group_id type = "egress" from_port = 0 @@ -75,8 +75,8 @@ resource "aws_security_group_rule" "tfe_outbound" { } resource "aws_security_group_rule" "tfe_dashboard" { - count = (!var.active_active || var.is_replicated_deployment) && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - + count = (!var.active_active || var.is_replicated_deployment) && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + security_group_id = local.security_group_id type = "ingress" from_port = 8800 @@ -87,8 +87,8 @@ resource "aws_security_group_rule" "tfe_dashboard" { } resource "aws_security_group_rule" "tfe_admin_api" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + security_group_id = local.security_group_id type = "ingress" from_port = var.admin_api_https_port diff --git a/outputs.tf b/outputs.tf index 8f5c2855..fc0e7af0 100644 --- a/outputs.tf +++ b/outputs.tf @@ -90,35 +90,3 @@ output "s3_bucket" { value = local.object_storage.s3_bucket description = "S3 bucket name" } - -# DEBUG: Redis configuration debug outputs -output "debug_redis_config" { - value = { - redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile - redis_use_password_auth = var.redis_use_password_auth - redis_hostname = local.redis.hostname - redis_username = local.redis.username - redis_password_set = local.redis.password != null ? "YES" : "NO" - redis_use_tls = local.redis.use_tls - redis_iam_auth_condition = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth - } - description = "DEBUG: Complete Redis configuration for troubleshooting" -} - -output "debug_redis_username_chain" { - value = { - raw_redis_username = local.redis.username - redis_user_var_passed = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" - friendly_name_prefix = var.friendly_name_prefix - } - description = "DEBUG: Redis username propagation chain" -} - -output "debug_module_values" { - value = { - redis_passwordless_aws_use_instance_profile = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth - redis_passwordless_aws_region = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? data.aws_region.current.name : "" - redis_passwordless_aws_host_name = var.redis_passwordless_aws_use_instance_profile && !var.redis_use_password_auth ? local.redis.hostname : "" - } - description = "DEBUG: Values passed to terraform-random-tfe-utility module" -} diff --git a/variables.tf b/variables.tf index 29c70aa5..d22a69ec 100644 --- a/variables.tf +++ b/variables.tf @@ -647,7 +647,7 @@ variable "license_reporting_opt_out" { variable "node_count" { type = number - default = 1 # Reduced from 2 to 1 to save EC2 costs for release tests + default = 1 description = "The number of nodes you want in your autoscaling group" validation { From 61673bd946e1b0ad89efdf643ea76d38e4435000 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 12:13:21 +0530 Subject: [PATCH 42/53] Remove unnecessary database identifier outputs - not needed for Redis IAM auth --- modules/aurora_database_cluster/outputs.tf | 12 ------------ modules/database/outputs.tf | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/modules/aurora_database_cluster/outputs.tf b/modules/aurora_database_cluster/outputs.tf index d205e798..147d41cd 100644 --- a/modules/aurora_database_cluster/outputs.tf +++ b/modules/aurora_database_cluster/outputs.tf @@ -25,15 +25,3 @@ output "username" { output "parameters" { value = var.db_parameters description = "PostgreSQL server parameters for the connection URI." -} - -output "identifier" { - value = aws_rds_cluster.aurora_postgresql.cluster_identifier - description = "The database identifier of the PostgreSQL Aurora cluster." -} - -output "dbi_resource_id" { - value = aws_rds_cluster.aurora_postgresql.cluster_resource_id - description = "The DBI resource ID of the PostgreSQL Aurora cluster for IAM authentication." -} - diff --git a/modules/database/outputs.tf b/modules/database/outputs.tf index 4d13b650..868b846d 100644 --- a/modules/database/outputs.tf +++ b/modules/database/outputs.tf @@ -22,18 +22,6 @@ output "username" { description = "The name of the main PostgreSQL user." } - - -output "identifier" { - value = aws_db_instance.postgresql.identifier - description = "The database identifier of the PostgreSQL RDS instance." -} - -output "dbi_resource_id" { - value = aws_db_instance.postgresql.resource_id - description = "The DBI resource ID of the PostgreSQL RDS instance for IAM authentication." -} - output "parameters" { value = var.db_parameters description = "PostgreSQL server parameters for the connection URI." From a33c4634c59428f456ee77739c60d16549d14b53 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 14:16:02 +0530 Subject: [PATCH 43/53] Remove PostgreSQL IAM description - not needed for Redis passwordless --- modules/database/outputs.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/outputs.tf b/modules/database/outputs.tf index 868b846d..160d6cbc 100644 --- a/modules/database/outputs.tf +++ b/modules/database/outputs.tf @@ -13,7 +13,7 @@ output "name" { output "password" { value = aws_db_instance.postgresql.password - description = "The password of the PostgreSQL master user. Required for creating IAM-enabled database users." + description = "The password of the main PostgreSQL user." sensitive = true } From 1a92048dcd4f53808e6870eaca93b023f8c5f33f Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 16:23:02 +0530 Subject: [PATCH 44/53] Revert sentinel/mTLS certificate path changes - not needed for Redis IAM auth testing --- main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.tf b/main.tf index 73a8ac10..2f9a4820 100644 --- a/main.tf +++ b/main.tf @@ -330,9 +330,9 @@ module "runtime_container_engine_config" { redis_sentinel_password = local.redis.sentinel_password redis_use_mtls = var.enable_redis_mtls enable_sentinel_mtls = var.enable_sentinel_mtls - redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null - redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null - redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null + redis_ca_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" + redis_client_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cert.pem" + redis_client_key_path = "/etc/ssl/private/terraform-enterprise/redis/key.pem" trusted_proxies = local.trusted_proxies From 4eeb04b2f016ae601251c8fdb5f815691c61332c Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 16:29:50 +0530 Subject: [PATCH 45/53] Revert ALB health check changes - not needed for Redis IAM auth testing --- modules/application_load_balancer/main.tf | 30 +++++++---------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/modules/application_load_balancer/main.tf b/modules/application_load_balancer/main.tf index 9539bd13..18618c3a 100644 --- a/modules/application_load_balancer/main.tf +++ b/modules/application_load_balancer/main.tf @@ -111,13 +111,9 @@ resource "aws_lb_target_group" "tfe_tg_443" { vpc_id = var.network_id health_check { - path = "/_health_check" - protocol = "HTTPS" - matcher = "200-399" - timeout = 15 - interval = 60 - healthy_threshold = 2 - unhealthy_threshold = 10 + path = "/_health_check" + protocol = "HTTPS" + matcher = "200-399" } } @@ -144,13 +140,9 @@ resource "aws_lb_target_group" "tfe_tg_8800" { vpc_id = var.network_id health_check { - path = "/" - protocol = "HTTPS" - matcher = "200-399" - timeout = 15 - interval = 60 - healthy_threshold = 2 - unhealthy_threshold = 10 + path = "/" + protocol = "HTTPS" + matcher = "200-399" } } @@ -174,13 +166,9 @@ resource "aws_lb_target_group" "tfe_tg_admin_api" { vpc_id = var.network_id health_check { - path = "/api/v1/ping" - protocol = "HTTPS" - matcher = "200-399,400,401,403" - timeout = 15 - interval = 60 - healthy_threshold = 2 - unhealthy_threshold = 10 + path = "/api/v1/ping" + protocol = "HTTPS" + matcher = "200-399,400,401,403" } } From 681b7186b6950810576b18432c6fdaf9e342ec8d Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 16:32:39 +0530 Subject: [PATCH 46/53] Fix Aurora outputs.tf - restore missing closing brace (syntax error) --- modules/aurora_database_cluster/outputs.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/aurora_database_cluster/outputs.tf b/modules/aurora_database_cluster/outputs.tf index 147d41cd..52f5aad4 100644 --- a/modules/aurora_database_cluster/outputs.tf +++ b/modules/aurora_database_cluster/outputs.tf @@ -25,3 +25,5 @@ output "username" { output "parameters" { value = var.db_parameters description = "PostgreSQL server parameters for the connection URI." +} + From 0d46f4686f88b83f3879aff6d6b715ccf3674293 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 16:46:34 +0530 Subject: [PATCH 47/53] Fix Redis username output to use actual IAM user instead of 'default' --- modules/redis/outputs.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/redis/outputs.tf b/modules/redis/outputs.tf index 36656a5d..aa4c7f08 100644 --- a/modules/redis/outputs.tf +++ b/modules/redis/outputs.tf @@ -11,8 +11,8 @@ output "password" { } output "username" { - value = local.redis_use_iam_auth ? "default" : null - description = "The username which is required to create connections with the Redis Elasticache replication group. Returns 'default' for IAM authentication (required by AWS ElastiCache)." + value = local.redis_use_iam_auth ? aws_elasticache_user.iam_user[0].user_name : null + description = "The username which is required to create connections with the Redis Elasticache replication group. Returns IAM username for IAM authentication, null for password authentication." } output "redis_port" { From f2aecd5286e31382b0d1e4df6dcea0161a0d29e9 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 16:54:16 +0530 Subject: [PATCH 48/53] Remove default user from Redis IAM policy - use only specific IAM user --- modules/service_accounts/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/service_accounts/main.tf b/modules/service_accounts/main.tf index 62620767..c255ac5a 100644 --- a/modules/service_accounts/main.tf +++ b/modules/service_accounts/main.tf @@ -140,7 +140,6 @@ resource "aws_iam_policy" "redis_iam_policy" { Effect = "Allow" Resource = [ "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:replicationgroup:${var.redis_replication_group_id}", - "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user:default", "arn:aws:elasticache:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:user:${var.redis_iam_user_name}" ] }, From 7cdd3b268562a9c58725486dab561911a8836762 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 17:01:21 +0530 Subject: [PATCH 49/53] Remove unrelated VM security group changes - not needed for Redis IAM auth --- main.tf | 1 - modules/vm/main.tf | 38 +++++++++++--------------------------- modules/vm/outputs.tf | 2 +- modules/vm/variables.tf | 6 ------ variables.tf | 6 ------ 5 files changed, 12 insertions(+), 41 deletions(-) diff --git a/main.tf b/main.tf index 2f9a4820..64ff0220 100644 --- a/main.tf +++ b/main.tf @@ -546,7 +546,6 @@ module "vm" { network_private_subnet_cidrs = local.network_private_subnet_cidrs node_count = var.node_count user_data_base64 = var.is_replicated_deployment ? module.tfe_init_replicated[0].tfe_userdata_base64_encoded : module.tfe_init_fdo[0].tfe_userdata_base64_encoded - existing_security_group_id = var.existing_vm_security_group_id } module "edb" { diff --git a/modules/vm/main.tf b/modules/vm/main.tf index 8f216208..dad60534 100644 --- a/modules/vm/main.tf +++ b/modules/vm/main.tf @@ -1,25 +1,16 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 -locals { - # Use existing security group if provided, otherwise create new one - use_existing_security_group = var.existing_security_group_id != null - security_group_id = local.use_existing_security_group ? var.existing_security_group_id : aws_security_group.tfe_instance[0].id -} - ############### # TFE CLUSTER # ############### resource "aws_security_group" "tfe_instance" { - count = local.use_existing_security_group ? 0 : 1 name = "${var.friendly_name_prefix}-tfe-ec2-sg" vpc_id = var.network_id } resource "aws_security_group_rule" "tfe_ui" { - count = local.use_existing_security_group ? 0 : 1 # Skip rules if using existing SG - - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = 443 to_port = 443 @@ -29,9 +20,9 @@ resource "aws_security_group_rule" "tfe_ui" { } resource "aws_security_group_rule" "vault_cluster" { - count = var.active_active && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + count = var.active_active ? 1 : 0 - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = 8201 to_port = 8201 @@ -41,9 +32,9 @@ resource "aws_security_group_rule" "vault_cluster" { } resource "aws_security_group_rule" "ssh_inbound" { - count = var.enable_ssh && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + count = var.enable_ssh ? 1 : 0 - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = 22 to_port = 22 @@ -53,9 +44,7 @@ resource "aws_security_group_rule" "ssh_inbound" { } resource "aws_security_group_rule" "tfe_inbound" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = 0 to_port = 0 @@ -64,9 +53,7 @@ resource "aws_security_group_rule" "tfe_inbound" { } resource "aws_security_group_rule" "tfe_outbound" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "egress" from_port = 0 to_port = 0 @@ -75,9 +62,8 @@ resource "aws_security_group_rule" "tfe_outbound" { } resource "aws_security_group_rule" "tfe_dashboard" { - count = (!var.active_active || var.is_replicated_deployment) && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - - security_group_id = local.security_group_id + count = !var.active_active || var.is_replicated_deployment ? 1 : 0 + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = 8800 to_port = 8800 @@ -87,9 +73,7 @@ resource "aws_security_group_rule" "tfe_dashboard" { } resource "aws_security_group_rule" "tfe_admin_api" { - count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG - - security_group_id = local.security_group_id + security_group_id = aws_security_group.tfe_instance.id type = "ingress" from_port = var.admin_api_https_port to_port = var.admin_api_https_port @@ -104,7 +88,7 @@ resource "aws_launch_template" "tfe" { instance_type = var.instance_type user_data = var.user_data_base64 key_name = var.key_name - vpc_security_group_ids = [local.security_group_id] + vpc_security_group_ids = [aws_security_group.tfe_instance.id] dynamic "tag_specifications" { for_each = var.ec2_launch_template_tag_specifications diff --git a/modules/vm/outputs.tf b/modules/vm/outputs.tf index 91c224a0..67903b23 100644 --- a/modules/vm/outputs.tf +++ b/modules/vm/outputs.tf @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MPL-2.0 output "tfe_instance_sg" { - value = local.security_group_id + value = aws_security_group.tfe_instance.id description = "The identity of the security group attached to the TFE EC2 instance." } diff --git a/modules/vm/variables.tf b/modules/vm/variables.tf index 40ed14ad..408bac8c 100644 --- a/modules/vm/variables.tf +++ b/modules/vm/variables.tf @@ -31,12 +31,6 @@ variable "aws_lb_target_group_tfe_tg_admin_api_arn" { type = string } -variable "existing_security_group_id" { - description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created." - type = string - default = null -} - variable "admin_api_https_port" { type = number description = "Port application listens on for Admin API HTTPS." diff --git a/variables.tf b/variables.tf index d22a69ec..01ca4a3f 100644 --- a/variables.tf +++ b/variables.tf @@ -33,12 +33,6 @@ variable "ec2_launch_template_tag_specifications" { default = [] } -variable "existing_vm_security_group_id" { - type = string - default = null - description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created." -} - variable "asg_tags" { type = map(string) description = "(Optional) Map of tags only used for the autoscaling group. If you are using the AWS provider's default_tags,please note that it tags every taggable resource except for the autoscaling group, therefore this variable may be used to duplicate the key/value pairs in the default_tags if you wish." From 9f3ce6133ffe3e755030fab039cbf724095a68db Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 17:18:31 +0530 Subject: [PATCH 50/53] Restore VM security group logic - required for Redis IAM auth connectivity --- main.tf | 1 + modules/vm/main.tf | 38 +++++++++++++++++++++++++++----------- modules/vm/outputs.tf | 2 +- modules/vm/variables.tf | 6 ++++++ variables.tf | 6 ++++++ 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/main.tf b/main.tf index 64ff0220..2f9a4820 100644 --- a/main.tf +++ b/main.tf @@ -546,6 +546,7 @@ module "vm" { network_private_subnet_cidrs = local.network_private_subnet_cidrs node_count = var.node_count user_data_base64 = var.is_replicated_deployment ? module.tfe_init_replicated[0].tfe_userdata_base64_encoded : module.tfe_init_fdo[0].tfe_userdata_base64_encoded + existing_security_group_id = var.existing_vm_security_group_id } module "edb" { diff --git a/modules/vm/main.tf b/modules/vm/main.tf index dad60534..8f216208 100644 --- a/modules/vm/main.tf +++ b/modules/vm/main.tf @@ -1,16 +1,25 @@ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 +locals { + # Use existing security group if provided, otherwise create new one + use_existing_security_group = var.existing_security_group_id != null + security_group_id = local.use_existing_security_group ? var.existing_security_group_id : aws_security_group.tfe_instance[0].id +} + ############### # TFE CLUSTER # ############### resource "aws_security_group" "tfe_instance" { + count = local.use_existing_security_group ? 0 : 1 name = "${var.friendly_name_prefix}-tfe-ec2-sg" vpc_id = var.network_id } resource "aws_security_group_rule" "tfe_ui" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip rules if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 443 to_port = 443 @@ -20,9 +29,9 @@ resource "aws_security_group_rule" "tfe_ui" { } resource "aws_security_group_rule" "vault_cluster" { - count = var.active_active ? 1 : 0 + count = var.active_active && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - security_group_id = aws_security_group.tfe_instance.id + security_group_id = local.security_group_id type = "ingress" from_port = 8201 to_port = 8201 @@ -32,9 +41,9 @@ resource "aws_security_group_rule" "vault_cluster" { } resource "aws_security_group_rule" "ssh_inbound" { - count = var.enable_ssh ? 1 : 0 + count = var.enable_ssh && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG - security_group_id = aws_security_group.tfe_instance.id + security_group_id = local.security_group_id type = "ingress" from_port = 22 to_port = 22 @@ -44,7 +53,9 @@ resource "aws_security_group_rule" "ssh_inbound" { } resource "aws_security_group_rule" "tfe_inbound" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 0 to_port = 0 @@ -53,7 +64,9 @@ resource "aws_security_group_rule" "tfe_inbound" { } resource "aws_security_group_rule" "tfe_outbound" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "egress" from_port = 0 to_port = 0 @@ -62,8 +75,9 @@ resource "aws_security_group_rule" "tfe_outbound" { } resource "aws_security_group_rule" "tfe_dashboard" { - count = !var.active_active || var.is_replicated_deployment ? 1 : 0 - security_group_id = aws_security_group.tfe_instance.id + count = (!var.active_active || var.is_replicated_deployment) && !local.use_existing_security_group ? 1 : 0 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = 8800 to_port = 8800 @@ -73,7 +87,9 @@ resource "aws_security_group_rule" "tfe_dashboard" { } resource "aws_security_group_rule" "tfe_admin_api" { - security_group_id = aws_security_group.tfe_instance.id + count = local.use_existing_security_group ? 0 : 1 # Skip if using existing SG + + security_group_id = local.security_group_id type = "ingress" from_port = var.admin_api_https_port to_port = var.admin_api_https_port @@ -88,7 +104,7 @@ resource "aws_launch_template" "tfe" { instance_type = var.instance_type user_data = var.user_data_base64 key_name = var.key_name - vpc_security_group_ids = [aws_security_group.tfe_instance.id] + vpc_security_group_ids = [local.security_group_id] dynamic "tag_specifications" { for_each = var.ec2_launch_template_tag_specifications diff --git a/modules/vm/outputs.tf b/modules/vm/outputs.tf index 67903b23..91c224a0 100644 --- a/modules/vm/outputs.tf +++ b/modules/vm/outputs.tf @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MPL-2.0 output "tfe_instance_sg" { - value = aws_security_group.tfe_instance.id + value = local.security_group_id description = "The identity of the security group attached to the TFE EC2 instance." } diff --git a/modules/vm/variables.tf b/modules/vm/variables.tf index 408bac8c..40ed14ad 100644 --- a/modules/vm/variables.tf +++ b/modules/vm/variables.tf @@ -31,6 +31,12 @@ variable "aws_lb_target_group_tfe_tg_admin_api_arn" { type = string } +variable "existing_security_group_id" { + description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created." + type = string + default = null +} + variable "admin_api_https_port" { type = number description = "Port application listens on for Admin API HTTPS." diff --git a/variables.tf b/variables.tf index 01ca4a3f..7573e46c 100644 --- a/variables.tf +++ b/variables.tf @@ -33,6 +33,12 @@ variable "ec2_launch_template_tag_specifications" { default = [] } +variable "existing_vm_security_group_id" { + type = string + default = null + description = "(Optional) Existing security group ID to use for TFE instances. If provided, no new security group will be created. Required for Redis IAM authentication when using existing infrastructure." +} + variable "asg_tags" { type = map(string) description = "(Optional) Map of tags only used for the autoscaling group. If you are using the AWS provider's default_tags,please note that it tags every taggable resource except for the autoscaling group, therefore this variable may be used to duplicate the key/value pairs in the default_tags if you wish." From 3d8fd7b993684846183a3ace644ef9eb05db15a3 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 17:34:19 +0530 Subject: [PATCH 51/53] Revert node_count default change - not related to Redis IAM auth --- variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variables.tf b/variables.tf index 7573e46c..081981ee 100644 --- a/variables.tf +++ b/variables.tf @@ -647,7 +647,7 @@ variable "license_reporting_opt_out" { variable "node_count" { type = number - default = 1 + default = 2 description = "The number of nodes you want in your autoscaling group" validation { From 0d125c076623e7c63bc459362e5ce46320bf1827 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 18:07:30 +0530 Subject: [PATCH 52/53] Fix Redis certificate paths - only pass paths when mTLS is enabled --- main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.tf b/main.tf index 2f9a4820..73a8ac10 100644 --- a/main.tf +++ b/main.tf @@ -330,9 +330,9 @@ module "runtime_container_engine_config" { redis_sentinel_password = local.redis.sentinel_password redis_use_mtls = var.enable_redis_mtls enable_sentinel_mtls = var.enable_sentinel_mtls - redis_ca_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" - redis_client_cert_path = "/etc/ssl/private/terraform-enterprise/redis/cert.pem" - redis_client_key_path = "/etc/ssl/private/terraform-enterprise/redis/key.pem" + redis_ca_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cacert.pem" : null + redis_client_cert_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/cert.pem" : null + redis_client_key_path = var.enable_redis_mtls || var.enable_sentinel_mtls ? "/etc/ssl/private/terraform-enterprise/redis/key.pem" : null trusted_proxies = local.trusted_proxies From 62fb07506f95f18b9c34fa442b935f9ca7b0b833 Mon Sep 17 00:00:00 2001 From: RAVI PRAKASH Date: Fri, 21 Nov 2025 19:51:29 +0530 Subject: [PATCH 53/53] Decouple Redis encryption from IAM auth - they are independent features --- modules/redis/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/redis/main.tf b/modules/redis/main.tf index 3f15cdb0..457a1471 100644 --- a/modules/redis/main.tf +++ b/modules/redis/main.tf @@ -88,7 +88,7 @@ resource "aws_elasticache_replication_group" "redis" { auth_token = var.redis_encryption_in_transit && local.redis_use_password_auth ? random_id.redis_password[0].hex : null # Transit encryption is required when using user groups (IAM authentication) - transit_encryption_enabled = var.redis_encryption_in_transit || local.redis_use_iam_auth + transit_encryption_enabled = var.redis_encryption_in_transit at_rest_encryption_enabled = var.redis_encryption_at_rest kms_key_id = var.redis_encryption_at_rest ? var.kms_key_arn : null