From 7ad415f7fb41a4b47b9ce83c37074d980367fc2d Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sat, 30 Apr 2022 12:55:26 +0200 Subject: [PATCH] hswaw/paperless: initial deployment Change-Id: Ie6fb0df0bfa047e4fd561c6de8b26ab0fbebbcb8 Reviewed-on: https://gerrit.hackerspace.pl/c/hscloud/+/1305 Reviewed-by: q3k --- hswaw/paperless/Dockerfile | 15 +++ hswaw/paperless/paperless.libsonnet | 188 ++++++++++++++++++++++++++++ hswaw/paperless/prod.jsonnet | 5 + 3 files changed, 208 insertions(+) create mode 100644 hswaw/paperless/Dockerfile create mode 100644 hswaw/paperless/paperless.libsonnet create mode 100644 hswaw/paperless/prod.jsonnet diff --git a/hswaw/paperless/Dockerfile b/hswaw/paperless/Dockerfile new file mode 100644 index 00000000..af9a3ee8 --- /dev/null +++ b/hswaw/paperless/Dockerfile @@ -0,0 +1,15 @@ +# Note: this is required to run the container as non-root. + +# Update: +# export VERSION=1.7.0 +# docker build --build-arg VERSION -t registry.k0.hswaw.net/informatic/paperless-ngx:$VERSION . +# docker push registry.k0.hswaw.net/informatic/paperless-ngx:$VERSION + +ARG VERSION=1.7.0 +FROM ghcr.io/paperless-ngx/paperless-ngx:${VERSION} + +# Install polish tesseract training data +RUN apt-get update && apt-get install -y tesseract-ocr-pol && rm -rf /var/lib/apt/lists/* + +# Remove privilege dropping and use paperless user directly everywhere +RUN sed -i 's/gosu paperless//g' /sbin/docker-entrypoint.sh && sed -i -e 's;user=.*;;g' -e 's;logfile=/var/.*;logfile=/dev/null;g' /etc/supervisord.conf diff --git a/hswaw/paperless/paperless.libsonnet b/hswaw/paperless/paperless.libsonnet new file mode 100644 index 00000000..bed51e97 --- /dev/null +++ b/hswaw/paperless/paperless.libsonnet @@ -0,0 +1,188 @@ +# kubectl -n paperless create secret generic paperless-proxy --from-literal=cookie_secret=$(pwgen 32 1) --from-literal=oidc_secret=... +# kubectl -n paperless create secret generic paperless --from-literal=postgres_password=$(pwgen 32 1) --from-literal=redis_password=$(pwgen 32 1) --from-literal=secret_key=$(pwgen 32 1) + +# There is no way of handling superusers (Admin panel access) automatically when +# using OAuth2-Proxy, thus we need to run the following command to mark the +# first user as such: +# kubectl -n paperless exec -it deploy/paperless -c paperless -- python ./manage.py shell -c "from django.contrib.auth.models import User; u = User.objects.get_by_natural_key('informatic'); u.is_superuser = True; u.is_staff = True; u.save()" + +local kube = import "../../kube/kube.libsonnet"; +local postgres = import "../../kube/postgres.libsonnet"; +local redis = import "../../kube/redis.libsonnet"; + +{ + local app = self, + local cfg = self.cfg, + + cfg:: { + namespace: "paperless", + domain: "paperless.hackerspace.pl", + + images: { + paperless: "registry.k0.hswaw.net/informatic/paperless-ngx@sha256:78b17e3050f7edea1e8c659c433ebcb6365bb93280a2698e3322075f988b1f41", + proxy: "quay.io/oauth2-proxy/oauth2-proxy:v7.2.1", + }, + + storageClassName: "waw-hdd-redundant-3", + }, + + ns: kube.Namespace(cfg.namespace), + + redis: redis { + cfg+: { + namespace: cfg.namespace, + storageClassName: cfg.storageClassName, + appName: "paperless", + image: "redis:6.0", + password: { secretKeyRef: { name: "paperless", key: "redis_password" } }, + }, + }, + + postgres: postgres { + cfg+: { + namespace: cfg.namespace, + appName: "paperless", + database: "paperless", + username: "paperless", + + password: { secretKeyRef: { name: "paperless", key: "postgres_password" } }, + storageClassName: cfg.storageClassName, + storageSize: "20Gi", + }, + bouncer: {}, + }, + + dataVolume: app.ns.Contain(kube.PersistentVolumeClaim("paperless-data")) { + spec+: { + storageClassName: cfg.storageClassName, + accessModes: [ "ReadWriteOnce" ], + resources: { + requests: { + storage: "100Gi", + }, + }, + }, + }, + + deploy: app.ns.Contain(kube.Deployment("paperless")) { + spec+: { + replicas: 1, + template+: { + spec+: { + volumes_: { + data: kube.PersistentVolumeClaimVolume(app.dataVolume), + }, + + securityContext: { + runAsUser: 1000, + runAsGroup: 1000, + fsGroup: 1000, + }, + + default_container:: "auth", + containers_: { + auth: kube.Container("authproxy") { + image: cfg.images.proxy, + ports_: { + http: { containerPort: 8001 }, + }, + + env_: { + OAUTH2_PROXY_UPSTREAMS: "http://127.0.0.1:8000", + OAUTH2_PROXY_HTTP_ADDRESS: "0.0.0.0:8001", + + OAUTH2_PROXY_COOKIE_SECRET: { secretKeyRef: { name: "paperless-proxy", key: "cookie_secret" } }, + + OAUTH2_PROXY_PROVIDER: "oidc", + OAUTH2_PROXY_OIDC_ISSUER_URL: "https://sso.hackerspace.pl", + OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: "true", + + OAUTH2_PROXY_CLIENT_ID: "b4859334-140b-432a-81f6-8f3e135e021a", + OAUTH2_PROXY_CLIENT_SECRET: { secretKeyRef: { name: "paperless-proxy", key: "oidc_secret" } }, + + OAUTH2_PROXY_EMAIL_DOMAINS: "*", + OAUTH2_PROXY_ALLOWED_GROUPS: "zarzad", + + # Security considerations: + # + # * OAuth2-Proxy *will* strip X-Forwarded-User + # header from requests passed through to + # endpoint, preventing authentication bypass + # + # * OAuth2-Proxy *will not* strip Authorization + # header - that can either be a user token, + # or a username/password pair. Former can only + # be generated by staff/superuser in Admin + # panel, and the latter will not work for our + # OAuth2 autogenerated users since these do + # not have any password set + OAUTH2_PROXY_SKIP_AUTH_ROUTES: "^/api/.*", + }, + }, + + paperless: kube.Container("paperless") { + image: cfg.images.paperless, + resources: { + requests: { cpu: "500m", memory: "1024M" }, + limits: { cpu: "4", memory: "6144M" }, + }, + env_: { + PAPERLESS_PORT: "8000", + + PAPERLESS_SECRET_KEY: { secretKeyRef: { name: "paperless", key: "secret_key" } }, + + A_REDIS_PASSWORD: app.redis.cfg.password, + PAPERLESS_REDIS: "redis://:$(A_REDIS_PASSWORD)@redis:6379", + + PAPERLESS_DBHOST: "postgres", + PAPERLESS_DBNAME: app.postgres.cfg.database, + PAPERLESS_DBUSER: app.postgres.cfg.username, + PAPERLESS_DBPASS: app.postgres.cfg.password, + + PAPERLESS_ENABLE_HTTP_REMOTE_USER: "true", + PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME: "HTTP_X_FORWARDED_USER", + + PAPERLESS_OCR_LANGUAGE: "pol", + PAPERLESS_OCR_MODE: "force", + PAPERLESS_DATE_ORDER: "YMD", + }, + + volumeMounts: [ + { name: "data", mountPath: "/usr/src/paperless/data", subPath: "data" }, + { name: "data", mountPath: "/usr/src/paperless/media", subPath: "media" }, + { name: "data", mountPath: "/usr/src/paperless/consume", subPath: "consume" }, + ], + }, + }, + }, + }, + }, + }, + + service: app.ns.Contain(kube.Service("paperless")) { + target_pod:: app.deploy.spec.template, + }, + + ingress: app.ns.Contain(kube.Ingress("paperless")) { + metadata+: { + annotations+: { + "kubernetes.io/tls-acme": "true", + "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod", + "nginx.ingress.kubernetes.io/proxy-body-size": "0", + }, + }, + spec+: { + tls: [ { hosts: [ cfg.domain ], secretName: "paperless-tls" } ], + rules: [ + { + host: cfg.domain, + http: { + paths: [ + { path: "/", backend: app.service.name_port }, + ], + }, + }, + ], + }, + } +} diff --git a/hswaw/paperless/prod.jsonnet b/hswaw/paperless/prod.jsonnet new file mode 100644 index 00000000..84508361 --- /dev/null +++ b/hswaw/paperless/prod.jsonnet @@ -0,0 +1,5 @@ +local paperless = import "./paperless.libsonnet"; + +{ + prod: paperless {}, +}