Skip to content
Closed
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
10 changes: 6 additions & 4 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ locals {
parameters = null
}

aurora_database = try(module.aurora_database[0], local.default_database)
mtls_database = try(module.database_mtls[0], local.default_database)
enterprise_db = try(module.edb[0], local.default_database)
standard_db = try(module.database[0], local.default_database)
aurora_database = try(module.aurora_database[0], local.default_database)
mtls_database = try(module.database_mtls[0], local.default_database)
enterprise_db = try(module.edb[0], local.default_database)
standard_db = try(module.database[0], local.default_database)

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
29 changes: 16 additions & 13 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ module "database" {
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 +254,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 = "./modules/runtime_container_engine_config"
count = var.is_replicated_deployment ? 0 : 1

tfe_license = var.hc_license
Expand Down Expand Up @@ -286,15 +287,17 @@ 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 = 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_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 Down Expand Up @@ -343,7 +346,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 = "./modules/tfe_init"
count = var.is_replicated_deployment ? 0 : 1

cloud = "aws"
Expand Down Expand Up @@ -388,7 +391,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 = "./modules/settings"
count = var.is_replicated_deployment ? 1 : 0

# TFE Base Configuration
Expand Down Expand Up @@ -450,7 +453,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 = "./modules/tfe_init_replicated"
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
}
53 changes: 53 additions & 0 deletions modules/postgres-passwordless/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# postgres-passwordless Module

This module provisions a PostgreSQL instance with passwordless authentication on an EC2 instance for use with Terraform Enterprise. This module follows the same pattern as the `database-mtls` module but without certificate handling.

## Features
- EC2-based PostgreSQL deployment with Docker
- Security group configuration for PostgreSQL access
- Route53 DNS record for easy access
- Random password generation (for admin setup)
- SSH key pair generation for EC2 access
- Automated PostgreSQL setup via user data script

## Usage Example
```hcl
module "postgres_passwordless" {
source = "./modules/postgres-passwordless"
domain_name = "example.com"
db_name = "tfe"
db_username = "tfeadmin"
network_id = var.vpc_id
network_public_subnets = var.public_subnet_ids
friendly_name_prefix = "tfe"
aws_iam_instance_profile = var.iam_instance_profile
}
```

## Variables
- `domain_name`: Route 53 hosted zone name for DNS record
- `db_name`: PostgreSQL database name
- `db_username`: PostgreSQL username
- `network_id`: VPC ID for security group
- `network_public_subnets`: List of public subnet IDs
- `friendly_name_prefix`: Prefix for resource names
- `aws_iam_instance_profile`: IAM instance profile for the EC2 instance

## Outputs
- `postgres_db_endpoint`: The FQDN of the PostgreSQL instance
- `postgres_db_sg_id`: The security group ID for the PostgreSQL instance
- `postgres_db_password`: The password for the PostgreSQL instance (sensitive)

## Files Structure
- `main.tf`: Main Terraform configuration
- `variables.tf`: Variable definitions
- `outputs.tf`: Output definitions
- `data.tf`: Data source definitions
- `versions.tf`: Provider version constraints
- `files/fetch_cert_and_start_server.sh`: Script to set up PostgreSQL on EC2

## Notes
- This module creates an EC2 instance running PostgreSQL in Docker
- The instance is configured for passwordless authentication patterns
- A Route53 DNS record is created for easy access
- SSH access is configured for troubleshooting
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"
]
}
}
45 changes: 45 additions & 0 deletions modules/postgres-passwordless/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

output "endpoint" {
description = "The connection endpoint of the PostgreSQL instance in address:port format."
value = aws_route53_record.postgres_db_dns.fqdn
}

output "name" {
description = "The name of the PostgreSQL instance."
value = var.db_name
}

output "password" {
description = "The password of the main PostgreSQL user."
value = random_string.postgres_db_password.result
sensitive = true
}

output "username" {
description = "The name of the main PostgreSQL user."
value = var.db_username
}

output "parameters" {
description = "PostgreSQL server parameters for the connection URI."
value = var.db_parameters
}

# Legacy outputs for backward compatibility
output "postgres_db_endpoint" {
description = "The endpoint of the PostgreSQL instance."
value = aws_route53_record.postgres_db_dns.fqdn
}

output "postgres_db_sg_id" {
description = "The security group ID for the PostgreSQL instance."
value = aws_security_group.postgres_db_sg.id
}

output "postgres_db_password" {
description = "The password for the PostgreSQL instance."
value = random_string.postgres_db_password.result
sensitive = true
}
Loading
Loading