caddy-dns / cloudflare

Caddy module: dns.providers.cloudflare
Apache License 2.0
436 stars 59 forks source link

Read API token from file instead of environment variable #35

Closed pettijohn closed 2 years ago

pettijohn commented 2 years ago

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
}
pettijohn commented 2 years ago

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/

pettijohn commented 2 years ago

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:

https://github.com/pettijohn/cloudflare/commit/39673a76fc821898cada5112c889d0b021c3d3a5

mholt commented 2 years ago

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

pettijohn commented 2 years ago

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 2 years ago

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...)

pettijohn commented 2 years ago

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.