caddy-dns/cloudflare

Read API token from file instead of environment variable

pettijohn opened this issue · 6 comments

I am trying to spin up Caddy in a Docker container, passing a secret in the docker-compose file. Ref: https://docs.docker.com/engine/swarm/secrets/

Docker intentionally requires the contents of the secret to be in a file and not an environment variable. In a compose file it looks like:

services:
  reverseproxy:
    container_name: caddy
    build: .
    ports:
      - 443:443
      - 80:80
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - /shares/caddy/data:/data
      - /shares/caddy/config:/config
    secrets:
      - cloudflare-api-key
      
secrets:
  cloudflare-api-key:
    file: ./cloudflare-api-key.secret

At runtime, that copies the contents of the file ./cloudflare-api-key.secret into /run/secrets/cloudflare-api-key in a tmpfs in the container (ref docs linked above for explanation).

Is it possible to pass the API token as a path to a file rather than an environment variable?

tls {
    dns cloudflare /run/secrets/cloudflare-api-key
}

Note I worked around this by putting the secret in a .env file instead, but as the Docker documentation argues, this is probably less secure than putting it in a secret file https://docs.docker.com/compose/environment-variables/

FWIW I tried to write this but since I've never worked with Go I have no idea what I'm doing and it didn't seem to work. I spent way too much time trying to understand how to replace a module to even attempt to run the code. Anyway - here's a link to a broken/partial implementation:

pettijohn@39673a7

mholt commented

Can you use the --envfile flag to give Caddy the environment file that way? https://caddyserver.com/docs/command-line#caddy-run

This does work with some compose file magic. Overriding the entrypoint of the image is clunky as you can see but functional.

services:
  reverseproxy:
    container_name: caddy
    build: .
    restart: always
    ports:
      - 443:443
      - 80:80
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - ./site:/site
      - /shares/caddy/data:/data
      - /shares/caddy/config:/config
    secrets:
      - cloudflare-api-key
    entrypoint: ["caddy", "run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile", "--envfile", "/run/secrets/cloudflare-api-key"]

secrets:
  cloudflare-api-key:
    file: ./cloudflare-api-key.secret
mholt commented

Nice, thanks for posting your solution!

(Going to close if that's alright, since that works. Would prefer to not have to reinvent env files for each plugin...)

I think it's fine to close. https://docs.docker.com/engine/swarm/secrets/ says "Docker secrets do not set environment variables directly. This was a conscious decision, because environment variables can unintentionally be leaked between containers (for instance, if you use --link)." I think the caddy --envfile approach does not violate this because caddy loading its own environment state, not modifying the container's state (I assume). Seems like a fine approach.