From 7458a4cf2b191c715e2e3f737e952408a8e5b3ac Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Sun, 26 Nov 2023 11:30:29 +0100 Subject: [PATCH] refactor: rework container build and switch to distroless (#142) Reviewed-on: https://gitea.rknet.org/container/vaultwarden/pulls/142 Co-authored-by: Robert Kaussow Co-committed-by: Robert Kaussow --- .dictionary | 1 + .woodpecker/build-container.yml | 12 ----- Containerfile | 83 ++++++++++++++++++++---------- Makefile | 31 ----------- README.md | 56 +------------------- overlay/etc/templates/env.tmpl | 85 ------------------------------- overlay/usr/local/bin/entrypoint | 20 -------- overlay/usr/local/bin/healthcheck | 10 ---- 8 files changed, 59 insertions(+), 239 deletions(-) delete mode 100644 Makefile delete mode 100644 overlay/etc/templates/env.tmpl delete mode 100755 overlay/usr/local/bin/entrypoint delete mode 100755 overlay/usr/local/bin/healthcheck diff --git a/.dictionary b/.dictionary index 275e5b1..a28e89b 100644 --- a/.dictionary +++ b/.dictionary @@ -1,2 +1,3 @@ (V|v)aultwarden Bitwarden +distroless diff --git a/.woodpecker/build-container.yml b/.woodpecker/build-container.yml index 41d1663..735ce69 100644 --- a/.woodpecker/build-container.yml +++ b/.woodpecker/build-container.yml @@ -6,18 +6,6 @@ when: - ${CI_REPO_DEFAULT_BRANCH} steps: - binary: - image: docker.io/clux/muslrust:stable - commands: - - apt-get -qq update && apt-get install -yqq --no-install-recommends libpq-dev - - make build - - executable: - image: docker.io/alpine - commands: - - src/target/x86_64-unknown-linux-musl/release/vaultwarden --help - - src/target/x86_64-unknown-linux-musl/release/vaultwarden --version - security-build: image: quay.io/thegeeklab/wp-docker-buildx:1 settings: diff --git a/Containerfile b/Containerfile index d4671f0..7f26e17 100644 --- a/Containerfile +++ b/Containerfile @@ -1,42 +1,71 @@ -FROM docker.io/thegeeklab/alpine:latest@sha256:881dac782c1de3466e2ab092847aebd34e187157c20701e40f51b7a6adf15076 - -LABEL maintainer="Robert Kaussow " -LABEL org.opencontainers.image.authors="Robert Kaussow " -LABEL org.opencontainers.image.title="vaultwarden" -LABEL org.opencontainers.image.url="https://gitea.rknet.org/container/vaultwarden" -LABEL org.opencontainers.image.source="https://gitea.rknet.org/container/vaultwarden" -LABEL org.opencontainers.image.documentation="https://gitea.rknet.org/container/vaultwarden" +FROM docker.io/clux/muslrust:1.74.0-stable as build ARG WEBVAULT_VERSION +ARG VAULTWARDEN_VERSION + +ARG DEBIAN_FRONTEND=noninteractive +ARG LANG=C.UTF-8 +ARG TZ=UTC +ARG RUSTFLAGS="-C link-arg=-s" +ARG DB=sqlite,postgresql + +ARG TARGETPLATFORM # renovate: datasource=github-releases depName=dani-garcia/bw_web_builds versioning=loose ENV WEBVAULT_VERSION="${WEBVAULT_VERSION:-v2023.10.0}" +# renovate: datasource=github-releases depName=dani-garcia/vaultwarden +ENV VAULTWARDEN_VERSION="${VAULTWARDEN_VERSION:-1.30.1}" -ADD overlay/ / +WORKDIR /src -RUN apk --update add --virtual .build-deps tar curl && \ - apk --update add openssl postgresql-libs sqlite ca-certificates && \ - mkdir -p /app/web-vault /app/data && \ - echo "Using Web Vault version '${WEBVAULT_VERSION##v}' ..." && \ +RUN apt-get update && apt-get install -y --no-install-recommends && \ + mkdir -p /release/web-vault && \ + mkdir -p /data + +RUN echo "Using Vaultwarden version '${VAULTWARDEN_VERSION##v}'" && \ + curl -sSL "https://github.com/dani-garcia/vaultwarden/archive/${VAULTWARDEN_VERSION##v}.tar.gz" | \ + tar xz --strip-components=1 && \ + echo "Using Web Vault version '${WEBVAULT_VERSION##v}'" && \ curl -SsfL "https://github.com/dani-garcia/bw_web_builds/releases/download/${WEBVAULT_VERSION}/bw_web_${WEBVAULT_VERSION}.tar.gz" | \ - tar xz -C /app && \ - apk del .build-deps && \ - rm -rf /var/cache/apk/* && \ - rm -rf /tmp/* && \ - chown -R app:app /app + tar xz -C /release -ADD src/target/x86_64-unknown-linux-musl/release/vaultwarden /app +RUN echo "Building for platform '$TARGETPLATFORM'" && \ + case "$TARGETPLATFORM" in \ + "linux/amd64") echo x86_64-unknown-linux-musl > rust_target ;; \ + "linux/arm64") echo aarch64-unknown-linux-musl > rust_target ;; \ + *) exit 1 ;; \ +esac -VOLUME /app/data +RUN rustup set profile minimal && \ + rustup target add $(cat rust_target) && \ + VW_VERSION="${VAULTWARDEN_VERSION##v}" cargo build -j 8 --features "$DB" --target $(cat rust_target) --release -EXPOSE 8080 -EXPOSE 3012 +RUN ldd target/$(cat rust_target)/release/vaultwarden && \ + target/$(cat rust_target)/release/vaultwarden --help && \ + target/$(cat rust_target)/release/vaultwarden --version -USER app +FROM gcr.io/distroless/cc + +LABEL maintainer="Robert Kaussow " +LABEL org.opencontainers.image.authors="Robert Kaussow " +LABEL org.opencontainers.image.title="vaultwarden" +LABEL org.opencontainers.image.url="https://gitea.rknet.org/container/vaultwarden" +LABEL org.opencontainers.image.source="https://gitea.rknet.org/container/vaultwarden" +LABEL org.opencontainers.image.documentation="https://gitea.rknet.org/container/vaultwarden" + +ENV DATA_FOLDER=/data +ENV ROCKET_ADDRESS=0.0.0.0 +ENV ROCKET_PORT=8000 +ENV WEBSOCKET_ADDRESS=0.0.0.0 +ENV WEBSOCKET_PORT=3012 + +COPY --from=build --chown=65532:65532 /data /data +COPY --from=build /release/web-vault /web-vault +COPY --from=build /src/target/**/release/vaultwarden / + +EXPOSE 8000 +EXPOSE 3012 STOPSIGNAL SIGTERM -ENTRYPOINT ["/usr/local/bin/entrypoint"] -HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD /usr/local/bin/healthcheck -WORKDIR /app -CMD [] +CMD ["/vaultwarden"] diff --git a/Makefile b/Makefile deleted file mode 100644 index 7959b68..0000000 --- a/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# renovate: datasource=github-releases depName=dani-garcia/vaultwarden -export BUILD_VERSION ?= 1.30.1 -export DEBIAN_FRONTEND ?= noninteractive -export LANG ?= C.UTF-8 -export TZ ?= UTC -export RUSTFLAGS ?= -C link-arg=-s - -DB ?= sqlite,postgresql -SRC := src - -.PHONY: all -all: build - -.PHONY: build -build: build-src build-bin - -.PHONY: build-src -build-src: - mkdir -p $(SRC); \ - curl -sSL "https://github.com/dani-garcia/vaultwarden/archive/$${BUILD_VERSION##v}.tar.gz" | tar xz -C $(SRC) --strip-components=1 - -.PHONY: build-bin -build-bin: - rustup set profile minimal && \ - cd $(SRC) && \ - rustup target add x86_64-unknown-linux-musl && \ - BWRS_VERSION="$${BUILD_VERSION##v}" cargo build -j 8 --features $(DB) --release - -.PHONY: clean -clean: - rm -rf $(SRC) diff --git a/README.md b/README.md index 2e5bb3b..367c0a6 100644 --- a/README.md +++ b/README.md @@ -12,65 +12,13 @@ Custom image for Vaultwarden password manager -Custom rootless container image for [vaultwarden](https://github.com/dani-garcia/vaultwarden). Vaultwarden is a Bitwarden server API implementation written in Rust compatible with upstream Bitwarden clients, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal. +Custom distroless container image for [Vaultwarden](https://github.com/dani-garcia/vaultwarden). Vaultwarden is a Bitwarden server API implementation written in Rust compatible with upstream Bitwarden clients. > **WARNING**: This version only supports SQLite and PostgreSQL databases. ## Configuration -```Shell -VAULTWARDEN_DATABASE_URL= - -VAULTWARDEN_TEMPLATES_FOLDER= -VAULTWARDEN_RELOAD_TEMPLATES=False - -VAULTWARDEN_IP_HEADER=X-Forwarded-For - -VAULTWARDEN_ICON_CACHE_TTL=2592000 -VAULTWARDEN_ICON_CACHE_NEGTTL=259200 - -VAULTWARDEN_WEB_VAULT_ENABLED=True -VAULTWARDEN_WEBSOCKET_ENABLED=False - -VAULTWARDEN_EXTENDED_LOGGING=True -VAULTWARDEN_LOG_LEVEL=Info - -VAULTWARDEN_DISABLE_ICON_DOWNLOAD=False -VAULTWARDEN_ICON_DOWNLOAD_TIMEOUT=10 -VAULTWARDEN_ICON_BLACKLIST_REGEXL= -VAULTWARDEN_ICON_BLACKLIST_NON_GLOBAL_IPS=True - -VAULTWARDEN_DISABLE_2FA_REMEMBER=False -VAULTWARDEN_SIGNUPS_ALLOWED=True -VAULTWARDEN_SIGNUPS_VERIFY=False -VAULTWARDEN_SIGNUPS_VERIFY_RESEND_TIME=3600 -VAULTWARDEN_SIGNUPS_VERIFY_RESEND_LIMIT=6 -VAULTWARDEN_SIGNUPS_DOMAINS_WHITELIST= - -VAULTWARDEN_INVITATIONS_ALLOWED=True - -# Set an indicidual admin token to enable the admin UI -VAULTWARDEN_ADMIN_TOKEN= - -VAULTWARDEN_PASSWORD_ITERATIONS=100000 -VAULTWARDEN_SHOW_PASSWORD_HINT=True -VAULTWARDEN_DOMAIN=http://localhost/ - -VAULTWARDEN_AUTHENTICATOR_DISABLE_TIME_DRIFT=False - -# If you dont set a smtp host, all other smpt settings will be ignored -VAULTWARDEN_SMTP_HOST= -VAULTWARDEN_SMTP_FROM= -VAULTWARDEN_SMTP_FROM_NAME=vaultwarden -VAULTWARDEN_SMTP_PORT=465 -VAULTWARDEN_SMTP_SECURITY=force_tls -VAULTWARDEN_SMTP_USERNAME= -VAULTWARDEN_SMTP_PASSWORD= -VAULTWARDEN_SMTP_AUTH_MECHANISM=Plain -VAULTWARDEN_SMTP_TIMEOUT=15 - -VAULTWARDEN_ROCKET_WORKERS= -``` +In Vaultwarden the configuration can be done either via environment variables or the admin page. A complete list of all environment variables can be found in the [Vaultwarden Repository](https://github.com/dani-garcia/vaultwarden/blob/main/.env.template). ## License diff --git a/overlay/etc/templates/env.tmpl b/overlay/etc/templates/env.tmpl deleted file mode 100644 index 6efadc2..0000000 --- a/overlay/etc/templates/env.tmpl +++ /dev/null @@ -1,85 +0,0 @@ -## Vaultwarden Configuration File -DATA_FOLDER=/app/data -RSA_KEY_FILENAME=/app/data/rsa_key -ICON_CACHE_FOLDER=/app/data/icon_cache -ATTACHMENTS_FOLDER=/app/data/attachments - -{{ if (getenv "VAULTWARDEN_DATABASE_URL") -}} -DATABASE_URL={{ getenv "VAULTWARDEN_DATABASE_URL" }} -{{ end -}} - -USER_ATTACHMENT_LIMIT={{ getenv "VAULTWARDEN_USER_ATTACHMENT_LIMIT" "1024" }} -ORG_ATTACHMENT_LIMIT={{ getenv "VAULTWARDEN_ORG_ATTACHMENT_LIMIT" "1024" }} - -{{ if (getenv "VAULTWARDEN_TEMPLATES_FOLDER") -}} -TEMPLATES_FOLDER={{ getenv "VAULTWARDEN_TEMPLATES_FOLDER" }} -{{ end -}} -RELOAD_TEMPLATES={{ getenv "VAULTWARDEN_RELOAD_TEMPLATES" "false" | conv.ToBool }} - -IP_HEADER={{ getenv "VAULTWARDEN_IP_HEADER" "X-Forwarded-For" }} - -ICON_CACHE_TTL={{ getenv "VAULTWARDEN_ICON_CACHE_TTL" "2592000" }} -ICON_CACHE_NEGTTL={{ getenv "VAULTWARDEN_ICON_CACHE_NEGTTL" "259200" }} - -WEB_VAULT_FOLDER=/app/web-vault/ -WEB_VAULT_ENABLED={{ getenv "VAULTWARDEN_WEB_VAULT_ENABLED" "true" | conv.ToBool }} - -WEBSOCKET_ENABLED={{ getenv "VAULTWARDEN_WEBSOCKET_ENABLED" "false" | conv.ToBool }} -WEBSOCKET_ADDRESS=0.0.0.0 -WEBSOCKET_PORT=3012 - -EXTENDED_LOGGING={{ getenv "VAULTWARDEN_EXTENDED_LOGGING" "true" | conv.ToBool }} -LOG_LEVEL={{ getenv "VAULTWARDEN_LOG_LEVEL" "Info" }} - -ENABLE_DB_WAL=true - -DISABLE_ICON_DOWNLOAD={{ getenv "VAULTWARDEN_DISABLE_ICON_DOWNLOAD" "false" | conv.ToBool }} -ICON_DOWNLOAD_TIMEOUT={{ getenv "VAULTWARDEN_ICON_DOWNLOAD_TIMEOUT" "10" }} -{{ if (getenv "VAULTWARDEN_ICON_BLACKLIST_REGEXL") -}} -ICON_BLACKLIST_REGEX={{ getenv "VAULTWARDEN_ICON_BLACKLIST_REGEXL" }} -{{ end -}} -ICON_BLACKLIST_NON_GLOBAL_IPS={{ getenv "VAULTWARDEN_ICON_BLACKLIST_NON_GLOBAL_IPS" "true" | conv.ToBool }} - -DISABLE_2FA_REMEMBER={{ getenv "VAULTWARDEN_DISABLE_2FA_REMEMBER" "false" | conv.ToBool }} - -SIGNUPS_ALLOWED={{ getenv "VAULTWARDEN_SIGNUPS_ALLOWED" "true" | conv.ToBool }} -SIGNUPS_VERIFY={{ getenv "VAULTWARDEN_SIGNUPS_VERIFY" "false" | conv.ToBool }} -SIGNUPS_VERIFY_RESEND_TIME={{ getenv "VAULTWARDEN_SIGNUPS_VERIFY_RESEND_TIME" "3600" }} -SIGNUPS_VERIFY_RESEND_LIMIT={{ getenv "VAULTWARDEN_SIGNUPS_VERIFY_RESEND_LIMIT" "6" }} -{{ if (getenv "VAULTWARDEN_SIGNUPS_DOMAINS_WHITELIST") -}} -SIGNUPS_DOMAINS_WHITELIST={{ getenv "VAULTWARDEN_SIGNUPS_DOMAINS_WHITELIST" }} -{{ end -}} - -INVITATIONS_ALLOWED={{ getenv "VAULTWARDEN_INVITATIONS_ALLOWED" "true" | conv.ToBool }} -INVITATION_ORG_NAME={{ getenv "VAULTWARDEN_INVITATION_ORG_NAME" "Vaultwarden" }} - -{{ if (getenv "VAULTWARDEN_ADMIN_TOKEN") -}} -ADMIN_TOKEN={{ getenv "VAULTWARDEN_ADMIN_TOKEN" }} -{{ end -}} -DISABLE_ADMIN_TOKEN=false - -PASSWORD_ITERATIONS={{ getenv "VAULTWARDEN_PASSWORD_ITERATIONS" "100000" }} -SHOW_PASSWORD_HINT={{ getenv "VAULTWARDEN_SHOW_PASSWORD_HINT" "true" | conv.ToBool }} -DOMAIN={{ getenv "VAULTWARDEN_DOMAIN" "http://localhost/" }} - -AUTHENTICATOR_DISABLE_TIME_DRIFT={{ getenv "VAULTWARDEN_AUTHENTICATOR_DISABLE_TIME_DRIFT" "false" | conv.ToBool }} - -ROCKET_ADDRESS=0.0.0.0 -ROCKET_PORT=8080 -{{ if (getenv "VAULTWARDEN_ROCKET_WORKERS") -}} -ROCKET_WORKERS={{ getenv "VAULTWARDEN_ROCKET_WORKERS" }} -{{ end -}} - -{{ if (getenv "VAULTWARDEN_SMTP_HOST") -}} -SMTP_HOST={{ getenv "VAULTWARDEN_SMTP_HOST" }} -SMTP_FROM={{ getenv "VAULTWARDEN_SMTP_FROM" }} -SMTP_FROM_NAME={{ getenv "VAULTWARDEN_SMTP_FROM_NAME" "Vaultwarden" }} -SMTP_PORT={{ getenv "VAULTWARDEN_SMTP_PORT" "465" }} -SMTP_SECURITY={{ getenv "VAULTWARDEN_SMTP_SECURITY" "force_tls" }} -{{ if (getenv "VAULTWARDEN_SMTP_USERNAME") -}} -SMTP_USERNAME={{ getenv "VAULTWARDEN_SMTP_USERNAME" }} -SMTP_PASSWORD={{ getenv "VAULTWARDEN_SMTP_PASSWORD" }} -{{ end -}} -SMTP_AUTH_MECHANISM={{ getenv "VAULTWARDEN_SMTP_AUTH_MECHANISM" "Plain" }} -SMTP_TIMEOUT={{ getenv "VAULTWARDEN_SMTP_TIMEOUT" "15" }} -{{ end -}} diff --git a/overlay/usr/local/bin/entrypoint b/overlay/usr/local/bin/entrypoint deleted file mode 100755 index 42548db..0000000 --- a/overlay/usr/local/bin/entrypoint +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env sh - -# shellcheck disable=SC3040 -set -eo pipefail - -# shellcheck disable=SC1091 -. /usr/local/lib/log.sh - -/usr/local/bin/gomplate -o /app/.env -f /etc/templates/env.tmpl - -if [ -n "$VAULTWARDEN_DATABASE_URL" ]; then - WAITFOR_HOST=$(/usr/local/bin/url-parser --url "$VAULTWARDEN_DATABASE_URL" host) - WAITFOR_PORT=$(/usr/local/bin/url-parser --url "$VAULTWARDEN_DATABASE_URL" port) - - log_info "Wait for database server on '${WAITFOR_HOST}:${WAITFOR_PORT:-5432}'" - /usr/local/bin/wait-for "${WAITFOR_HOST}":"${WAITFOR_PORT:-5432}" -fi - -log_info "Start Vaultwarden Server\n" -exec /app/vaultwarden diff --git a/overlay/usr/local/bin/healthcheck b/overlay/usr/local/bin/healthcheck deleted file mode 100755 index 5c225b7..0000000 --- a/overlay/usr/local/bin/healthcheck +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env sh - -# shellcheck disable=SC3040 -set -eo pipefail - -URL=http://127.0.0.1:8080/alive - -wget --quiet --tries=1 --spider ${URL} || exit 1 - -exit 0