From af09adcc45b3c9a7a18d84fcaf12e42e72c03e58 Mon Sep 17 00:00:00 2001 From: LH Date: Wed, 27 May 2020 14:45:12 +0200 Subject: [PATCH] feat: First version (#1) --- .dockeringore | 1 + .gitattributes | 3 +- .github/settings.yml | 2 +- .github/workflows/ci.yml | 4 +- .github/workflows/ci_cd.yml | 4 +- .gitignore | 1 + Dockerfile | 42 ++++++++++- README.md | 41 ++++++----- docker-compose.yml | 4 +- fs/cron/cron-tick | 3 + fs/etc/cont-init.d/98-verify-args.sh | 5 ++ fs/etc/cont-init.d/99-first-execution.sh | 4 ++ package.json | 8 +-- tests/.idea/compiler.xml | 4 +- tests/.idea/dictionaries/lholota.xml | 7 ++ tests/.idea/jarRepositories.xml | 5 ++ tests/.project | 2 +- .../org.eclipse.buildship.core.prefs | 11 +++ tests/build.gradle | 12 +++- .../src/test/java/CertbotContainerShould.java | 70 +++++++++++++++++++ .../CertbotContainerWithoutEmailShould.java | 50 +++++++++++++ tests/src/test/java/TestConfiguration.java | 53 ++++++++++++++ .../helpers/CertbotDockerTagResolver.java | 9 +++ 23 files changed, 311 insertions(+), 34 deletions(-) create mode 100644 .dockeringore create mode 100644 fs/cron/cron-tick create mode 100644 fs/etc/cont-init.d/98-verify-args.sh create mode 100644 fs/etc/cont-init.d/99-first-execution.sh create mode 100644 tests/.idea/dictionaries/lholota.xml create mode 100644 tests/src/test/java/CertbotContainerShould.java create mode 100644 tests/src/test/java/CertbotContainerWithoutEmailShould.java create mode 100644 tests/src/test/java/TestConfiguration.java create mode 100644 tests/src/test/java/helpers/CertbotDockerTagResolver.java diff --git a/.dockeringore b/.dockeringore new file mode 100644 index 0000000..3598c30 --- /dev/null +++ b/.dockeringore @@ -0,0 +1 @@ +tests \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 52f5301..c94f078 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,5 @@ * text=auto *.sh eol=lf **/run eol=lf -*/services.d/* eol=lf \ No newline at end of file +*/services.d/* eol=lf +cron-tick eol=lf \ No newline at end of file diff --git a/.github/settings.yml b/.github/settings.yml index f980fff..56e93fc 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -21,7 +21,7 @@ branches: protection: required_status_checks: strict: true - contexts: [ ".github/workflows/ci.yml" ] + contexts: [ "build" ] required_pull_request_reviews: null enforce_admins: false restrictions: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25d8109..55d36be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ on: pull_request: env: - IMAGE_NAME: "homecentr/$$IMAGE_NAME$$" + IMAGE_NAME: "homecentr/certbot" jobs: build: @@ -30,7 +30,7 @@ jobs: run: docker build . -t ${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.docker_tag }} - name: Test Docker image - run: cd tests && sudo gradle test --info -Dimage_tag=${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.docker_tag }} + run: cd tests && sudo gradle test --info -Ddocker_image_tag=${{ env.IMAGE_NAME }}:${{ steps.vars.outputs.docker_tag }} -Droot_domain=${{ secrets.ROOT_DOMAIN }} -Dacme_email=${{ secrets.ACME_EMAIL }} -Dcloudflare_token=${{ secrets.CLOUDFLARE_TOKEN }} - name: Scan with Phonito Security uses: phonito/phonito-scanner-action@master diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml index f85445f..4bd25e4 100644 --- a/.github/workflows/ci_cd.yml +++ b/.github/workflows/ci_cd.yml @@ -5,7 +5,7 @@ on: - master env: - IMAGE_NAME: "homecentr/$$IMAGE_NAME$$" + IMAGE_NAME: "homecentr/certbot" jobs: build: @@ -40,7 +40,7 @@ jobs: - name: Test Docker image if: env.RELEASE_VERSION != '' - run: cd tests && sudo gradle test -Dimage_tag=${{ env.IMAGE_NAME }}:${{ env.RELEASE_VERSION }} + run: cd tests && sudo gradle test -Ddocker_image_tag=${{ env.IMAGE_NAME }}:${{ env.RELEASE_VERSION }} -Droot_domain=${{ secrets.ROOT_DOMAIN }} -Dacme_email=${{ secrets.ACME_EMAIL }} -Dcloudflare_token=${{ secrets.CLOUDFLARE_TOKEN }} - name: Scan with Phonito Security if: env.RELEASE_VERSION != '' diff --git a/.gitignore b/.gitignore index 79cc10f..1f7244f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.tmp *.class *.jar *.war diff --git a/Dockerfile b/Dockerfile index c3c78df..7c1974f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1 +1,41 @@ -FROM alpine \ No newline at end of file +FROM certbot/certbot:v1.4.0 as certbot + +FROM homecentr/cron-base:1.2.0 + +ARG CERTBOT_PIP_VERSION="1.4.0" + +ENV CERTBOT_ARGS="" +ENV CRON_SCHEDULE="30 * * * *" +ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2 + +COPY --from=certbot /usr/local/bin/certbot /usr/local/bin/certbot + +RUN apk add --no-cache python3=3.8.2-r0 && \ + apk add --no-cache --virtual deps \ + python3-dev=3.8.2-r0 \ + gcc=9.2.0-r4 \ + libffi-dev=3.2.1-r6 \ + openssl-dev=1.1.1g-r0 \ + musl-dev=1.1.24-r2 && \ + pip3 install --upgrade pip==20.1.1 && \ + pip3 install \ + setuptools==46.4.0 \ + acme==${CERTBOT_PIP_VERSION} \ + certbot==${CERTBOT_PIP_VERSION} \ + certbot-dns-cloudflare==${CERTBOT_PIP_VERSION} \ + certbot-dns-cloudxns==${CERTBOT_PIP_VERSION} \ + certbot-dns-digitalocean==${CERTBOT_PIP_VERSION} \ + certbot-dns-dnsimple==${CERTBOT_PIP_VERSION} \ + certbot-dns-dnsmadeeasy==${CERTBOT_PIP_VERSION} \ + certbot-dns-google==${CERTBOT_PIP_VERSION} \ + certbot-dns-linode==${CERTBOT_PIP_VERSION} \ + certbot-dns-luadns==${CERTBOT_PIP_VERSION} \ + certbot-dns-nsone==${CERTBOT_PIP_VERSION} \ + certbot-dns-ovh==${CERTBOT_PIP_VERSION} \ + certbot-dns-rfc2136==${CERTBOT_PIP_VERSION} \ + certbot-dns-route53==${CERTBOT_PIP_VERSION} && \ + apk del deps + +COPY ./fs/ / + +VOLUME "/etc/letsnecrypt" \ No newline at end of file diff --git a/README.md b/README.md index 80482d2..c7dbce3 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,56 @@ -[![Project status](https://badgen.net/badge/project%20status/stable%20%26%20actively%20maintaned?color=green)](https://github.com/homecentr/docker-$$IMAGE_NAME$$/graphs/commit-activity) [![](https://badgen.net/github/label-issues/homecentr/docker-$$IMAGE_NAME$$/bug?label=open%20bugs&color=green)](https://github.com/homecentr/docker-$$IMAGE_NAME$$/labels/bug) [![](https://badgen.net/github/release/homecentr/docker-$$IMAGE_NAME$$)](https://hub.docker.com/repository/docker/homecentr/$$IMAGE_NAME$$) -[![](https://badgen.net/docker/pulls/homecentr/$$IMAGE_NAME$$)](https://hub.docker.com/repository/docker/homecentr/$$IMAGE_NAME$$) -[![](https://badgen.net/docker/size/homecentr/$$IMAGE_NAME$$)](https://hub.docker.com/repository/docker/homecentr/$$IMAGE_NAME$$) +[![Project status](https://badgen.net/badge/project%20status/stable%20%26%20actively%20maintaned?color=green)](https://github.com/homecentr/docker-certbot/graphs/commit-activity) [![](https://badgen.net/github/label-issues/homecentr/docker-certbot/bug?label=open%20bugs&color=green)](https://github.com/homecentr/docker-certbot/labels/bug) [![](https://badgen.net/github/release/homecentr/docker-certbot)](https://hub.docker.com/repository/docker/homecentr/certbot) +[![](https://badgen.net/docker/pulls/homecentr/certbots://hub.docker.com/repository/docker/homecentr/certbot +[![](https://badgen.net/docker/size/homecentr/certbots://hub.docker.com/repository/docker/homecentr/certbot -![CI/CD on master](https://github.com/homecentr/docker-$$IMAGE_NAME$$/workflows/CI/CD%20on%20master/badge.svg) -![Regular Docker image vulnerability scan](https://github.com/homecentr/docker-$$IMAGE_NAME$$/workflows/Regular%20Docker%20image%20vulnerability%20scan/badge.svg) +![CI/CD on master](https://github.com/homecentr/docker-certbot/CI/CD%20on%20master/badge.svg) +![Regular Docker image vulnerability scan](https://github.com/homecentr/docker-certbot/Regular%20Docker%20image%20vulnerability%20scan/badge.svg) -# HomeCentr - $$IMAGE_NAME$$ +# HomeCentr - certbot +The image contains [Certbot](https://certbot.eff.org/) compliant with the HomeCenter docker images standard (S6 overlay, privilege drop etc.). All DNS plugins endorsed by Certbot are installed ([list](https://certbot.eff.org/docs/using.html#dns-plugins)). + +This image is supposed to be used as a single purpose certificate manager. It does not include any reverse proxy. The proxy should be running in a separate container and read the certificates from a mounted volume. ## Usage ```yml version: "3.7" services: - $$IMAGE_NAME$$: + certbot build: . - image: homecentr/$$IMAGE_NAME$$ + image: homecentr/certbot + # Example uses Cloudflare dns verification, if you use a different provider, you need to adjust the arguments + environment: + CERTBOT_ARGS: "--email john@doe.com --dns-cloudflare --dns-cloudflare-credentials /secrets/cloudflare.ini" + volumes: + - cloudflare.ini:/secrets/cloudflare.ini ``` +> If you are just testing/are not 100% sure the arguments are correct, add the `--dry-run` which will not actually make the request to Let's encrypt or `--staging` argument which will use [Let's encrypts staging servers](https://letsencrypt.org/docs/staging-environment/) instead of the production ones. The production servers have low rate limits and running too many unsuccessful requests could **block you out for a week**. + ## Environment variables | Name | Default value | Description | |------|---------------|-------------| -| PUID | 7077 | UID of the user $$IMAGE_NAME$$ should be running as. | -| PGID | 7077 | GID of the user $$IMAGE_NAME$$ should be running as. | +| PUID | 7077 | UID of the user certbot be running as. | +| PGID | 7077 | GID of the user certbot be running as. | +| CERTBOT_ARGS | | Additional arguments passed to certbot's `certonly` command. The argument `--agree-tos` is passed automatically, but you have to provide the `--email` argument. | ## Exposed ports -| Port | Protocol | Description | -|------|------|-------------| -| 80 | TCP | Some useful details | +This image does not expose any ports. ## Volumes | Container path | Description | |------------|---------------| -| /config | Some useful details | +| /etc/letsencrypt | Contains the provisioned certificates. Please note that the "files" in the `/etc/letsencrypt/*` are just symlinks and therefore when mounting, you need to mount either the whole `/etc/letsencrypt/` directory or mount both `/etc/letsencrypt/live` and `/etc/letsencrypt/archive` on same relative levels. | ## Security -The container is regularly scanned for vulnerabilities and updated. Further info can be found in the [Security tab](https://github.com/homecentr/docker-$$IMAGE_NAME$$/security). +The container is regularly scanned for vulnerabilities and updated. Further info can be found in the [Security tab](https://github.com/homecentr/docker-certbot). ### Container user -The container supports privilege drop. Even though the container starts as root, it will use the permissions only to perform the initial set up. The $$IMAGE_NAME$$ process runs as UID/GID provided in the PUID and PGID environment variables. +The container supports privilege drop. Even though the container starts as root, it will use the permissions only to perform the initial set up. The certbots runs as UID/GID provided in the PUID and PGID environment variables. :warning: Do not change the container user directly using the `user` Docker compose property or using the `--user` argument. This would break the privilege drop logic. \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 980a102..f82a2d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ version: "3.7" services: - $$IMAGE_NAME$$: + certbot: build: . - image: homecentr/$$IMAGE_NAME$$ + image: homecentr/certbot restart: unless-stopped \ No newline at end of file diff --git a/fs/cron/cron-tick b/fs/cron/cron-tick new file mode 100644 index 0000000..f5f8bca --- /dev/null +++ b/fs/cron/cron-tick @@ -0,0 +1,3 @@ +#!/usr/bin/env ash + +certbot certonly --agree-tos --non-interactive --no-permissions-check $CERTBOT_ARGS \ No newline at end of file diff --git a/fs/etc/cont-init.d/98-verify-args.sh b/fs/etc/cont-init.d/98-verify-args.sh new file mode 100644 index 0000000..9d867f1 --- /dev/null +++ b/fs/etc/cont-init.d/98-verify-args.sh @@ -0,0 +1,5 @@ +#!/usr/bin/with-contenv ash + +if [[ "$CERTBOT_ARGS" != *"--email"* ]]; then + echo "The CERTBOT_ARGS variable must contain '--email' as certbot is executed in a non-interactive way." +fi \ No newline at end of file diff --git a/fs/etc/cont-init.d/99-first-execution.sh b/fs/etc/cont-init.d/99-first-execution.sh new file mode 100644 index 0000000..78d1415 --- /dev/null +++ b/fs/etc/cont-init.d/99-first-execution.sh @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv ash + +echo "Executing the certbot immediately to ensure the certificate exists..." +cron-tick-execute \ No newline at end of file diff --git a/package.json b/package.json index 753e3e2..3b8ac48 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,15 @@ { - "name": "homecentr-$$IMAGE_NAME$$", + "name": "homecentr-certbot", "version": "1.0.0", "description": "", "repository": { "type": "git", - "url": "git+https://github.com/homecentr/docker-$$IMAGE_NAME$$.git" + "url": "git+https://github.com/homecentr/docker-certbot" }, "author": "", "license": "MIT", "bugs": { - "url": "https://github.com/homecentr/docker-$$IMAGE_NAME$$/issues" + "url": "https://github.com/homecentr/docker-certbot" }, - "homepage": "https://github.com/homecentr/docker-$$IMAGE_NAME$$#readme" + "homepage": "https://github.com/homecentr/docker-certbot" } diff --git a/tests/.idea/compiler.xml b/tests/.idea/compiler.xml index 098cf64..c35d1b0 100644 --- a/tests/.idea/compiler.xml +++ b/tests/.idea/compiler.xml @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/tests/.idea/dictionaries/lholota.xml b/tests/.idea/dictionaries/lholota.xml new file mode 100644 index 0000000..6798fcb --- /dev/null +++ b/tests/.idea/dictionaries/lholota.xml @@ -0,0 +1,7 @@ + + + + cloudflare + + + \ No newline at end of file diff --git a/tests/.idea/jarRepositories.xml b/tests/.idea/jarRepositories.xml index fdc392f..5060e6b 100644 --- a/tests/.idea/jarRepositories.xml +++ b/tests/.idea/jarRepositories.xml @@ -16,5 +16,10 @@