ldez/traefik-certs-dumper

Example fails, when you have more than one certresolver configured

tobiashochguertel opened this issue · 4 comments

I figured out that the following line makes trouble when you have more than one certresolvers activated in your traefik setup:

here a quick way to understand:

image

I modified the test to the following jq command:

image

My complete solution:

  traefik-certs-dumper:
    image: ldez/traefik-certs-dumper:v2.7.4
    entrypoint: sh -c 'set -x; apk add jq; while ! [ -e /data/acme.json ] || ! [ `jq ".http | .Certificates | length" /data/acme.json` != 0 ]; do sleep 1; done && traefik-certs-dumper file --version v2 --watch --source /data/acme.json --dest ./data/certs'
    volumes:
      - /opt/docker-volumes/traefik:/data

Otherwise, jq ".[] | .Certificates | length" returns "22 1", and then ... ! [ jq ".[] | .Certificates | length" /data/acme.json != 0 ] ... is evaluated to: ... ! [ 22 1 != 0 ] ... an you get an Error sh: 1: unknown operand (reference the issue #128) or as I was playing around to find this issue: ./bla.sh: line 3: [: too many arguments

hope this helps, someone who has same issues.

Thanks for this project 👍

really useful. thank you for fixing this. to be clear, the solution above should be replaced within the v2 compose example otherwise the unknown operand error will occur.

"entrypoint: sh -c 'set -x; apk add jq; while ! [ -e /data/acme.json ] || ! [ jq ".http | .Certificates | length" /data/acme.json != 0 ]; do sleep 1; done && traefik-certs-dumper file --version v2 --watch --source /data/acme.json --dest ./data/certs'"

TL;DR: If you have certs in acme.json, you don't need the while loop and can get past the issues in this issue by removing it.

Using the v2 example, with paths slightly modified, is throwing the sh: 0: unknown operand error for me.

    entrypoint: sh -c '
      apk add jq
      ; while ! [ -e /etc/traefik/acme.json ]
      || ! [ `jq ".[] | .Certificates | length" /etc/traefik/acme.json` != 0 ]; do
      sleep 1
      ; done
      && traefik-certs-dumper file --version v2 --watch
      --source /etc/traefik/acme.json --dest /etc/traefik/certs'

Output:

...
docker-swarm-service-task-name    | sh: 0: unknown operand
docker-swarm-service-task-name    | sh: 0: unknown operand
docker-swarm-service-task-name    | sh: 0: unknown operand
...

@tobiashochguertel 's example also fails.

entrypoint: sh -c 'set -x; apk add jq; while ! [ -e /etc/traefik/acme.json ] || ! [ `jq ".http | .Certificates | length" /etc/traefik/acme.json` != 0 ]; do sleep 1; done && traefik-certs-dumper file --version v2 --watch --source /etc/traefik/acme.json --dest /etc/traefik/certs'

output:

docker-swarm-service-task-name    | + apk add jq
docker-swarm-service-task-name    | fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/main/x86_64/APKINDEX.tar.gz
docker-swarm-service-task-name    | fetch https://dl-cdn.alpinelinux.org/alpine/v3.15/community/x86_64/APKINDEX.tar.gz
docker-swarm-service-task-name    | (1/2) Installing oniguruma (6.9.7.1-r0)
docker-swarm-service-task-name    | (2/2) Installing jq (1.6-r1)
docker-swarm-service-task-name    | Executing busybox-1.34.1-r3.trigger
docker-swarm-service-task-name    | OK: 7 MiB in 16 packages
docker-swarm-service-task-name    | + '[' -e /etc/traefik/acme.json ]
docker-swarm-service-task-name    | + jq '.http | .Certificates | length' /etc/traefik/acme.json
docker-swarm-service-task-name    | + '[' 0 '!=' 0 ]
docker-swarm-service-task-name    | + sleep 1
docker-swarm-service-task-name    | + '[' -e /etc/traefik/acme.json ]
docker-swarm-service-task-name    | + jq '.http | .Certificates | length' /etc/traefik/acme.json
docker-swarm-service-task-name    | + '[' 0 '!=' 0 ]
docker-swarm-service-task-name    | + sleep 1
...

I have three resolvers configured. Let's Encrypt, Let's Encrypt Staging, and an internal custom Step Ca.

Currently only the Let's Encrypt has any certs in it. So jq gives me:

$ jq ".[] | .Certificates | length" /etc/traefik/acme.json 
13
0
0

Here is my slightly sanitized compose service:

  swarm-traefik-certs-dumper:
    image: ldez/traefik-certs-dumper:v2.8.1
    container_name: swarm-traefik-certs-dumper
    hostname: swarm-traefik-certs-dumper
    restart: always
    entrypoint: sh -c '
      apk add jq
      ; while ! [ -e /etc/traefik/acme.json ]
      || ! [ `jq ".[] | .Certificates | length" /etc/traefik/acme.json` != 0 ]; do
      sleep 1
      ; done
      && traefik-certs-dumper file --version v2 --watch
      --source /etc/traefik/acme.json --dest /etc/traefik/certs'
    labels:
      traefik.enable: "false"
    environment:
      - LEGO_CA_CERTIFICATES=/usr/local/share/ca-certificates/stepca_root_ca.crt
      - LEGO_CA_SERVER_NAME=stepca.internal
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /etc/traefik:/etc/traefik:rw
      - /usr/local/share/ca-certificates/stepca_intermediate_ca.crt:/usr/local/share/ca-certificates/stepca_intermediate_ca.crt
      - /usr/local/share/ca-certificates/stepca_root_ca.crt:/usr/local/share/ca-certificates/stepca_root_ca.crt
    deploy:
      restart_policy:
        condition: any

All that said, if I remove the while loop, it works.

    entrypoint: sh -c '
      apk add jq
      && traefik-certs-dumper file --version v2 --watch
      --source /etc/traefik/acme.json --dest /etc/traefik/certs'

Now I have my certs in /etc/traefik/certs.

While writing this, I started wondering, why isn't the while loop logic in the main binary?

Anyway, thanks for the tool :D, hopefully my post will help someone down the road.

ma-ef commented

In my case the command jq ".[] | .Certificates | length" /data/acme.json prints out more than one line as I have defined more than one resolver:
4
9
The solution therefore is to add up the lines (4+9=13). This can be accomplished with jq -s "add". The new entrypoint script therefore looks as follows:

    entrypoint: sh -c '
      apk add jq
      ; while ! [ -e /data/acme.json ]
      || ! [ `jq ".[] | .Certificates | length" /data/acme.json | jq -s "add"` != 0 ]; do
      sleep 1
      ; done
      && traefik-certs-dumper file --version v2 --watch
      --source /data/acme.json --dest /data/certs'
tsvsj commented

@ma-ef: Thanks for pointing that out. That helped me a lot.