Introduction
This guide provides a step-by-step procedure for converting a mounted disk Flexible Deployment Options (FDO) Docker deployment of Terraform Enterprise to use self-managed external services for PostgreSQL and object storage (Minio). This approach allows for testing Terraform Enterprise with external services without provisioning cloud infrastructure.
Prerequisites
Before you begin, ensure you have the following:
- An existing mounted disk FDO Docker deployment of Terraform Enterprise. This guide assumes a deployment similar to the example disk mode configuration.
- Any load balancer health checks are disabled to prevent the instance from being terminated during this procedure.
Procedure
Follow these steps to migrate your Terraform Enterprise instance to external services. Note that you must replace placeholder values like <HOST_DISK_PATH> with values from your environment.
Step 1: Configure and Start Minio Object Storage
-
Add a service for Minio to your
docker-compose.ymlfile.minio: image: quay.io/minio/minio volumes: - type: bind source: /opt/minio target: /data command: server /data ports: - "9000:9000" -
Start the
minioDocker Compose service.$ docker compose up -d minio
-
Export the default Minio credentials to your environment. The default username and password is
minioadmin.$ export AWS_SECRET_ACCESS_KEY="minioadmin" $ export AWS_ACCESS_KEY_ID="minioadmin"
-
Create the bucket for Terraform Enterprise.
$ aws --region us-east-1 --endpoint-url http://localhost:9000 s3 mb s3://tfe
Step 2: Migrate Existing Data to Minio
Copy existing objects from your mounted disk to the new Minio bucket. Note that some directories may not exist, depending on the usage of your Terraform Enterprise instance.
-
Set an environment variable for your host disk path.
$ export DISK_PATH=<HOST_DISK_PATH>
-
Copy the data to the
tfebucket in Minio.$ 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
Step 3: Configure and Start PostgreSQL Service
The self-managed PostgreSQL service will use the same data directory as the bundled PostgreSQL. You must use the same PostgreSQL version and existing initialization parameters.
-
Get the PostgreSQL version from your running Terraform Enterprise container.
## Replace <TFE_CONTAINER> with your container name or ID $ docker exec -ti <TFE_CONTAINER> bash $ /usr/lib/postgresql/<MAJOR_VERSION>/bin/postgres -V
-
Extract the auto-generated PostgreSQL password for the
hashicorpuser.$ docker exec <TFE_CONTAINER> tfectl app config --unredacted | jq -r '.database.url'
-
Add the PostgreSQL service to your
docker-compose.ymlfile. Replace<POSTGRES_VERSION>,<TFE_DATABASE_PASSWORD>, and<DISK_PATH>with your values.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
Step 4: Update PostgreSQL Client Authentication
Because PostgreSQL now runs in a separate container, you must modify its client authentication configuration to allow connections from the Docker network.
-
Get the subnet of the Docker bridge network for your Docker Compose project.
$ docker network inspect <TFE_DOCKER_BRIDGE_NETWORK_NAME> -f json | jq -r '.[].IPAM.Config[].Subnet'
-
Open the
pg_hba.conffile on the host machine.$ vi $DISK_PATH/postgres/pgdata/pg_hba.conf
-
Add the following line to allow connections from the Docker bridge subnet using password authentication. Replace
<DOCKER_BRIDGE_CIDR>with the subnet from the previous command.host all all <DOCKER_BRIDGE_CIDR> md5
Step 5: Reconfigure Terraform Enterprise
Update the Terraform Enterprise service in your docker-compose.yml file to use the new external services.
-
Add or update the following environment variables in the
environmentsection of the Terraform Enterprise 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
Step 6: Restart Services
-
Stop the Terraform Enterprise service.
$ docker compose down <TFE_DOCKER_COMPOSE_SERVICE_NAME>
-
Start the
postgresservice.$ docker compose up -d postgres
-
Start the reconfigured Terraform Enterprise service.
$ docker compose up -d <TFE_DOCKER_COMPOSE_SERVICE_NAME>
Optional: Enable TLS
Step 1: Generate Certificate and Key Pairs
Navigate to a directory for your certificates (e.g., certs) and run the following script to generate self-signed certificates 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"; \
doneStep 2: Configure Certificate Authority (CA) Bundle
-
Add both certificates to the Terraform Enterprise CA bundle.
$ cat minio-cert.pem postgres-cert.pem > bundle.pem
-
Rename the Minio certificate and key files, as Minio expects specific filenames.
$ mv minio-cert.pem public.crt $ mv minio-key.pem private.key
-
Change the ownership of the PostgreSQL certificate and key files to the
postgresuser (user ID999).$ chown 999:999 postgres-*.pem
Step 3: Enable TLS in External Services
-
In your
docker-compose.ymlfile, add a volume to theminioservice to mount the certificates.minio: # ... volumes: - type: bind source: ./certs target: /certs -
Update the
commandof theminioservice to specify the certificates directory.command: server --certs-dir /certs /data
-
Add a volume to the
postgresservice to mount the certificates.postgres: # ... volumes: # ... - type: bind source: ./certs target: /var/lib/postgresql/certs -
Update the
postgresservicecommandto enable SSL.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
Step 4: Update Terraform Enterprise for TLS
Update the following environment variables in the Terraform Enterprise service configuration to connect to the external services with TLS.
TFE_OBJECT_STORAGE_S3_ENDPOINT: https://minio:9000 TFE_DATABASE_PARAMETERS: sslmode=require