I have difficulties using the Vault dev server mode in docker-compose environment. Other people have difficulties too.

Partly it’s due to incomplete/imperfect Vault documentation. I had to skim through the source code to understand what parameters can be used for some commands and for the dev server itself. Some of these were hard to find in the documentation.

Objective

I want Vault running in compose env with these features enabled on start:

  • automatically unsealed
  • enabled Vault Transit Engine
  • two signing keys in Transit Engine, one ECDSA and one ED25519 with names key1 and key2
  • predefined root token which can be embedded in all services needing to communicate with it

Here is a solution that works well.

TL;DR

Just use this. If you want to read some details follow below.

docker-compose.yml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  vault:
    hostname: vault
    container_name: vault
    image: vault:1.10.3
    environment:
      VAULT_ADDR: "http://0.0.0.0:8200"
      VAULT_API_ADDR: "http://0.0.0.0:8200"
    ports:
      - "8200:8200"
    volumes:
      - ./volumes/vault/file:/vault/file:rw
    cap_add:
      - IPC_LOCK
    entrypoint: vault server -dev -dev-listen-address="0.0.0.0:8200" -dev-root-token-id="root"

  vault-init:
    container_name: vault-init
    image: vault:1.10.3
    volumes:
      - ./vault-init.sh:/vault-init.sh
    depends_on:
      - vault
    restart: "no"
    entrypoint: sh -c "/vault-init.sh"

vault-init.sh

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#! /bin/sh

set -e

export VAULT_ADDR=http://vault:8200

# give some time for Vault to start and be ready
sleep 3

# login with root token at $VAULT_ADDR
vault login root

# enable vault transit engine
vault secrets enable transit

# create key1 with type ed25519
vault write -f transit/keys/key1 type=ed25519

# create key2 with type ecdsa-p256
vault write -f transit/keys/key2 type=ecdsa-p256

That’s it.

Details

The dev server is always unsealed by default, so our first objective is achieved.

The flag -dev-listen-address allows to bind to all interfaces, otherwise the Dev Server automatically binds to 127.0.0.1. This prevents it from being visible from other containers in the docker-compose network. It also prevents the Vault UI from being accessible from the host machine at http://localhost:8200/ui/vault

The flag -dev-root-token-id sets a predefined root token for the dev server. The token can be set as a configuration variable in all services which need to communicate with the Vault. (two objectives achieved)

The other two objectives - enable Transit Engine and create two keys inside it - are achieved by the vault-init.sh script which is started once as a separate container. It connects to the running Vault container at http://vault:8200, enables the Transit Engine and creates two keys.

Most parameters of the command to create keys are also undocumented. For example, to create a key of specific type, we can pass in a key=value pair. Looking at the source code you can see how parameters are read from stdin. To learn what parameters could be used in this (and other commands) I was observing the HTTP requests passed from the Vault UI in the browser to the Vault backend. For example, to create a a key with specific type you can use:

1
vault write -f transit/keys/key1 type=ed25519

The type parameter is undocumented, but there are many others that can be passed as well, but you’ll have to look through the source code to see what can be used for your specific use case.