diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..18e6153 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,145 @@ +# build 0 +labels: + hostname: "macmini7" +clone: + git: + image: woodpeckerci/plugin-git + settings: + partial: false + depth: 1 +steps: + # Build Step for staging Branch + build-staging: + name: build-staging + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Building application for staging branch" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose build + - docker compose -f docker-compose.staging.yml build --no-cache + when: + branch: main + event: push + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + deploy-new: + name: deploy-new + when: + branch: main + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose push + - docker compose -f docker-compose.staging.yml push + # - docker stack deploy --with-registry-auth -c ./stack.staging.yml $${CI_REPO_NAME}-staging + + # # Wait for Deploy to Complete + # wait-for-deploy-staging: + # name: wait-for-deploy-staging + # image: woodpeckerci/plugin-git + # commands: + # - echo "Waiting for staging deploy step to complete rollout." + # - sleep 60 + # when: + # - branch: main + # - event: push + + # # Run Automated Tests on staging Branch + # test-staging: + # name: run-tests-staging + # image: git.nixc.us/colin/playwright:latest + # secrets: [ base_url ] + # when: + # - branch: main + # - event: push + # - path: + # include: [ 'tests/', 'src/','docker-compose.staging.yml', 'docker-compose.production.yml', '*.tests.ts' ] # Specify paths relevant to tests + # volumes: + # - /var/run/docker.sock:/var/run/docker.sock:ro + + cleanup-staging: + name: cleanup-staging + when: + branch: main + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + # - docker stack rm $${CI_REPO_NAME}-staging + ## added fault tolerance for docker stack rm + - for i in {1..5}; do docker stack rm ${CI_REPO_NAME}-staging && break || sleep 10; done + - docker compose -f docker-compose.staging.yml down + - docker compose -f docker-compose.staging.yml rm -f + + # Build Step for staging Branch + build-push-production: + name: build-push-production + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "Building application for staging branch" + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - echo compose build + - docker compose -f docker-compose.production.yml build --no-cache + - docker compose -f docker-compose.production.yml push + when: + branch: main + event: [push, cron] + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + # Deploy to Production Branch + deploy-production: + name: deploy-production + image: woodpeckerci/plugin-docker-buildx + secrets: [REGISTRY_USER, REGISTRY_PASSWORD, QBT_PASSWORD] + volumes: + - /var/run/docker.sock:/var/run/docker.sock + commands: + - echo "$${REGISTRY_PASSWORD}" | docker login -u "$${REGISTRY_USER}" --password-stdin git.nixc.us + - docker stack deploy --with-registry-auth -c ./stack.production.yml $${CI_REPO_NAME} + # - docker image rm git.nixc.us/colin/$${CI_REPO_NAME}:production + when: + branch: main + event: [push, cron] + # path: + # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] + + + # # Wait for Deploy to Complete + # wait-for-deploy-production: + # name: wait-for-deploy-production + # image: woodpeckerci/plugin-git + # commands: + # - echo "Waiting for deploy step to complete rollout." + # - sleep 60 + # when: + # branch: main + # event: push + + # # Run Post-Deployment Smoke Tests + # post-deploy-smoke-tests-git-nixc-us: + # name: run-post-deploy-smoke-tests-git-nixc-us + # image: git.nixc.us/colin/playwright:latest + # # secrets: [TEST_USER, TEST_PASSWORD] + # environment: + # - BASE_URL=https://git.nixc.us + # when: + # branch: main + # event: push + # # path: + # # include: [ 'stack.production.yml', 'stack.staging.yml', 'docker-compose.staging.yml', 'docker-compose.production.yml', 'Dockerfile', '*.tests.ts' ] \ No newline at end of file diff --git a/docker-compose.production.yml b/docker-compose.production.yml new file mode 100644 index 0000000..a7b127b --- /dev/null +++ b/docker-compose.production.yml @@ -0,0 +1,18 @@ +version: '3.8' + +services: + mariadb: + build: + context: ./docker/mariadb/ + dockerfile: Dockerfile.production + image: git.nixc.us/nixius/media:production-mariadb + redis: + build: + context: ./docker/redis/ + dockerfile: Dockerfile.production + image: git.nixc.us/nixius/media:production-redis + authelia: + build: + context: ./docker/authelia/ + dockerfile: Dockerfile.production + image: git.nixc.us/nixius/media:production-authelia \ No newline at end of file diff --git a/docker-compose.staging.yml b/docker-compose.staging.yml new file mode 100644 index 0000000..62d376f --- /dev/null +++ b/docker-compose.staging.yml @@ -0,0 +1,33 @@ +version: '3.8' + +services: + jellyfin: + build: + context: ./docker/jellyfin/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-jellyfin + qbt: + build: + context: ./docker/qbt/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-qbt + sonarr: + build: + context: ./docker/sonarr/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-sonarr + radarr: + build: + context: ./docker/radarr/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-radarr + jackett: + build: + context: ./docker/jackett/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-jackett + socks5: + build: + context: ./docker/socks5/ + dockerfile: Dockerfile + image: git.nixc.us/colin/media:staging-socks5 \ No newline at end of file diff --git a/docker/authelia/Dockerfile b/docker/authelia/Dockerfile new file mode 100644 index 0000000..e8c462f --- /dev/null +++ b/docker/authelia/Dockerfile @@ -0,0 +1,10 @@ +FROM authelia/authelia:4 + +COPY config/ /config/ + +CMD ["authelia", \ + "--config=/config/configuration.server.yml", \ + "--config=/config/configuration.ldap.yml", \ + "--config=/config/configuration.acl.yml", \ + "--config=/config/configuration.identity.providers.yml", \ + "--config=/config/configuration.oidc.clients.yml"] diff --git a/docker/authelia/Dockerfile.production b/docker/authelia/Dockerfile.production new file mode 100644 index 0000000..6e84c56 --- /dev/null +++ b/docker/authelia/Dockerfile.production @@ -0,0 +1 @@ +FROM git.nixc.us/nixius/authelia:staging-authelia \ No newline at end of file diff --git a/docker/authelia/config/configuration.acl.yml b/docker/authelia/config/configuration.acl.yml new file mode 100644 index 0000000..3e41bc0 --- /dev/null +++ b/docker/authelia/config/configuration.acl.yml @@ -0,0 +1,24 @@ +access_control: + default_policy: deny + rules: + + # Allow free access from local network + - domain: "*.{{ env "TRAEFIK_DOMAIN" }}" + policy: bypass + networks: + - 192.168.0.0/16 + - 172.16.0.0/12 + - 10.0.0.0/8 + + # Put WAN Access rules here + - domain: {{ env "TRAEFIK_DOMAIN" }} + resources: + - "^/.well-known([/?].*)?$" + policy: bypass + + - domain: {{ env "TRAEFIK_DOMAIN" }} + subject: "group:admin" + policy: two_factor + + - domain: headscale.{{ env "TRAEFIK_DOMAIN" }} + policy: bypass \ No newline at end of file diff --git a/docker/authelia/config/configuration.identity.providers.yml b/docker/authelia/config/configuration.identity.providers.yml new file mode 100644 index 0000000..659924a --- /dev/null +++ b/docker/authelia/config/configuration.identity.providers.yml @@ -0,0 +1,19 @@ +identity_providers: + oidc: + lifespans: + access_token: 1h + authorize_code: 1m + id_token: 1h + refresh_token: 90m + enable_client_debug_messages: false + enforce_pkce: public_clients_only + cors: + endpoints: + - authorization + - token + - revocation + - introspection + - userinfo + allowed_origins: + - "*" + allowed_origins_from_client_redirect_uris: false \ No newline at end of file diff --git a/docker/authelia/config/configuration.ldap.yml b/docker/authelia/config/configuration.ldap.yml new file mode 100644 index 0000000..e69de29 diff --git a/docker/authelia/config/configuration.oidc.clients.yml b/docker/authelia/config/configuration.oidc.clients.yml new file mode 100644 index 0000000..a39db0c --- /dev/null +++ b/docker/authelia/config/configuration.oidc.clients.yml @@ -0,0 +1,32 @@ +identity_providers: + oidc: + hmac_secret: {{ secret "/config/secrets/IDENTITY_PROVIDERS_OIDC_HMAC_SECRET" }} + jwks: + - key: {{ secret "/config/secrets/IDENTITY_PROVIDERS_OIDC_JWKS_KEY" | mindent 10 "|" | msquote }} + + authorization_policies: + + headscale: + default_policy: deny + rules: + - policy: one_factor + subject: group:headscale +# To generate secrets: +# docker exec -it authelia authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + clients: + + - client_id: headscale + client_name: Headscale + client_secret: {{ secret "/config/secrets/CLIENT_SECRET_HEADSCALE" }} + public: false + authorization_policy: headscale + consent_mode: implicit + scopes: + - openid + - email + - profile + redirect_uris: + - https://headscale.{{ env "TRAEFIK_DOMAIN" }}/oidc/callback + - https://headscale.{{ env "TRAEFIK_DOMAIN" }}/admin/oidc/callback # headplane on same domain as headscale + # - https://headplane.{{ env "TRAEFIK_DOMAIN" }}/admin/oidc/callback # headplane on it's own domain + userinfo_signed_response_alg: none \ No newline at end of file diff --git a/docker/authelia/config/configuration.server.yml b/docker/authelia/config/configuration.server.yml new file mode 100644 index 0000000..e69de29 diff --git a/docker/mariadb/Dockerfile b/docker/mariadb/Dockerfile new file mode 100644 index 0000000..f0169e9 --- /dev/null +++ b/docker/mariadb/Dockerfile @@ -0,0 +1 @@ +FROM mariadb:latest \ No newline at end of file diff --git a/docker/mariadb/Dockerfile.production b/docker/mariadb/Dockerfile.production new file mode 100644 index 0000000..cd71573 --- /dev/null +++ b/docker/mariadb/Dockerfile.production @@ -0,0 +1 @@ +FROM git.nixc.us/nixius/authelia:staging-mariadb \ No newline at end of file diff --git a/docker/redis/Dockerfile b/docker/redis/Dockerfile new file mode 100644 index 0000000..94c1dec --- /dev/null +++ b/docker/redis/Dockerfile @@ -0,0 +1 @@ +FROM ghcr.io/microsoft/garnet \ No newline at end of file diff --git a/docker/redis/Dockerfile.production b/docker/redis/Dockerfile.production new file mode 100644 index 0000000..89c2b55 --- /dev/null +++ b/docker/redis/Dockerfile.production @@ -0,0 +1 @@ +FROM git.nixc.us/nixius/authelia:staging-redis \ No newline at end of file diff --git a/pullup.sh b/pullup.sh new file mode 100755 index 0000000..3755618 --- /dev/null +++ b/pullup.sh @@ -0,0 +1,31 @@ +#!/bin/bash +commit_message=${1:-"pullup"} + +update_submodule() { + local submodule_path="$1" + if [ -d "$submodule_path" ]; then + echo "Updating submodule: $submodule_path" + cd "$submodule_path" || return + git checkout main + git pull origin main + cd - || return + else + echo "Submodule path $submodule_path does not exist." + fi +} + +# Update submodules ./.woodpecker/ and ./secrets/ +update_submodule "./.woodpecker" +update_submodule "./secrets" + +# Add changes to the staging area +git add . + +# Commit changes with a custom message, if provided, or a default message +commit_message=${1:-"pullup"} +git commit -m "$commit_message" + +# Push changes to the remote repository +git push + +echo "Submodules are updated and changes are pushed to the main repository." diff --git a/secrets b/secrets index 8ecec76..cdf31e6 160000 --- a/secrets +++ b/secrets @@ -1 +1 @@ -Subproject commit 8ecec767c117ec3b03d52fcfeba3602ced4cb6df +Subproject commit cdf31e6df66fbb0e6d2b2497845dc32ac2f17bad diff --git a/secrets.sh b/secrets.sh new file mode 100644 index 0000000..e69de29 diff --git a/stack.production.yml b/stack.production.yml new file mode 100644 index 0000000..911b7f1 --- /dev/null +++ b/stack.production.yml @@ -0,0 +1,106 @@ +version: '3.7' +x-authelia-env: &authelia-env + X_AUTHELIA_EMAIL: authelia@nixc.us + X_AUTHELIA_SITE_NAME: ATLAS + # X_AUTHELIA_DUO_HOSTNAME: my_duo_hostname + X_AUTHELIA_CONFIG_FILTERS: template + X_AUTHELIA_LDAP_DOMAIN: dc=nixc,dc=us + TRAEFIK_DOMAIN: nixc.us + # CONFIG: /home/deleted-porcupine/docker-configs + +networks: + default: + driver: overlay + traefik: + external: true + ad: + external: true +services: + authelia: + image: git.nixc.us/nixius/authelia:production-authelia + command: + - "authelia" + - "--config=/config/configuration.server.yml" + - "--config=/config/configuration.ldap.yml" + - "--config=/config/configuration.acl.yml" + - "--config=/config/configuration.identity.providers.yml" + - "--config=/config/configuration.oidc.clients.yml" + environment: + <<: *authelia-env + volumes: + - /mnt/tank/persist/nixc.us/authelia/production/config/db.sqlite3:/config/db.sqlite3 + networks: + - traefik + - default + - ad + deploy: + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true + labels: + - "us.nixc.autodeploy=true" + - 'traefik.enable=true' + - 'traefik.http.routers.production-authelia_authelia.tls=true' + - "traefik.http.services.production-authelia_authelia.loadbalancer.server.port=9091" + - 'traefik.http.routers.production-authelia_authelia.rule=Host(`login.nixc.us`)' + - 'traefik.http.routers.production-authelia_authelia.entrypoints=websecure' + - "traefik.http.routers.production-authelia_authelia.tls.certresolver=letsencryptresolver" + - "traefik.http.routers.production-authelia_authelia.service=authelia_authelia" + - "traefik.docker.network=traefik" + ## Authelia recommendations + - 'traefik.http.middlewares.production-authelia_authelia.forwardauth.address=http://authelia_authelia:9091/api/verify?rd=https://login.nixc.us/' + - 'traefik.http.middlewares.production-authelia_authelia.forwardauth.trustForwardHeader=true' + - 'traefik.http.middlewares.production-authelia_authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' + - 'traefik.http.middlewares.production-authelia-basic.forwardauth.address=http://authelia_authelia:9091/api/verify?auth=basic' + - 'traefik.http.middlewares.production-authelia-basic.forwardauth.trustForwardHeader=true' + - 'traefik.http.middlewares.production-authelia-basic.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' + + redis: + image: git.nixc.us/nixius/authelia:production-redis + # command: redis-server --appendonly yes + deploy: + replicas: 1 + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true +# preferences: +# - spread: node.id + labels: + - traefik.enable=false + - "us.nixc.autodeploy=true" + volumes: + - /mnt/tank/persist/nixc.us/authelia/production/redis:/data + networks: + - default + + mariadb: + image: git.nixc.us/nixius/authelia:production-mariadb + # restart: always + environment: + MYSQL_ROOT_PASSWORD: authelia + MYSQL_DATABASE: authelia + MYSQL_USER: authelia + MYSQL_PASSWORD: authelia + volumes: + - '/mnt/tank/persist/nixc.us/authelia/production/db:/var/lib/mysql' + deploy: + replicas: 1 + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true + # placement: + # constraints: + # - node.role == manager + # preferences: + # - spread: node.id + labels: + - traefik.enable=false + - "us.nixc.autodeploy=true" + networks: + - default diff --git a/stack.staging.yml b/stack.staging.yml new file mode 100644 index 0000000..145f081 --- /dev/null +++ b/stack.staging.yml @@ -0,0 +1,107 @@ +version: '3.7' +x-authelia-env: &authelia-env + X_AUTHELIA_EMAIL: authelia@nixc.us + X_AUTHELIA_SITE_NAME: ATLAS + # X_AUTHELIA_DUO_HOSTNAME: my_duo_hostname + X_AUTHELIA_CONFIG_FILTERS: template + X_AUTHELIA_LDAP_DOMAIN: dc=nixc,dc=us + TRAEFIK_DOMAIN: nixc.us + # CONFIG: /home/deleted-porcupine/docker-configs + +networks: + default: + driver: overlay + traefik: + external: true + ad: + external: true +services: + authelia: + image: git.nixc.us/nixius/authelia:staging-authelia + command: + - "authelia" + - "--config=/config/configuration.server.yml" + - "--config=/config/configuration.ldap.yml" + - "--config=/config/configuration.acl.yml" + - "--config=/config/configuration.identity.providers.yml" + - "--config=/config/configuration.oidc.clients.yml" + environment: + <<: *authelia-env + # volumes: + # - /mnt/tank/persist/nixc.us/authelia/staging/config:/config + networks: + - traefik + - default + - ad + deploy: + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true + labels: + - "us.nixc.autodeploy=true" + ## https://www.staging-authelia_authelia.com/docs/deployment/supported-proxies/traefik2.x.html + - 'traefik.enable=true' + - 'traefik.http.routers.staging-authelia_authelia.tls=true' + - "traefik.http.services.staging-authelia_authelia.loadbalancer.server.port=9091" + - 'traefik.http.routers.staging-authelia_authelia.rule=Host(`staging.login.nixc.us`)' + - 'traefik.http.routers.staging-authelia_authelia.entrypoints=websecure' + - "traefik.http.routers.staging-authelia_authelia.tls.certresolver=letsencryptresolver" + - "traefik.http.routers.staging-authelia_authelia.service=authelia_authelia" + - "traefik.docker.network=traefik" +## Authelia recommendations + - 'traefik.http.middlewares.staging-authelia_authelia.forwardauth.address=http://authelia_authelia:9091/api/verify?rd=https://login.nixc.us/' + - 'traefik.http.middlewares.staging-authelia_authelia.forwardauth.trustForwardHeader=true' + - 'traefik.http.middlewares.staging-authelia_authelia.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' + - 'traefik.http.middlewares.staging-authelia-basic.forwardauth.address=http://authelia_authelia:9091/api/verify?auth=basic' + - 'traefik.http.middlewares.staging-authelia-basic.forwardauth.trustForwardHeader=true' + - 'traefik.http.middlewares.staging-authelia-basic.forwardauth.authResponseHeaders=Remote-User, Remote-Groups, Remote-Name, Remote-Email' + + redis: + image: git.nixc.us/nixius/authelia:staging-redis + # command: redis-server --appendonly yes + deploy: + replicas: 1 + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true +# preferences: +# - spread: node.id + labels: + - traefik.enable=false + - "us.nixc.autodeploy=true" + volumes: + - /mnt/tank/persist/nixc.us/authelia/staging/redis:/data + networks: + - default + + mariadb: + image: git.nixc.us/nixius/authelia:staging-mariadb + # restart: always + environment: + MYSQL_ROOT_PASSWORD: authelia + MYSQL_DATABASE: authelia + MYSQL_USER: authelia + MYSQL_PASSWORD: authelia + volumes: + - '/mnt/tank/persist/nixc.us/authelia/staging/db:/var/lib/mysql' + deploy: + replicas: 1 + placement: + constraints: +## - node.labels.role == db + - node.hostname == ingress.nixc.us +# - node.labels.mac-rack == true + # placement: + # constraints: + # - node.role == manager + # preferences: + # - spread: node.id + labels: + - traefik.enable=false + - "us.nixc.autodeploy=true" + networks: + - default