Overview
This guide outlines a step-by-step approach to converting a mounted disk FDO Docker deployment to external services mode using self-managed PostgreSQL and object storage (Minio). This is ideal for swift testing Terraform Enterprise against external services without needing to provision the required cloud infrastructure.
Prerequisites
- Existing Mounted Disk FDO Docker deployment. This guide assumes a deployment loosely matching the example disk mode configuration.
- Any load balancer health checks have been disabled in order to prevent the instance from being terminated during this procedure.
Procedure
Add a service for Minio to the Docker Compose file named minio.
minio: image: quay.io/minio/minio volumes: - type: bind source: /opt/minio target: /data command: server /data ports: - "9000:9000"
Start the minio Docker Compose service.
docker compose up -d minio
Export the default credentials to the environment ("minioadmin" is the default username and password).
export AWS_SECRET_ACCESS_KEY="minioadmin" export AWS_ACCESS_KEY_ID="minioadmin"
Create the Terraform Enterprise bucket.
aws --region us-east-1 --endpoint-url http://localhost:9000 s3 mb s3://tfe
Copy any existing objects to the Minio bucket (note that not all of these directories will exist, depending on the usage of the TFE instance).
export DISK_PATH=<HOST_DISK_PATH> aws --region us-east-1 --endpoint-url http://localhost:9000 s3 cp --recursive $DISK_PATH/aux/archivist/terraform s3://tfe/archivistterraform aws --region us-east-1 --endpoint-url http://localhost:9000 s3 cp --recursive $DISK_PATH/aux/archivist/sentinel s3://tfe/archivistsentinel aws --region us-east-1 --endpoint-url http://localhost:9000 s3 cp --recursive $DISK_PATH/aux/archivist/plan-export s3://tfe/archivistplan-export aws --region us-east-1 --endpoint-url http://localhost:9000 s3 cp --recursive $DISK_PATH/aux/archivist/policy-set-versions s3://tfe/archivistpolicy-set-versions
The self-managed PostgreSQL will use the same data directory as the bundled PostgreSQL in the Terraform Enterprise container. Since it will need to be the same version of PostgreSQL and will use existing initialization parameters, you will need to obtain some information.
Get the PostgreSQL version used in the running version of Terraform Enterprise.
docker exec -ti <TFE_CONTAINER> bash /usr/lib/postgresql/<MAJOR_VERSION>/bin/postgres -V
Extract the auto-generated PostgreSQL password for the default hashicorp user from the database URL.
docker exec <TFE_CONTAINER> tfectl app config --unredacted | jq -r '.database.url'
Add the following service to the Docker Compose file for PostgreSQL.
postgres: image: postgres:<POSTGRES_VERSION> environment: POSTGRES_PASSWORD: '<TFE_DATABASE_PASSWORD>' POSTGRES_USER: hashicorp command: > postgres -c listen_addresses=* volumes: - type: bind source: <DISK_PATH>/postgres/pgdata target: /var/lib/postgresql/data
Because PostgreSQL will now run in a separate container on the custom Docker bridge network created for the Docker Compose project, its client authentication configuration must be modified to allow connections from any IPs on this network via password authentication.
Run the following command to get the subnet of the Docker bridge network created for the Docker Compose project.
docker network inspect <TFE_DOCKER_BRIDGE_NETWORK_NAME> -f json | jq -r '.[].IPAM.Config[].Subnet'
Open the pg_hba.conf file at its location in the disk path the host.
vi $DISK_PATH/postgres/pgdata/pg_hba.conf
Add the following line to allow connections from source IP addresses on this Docker bridge subnet via password authentication.
host all all <DOCKER_BRIDGE_CIDR> md5
Add or update the following configuration in the environment section of the Terraform Enterprise Docker Compose service.
TFE_DATABASE_HOST: postgres TFE_DATABASE_NAME: hashicorp TFE_DATABASE_USER: hashicorp TFE_DATABASE_PASSWORD: '<POSTGRESQL_PASSWORD>' TFE_DATABASE_PARAMETERS: "sslmode=disable" TFE_OBJECT_STORAGE_TYPE: s3 TFE_OBJECT_STORAGE_S3_ACCESS_KEY_ID: minioadmin TFE_OBJECT_STORAGE_S3_SECRET_ACCESS_KEY: minioadmin TFE_OBJECT_STORAGE_S3_BUCKET: tfe TFE_OBJECT_STORAGE_S3_ENDPOINT: http://minio:9000 TFE_OBJECT_STORAGE_S3_REGION: us-east-1
Change the operational mode to external.
TFE_OPERATIONAL_MODE: external
Stop Terraform Enterprise.
docker compose down <TFE_DOCKER_COMPOSE_SERVICE_NAME>
Start the postgres Docker Compose service.
docker compose up -d postgres
Start Terraform Enterprise.
docker compose up -d <TFE_DOCKER_COMPOSE_SERVICE_NAME>
Optional Additional Configuration
Enable TLS
Generate Certificate/Key Pairs
Navigate to the directory containing the certificates (i.e certs) and run the following Bash to generate a self-signed certificate for PostgreSQL and Minio.
EXTERNAL_SERVICES="postgres minio" for service in $EXTERNAL_SERVICES do openssl req -x509 -newkey rsa:4096 -keyout $service-key.pem -out $service-cert.pem -days 365 -nodes -subj "/C=US/ST=CA/L=San Fransisco/O=HashiCorp/CN=$service" -addext "subjectAltName=DNS:$service" done
Add both certificates to the Terraform Enterprise CA bundle.
cat minio-cert.pem postgres-cert.pem > bundle.pem
Minio expects the certificate and key files to have a particular file names, so rename the files accordingly.
mv minio-cert.pem public.crt mv minio-key.pem private.key
Postgres runs under the postgres user in the container, so make sure the certificate/key files are owned by that user (it is user ID 999).
chown 999:999 postgres-*.pem
Enable TLS in External Services
Add a volume to the minio service.
minio: ... volumes: - type: bind source: ./certs target: /certs
Update the command of the minio service with a flag to specify the directory in which the certificate and key are stored.
command: server --certs-dir /certs /data
Add a volume to the postgres service
postgres: ... volumes: ... - type: bind source: ./certs target: /var/lib/postgresql/certs
Update its command to enable ssl.
postgres: ... command: > postgres -c listen_addresses=* -c ssl=on -c ssl_cert_file=/var/lib/postgresql/certs/postgres-cert.pem -c ssl_key_file=/var/lib/postgresql/certs/postgres-key.pem
Update the Terraform Enterprise settings to configure Terraform Enterprise to connect to the services with TLS.
TFE_OBJECT_STORAGE_S3_ENDPOINT: https://minio:9000 TFE_DATABASE_PARAMETERS: sslmode=require