Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ locals {

selected_database = (
var.enable_aurora && var.db_use_mtls ? error("Both enable_aurora and db_use_mtls cannot be true.") :
var.enable_aurora && var.postgres_enable_iam_auth ? error("Both enable_aurora and postgres_enable_iam_auth cannot be true.") :
var.db_use_mtls && var.postgres_enable_iam_auth ? error("Both db_use_mtls and postgres_enable_iam_auth cannot be true.") :
var.enable_aurora ? local.aurora_database :
var.db_use_mtls ? local.mtls_database :
var.enable_edb ? local.enterprise_db :
Expand Down
101 changes: 58 additions & 43 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ 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
postgres_enable_iam_auth = var.postgres_enable_iam_auth && !var.postgres_use_password_auth
db_username = var.db_username
db_iam_username = var.db_iam_username != null ? var.db_iam_username : ""
db_identifier = local.enable_database_module ? module.database[0].identifier : (
var.enable_aurora ? module.aurora_database[0].identifier : ""
)
db_resource_id = local.enable_database_module ? module.database[0].dbi_resource_id : (
var.enable_aurora ? module.aurora_database[0].dbi_resource_id : ""
)
}

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -94,6 +104,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"
}

Expand Down Expand Up @@ -161,21 +172,22 @@ module "database" {
source = "./modules/database"
count = local.enable_database_module ? 1 : 0

db_size = var.db_size
db_backup_retention = var.db_backup_retention
db_backup_window = var.db_backup_window
db_name = var.db_name
db_parameters = var.db_parameters
db_username = var.db_username
engine_version = var.postgres_engine_version
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
kms_key_arn = local.kms_key_arn
allow_major_version_upgrade = var.allow_major_version_upgrade
allow_multiple_azs = var.allow_multiple_azs
db_size = var.db_size
db_backup_retention = var.db_backup_retention
db_backup_window = var.db_backup_window
db_name = var.db_name
db_parameters = var.db_parameters
db_username = var.db_username
engine_version = var.postgres_engine_version
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
kms_key_arn = local.kms_key_arn
allow_major_version_upgrade = var.allow_major_version_upgrade
allow_multiple_azs = var.allow_multiple_azs
enable_iam_database_authentication = var.postgres_enable_iam_auth && !var.postgres_use_password_auth
}

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -253,7 +265,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-postgres-passwordless"
count = var.is_replicated_deployment ? 0 : 1

tfe_license = var.hc_license
Expand Down Expand Up @@ -286,15 +298,18 @@ module "runtime_container_engine_config" {
iact_time_limit = var.iact_subnet_time_limit
run_pipeline_image = var.run_pipeline_image

database_name = local.database.name
database_user = local.database.username
database_password = local.database.password
database_host = local.database.endpoint
database_parameters = local.database.parameters
database_use_mtls = var.db_use_mtls
database_ca_cert_file = "/etc/ssl/private/terraform-enterprise/postgres/ca.crt"
database_client_cert_file = "/etc/ssl/private/terraform-enterprise/postgres/cert.crt"
database_client_key_file = "/etc/ssl/private/terraform-enterprise/postgres/key.key"
database_name = local.database.name
database_user = var.postgres_enable_iam_auth && var.db_iam_username != null ? var.db_iam_username : local.database.username
database_password = var.postgres_use_password_auth ? local.database.password : ""
database_host = local.database.endpoint
database_parameters = local.database.parameters
database_use_mtls = var.db_use_mtls
database_ca_cert_file = "/etc/ssl/private/terraform-enterprise/postgres/ca.crt"
database_client_cert_file = "/etc/ssl/private/terraform-enterprise/postgres/cert.crt"
database_client_key_file = "/etc/ssl/private/terraform-enterprise/postgres/key.key"
# Enable PostgreSQL IAM authentication for isolated testing
database_passwordless_aws_use_iam = var.postgres_enable_iam_auth && !var.postgres_use_password_auth
database_passwordless_aws_region = var.postgres_enable_iam_auth && !var.postgres_use_password_auth ? data.aws_region.current.name : ""

explorer_database_name = local.explorer_database.name
explorer_database_user = local.explorer_database.username
Expand All @@ -312,21 +327,21 @@ 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_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 = "/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_host = local.redis.hostname
redis_user = local.redis.username
redis_password = var.redis_use_password_auth ? local.redis.password : ""
redis_use_tls = local.redis.use_tls
redis_use_auth = local.redis.use_password_auth || (var.redis_enable_iam_auth && !var.redis_use_password_auth)
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 = var.redis_use_password_auth ? 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"


trusted_proxies = local.trusted_proxies
Expand All @@ -343,7 +358,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-postgres-passwordless"
count = var.is_replicated_deployment ? 0 : 1

cloud = "aws"
Expand Down Expand Up @@ -388,7 +403,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-postgres-passwordless"
count = var.is_replicated_deployment ? 1 : 0

# TFE Base Configuration
Expand Down Expand Up @@ -450,7 +465,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-postgres-passwordless"
count = var.is_replicated_deployment ? 1 : 0

# TFE & Replicated Configuration data
Expand Down
3 changes: 3 additions & 0 deletions modules/database/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,7 @@ resource "aws_db_instance" "postgresql" {
kms_key_id = var.kms_key_arn
storage_type = "gp2"
vpc_security_group_ids = [aws_security_group.postgresql.id]

# Enable IAM database authentication if requested
iam_database_authentication_enabled = var.enable_iam_database_authentication
}
6 changes: 6 additions & 0 deletions modules/database/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,9 @@ variable "allow_multiple_azs" {
description = "Determine Amazon RDS Postgres deployment strategy."
default = true
}

variable "enable_iam_database_authentication" {
type = bool
description = "Enable IAM database authentication for the RDS instance."
default = false
}
23 changes: 23 additions & 0 deletions modules/postgres-passwordless/data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

data "aws_ami" "ubuntu" {
most_recent = true

filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}

filter {
name = "virtualization-type"
values = ["hvm"]
}

owners = ["099720109477"] # Canonical
}

data "aws_route53_zone" "postgres_zone" {
name = var.domain_name
private_zone = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

set -eu pipefail

apt-get update -y && apt-get install -y docker.io postgresql-client openssl unzip jq
systemctl enable --now docker
usermod -aG docker ubuntu

curl -sS --noproxy '*' "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m | grep -q 'arm\|aarch' && echo 'aarch64' || echo 'x86_64').zip" -o "awscliv2.zip" > /dev/null 2>&1
unzip -q awscliv2.zip > /dev/null 2>&1
./aws/install > /dev/null 2>&1
rm -rf aws awscliv2.zip > /dev/null 2>&1

# For passwordless postgres, we start with basic configuration
# IAM authentication will be handled at the RDS level
docker run -d \
--name postgres \
-p 5432:5432 \
-e POSTGRES_USER="$POSTGRES_USER" \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-e POSTGRES_DB="$POSTGRES_DB" \
postgres:16

# Wait until PostgreSQL is up
echo "Waiting for PostgreSQL to become ready..."
timeout=180
start=$(date +%s)
while ! docker exec postgres pg_isready -U "$POSTGRES_USER" >/dev/null 2>&1; do
sleep 1
[[ $(( $(date +%s) - start )) -gt $timeout ]] && echo "Timeout waiting for PostgreSQL" && docker logs postgres && exit 1
done

echo "PostgreSQL with passwordless authentication is fully up and running."
113 changes: 113 additions & 0 deletions modules/postgres-passwordless/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

# This module provisions a PostgreSQL instance with passwordless authentication (IAM or similar)
# Adapted from database-mtls module, but without client certs/keys and with passwordless config

resource "random_string" "postgres_db_password" {
length = 128
special = true
override_special = "#$%&*"
}

resource "aws_route53_record" "postgres_db_dns" {
zone_id = data.aws_route53_zone.postgres_zone.zone_id
name = "${var.friendly_name_prefix}-postgres-passwordless"
type = "A"
ttl = 300

records = [aws_instance.postgres_db_instance.public_ip]
}

resource "aws_security_group" "postgres_db_sg" {
description = "The security group of the PostgreSQL deployment for TFE."
name = "${var.friendly_name_prefix}-postgres-passwordless"
vpc_id = var.network_id
}

resource "aws_security_group_rule" "postgres_db_ingress" {
security_group_id = aws_security_group.postgres_db_sg.id
type = "ingress"
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "postgres_db_ssh_ingress" {
security_group_id = aws_security_group.postgres_db_sg.id
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_security_group_rule" "postgres_db_egress" {
security_group_id = aws_security_group.postgres_db_sg.id
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

resource "aws_instance" "postgres_db_instance" {
ami = data.aws_ami.ubuntu.id
instance_type = "m5.xlarge"
associate_public_ip_address = true
vpc_security_group_ids = [aws_security_group.postgres_db_sg.id]
iam_instance_profile = var.aws_iam_instance_profile
key_name = aws_key_pair.ec2_key.key_name
subnet_id = var.network_public_subnets[0]
root_block_device {
volume_type = "gp3"
volume_size = 100
delete_on_termination = true
encrypted = true
}

tags = {
Name = "Terraform-Postgres-Passwordless"
}
}

resource "local_file" "postgres_db_private_key" {
content = tls_private_key.postgres_db_ssh_key.private_key_pem
filename = "${path.module}/${var.friendly_name_prefix}-ec2-postgres-key.pem"
file_permission = "0600"
}

resource "tls_private_key" "postgres_db_ssh_key" {
algorithm = "RSA"
rsa_bits = 4096
}

resource "aws_key_pair" "ec2_key" {
key_name = "${var.friendly_name_prefix}-ec2-postgres-key"
public_key = tls_private_key.postgres_db_ssh_key.public_key_openssh
}

resource "null_resource" "postgres_db_server_start" {
depends_on = [aws_route53_record.postgres_db_dns]

connection {
type = "ssh"
user = "ubuntu"
private_key = tls_private_key.postgres_db_ssh_key.private_key_pem
host = aws_route53_record.postgres_db_dns.fqdn
}

provisioner "file" {
source = "${path.module}/files/fetch_cert_and_start_server.sh"
destination = "/home/ubuntu/fetch_cert_and_start_server.sh"
}

provisioner "remote-exec" {
inline = [
"sleep 60",
"chmod +x /home/ubuntu/fetch_cert_and_start_server.sh",
"sudo POSTGRES_PASSWORD='${random_string.postgres_db_password.result}' POSTGRES_USER=${var.db_username} POSTGRES_DB=${var.db_name} /home/ubuntu/fetch_cert_and_start_server.sh"
]
}
}
Loading
Loading