Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
dc1b2f8
feat: add PostgreSQL AWS IAM authentication support
raviharshicorp Nov 5, 2025
900ca2e
Fix PostgreSQL IAM authentication template variable mapping
raviharshicorp Nov 12, 2025
fe76681
Add automated PostgreSQL IAM user creation
raviharshicorp Nov 12, 2025
5a84216
Fix AWS region configuration for PostgreSQL IAM user creation
raviharshicorp Nov 12, 2025
4f60be5
Add DATABASE_URL environment variable for PostgreSQL IAM authentication
raviharshicorp Nov 12, 2025
772f18e
Fix DATABASE_URL construction for null password in IAM auth
raviharshicorp Nov 12, 2025
19a7d7e
Fix DATABASE_URL for PostgreSQL IAM auth: add placeholder password
raviharshicorp Nov 12, 2025
4473130
Implement AWS RDS IAM authentication with runtime token generation
raviharshicorp Nov 12, 2025
0f5b8a9
Fix PostgreSQL IAM auth: use pgmultiauth library approach
raviharshicorp Nov 12, 2025
e81d3fa
Fix DATABASE_URL construction: remove duplicate port specification
raviharshicorp Nov 12, 2025
8f6ce5b
Remove TFE_DATABASE_PASSWORD entirely for IAM authentication
raviharshicorp Nov 13, 2025
6639de4
Fix PostgreSQL IAM auth by adding TFE_DATABASE_PASSWORDLESS environme…
raviharshicorp Nov 13, 2025
bc92f8c
Fix PostgreSQL passwordless authentication environment variables
raviharshicorp Nov 14, 2025
349ad9a
Remove unwanted Atlas environment variables for PostgreSQL IAM auth
raviharshicorp Nov 14, 2025
929385d
Add automated PostgreSQL IAM user setup during instance startup
raviharshicorp Nov 15, 2025
be9c385
Optimize user_data script to fit AWS 16KB limit
raviharshicorp Nov 15, 2025
56adf6b
Fix cloud-init script failures for PostgreSQL IAM setup
raviharshicorp Nov 15, 2025
7ef4799
Replace SSM approach with direct PostgreSQL IAM user creation
raviharshicorp Nov 15, 2025
78ee692
Ultra-compact PostgreSQL IAM user setup to fit 16KB limit
raviharshicorp Nov 15, 2025
cbcdf17
Fix PostgreSQL IAM user creation with better logging and error handling
raviharshicorp Nov 17, 2025
f05f510
Remove PostgreSQL IAM user setup from user_data script
raviharshicorp Nov 17, 2025
30901b7
Restore PostgreSQL IAM user creation in user_data script
raviharshicorp Nov 17, 2025
be42204
Create ultra-compact PostgreSQL IAM user setup for AWS 16KB limit
raviharshicorp Nov 17, 2025
fcc9bec
Remove postgres_iam_setup_ssm_document variable and references
raviharshicorp Nov 17, 2025
0a09d3c
Clean up postgres passwordless implementation
raviharshicorp Nov 20, 2025
bc26dc9
Fix tflint warnings: remove 8 unused variable declarations
raviharshicorp Nov 20, 2025
df2c413
Fix tflint warnings: remove 2 unused database IAM variable declarations
raviharshicorp Nov 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions modules/runtime_container_engine_config/database_config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

locals {
database = {
TFE_DATABASE_USER = var.database_user
TFE_DATABASE_PASSWORD = var.database_password
TFE_DATABASE_USER = var.database_user
# For IAM authentication, set empty password but ensure the variable exists
TFE_DATABASE_PASSWORD = var.database_passwordless_aws_use_iam ? "" : var.database_password
TFE_DATABASE_HOST = var.database_host
TFE_DATABASE_NAME = var.database_name
TFE_DATABASE_PARAMETERS = var.database_parameters
Expand All @@ -14,16 +15,20 @@ locals {
TFE_DATABASE_CLIENT_KEY_FILE = var.database_client_key_file
TFE_DATABASE_PASSWORDLESS_AZURE_USE_MSI = var.database_passwordless_azure_use_msi
TFE_DATABASE_PASSWORDLESS_AZURE_CLIENT_ID = var.database_passwordless_azure_client_id
# Enable AWS instance profile for IAM authentication
TFE_DATABASE_USE_INSTANCE_PROFILE = var.database_passwordless_aws_use_iam
# Additional environment variables for TFE config validation bypass
TFE_DATABASE_PASSWORDLESS_AWS_USE_INSTANCE_PROFILE = var.database_passwordless_aws_use_iam
TFE_DATABASE_PASSWORDLESS_AWS_REGION = var.database_passwordless_aws_region
}
database_configuration = local.disk ? {} : local.database
# Filter out null values so they don't appear in the compose file at all
database_configuration = local.disk ? {} : { for k, v in local.database : k => v if v != null }
explorer_database = {
TFE_EXPLORER_DATABASE_HOST = var.explorer_database_host
TFE_EXPLORER_DATABASE_NAME = var.explorer_database_name
TFE_EXPLORER_DATABASE_USER = var.explorer_database_user
TFE_EXPLORER_DATABASE_PASSWORD = var.explorer_database_password
TFE_EXPLORER_DATABASE_PARAMETERS = var.explorer_database_parameters
TFE_EXPLORER_DATABASE_PASSWORDLESS_AZURE_USE_MSI = var.explorer_database_passwordless_azure_use_msi
TFE_EXPLORER_DATABASE_PASSWORDLESS_AZURE_CLIENT_ID = var.explorer_database_passwordless_azure_client_id
TFE_EXPLORER_DATABASE_HOST = var.explorer_database_host
TFE_EXPLORER_DATABASE_NAME = var.explorer_database_name
TFE_EXPLORER_DATABASE_USER = var.explorer_database_user
TFE_EXPLORER_DATABASE_PASSWORD = var.explorer_database_password
TFE_EXPLORER_DATABASE_PARAMETERS = var.explorer_database_parameters
}
explorer_database_configuration = var.explorer_database_host == null ? {} : local.explorer_database
}
24 changes: 12 additions & 12 deletions modules/runtime_container_engine_config/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,18 @@ variable "database_passwordless_azure_client_id" {
description = "Azure Managed Service Identity (MSI) Client ID. If not set, System Assigned Managed Identity will be used."
}

variable "database_passwordless_aws_use_iam" {
default = false
type = bool
description = "Whether or not to use AWS IAM authentication to connect to the PostgreSQL database. Defaults to false if no value is given."
}

variable "database_passwordless_aws_region" {
default = ""
type = string
description = "AWS region for IAM database authentication. Required when database_passwordless_aws_use_iam is true."
}

variable "explorer_database_host" {
type = string
default = null
Expand Down Expand Up @@ -136,18 +148,6 @@ variable "explorer_database_user" {
description = "PostgreSQL user. Required when TFE_OPERATIONAL_MODE is external or active-active."
}

variable "explorer_database_passwordless_azure_use_msi" {
default = false
type = bool
description = "Whether or not to use Azure Managed Service Identity (MSI) to connect to the explorer PostgreSQL database. Defaults to false if no value is given."
}

variable "explorer_database_passwordless_azure_client_id" {
default = ""
type = string
description = "Azure Managed Service Identity (MSI) Client ID for explorer database. If not set, System Assigned Managed Identity will be used."
}

variable "disk_path" {
default = null
description = "The pathname of the directory in which Terraform Enterprise will store data in Mounted Disk mode. Required when var.operational_mode is 'disk'."
Expand Down
15 changes: 15 additions & 0 deletions modules/tfe_init/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,22 @@ locals {
redis_bootstrap_key_pathname = local.redis_bootstrap_key_pathname
redis_bootstrap_ca_pathname = local.redis_bootstrap_ca_pathname

# Database configuration for templates
Database = {
Passwordless = {
AWSUseInstanceProfile = var.database_passwordless_aws_use_iam
AWSRegion = var.database_passwordless_aws_region
}
}

database_azure_msi_auth_enabled = var.database_passwordless_azure_use_msi
database_aws_iam_auth_enabled = var.database_passwordless_aws_use_iam
database_aws_iam_region = var.database_passwordless_aws_region
database_host = var.database_host
database_name = var.database_name
admin_database_username = var.admin_database_username
admin_database_password = var.admin_database_password
database_iam_username = var.database_iam_username

proxy_ip = var.proxy_ip
proxy_port = var.proxy_port
Expand Down
17 changes: 17 additions & 0 deletions modules/tfe_init/templates/aws.ubuntu.docker.tfe.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,21 @@ mkdir -p $tfe_dir

echo ${docker_compose} | base64 -d > $tfe_dir/compose.yaml

%{ if database_iam_username != null && database_iam_username != "" ~}
echo "[$(date +"%FT%T")] Setting up PostgreSQL IAM user" | tee -a $log_pathname
sudo apt-get update -qq && sudo apt-get install -y postgresql-client-16 >/dev/null 2>&1
export PGPASSWORD="${admin_database_password}"
for i in $(seq 1 20); do
if psql -h "${database_host}" -U "${admin_database_username}" -d "${database_name}" -c "SELECT 1;" >/dev/null 2>&1; then
echo "DB connected on attempt $i" | tee -a $log_pathname
psql -h "${database_host}" -U "${admin_database_username}" -d "${database_name}" -c "DO \$\$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${database_iam_username}') THEN CREATE USER \"${database_iam_username}\" WITH LOGIN; GRANT rds_iam TO \"${database_iam_username}\"; GRANT CONNECT ON DATABASE \"${database_name}\" TO \"${database_iam_username}\"; GRANT USAGE, CREATE ON SCHEMA public TO \"${database_iam_username}\"; GRANT ALL ON ALL TABLES IN SCHEMA public TO \"${database_iam_username}\"; GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO \"${database_iam_username}\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO \"${database_iam_username}\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO \"${database_iam_username}\"; RAISE NOTICE 'IAM user created'; ELSE RAISE NOTICE 'IAM user exists'; END IF; END \$\$;" >/dev/null 2>&1
echo "IAM user ${database_iam_username} ready" | tee -a $log_pathname
break
else
echo "DB attempt $i/20 failed" | tee -a $log_pathname
sleep 10
fi
done
%{ endif ~}

docker compose -f /etc/tfe/compose.yaml up -d
89 changes: 89 additions & 0 deletions modules/tfe_init/templates/tfe.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,95 @@ mkdir -p $tfe_dir

echo ${docker_compose} | base64 -d > $tfe_dir/compose.yaml

%{ if database_aws_iam_auth_enabled ~}
echo "[$(date +"%FT%T")] [Terraform Enterprise] Setting up PostgreSQL IAM user" | tee -a $log_pathname

# Set AWS region for CLI commands
export AWS_DEFAULT_REGION="${database_aws_iam_region}"
echo "[$(date +"%FT%T")] [Terraform Enterprise] AWS region set to: $AWS_DEFAULT_REGION" | tee -a $log_pathname

# Install PostgreSQL client for database operations
if command -v apt-get >/dev/null 2>&1; then
echo "[$(date +"%FT%T")] [Terraform Enterprise] Installing PostgreSQL client" | tee -a $log_pathname
apt-get update -qq
apt-get install -y postgresql-client-15 postgresql-client-common
elif command -v yum >/dev/null 2>&1; then
echo "[$(date +"%FT%T")] [Terraform Enterprise] Installing PostgreSQL client" | tee -a $log_pathname
yum update -y
yum install -y postgresql15
fi

# Function to create PostgreSQL IAM user
create_postgres_iam_user() {
local db_endpoint="${database_host}"
local admin_user="${admin_database_username}"
local admin_password="${admin_database_password}"
local iam_user="${database_iam_username}"
local db_name="${database_name}"

echo "[$(date +"%FT%T")] [Terraform Enterprise] Creating PostgreSQL IAM user: $iam_user" | tee -a $log_pathname

# Wait for database to be ready
echo "[$(date +"%FT%T")] [Terraform Enterprise] Waiting for PostgreSQL database to be ready..." | tee -a $log_pathname
max_attempts=30
attempt=0

while [ $attempt -lt $max_attempts ]; do
if PGPASSWORD="$admin_password" psql -h "$db_endpoint" -U "$admin_user" -d "$db_name" -c 'SELECT 1;' >/dev/null 2>&1; then
echo "[$(date +"%FT%T")] [Terraform Enterprise] Database is ready!" | tee -a $log_pathname
break
fi
attempt=$((attempt + 1))
echo "[$(date +"%FT%T")] [Terraform Enterprise] Waiting for PostgreSQL... (attempt $attempt/$max_attempts)" | tee -a $log_pathname
sleep 10
done

if [ $attempt -ge $max_attempts ]; then
echo "[$(date +"%FT%T")] [Terraform Enterprise] ERROR: Database not ready after $max_attempts attempts" | tee -a $log_pathname
return 1
fi

# Create IAM user
echo "[$(date +"%FT%T")] [Terraform Enterprise] Creating IAM user in PostgreSQL..." | tee -a $log_pathname
PGPASSWORD="$admin_password" psql -h "$db_endpoint" -U "$admin_user" -d "$db_name" -v ON_ERROR_STOP=1 << EOF
DO \$\$
BEGIN
-- Check if user exists
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '$iam_user') THEN
-- Create the IAM user
CREATE USER "$iam_user";
-- Grant rds_iam role (this role exists automatically in RDS PostgreSQL with IAM auth enabled)
GRANT rds_iam TO "$iam_user";
-- Grant necessary database permissions
GRANT CONNECT ON DATABASE "$db_name" TO "$iam_user";
GRANT USAGE ON SCHEMA public TO "$iam_user";
GRANT CREATE ON SCHEMA public TO "$iam_user";
-- Grant table permissions
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$iam_user";
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO "$iam_user";
-- Grant default privileges for future objects
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO "$iam_user";
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO "$iam_user";
RAISE NOTICE 'Successfully created IAM user: $iam_user';
ELSE
RAISE NOTICE 'IAM user already exists: $iam_user';
END IF;
END
\$\$;
EOF

if [ $? -eq 0 ]; then
echo "[$(date +"%FT%T")] [Terraform Enterprise] PostgreSQL IAM user setup completed successfully" | tee -a $log_pathname
else
echo "[$(date +"%FT%T")] [Terraform Enterprise] ERROR: Failed to create PostgreSQL IAM user" | tee -a $log_pathname
return 1
fi
}

# Create the IAM user before starting TFE
create_postgres_iam_user
%{ endif ~}

docker compose -f /etc/tfe/compose.yaml up -d

%{ if distribution == "rhel" && cloud != "google" ~}
Expand Down
18 changes: 18 additions & 0 deletions modules/tfe_init/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,21 @@ variable "database_passwordless_azure_use_msi" {
type = bool
description = "Whether or not to use Azure Managed Service Identity (MSI) to connect to the PostgreSQL database. Defaults to false if no value is given."
}

variable "database_passwordless_aws_use_iam" {
default = false
type = bool
description = "Whether or not to use AWS IAM authentication to connect to the PostgreSQL database. Defaults to false if no value is given."
}

variable "database_passwordless_aws_region" {
default = ""
type = string
description = "AWS region for IAM database authentication. Required when database_passwordless_aws_use_iam is true."
}

variable "database_iam_username" {
default = null
type = string
description = "PostgreSQL IAM user for AWS IAM authentication."
}
Loading