Dekim
Dekim

Reputation: 654

Local Vault using docker-compose

I'm having big trouble running Vault in docker-compose.

My requirements are :

My current docker-compose

version: '2.3'
services:
  vault-dev:
    image: vault:1.2.1
    restart: always
    container_name: vault-dev
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: "myroot"
      VAULT_LOCAL_CONFIG: '{"backend": {"file": {"path": "/vault/file"}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h"}'
    ports:
      - "8200:8200"
    volumes:
      - ./storagedc/vault/file:/vault/file

However, when the container restart, I get the log

==> Vault server configuration:

             Api Address: http://0.0.0.0:8200
                     Cgo: disabled
         Cluster Address: https://0.0.0.0:8201
              Listener 1: tcp (addr: "0.0.0.0:8200", cluster address: "0.0.0.0:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: info
                   Mlock: supported: true, enabled: false
                 Storage: file
                 Version: Vault v1.2.1

Error initializing Dev mode: Vault is already initialized

Is there any recommendation on that matter?

Upvotes: 8

Views: 11379

Answers (3)

Shrey Gupta
Shrey Gupta

Reputation: 392

I created a setup that works well with file backend and without -dev flag

https://github.com/with-shrey/VaultDevSetup-Docker

Upvotes: -1

luben
luben

Reputation: 2712

I'd like to suggest a simpler solution for local development with docker-compose.

  • Vault is always unsealed
  • Vault UI is enabled and accessible at http://localhost:8200/ui/vault on your dev machine
  • Vault has predefined root token which can be used by services to communicate with it

docker-compose.yml

vault:
    hostname: vault
    container_name: vault
    image: vault:1.12.0
    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"

Upvotes: 1

Anya Shenanigans
Anya Shenanigans

Reputation: 94839

I'm going to pseudo-code an answer to work around the problems specified, but please note that this is a massive hack and should NEVER be deployed in production as a hard-coded master key and single unseal key is COLOSSALLY INSECURE.

So, you want a test vault server, with persistence.

You can accomplish this, it will need a little bit of work because of the default behavior of the vault container - if you just start it, it will start with a dev mode container, which won't allow for persistence. Just adding persistence via the environment variable won't solve that problem entirely because it will conflict with the default start mode of the container.

so we need to replace this entrypoint script with something that does what we want it to do instead.

First we copy the script out of the container:

$ docker create --name vault vault:1.2.1
$ docker cp vault:/usr/local/bin/docker-entrypoint.sh .
$ docker rm vault

For simplicity, we're going to edit the file and mount it into the container using the docker-compose file. I'm not going to make it really functional - just enough to get it to do what's desired. The entire point here is sample, not something that is usable in production.

My customizations all start at about line 98 - first we launch a dev-mode server in order to record the unseal key, then we terminate the dev mode server.

# Here's my customization:
if [ ! -f /vault/unseal/sealfile ]; then
  # start in dev mode, in the background to record the unseal key
  su-exec vault vault server \
    -dev -config=/vault/config \
    -dev-root-token-id="$VAULT_DEV_ROOT_TOKEN_ID" \
    2>&1 | tee /vault/unseal/sealfile &
  while ! grep -q 'core: vault is unsealed' /vault/unseal/sealfile; do
    sleep 1
  done
  kill %1
fi

Next we check for supplemental config. This is where the extra config goes for disabling TLS, and for binding the appropriate interface.

if [ -n "$VAULT_SUPPLEMENTAL_CONFIG" ]; then
  echo "$VAULT_SUPPLEMENTAL_CONFIG" > "$VAULT_CONFIG_DIR/supplemental.json"
fi

Then we launch vault in 'release' mode:

if [ "$(id -u)" = '0' ]; then
  set -- su-exec vault "$@"
  "$@"&

Then we get the unseal key from the sealfile:

  unseal=$(sed -n 's/Unseal Key: //p' /vault/unseal/sealfile)
  if [ -n "$unseal" ]; then
    while ! vault operator unseal "$unseal"; do
      sleep 1
    done
  fi

We just wait for the process to terminate:

  wait
  exit $?
fi

There's a full gist for this on github.

Now the docker-compose.yml for doing this is slightly different to your own:

version: '2.3'
services:
  vault-dev:
    image: vault:1.2.1
    restart: always
    container_name: vault-dev
    command: [ 'vault', 'server', '-config=/vault/config' ]
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: "myroot"
      VAULT_LOCAL_CONFIG: '{"backend": {"file": {"path": "/vault/file"}}, "default_lease_ttl": "168h", "max_lease_ttl": "720h"}'
      VAULT_SUPPLEMENTAL_CONFIG: '{"ui":true, "listener": {"tcp":{"address": "0.0.0.0:8200", "tls_disable": 1}}}'
      VAULT_ADDR: "http://127.0.0.1:8200"
    ports:
      - "8200:8200"
    volumes:
      - ./vault:/vault/file
      - ./unseal:/vault/unseal
      - ./docker-entrypoint.sh:/usr/local/bin/docker-entrypoint.sh
    cap_add:
      - IPC_LOCK

The command is the command to execute. This is what's in the "$@"& of the script changes.

I've added VAULT_SUPPLEMENTAL_CONFIG for the non-dev run. It needs to specify the interfaces, it needs to turn of tls. I added the ui, so I can access it using http://127.0.0.1:8200/ui. This is part of the changes I made to the script.

Because this is all local, for me, test purposes, I'm mounting ./vault as the data directory, I'm mounting ./unseal as the place to record the unseal code and mounting ./docker-entrypoint.sh as the entrypoint script.

I can docker-compose up this and it launches a persistent vault - there are some errors on the log as I try to unseal before the server has launched, but it works, and persists across multiple docker-compose runs.

Again, to mention that this is completely unsuitable for any form of long-term use. You're better off using docker's own secrets engine if you're doing things like this.

Upvotes: 4

Related Questions