Terraform
Podman installation
This guide describes how to install and run Terraform Enterprise on Podman. These instructions are specific to Red Hat Enterprise Linux (RHEL) 8 and 9 hosts and use a Kubernetes YAML to define Podman resources. This workflow sets up rootful Podman with a non-root user. As a result, the Podman service runs as root while processes within the container run as non-root.
Requirements
Before you begin, ensure you meet the Podman requirements for installing Terraform Enterprise on Podman.
Mounted Disk operational mode
- Durable storage from the cloud provider of your choice. This configuration uses a volume mount to store Terraform Enterprise application data. The path you specify as the source of the volume mount must exist on the instance running Terraform Enterprise.
External Services operational mode
- PostgreSQL database server
- Blob storage (AWS S3, Azure Cloud Storage, Google Cloud Storage, or any S3-compatible storage service)
Active/Active operational mode
- PostgreSQL database server.
- Object-based storage, such as AWS S3, Azure Cloud Storage, Google Cloud Storage, or any S3-compatible storage service.
- Redis version 6 or 7. Redis Cluster is not currently supported.
Set up
Connect to the instance where you want to run Terraform Enterprise.
Log in as the root user.
For Mounted Disk installations, create a directory to be used for TFE data storage. Terraform Enterprise uses this directory as a volume mount to store application data.
Create a directory for your TLS certificate (
cert.pem
), TLS private key (key.pem
), and CA certificates bundle (bundle.pem
). If you do not have a CA certificates bundle, place your TLS certificate (cert.pem
) insidebundle.pem
instead. When finished, this directory resembles the following tree:├── cert.pem ├── key.pem └── bundle.pem
Create a YAML file and populate it with your desired pod configuration. If you use one of the following example configurations, replace values enclosed in
<>
with your installation's values. For example, setTFE_HOSTNAME
to the DNS hostname you use to access Terraform Enterprise.
Active/Active operational mode Kubernetes YAML example
Refer to Operation Modes for additional information.
- We recommend automating the Podman requirements listed in this section. These must be in place before downloading and installing Terraform Enterprise.
Download and install image
Log in to the Terraform Enterprise container image registry, using
terraform
as the username, and your Hashicorp Terraform Enterprise license as the password:$ echo "<HASHICORP_LICENSE>" | podman login --username terraform images.releases.hashicorp.com --password-stdin
Pull the Terraform Enterprise image from the registry.
$ podman pull images.releases.hashicorp.com/hashicorp/terraform-enterprise:<vYYYYMM-#>
Run
Create a Terraform Enterprise pod by running the following command:
$ podman play kube <path_to_YAML_file>
In a separate terminal session, you can monitor the logs by running the following command:
$ podman logs -f <container_name>
Monitor the health of the application until it starts reporting healthy with the following command:
$ podman exec <container_name> tfe-health-check-status
Create initial admin user
Provision your first administrative user and start using Terraform Enterprise.
Service management
To learn more about managing the lifecycle of Podman pods, refer to the Podman docs for more information about pods. We have included possible options for managing a pod's lifecycle on a RHEL host for convenience.
Systemd
Complete the following steps to create a systemd
service that automatically starts your pod and its containers. We
recommend using Quadlet, which is an opinionated tool for running Podman
containers, to deploy systemd
. Quadlet generates a systemd
service that manages the Terraform Enterprise pod and
all containers, including the internal infrastructure container.
Ensure the Terraform Enterprise pod is not running.
Navigate to
/etc/containers/systemd/
. Define the service files in this directory.Create a Quadlet unit file for the Terraform Enterprise pod and container at
/etc/containers/systemd/terraform-enterprise.kube
:[Install] WantedBy=default.target [Service] Restart=always [Kube] Yaml=kube.yaml
Copy your Kubernetes YAML file to
/etc/containers/systemd/tfe.yaml
:$ cp <path_to_YAML_file> /etc/containers/systemd/tfe.yaml
Reload the
systemd
daemon and enable the service:$ systemctl daemon-reload $ systemctl start terraform-enterprise.service
Check the status of your service:
$ systemctl status terraform-enterprise.service ● terraform-enterprise.service Loaded: loaded (/etc/containers/systemd/terraform-enterprise.kube; generated) Active: active (running) since Sun 2024-02-25 21:15:55 UTC; 15min ago Main PID: 35893 (conmon) Tasks: 4 (limit: 404901) Memory: 5.2M CGroup: /system.slice/terraform-enterprise.service ├─35893 /usr/bin/conmon --api-version 1 -c 74f1271d9a481711950c62b509f126c3fdf8678a9d552c5ccc692eb6ed5cf4d1 -u 74f1271d9a481711950c62b509f126c3fdf8678a9d552c5ccc692eb6ed5cf4d1 -> ├─36028 /usr/sbin/dnsmasq -u root --conf-file=/run/containers/cni/dnsname/podman-default-kube-network/dnsmasq.conf ├─36030 /usr/bin/conmon --api-version 1 -c 973d3ff4f7ada5880a9947be4d90b3d556c7ce841037de34c7eaa07c044a3ec0 -u 973d3ff4f7ada5880a9947be4d90b3d556c7ce841037de34c7eaa07c044a3ec0 -> └─36083 /usr/bin/conmon --api-version 1 -c 435ea68e87dbef3c0965ffdfb9fe1fc36c5500a63eb00dc0fe2499aaa560a563 -u 435ea68e87dbef3c0965ffdfb9fe1fc36c5500a63eb00dc0fe2499aaa560a563 ->
Kubernetes pod specification reference
This is not an exhaustive list of configuration options. Refer to Configuration Reference for a list of all the configuration options.
Mounted Disk
This Kubernetes YAML deploys Terraform Enterprise in Mounted Disk mode as a pod composed of a Terraform Enterprise container.
---
apiVersion: "v1"
kind: "Pod"
metadata:
labels:
app: "terraform-enterprise"
name: "terraform-enterprise"
spec:
restartPolicy: "Never"
containers:
- env:
- name: "TFE_OPERATIONAL_MODE"
value: "disk"
- name: "TFE_LICENSE"
value: "<HashiCorp license>"
- name: "TFE_HOSTNAME"
value: "<Hostname>"
- name: "TFE_HTTP_PORT"
value: "8080"
- name: "TFE_HTTPS_PORT"
value: "8443"
- name: "TFE_TLS_CERT_FILE"
value: "/etc/ssl/private/terraform-enterprise/cert.pem"
- name: "TFE_TLS_KEY_FILE"
value: "/etc/ssl/private/terraform-enterprise/key.pem"
- name: "TFE_TLS_CA_BUNDLE_FILE"
value: "/etc/ssl/private/terraform-enterprise/bundle.pem"
- name: "TFE_DISK_CACHE_VOLUME_NAME"
value: "terraform-enterprise_terraform-enterprise-cache"
- name: "TFE_LICENSE_REPORTING_OPT_OUT"
value: "true"
- name: "TFE_ENCRYPTION_PASSWORD"
value: "<Encryption password>"
image: "images.releases.hashicorp.com/hashicorp/terraform-enterprise:<vYYYYMM-#>"
name: "terraform-enterprise"
ports:
- containerPort: 8080
hostPort: 80
- containerPort: 8443
hostPort: 443
- containerPort: 9090
hostPort: 9090
securityContext:
capabilities:
add:
- "CAP_IPC_LOCK"
readOnlyRootFilesystem: true
seLinuxOptions:
type: "spc_t"
volumeMounts:
- mountPath: "/etc/ssl/private/terraform-enterprise"
name: "certs"
- mountPath: "/var/log/terraform-enterprise"
name: "log"
- mountPath: "/run"
name: "run"
- mountPath: "/tmp"
name: "tmp"
- mountPath: "/var/lib/terraform-enterprise"
name: "data"
- mountPath: "/run/docker.sock"
name: "docker-sock"
- mountPath: "/var/cache/tfe-task-worker/terraform"
name: "terraform-enterprise_terraform-enterprise-cache-pvc"
volumes:
- hostPath:
path: "<path_to_certs_on_host>"
type: "Directory"
name: "certs"
- emptyDir:
medium: "Memory"
name: "log"
- emptyDir:
medium: "Memory"
name: "run"
- emptyDir:
medium: "Memory"
name: "tmp"
- hostPath:
path: "<mounted_disk_path_on_host>"
type: "Directory"
name: "data"
- hostPath:
path: "/var/run/docker.sock"
type: "File"
name: "docker-sock"
- name: "terraform-enterprise_terraform-enterprise-cache-pvc"
persistentVolumeClaim:
claimName: "terraform-enterprise_terraform-enterprise-cache"
External Services
The following Kubernetes YAML configuration deploys Terraform Enterprise in External Services mode as a pod composed of a Terraform Enterprise container.
---
apiVersion: "v1"
kind: "Pod"
metadata:
labels:
app: "terraform-enterprise"
name: "terraform-enterprise"
spec:
restartPolicy: "Never"
containers:
- env:
- name: "TFE_LICENSE"
value: "<HashiCorp license>"
- name: "TFE_HOSTNAME"
value: "<TFE hostname>"
- name: "TFE_OPERATIONAL_MODE"
value: "external"
- name: "TFE_HTTP_PORT"
value: "8080"
- name: "TFE_HTTPS_PORT"
value: "8443"
- name: "TFE_ENCRYPTION_PASSWORD"
value: "<Encryption password>"
- name: "TFE_DISK_CACHE_VOLUME_NAME"
value: "terraform-enterprise_terraform-enterprise-cache"
- name: "TFE_TLS_CA_BUNDLE_FILE"
value: "/etc/ssl/private/terraform-enterprise/bundle.pem"
- name: "TFE_TLS_CERT_FILE"
value: "/etc/ssl/private/terraform-enterprise/cert.pem"
- name: "TFE_TLS_KEY_FILE"
value: "/etc/ssl/private/terraform-enterprise/key.pem"
- name: "TFE_HTTP_PORT"
value: "8080"
- name: "TFE_HTTPS_PORT"
value: "8443"
# Database settings. See the configuration reference for more settings.
- name: "TFE_DATABASE_HOST"
value: "<Database hostname and port e.g. postgres:5432>"
- name: "TFE_DATABASE_NAME"
value: "<Database name e.g. hashicorp>"
- name: "TFE_DATABASE_PARAMETERS"
value: "<Database parameters e.g. sslmode=disable>"
- name: "TFE_DATABASE_PASSWORD"
value: "<Database password e.g. postgres>"
- name: "TFE_DATABASE_USER"
value: "<Database user e.g. postgres>"
# Object storage settings. See the configuration reference for more settings.
- name: "TFE_OBJECT_STORAGE_TYPE"
value: "s3"
- name: "TFE_OBJECT_STORAGE_S3_ACCESS_KEY_ID"
value: "<AWS Access Key ID>"
- name: "TFE_OBJECT_STORAGE_S3_SECRET_ACCESS_KEY"
value: "<AWS Secret Access Key>"
- name: "TFE_OBJECT_STORAGE_S3_BUCKET"
value: "<Bucket name>"
- name: "TFE_OBJECT_STORAGE_S3_REGION"
value: "<AWS region>"
image: "images.releases.hashicorp.com/hashicorp/terraform-enterprise:<vYYYYMM-#>"
name: "terraform-enterprise"
ports:
- containerPort: 8080
hostPort: 80
- containerPort: 8443
hostPort: 443
- containerPort: 8443
hostPort: 443
securityContext:
capabilities:
add:
- "CAP_IPC_LOCK"
readOnlyRootFilesystem: true
seLinuxOptions:
type: "spc_t"
volumeMounts:
- mountPath: "/etc/ssl/private/terraform-enterprise"
name: "certs"
- mountPath: "/var/log/terraform-enterprise"
name: "log"
- mountPath: "/run"
name: "run"
- mountPath: "/tmp"
name: "tmp"
- mountPath: "/run/docker.sock"
name: "docker-sock"
- mountPath: "/var/cache/tfe-task-worker/terraform"
name: "terraform-enterprise_terraform-enterprise-cache-pvc"
volumes:
- hostPath:
path: "<path_to_certs_on_host>"
type: "Directory"
name: "certs"
- emptyDir:
medium: "Memory"
name: "log"
- emptyDir:
medium: "Memory"
name: "run"
- emptyDir:
medium: "Memory"
name: "tmp"
- hostPath:
path: "/var/run/docker.sock"
type: "File"
name: "docker-sock"
- name: "terraform-enterprise_terraform-enterprise-cache-pvc"
persistentVolumeClaim:
claimName: "terraform-enterprise_terraform-enterprise-cache"
Active/Active
The following Kubernetes YAML configuration deploys Terraform Enterprise in Active/Active mode. In Active/Active mode, each node runs a Podman pod composed of a TFE container.
---
apiVersion: "v1"
kind: "Pod"
metadata:
labels:
app: "terraform-enterprise"
name: "terraform-enterprise"
spec:
containers:
- env:
- name: "TFE_LICENSE"
value: "<HashiCorp license>"
- name: "TFE_HOSTNAME"
value: "<TFE hostname>"
- name: "TFE_HTTP_PORT"
value: "8080"
- name: "TFE_HTTPS_PORT"
value: "8443"
- name: "TFE_OPERATIONAL_MODE"
value: "active-active"
- name: "TFE_ENCRYPTION_PASSWORD"
value: "<Encryption password>"
- name: "TFE_DISK_CACHE_VOLUME_NAME"
value: "terraform-enterprise_terraform-enterprise-cache"
- name: "TFE_TLS_CA_BUNDLE_FILE"
value: "/etc/ssl/private/terraform-enterprise/bundle.pem"
- name: "TFE_TLS_CERT_FILE"
value: "/etc/ssl/private/terraform-enterprise/cert.pem"
- name: "TFE_TLS_KEY_FILE"
value: "/etc/ssl/private/terraform-enterprise/key.pem"
# Database settings. See the configuration reference for more settings.
- name: "TFE_DATABASE_HOST"
value: "<Database hostname and port e.g. postgres:5432>"
- name: "TFE_DATABASE_NAME"
value: "<Database name e.g. hashicorp>"
- name: "TFE_DATABASE_PARAMETERS"
value: "<Database parameters e.g. sslmode=disable>"
- name: "TFE_DATABASE_PASSWORD"
value: "<Database password e.g. postgres>"
- name: "TFE_DATABASE_USER"
value: "<Database user e.g. postgres>"
# Object storage settings. See the configuration reference for more settings.
- name: "TFE_OBJECT_STORAGE_TYPE"
value: "s3"
- name: "TFE_OBJECT_STORAGE_S3_ACCESS_KEY_ID"
value: "<AWS Access Key ID>"
- name: "TFE_OBJECT_STORAGE_S3_SECRET_ACCESS_KEY"
value: "<AWS Secret Access Key>"
- name: "TFE_OBJECT_STORAGE_S3_BUCKET"
value: "<Bucket name>"
- name: "TFE_OBJECT_STORAGE_S3_REGION"
value: "<AWS region>"
# Redis settings. See the configuration reference for more settings.
- name: "TFE_REDIS_HOST"
value: "<Redis hostname and port>"
- name: "TFE_REDIS_PASSWORD"
value: "<Redis password>"
- name: "TFE_REDIS_USER"
value: "<Redis username>"
- name: "TFE_REDIS_USE_AUTH"
value: "<To use customized credential to authenticate? e.g. false>"
- name: "TFE_REDIS_USE_TLS"
value: "<To use tls? e.g. false>"
# Vault cluster settings.
# If you are using the default internal vault, this should be the private routable IP address of the node itself.
- name: "TFE_VAULT_CLUSTER_ADDRESS"
value: "https://10.0.66.189:8201"
image: "images.releases.hashicorp.com/hashicorp/terraform-enterprise:<vYYYYMM-#>"
name: "terraform-enterprise"
ports:
- containerPort: 8080
hostPort: 80
- containerPort: 8443
hostPort: 443
- containerPort: 8201
hostPort: 8201
securityContext:
capabilities:
add:
- "CAP_IPC_LOCK"
readOnlyRootFilesystem: true
seLinuxOptions:
type: "spc_t"
volumeMounts:
- mountPath: "/etc/ssl/private/terraform-enterprise"
name: "certs"
- mountPath: "/var/log/terraform-enterprise"
name: "log"
- mountPath: "/run"
name: "run"
- mountPath: "/tmp"
name: "tmp"
- mountPath: "/run/docker.sock"
name: "docker-sock"
- mountPath: "/var/cache/tfe-task-worker/terraform"
name: "terraform-enterprise_terraform-enterprise-cache-pvc"
restartPolicy: "Never"
volumes:
- hostPath:
path: "<path_to_certs_on_host>"
type: "Directory"
name: "certs"
- emptyDir:
medium: "Memory"
name: "log"
- emptyDir:
medium: "Memory"
name: "run"
- emptyDir:
medium: "Memory"
name: "tmp"
- hostPath:
path: "/var/run/docker.sock"
type: "File"
name: "docker-sock"
- name: "terraform-enterprise_terraform-enterprise-cache-pvc"
persistentVolumeClaim:
claimName: "terraform-enterprise_terraform-enterprise-cache"