Concourse requires a set of RSA keys for TSA (Transport Security Authority) authentication between web and worker nodes. Managing these keys is a bootstrapping problem: Concourse needs keys to start, but the keys should live in a secrets store.

For a runnable lab, see the concourse-terraform-unix directory in the IaC repository.

TSA Key Architecture

Concourse uses four key pairs:

  • TSA host key (tsa_host_key + tsa_host_key.pub): identifies the web node to workers.
  • Worker key (worker_key + worker_key.pub): identifies workers to the web node.
  • Authorized worker keys (authorized_worker_keys): the public keys of permitted workers.
  • Session signing key (session_signing_key): signs session tokens for the ATC API.

The web node holds the TSA host key and authorized worker keys. Workers connect using their worker key. If any key pair mismatches, the worker cannot authenticate and stays disconnected.

Vault Integration Pattern

Terraform reads keys from Vault using vault_generic_secret data sources, then writes them to local files and passes them to Docker containers:

data "vault_generic_secret" "tsa_host_key" {
  path = "secret/concourse/tsa_host_key"
}

The key files are written to disk with local_file resources and mounted into containers. The containers also retrieve keys at runtime via the Vault CLI in their entrypoint:

vault login ${VAULT_TOKEN} && \
vault kv get -field=value secret/concourse/tsa_host_key > /concourse-keys/tsa_host_key && \
dumb-init /usr/local/concourse/bin/concourse web

The Bootstrapping Problem

The containers need VAULT_TOKEN to start, but the token must be available before Vault can provide the keys. This creates a circular dependency:

Vault needs to be running -> token must exist -> container starts -> logs into Vault -> retrieves keys -> Concourse starts

In this lab, the token is passed as an environment variable. This works for testing but has operational risks:

  • VAULT_TOKEN in env is visible via docker inspect.
  • if Vault is unreachable at container startup, the entrypoint fails and the container crashes.
  • token rotation requires container restart.

For production, use a short-lived token generated by a trusted orchestrator or a Vault agent sidecar that handles token lifecycle separately.

Entrypoint Design

The entrypoint chains commands with &&. If any step fails, the container stops:

/bin/sh -c "vault login ${VAULT_TOKEN} && vault kv get ... && dumb-init concourse web"

This is correct behavior: a container that cannot retrieve its keys should not start. If the entrypoint swallowed errors, the container would run with missing keys and fail in harder-to-debug ways.

Dependencies

Terraform models the startup order explicitly:

concourse-db -> concourse-web -> concourse-worker

The database starts first because Concourse web needs it to migrate schemas. The worker starts after the web node because it needs the TSA endpoint.

The worker uses CONCOURSE_TSA_HOST=concourse-web:2222 to find the web node. If the web node restarts and its TSA host key changes, all workers must be updated with the new key.

Acceptance Criteria

  • Key files exist on disk before Concourse starts.
  • Web node reaches Vault and retrieves its keys at startup.
  • Worker authenticates to the web TSA and appears in the Concourse dashboard.
  • Container restart does not change key material.
  • VAULT_TOKEN is not visible in container logs.