From d0cb02102e3186eae6a624aff48a6812476325e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9D=D0=B8=D0=BA=D0=B8=D1=82=D0=B0=20=D0=A1=D1=8B=D1=87?= =?UTF-8?q?=D0=B5=D0=B2?= Date: Sat, 3 Jan 2026 23:09:01 +0100 Subject: [PATCH] Initial commit --- .gitignore | 7 +++ .gitlab-ci.yml | 25 ++++++++++ README.md | 101 +++++++++++++++++++++++++++++++++++++++++ backup/Dockerfile | 12 +++++ backup/backup.sh | 11 +++++ backup/crontab | 2 + dist/.gitkeep | 0 docker-bake.hcl | 62 +++++++++++++++++++++++++ docker-compose.yml | 53 +++++++++++++++++++++ proxy/Dockerfile | 13 ++++++ proxy/vaultwarden.conf | 33 ++++++++++++++ secrets/.gitkeep | 0 server/Dockerfile | 11 +++++ server/config.json | 59 ++++++++++++++++++++++++ 14 files changed, 389 insertions(+) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 README.md create mode 100644 backup/Dockerfile create mode 100644 backup/backup.sh create mode 100644 backup/crontab create mode 100644 dist/.gitkeep create mode 100644 docker-bake.hcl create mode 100644 docker-compose.yml create mode 100644 proxy/Dockerfile create mode 100644 proxy/vaultwarden.conf create mode 100644 secrets/.gitkeep create mode 100644 server/Dockerfile create mode 100644 server/config.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9d8be5a --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +secrets/* +!secrets/.gitkeep + +*.tar.gz +*.tar + +.DS_Store diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..685f52e --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,25 @@ +stages: + - build + +build-images: + stage: build + image: repo.nstart.local/nstart/docker-cli-buildx:1.0.0 + services: + - name: repo.nstart.local/nstart/docker-dind-ca:1.0.0 + alias: docker + command: ["--tls=false"] + variables: + DOCKER_HOST: tcp://docker:2375 + DOCKER_TLS_CERTDIR: "" + parallel: + matrix: + - BAKE_TARGET: + - server + - backup + - proxy + + script: + - echo $REGISTRY_PASSWORD | docker login -u $REGISTRY_USER --password-stdin $REGISTRY + - docker bake "$BAKE_TARGET" -f docker-bake.hcl --no-cache --push + only: + - master diff --git a/README.md b/README.md new file mode 100644 index 0000000..6d362a3 --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# Развертывание Vaultwarden + +Vaultwarden — это менеджер паролей с открытым исходным кодом, который позволяет +безопасно хранить и управлять вашими паролями, логинами и другими +конфиденциальными данными. + +## Сборка OCI-образа + +Для сборки необходимо выполнить команду: + +```sh +docker bake all +``` + +Загрузка образов в реестр: + +```sh +docker bake all --push +``` + +## Экспорт образов в tar + +Для экспорта необходимо выполнить команду: + +```sh +docker bake save +``` + +Архивы будут находиться в директории **dist** + +## Генерация Argon2-хеша токена + +Для безопасного хранения ADMIN_TOKEN вместо простого текста используется +Argon2id-PHC. + +Перед первым запуском необходимо сгенерировать секрет с Argon2-хеш секретного +токена.Для этого необходимо выполнить команду находясь в директории проекта: + +```sh +docker run --rm -ti \ + nstart/vaultwarden-server:1.0.1 \ + /vaultwarden hash --preset owasp \ + | tee >(grep 'ADMIN_TOKEN=' > secrets/vw_admin_token.txt) +``` + +## Переменные окружения + +Перед запуском нужно сформировать файлы с секретами. + +| Файл | Переменная окружения | Описание | +| ---------------------------- | -------------------- | ---------------------------- | +| ./secrets/vw_admin_token.txt | ADMIN_TOKEN | Argon2id-PHC хеш админ-токен | +| ./secrets/vw_sso_secret.txt | SSO_CLIENT_SECRET | Секрет клиента OIDC/SSO | + +## Запуск и остановка + +Для запуска необходимо выполнить команду находясь в директории проекта: + +```sh +docker compose up -d +``` + +Для остановки необходимо выполнить команду находясь в директории проекта: + +```sh +docker compose down +``` + +## Доступ к панели администратора (/admin) + +В целях безопасности закрыт прямой доступ к панели администрирования. + +Чтобы открыть панель локально на своей машине, можно установить SSH-туннель: + +```sh +ssh -L 8080:localhost:8080 root@srvvw01.nstart.local +``` + +и в браузер открыть + +## Резервное копирование + +Резервная копия упаковывает в **.tar.gz.**: + +- всего именованного volume **vaultwarden-data** +- секретов + +По умолчанию резервное копирование делается каждый день в 3 часа ночи. +Сохраняются последние 30 копий. + +Результаты резервного копирования хранятся в именованном volume +**vaultwarden-backup**. + +Для изменения времени и частоты и расписания резервного копирования необходимо +поправить файл **backup/crontab**. + +> ВНИМАНИЕ!!!!! Отправку резервных копий на удаленный сервер необходимо +настраивать сторонними средствами. + +В качестве планировщика используется Supercronic — специализированный +планировщик для контейнеров, не требующий дополнительных прав. diff --git a/backup/Dockerfile b/backup/Dockerfile new file mode 100644 index 0000000..23a2915 --- /dev/null +++ b/backup/Dockerfile @@ -0,0 +1,12 @@ +ARG BASE_REPO="repo.nstart.local/" +FROM ${BASE_REPO}library/alpine:3.22.1 + +LABEL org.opencontainers.image.title="VaultWarden backup" \ + org.opencontainers.image.description="Supercronic VaultWarden backup." + +RUN apk add --no-cache supercronic tar + +COPY --chmod=0755 backup.sh /usr/local/bin/backup.sh +COPY --chmod=0644 crontab /etc/supercronic/crontab + +CMD ["/usr/bin/supercronic", "/etc/supercronic/crontab"] diff --git a/backup/backup.sh b/backup/backup.sh new file mode 100644 index 0000000..f67b3e7 --- /dev/null +++ b/backup/backup.sh @@ -0,0 +1,11 @@ +#!/bin/sh +set -euo pipefail + +find /backup -type f -name 'vaultwarden-*.tar.gz' -mtime +30 -print -delete + +TIMESTAMP=$(date +'%Y%m%d_%H%M') +DEST="/backup/vaultwarden-${TIMESTAMP}.tar.gz" + +tar czf "$DEST" -C /data . + +echo "[backup] Created $DEST" diff --git a/backup/crontab b/backup/crontab new file mode 100644 index 0000000..fabec4b --- /dev/null +++ b/backup/crontab @@ -0,0 +1,2 @@ +# Ежедневный запуск в 03:00 +0 3 * * * /usr/local/bin/backup.sh >> /var/log/cron.log 2>&1 diff --git a/dist/.gitkeep b/dist/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docker-bake.hcl b/docker-bake.hcl new file mode 100644 index 0000000..898715c --- /dev/null +++ b/docker-bake.hcl @@ -0,0 +1,62 @@ +variable "registry" { + default = "repo.nstart.local" +} + +variable "base_repo" { + default = "repo.nstart.local/" +} + +variable "VERSION" { + default = "1.0.1" +} + +function "oci_labels" { + params = [name] + result = { + "org.opencontainers.image.version" = VERSION, + "org.opencontainers.image.vendor" = "New Start", + "org.opencontainers.image.authors" = "Sychev Nikita ", + } +} + +function "image_ref" { + params = [name] + result = registry != "" ? "${registry}/nstart/vaultwarden-${name}" : "nstart/vaultwarden-${name}" +} + +target "image" { + name = combo.image + + matrix = { + combo = [ + { image = "server" }, + { image = "backup" }, + { image = "proxy" } + ] + } + + platforms = ["linux/amd64"] + output = ["type=image"] + attest = [ + "type=sbom,generator=${registry}/docker/buildkit-syft-scanner:stable-1", + "type=provenance,mode=max" + ] + + context = combo.image + dockerfile = "Dockerfile" + + args = { + BASE_REPO = base_repo + } + + tags = [ + "${image_ref(combo.image)}:${VERSION}", + "${image_ref(combo.image)}:latest", + ] + + labels = oci_labels(combo.image) +} + +group "all" { + targets = ["image"] +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cfcd6b7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,53 @@ +services: + vaultwarden: + image: repo.nstart.local/nstart/vaultwarden-server:1.0.1 + container_name: vaultwarden-server + restart: unless-stopped + env_file: + - ./secrets/vw_admin_token.txt + - ./secrets/vw_sso_secret.txt + volumes: + - vaultwarden-data:/data + networks: + - vaultwarden + + proxy: + image: repo.nstart.local/nstart/vaultwarden-proxy:1.0.1 + container_name: vaultwarden-proxy + restart: unless-stopped + depends_on: + vaultwarden: + condition: service_healthy + ports: + - 8080:8080 + networks: + - vaultwarden + + backup: + image: repo.nstart.local/nstart/vaultwarden-backup:1.0.1 + container_name: vaultwarden-backup + restart: unless-stopped + depends_on: + vaultwarden: + condition: service_healthy + volumes: + - vaultwarden-backup:/backup + - vaultwarden-data:/data/vaultwarden:ro + - ./secrets:/data/secrets:ro + networks: + - vaultwarden + +volumes: + vaultwarden-data: + name: vaultwarden-data + vaultwarden-backup: + name: vaultwarden-backup + +networks: + vaultwarden: + driver: bridge + name: vaultwarden + ipam: + driver: default + config: + - subnet: 172.30.0.0/24 diff --git a/proxy/Dockerfile b/proxy/Dockerfile new file mode 100644 index 0000000..329826f --- /dev/null +++ b/proxy/Dockerfile @@ -0,0 +1,13 @@ +ARG BASE_REPO="repo.nstart.local/" +FROM ${BASE_REPO}library/nginx:1.29.1-alpine + +LABEL org.opencontainers.image.title="VaultWarden proxy" \ + org.opencontainers.image.description="NGINX VaultWarden proxy." + +COPY vaultwarden.conf /etc/nginx/conf.d/ + +HEALTHCHECK --interval=30s --timeout=3s CMD nginx -t || exit 1 + +EXPOSE 8080 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/proxy/vaultwarden.conf b/proxy/vaultwarden.conf new file mode 100644 index 0000000..4d4a469 --- /dev/null +++ b/proxy/vaultwarden.conf @@ -0,0 +1,33 @@ +upstream vaultwarden_upstream { + server vaultwarden-server:80; + keepalive 2; +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' ""; +} + +server { + listen 8080; + server_name _; + + client_max_body_size 525M; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + location /admin { + allow 172.30.0.0/24; + deny all; + proxy_pass http://vaultwarden_upstream; + } + + location / { + proxy_pass http://vaultwarden_upstream; + } +} diff --git a/secrets/.gitkeep b/secrets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 0000000..2725b22 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,11 @@ +ARG BASE_REPO="repo.nstart.local/" +FROM ${BASE_REPO}vaultwarden/server:testing-alpine + +LABEL org.opencontainers.image.title="VaultWarden server" \ + org.opencontainers.image.description="NStart VaultWarden server." + +COPY config.json /data/config.json + +HEALTHCHECK --interval=15s --timeout=10s CMD /healthcheck.sh || exit 1 + +CMD ["/start.sh"] diff --git a/server/config.json b/server/config.json new file mode 100644 index 0000000..0f1c4c8 --- /dev/null +++ b/server/config.json @@ -0,0 +1,59 @@ +{ + "domain": "https://vaultwarden.nstart.local", + "sends_allowed": true, + "incomplete_2fa_time_limit": 3, + "disable_icon_download": true, + "signups_allowed": false, + "signups_verify": false, + "signups_verify_resend_time": 3600, + "signups_verify_resend_limit": 6, + "invitations_allowed": false, + "emergency_access_allowed": false, + "email_change_allowed": false, + "password_iterations": 600000, + "password_hints_allowed": false, + "show_password_hint": false, + "invitation_org_name": "АО Новый Старт", + "ip_header": "X-Forwarded-For", + "icon_redirect_code": 302, + "icon_cache_ttl": 0, + "icon_cache_negttl": 259200, + "icon_download_timeout": 10, + "http_request_block_non_global_ips": true, + "disable_2fa_remember": true, + "authenticator_disable_time_drift": false, + "require_device_email": false, + "reload_templates": false, + "log_timestamp_format": "%Y-%m-%d %H:%M:%S.%3f", + "admin_session_lifetime": 20, + "increase_note_size_limit": false, + "sso_enabled": true, + "sso_only": true, + "sso_client_id": "vaultwarden", + "sso_authority": "https://auth.nstart.space/realms/nstart", + "sso_signups_match_email": true, + "sso_allow_unknown_email_verification": false, + "sso_scopes": "openid email profile", + "sso_pkce": true, + "sso_callback_path": "/identity/connect/oidc-signin", + "sso_auth_only_not_session": false, + "sso_client_cache_expiration": 0, + "sso_debug_tokens": false, + "_enable_yubico": false, + "_enable_duo": false, + "_enable_smtp": false, + "use_sendmail": false, + "smtp_security": "starttls", + "smtp_port": 587, + "smtp_from_name": "Vaultwarden", + "smtp_timeout": 15, + "smtp_embed_images": true, + "smtp_accept_invalid_certs": false, + "smtp_accept_invalid_hostnames": false, + "_enable_email_2fa": false, + "email_token_size": 6, + "email_expiration_time": 600, + "email_attempts_limit": 3, + "email_2fa_enforce_on_verified_invite": false, + "email_2fa_auto_fallback": false +}