Compare commits
24
Commits
927b5b4934
...
66bcca1858
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66bcca1858 | ||
|
|
99536c5355 | ||
|
|
9226043696 | ||
|
|
ea8dfc8c20 | ||
|
|
8bf9d92f7b | ||
|
|
56fb5716b5 | ||
|
|
ada7e751d8 | ||
|
|
fe2357ddb2 | ||
|
|
5525f7cf85 | ||
|
|
3a38271969 | ||
|
|
e0df8cfba5 | ||
|
|
3c8469e604 | ||
|
|
88e85fff56 | ||
|
|
5ccb60bd2a | ||
|
|
a49cdcb9d1 | ||
|
|
a2334bb236 | ||
|
|
fb2578d28a | ||
|
|
24e4e863fa | ||
|
|
b499fcb78a | ||
|
|
47d437375b | ||
|
|
278054a65f | ||
|
|
d6250d90c9 | ||
|
|
4a20a556b0 | ||
|
|
fe146b25c7 |
@@ -7,4 +7,5 @@ data/vmm_init/*
|
||||
*.qcow2
|
||||
*.sql
|
||||
*.iso
|
||||
*.git_bak
|
||||
!.gitkeep
|
||||
|
||||
@@ -15,37 +15,107 @@ domain:
|
||||
dc: "dc=ilnmors,dc=internal"
|
||||
org: "ilnmors"
|
||||
|
||||
# DNS configuration including bind and blocky should be set manually.
|
||||
# named.conf.j2 is also set manually.
|
||||
# Check the hosts.j2 when cname records are fixed
|
||||
|
||||
services:
|
||||
# common
|
||||
wireguard:
|
||||
domain:
|
||||
public: "vpn"
|
||||
ports:
|
||||
udp: "11290"
|
||||
crowdsec:
|
||||
domain: "crowdsec"
|
||||
domain:
|
||||
internal: "crowdsec"
|
||||
ports:
|
||||
https: "8080"
|
||||
sub:
|
||||
machines:
|
||||
- "fw"
|
||||
- "vmm"
|
||||
- "bk"
|
||||
- "infra"
|
||||
- "auth"
|
||||
- "app"
|
||||
bouncers:
|
||||
- "fw"
|
||||
- "caddy"
|
||||
dependency:
|
||||
cert: true
|
||||
kopia:
|
||||
domain:
|
||||
internal: "kopia"
|
||||
ports:
|
||||
https: "51515"
|
||||
uid: "951"
|
||||
dependency:
|
||||
cert: true
|
||||
caddy:
|
||||
ports:
|
||||
http: "2080"
|
||||
https: "2443"
|
||||
# fw
|
||||
bind:
|
||||
domain: "bind"
|
||||
domain:
|
||||
internal: "bind"
|
||||
ports:
|
||||
dns: "53"
|
||||
blocky:
|
||||
domain: "blocky"
|
||||
domain:
|
||||
internal: "blocky"
|
||||
ports:
|
||||
https: "443"
|
||||
dns: "53"
|
||||
dot: "853"
|
||||
dependency:
|
||||
cert: true
|
||||
# infra
|
||||
rustfs:
|
||||
domain:
|
||||
internal: "rustfs"
|
||||
public: "rustfs"
|
||||
ports:
|
||||
http: "9001"
|
||||
subuid: "110000"
|
||||
dependency:
|
||||
web: "infra-public"
|
||||
postgresql:
|
||||
domain: "postgresql"
|
||||
domain:
|
||||
internal: "postgresql"
|
||||
ports:
|
||||
tcp: "5432" # postgresql db connection port
|
||||
subuid: "100998"
|
||||
dependency:
|
||||
cert: true
|
||||
mariadb:
|
||||
domain:
|
||||
internal: "mariadb"
|
||||
ports:
|
||||
tcp: "3306" # mariadb db connection port
|
||||
subuid: "100998"
|
||||
dependency:
|
||||
cert: true
|
||||
ldap:
|
||||
domain: "ldap"
|
||||
domain:
|
||||
internal: "ldap"
|
||||
ports:
|
||||
http: "17170"
|
||||
ldaps: "6360"
|
||||
subuid: "100999"
|
||||
dependency:
|
||||
cert: true
|
||||
web: "infra-internal"
|
||||
db: "postgresql"
|
||||
maddy:
|
||||
domain:
|
||||
internal: "maddy"
|
||||
ports:
|
||||
smtp: "2587"
|
||||
imaps: "2993"
|
||||
dependency:
|
||||
cert: true
|
||||
db: "postgresql"
|
||||
ca:
|
||||
domain: "ca"
|
||||
domain:
|
||||
internal: "ca"
|
||||
ports:
|
||||
https: "9000"
|
||||
subuid: "100999"
|
||||
@@ -54,44 +124,157 @@ services:
|
||||
http: "9793"
|
||||
subuid: "165533"
|
||||
prometheus:
|
||||
domain: "prometheus"
|
||||
domain:
|
||||
internal: "prometheus"
|
||||
ports:
|
||||
https: "9090"
|
||||
subuid: "165533"
|
||||
dependency:
|
||||
cert: true
|
||||
web: "infra-internal"
|
||||
loki:
|
||||
domain: "loki"
|
||||
domain:
|
||||
internal: "loki"
|
||||
ports:
|
||||
https: "3100"
|
||||
subuid: "110000"
|
||||
dependency:
|
||||
cert: true
|
||||
grafana:
|
||||
domain: "grafana"
|
||||
domain:
|
||||
internal: "grafana"
|
||||
ports:
|
||||
http: "3000"
|
||||
http: "3000" # infra
|
||||
subuid: "100471"
|
||||
caddy:
|
||||
ports:
|
||||
http: "2080"
|
||||
https: "2443"
|
||||
nas:
|
||||
domain: "nas"
|
||||
ports:
|
||||
https: "5001"
|
||||
kopia:
|
||||
domain: "nas"
|
||||
ports:
|
||||
https: "51515"
|
||||
dependency:
|
||||
web: "infra-internal"
|
||||
db: "postgresql"
|
||||
# auth
|
||||
authelia:
|
||||
domain: "authelia"
|
||||
domain:
|
||||
public: "authelia"
|
||||
ports:
|
||||
http: "9091"
|
||||
dependency:
|
||||
web: "auth-public"
|
||||
db: "postgresql"
|
||||
# app
|
||||
redis:
|
||||
subuid: "100998"
|
||||
homepage:
|
||||
domain:
|
||||
public: "@"
|
||||
internal: "homepage.app"
|
||||
ports:
|
||||
http: "3000" # app
|
||||
dependency:
|
||||
web: "app-public"
|
||||
openwebui:
|
||||
domain:
|
||||
public: "openwebui"
|
||||
internal: "openwebui.app"
|
||||
ports:
|
||||
http: "8002"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
llama:
|
||||
ports:
|
||||
http: "10000"
|
||||
dependency:
|
||||
models:
|
||||
default: |
|
||||
n-gpu-layers = all
|
||||
kv-unified = true
|
||||
cache-prompt = true
|
||||
cache-type-k = q8_0
|
||||
cache-type-v = q8_0
|
||||
flash-attn = auto
|
||||
reasoning = off
|
||||
jinja = true
|
||||
lazy-mode = off
|
||||
Nemotron3.5-Lightning-30B-A3B: |
|
||||
model = /models/Nemotron3.5-Lightning-30B-A3B/Nemotron-3.5-Lightning-30B-A3B-Heretic-Uncensored-Q4_K_M-GGUF.gguf
|
||||
c = 65536
|
||||
parallel = 2
|
||||
load-on-startup = true
|
||||
# version: mradermacher/LFM2-24B-A2B-heretic-ara-GGUF
|
||||
# LFM2-24B-A2B: |
|
||||
# model = /models/LFM2-24B-A2B/LFM2-24B-A2B-heretic-ara.Q4_K_M.gguf
|
||||
# c = 65536
|
||||
# parallel = 2
|
||||
# load-on-startup = true
|
||||
# # version: SC117/LFM2.5-VL-3B-Uncensored-GGUF
|
||||
# LFM2-VL-3B: |
|
||||
# model = /models/LFM2-VL-3B/LFM2.5-VL-3B-Uncensored-Q4_K_M.gguf
|
||||
# mmproj = /models/LFM2-VL-3B/mmproj-LFM2.5-VL-3B-BF16.gguf
|
||||
# c = 65536
|
||||
# parallel = 1
|
||||
# load-on-startup = true
|
||||
# version: HauhauCS/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive-Q4_K_M
|
||||
# Qwen3.6: |
|
||||
# model = /models/Qwen3.6-35B-A3B/Qwen3.6-35B-A3B-Q4_K_M.gguf
|
||||
# mmproj = /models/Qwen3.6-35B-A3B/mmproj-Qwen3.6-35B-BF16.gguf
|
||||
# c = 65536
|
||||
# parallel = 2
|
||||
# load-on-startup = true
|
||||
# image-min-tokens = 1024
|
||||
# # version: HauhauCS/Qwen3.5-2B-Uncensored-HauhauCS-Aggressiv-Q8_0
|
||||
# Qwen3.5-image: |
|
||||
# model = /models/Qwen3.5-2B/Qwen3.5-2B-Q8_0.gguf
|
||||
# c = 32768
|
||||
# parallel = 1
|
||||
# load-on-startup = true
|
||||
# version: LiquidAI/LFM2.5-2.6B-GGUF
|
||||
# LFM2.5: |
|
||||
# model = /models/LFM2.5-2.6B/LFM2.5-2.6B-Q8_0.gguf
|
||||
# c = 32768
|
||||
# parallel = 2
|
||||
# load-on-startup = true
|
||||
stablediffusion:
|
||||
ports:
|
||||
http: "10001"
|
||||
dependency:
|
||||
models:
|
||||
active: "zImage"
|
||||
zImage: |
|
||||
--diffusion-model /models/zImage/moodyRealMix_zitV7Global-Q8_0.gguf \
|
||||
--llm /models/zImage/Qwen3-4B-Instruct-2507-Q4_K_M.gguf \
|
||||
--vae /models/zImage/ae.safetensors \
|
||||
--backend gpu \
|
||||
--cfg-scale 1.0 \
|
||||
--steps 9 \
|
||||
--vae-tiling \
|
||||
--vae-tile-size 32x32 \
|
||||
--vae-tile-overlap 0.5
|
||||
snappymail:
|
||||
domain:
|
||||
public: "webmail"
|
||||
internal: "webmail.app"
|
||||
ports:
|
||||
http: "8888"
|
||||
subuid: "100081"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
vaultwarden:
|
||||
domain:
|
||||
public: "vault"
|
||||
internal: "vault.app"
|
||||
ports:
|
||||
http: "8000"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
linkding:
|
||||
domain:
|
||||
public: "linkding"
|
||||
internal: "linkding.app"
|
||||
ports:
|
||||
http: "9090"
|
||||
subuid: "100032"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
gitea:
|
||||
domain:
|
||||
public: "gitea"
|
||||
@@ -99,32 +282,56 @@ services:
|
||||
ports:
|
||||
http: "3001"
|
||||
subuid: "100999"
|
||||
immich:
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
mastodon:
|
||||
domain:
|
||||
public: "immich"
|
||||
internal: "immich.app"
|
||||
public: "mastodon"
|
||||
internal: "mastodon.app"
|
||||
ports:
|
||||
http: "2283"
|
||||
http: "3002"
|
||||
api: "4000"
|
||||
redis: "6379"
|
||||
immich-ml:
|
||||
ports:
|
||||
http: "3003"
|
||||
paperless:
|
||||
subuid: "100990"
|
||||
route:
|
||||
api: "/api/v1/streaming*"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
groupoffice:
|
||||
domain:
|
||||
public: "paperless"
|
||||
internal: "paperless.app"
|
||||
public: "groupoffice"
|
||||
internal: "groupoffice.app"
|
||||
ports:
|
||||
http: "8001"
|
||||
redis: "6380"
|
||||
subuid: "100999"
|
||||
http: "8005"
|
||||
subuid: "100032"
|
||||
route:
|
||||
dav: true
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "mariadb"
|
||||
kaneo:
|
||||
domain:
|
||||
public: "kaneo"
|
||||
internal: "kaneo.app"
|
||||
ports:
|
||||
http: "8006"
|
||||
subuid: "101000"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
nextcloud:
|
||||
domain:
|
||||
public: "nextcloud"
|
||||
internal: "nextcloud.app"
|
||||
ports:
|
||||
http: "8002"
|
||||
redis: "6382"
|
||||
http: "8001"
|
||||
redis: "6380"
|
||||
subuid: "100032"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
collabora:
|
||||
domain:
|
||||
public: "collabora"
|
||||
@@ -132,70 +339,133 @@ services:
|
||||
ports:
|
||||
http: "9980"
|
||||
subuid: "101000"
|
||||
sure:
|
||||
dependency:
|
||||
web: "app-public"
|
||||
immich:
|
||||
domain:
|
||||
public: "sure"
|
||||
internal: "sure.app"
|
||||
public: "immich"
|
||||
internal: "immich.app"
|
||||
ports:
|
||||
http: "3002"
|
||||
redis: "6383"
|
||||
subuid: "100999"
|
||||
http: "2283"
|
||||
redis: "6381"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
immich-ml:
|
||||
ports:
|
||||
http: "3003"
|
||||
outline:
|
||||
domain:
|
||||
public: "outline"
|
||||
internal: "outline.app"
|
||||
ports:
|
||||
http: "3004"
|
||||
redis: "6384"
|
||||
redis: "6382"
|
||||
subuid: "101000"
|
||||
memos:
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
bookstack:
|
||||
domain:
|
||||
public: "memos"
|
||||
internal: "memos.app"
|
||||
public: "bookstack"
|
||||
internal: "bookstack.app"
|
||||
ports:
|
||||
http: "3005"
|
||||
subuid: "110000"
|
||||
mealie:
|
||||
http: "8004"
|
||||
subuid: "100032"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "mariadb"
|
||||
sure:
|
||||
domain:
|
||||
public: "mealie"
|
||||
internal: "mealie.app"
|
||||
public: "sure"
|
||||
internal: "sure.app"
|
||||
ports:
|
||||
http: "9001"
|
||||
subuid: "100910"
|
||||
http: "3006"
|
||||
redis: "6383"
|
||||
subuid: "100999"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
papra:
|
||||
domain:
|
||||
public: "papra"
|
||||
internal: "papra.app"
|
||||
ports:
|
||||
http: "1221"
|
||||
subuid: "100998"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
tandoor:
|
||||
domain:
|
||||
public: "tandoor"
|
||||
internal: "tandoor.app"
|
||||
ports:
|
||||
http: "8003"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
homebox:
|
||||
domain:
|
||||
public: "homebox"
|
||||
internal: "homebox.app"
|
||||
ports:
|
||||
http: "7745"
|
||||
dependency:
|
||||
web: "app-public"
|
||||
db: "postgresql"
|
||||
|
||||
version:
|
||||
packages:
|
||||
sops: "3.13.1"
|
||||
sops: "3.13.2"
|
||||
step: "0.30.2"
|
||||
kopia: "0.23.0"
|
||||
blocky: "0.29.0"
|
||||
alloy: "1.16.1"
|
||||
kopia: "0.23.1"
|
||||
blocky: "0.33.0"
|
||||
alloy: "1.17.1"
|
||||
containers:
|
||||
# common
|
||||
caddy: "2.11.4"
|
||||
# infra
|
||||
step: "0.30.2"
|
||||
ldap: "v0.6.3"
|
||||
x509-exporter: "4.1.0"
|
||||
prometheus: "v3.12.0"
|
||||
loki: "3.7.1"
|
||||
grafana: "13.0.1"
|
||||
rustfs: "1.0.0-rc.6"
|
||||
ca: "0.30.2"
|
||||
## Postgresql
|
||||
postgresql: "18.4"
|
||||
# For immich - https://github.com/immich-app/base-images/blob/main/postgres/versions.yaml
|
||||
# pgvector: "v0.8.1"
|
||||
postgresql: "18.6"
|
||||
## Mariadb
|
||||
mariadb: "12.3.3"
|
||||
### For immich - https://github.com/immich-app/base-images/blob/main/postgres/versions.yaml
|
||||
vectorchord: "1.1.1"
|
||||
## lldap
|
||||
ldap: "v0.6.3"
|
||||
## maddy
|
||||
maddy: "0.9.5"
|
||||
x509-exporter: "4.1.0"
|
||||
prometheus: "v3.14.0"
|
||||
loki: "3.7.7"
|
||||
grafana: "13.2.1"
|
||||
# Auth
|
||||
authelia: "4.39.20"
|
||||
# App
|
||||
vaultwarden: "1.36.0"
|
||||
gitea: "1.26.1"
|
||||
redis: "8.8.0"
|
||||
immich: "v2.7.5"
|
||||
paperless: "2.20.15"
|
||||
nextcloud: "33.0.5"
|
||||
collabora: "25.04.10.3.1"
|
||||
sure: "0.7.1"
|
||||
outline: "1.8.1"
|
||||
memos: "0.29.1"
|
||||
mealie: "v3.19.2"
|
||||
vaultwarden: "1.37.2"
|
||||
gitea: "1.27.3"
|
||||
redis: "8.10.1"
|
||||
immich: "v3.2.2"
|
||||
nextcloud: "34.0.3"
|
||||
collabora: "26.04.3.2.1"
|
||||
sure: "0.7.4"
|
||||
outline: "1.10.1"
|
||||
homebox: "0.26.2"
|
||||
homepage: "v2.0.0"
|
||||
snappymail: "v2.38.2"
|
||||
mastodon: "v4.6.7"
|
||||
papra: "26.6.1-rootless"
|
||||
tandoor: "2.6.13"
|
||||
bookstack: "26.5.4"
|
||||
linkding: "1.46.2"
|
||||
openwebui: "v0.11.3"
|
||||
# https://github.com/ggml-org/llama.cpp/pkgs/container/llama.cpp/versions
|
||||
llama: "server-vulkan-b10830"
|
||||
# https://github.com/leejet/stable-diffusion.cpp/pkgs/container/stable-diffusion.cpp
|
||||
# master-sycl@sha256:f27ebe3fea7dcb5978241425d3a115ba6736cfc33c42e75233f22f7411449e9c has problem in it, it cannot get vRAM from UMA properly
|
||||
# Pin due to a SYCL/UMA false-OOM regression in newer stable-diffusion.cpp ModelManager memory accounting.
|
||||
stablediffusion: "master-sycl@sha256:67ccb5d11bf55578f7938daeb7c9fee1d0dd1344c089c090b9065714d7960fd5"
|
||||
groupoffice: "26.0.43"
|
||||
kaneo: "2.23.2"
|
||||
|
||||
@@ -21,13 +21,51 @@ hardware:
|
||||
bus: "0x00"
|
||||
slot: "0x02"
|
||||
function: "0x0"
|
||||
hdd:
|
||||
disk:
|
||||
# NVMe is set when the hypervisor is initiated manually.
|
||||
nvme:
|
||||
serials:
|
||||
- "S5GXNX0T228635E"
|
||||
fs:
|
||||
type: "ext4"
|
||||
label: ""
|
||||
mount_point:
|
||||
- "/"
|
||||
- "/var/lib/libvirt"
|
||||
mount_opts: ""
|
||||
data:
|
||||
hdd0: "WMC6N0E617S8"
|
||||
hdd1: "P6HVTL0W"
|
||||
hdd2: "P2GH354H"
|
||||
hdd3: "P6GJKSMP"
|
||||
btrfs:
|
||||
label: "DATA"
|
||||
level: "raid10"
|
||||
mount_point: "{{ node['libvirt_path'] }}/data"
|
||||
serials:
|
||||
- "PN1138P2GH354H"
|
||||
- "PN2131P6GJKSMP"
|
||||
fs:
|
||||
type: "btrfs"
|
||||
label: "DATA"
|
||||
mount_point: "{{ node['libvirt_path'] }}/disk/data"
|
||||
mount_opts:
|
||||
- "defaults"
|
||||
- "noatime"
|
||||
- "nodatacow"
|
||||
- "degraded"
|
||||
- "nofail"
|
||||
btrfs:
|
||||
data_profile: "raid1"
|
||||
metadata_profile: "raid1"
|
||||
min_devices: 2
|
||||
backup:
|
||||
serials:
|
||||
- "PN1134P6HVTL0W"
|
||||
# Spare
|
||||
# - "WMC6N0E617S8"
|
||||
fs:
|
||||
type: "btrfs"
|
||||
label: "BACKUP"
|
||||
mount_point: "{{ node['libvirt_path'] }}/disk/backup"
|
||||
mount_opts:
|
||||
- "defaults"
|
||||
- "noatime"
|
||||
- "nodatacow"
|
||||
- "nofail"
|
||||
btrfs:
|
||||
data_profile: "single"
|
||||
metadata_profile: "dup"
|
||||
min_devices: 1
|
||||
|
||||
@@ -20,21 +20,12 @@ vm:
|
||||
<vcpupin vcpu='5' cpuset='11'/>
|
||||
<emulatorpin cpuset='10-11'/>
|
||||
shares: 1024
|
||||
memory: 16
|
||||
memory: 48
|
||||
storage: 256
|
||||
data_storage:
|
||||
name: "vdb"
|
||||
size: 3.5
|
||||
pool: "data"
|
||||
size: 1.75
|
||||
lan_mac: "0a:49:6e:4d:03:00"
|
||||
lan_net: "lan-net"
|
||||
lan_group: "vlan10-access"
|
||||
# PCIe passthrough address
|
||||
# result of `lspci | grep -i -e "sata controller" -e "vga"` and parse it.
|
||||
# Ex) 04:00.0 > domain: "0x0000", bus: "0x04", slot: "0x00", function: "0x0"
|
||||
pass_through:
|
||||
igpu:
|
||||
address: "0000:00:02.0"
|
||||
domain: "0x0000"
|
||||
bus: "0x00"
|
||||
slot: "0x02"
|
||||
function: "0x0"
|
||||
|
||||
@@ -12,12 +12,12 @@ vm:
|
||||
name: "auth"
|
||||
cpu: 2
|
||||
cpu_pin: |
|
||||
<vcpupin vcpu='0' cpuset='8'/>
|
||||
<vcpupin vcpu='1' cpuset='9'/>
|
||||
<emulatorpin cpuset='8-9'/>
|
||||
<vcpupin vcpu='0' cpuset='6'/>
|
||||
<vcpupin vcpu='1' cpuset='7'/>
|
||||
<emulatorpin cpuset='6-7'/>
|
||||
shares: 1024
|
||||
memory: 2
|
||||
storage: 64
|
||||
memory: 1
|
||||
storage: 32
|
||||
lan_mac: "0a:49:6e:4d:02:00"
|
||||
lan_net: "lan-net"
|
||||
lan_group: "vlan10-access"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# Node Factors
|
||||
node:
|
||||
name: "bk"
|
||||
group: "svadmins"
|
||||
uid: 2009
|
||||
home_path: "/home/bk"
|
||||
ssh_san: "{{ node['name'] }},{{ node['name'] }}.{{ domain['internal'] }}"
|
||||
local_san: "localhost {{ node['name'] }}.{{ domain['internal'] }}"
|
||||
# VM Factors
|
||||
vm:
|
||||
name: "bk"
|
||||
cpu: 2
|
||||
cpu_pin: |
|
||||
<vcpupin vcpu='0' cpuset='6'/>
|
||||
<vcpupin vcpu='1' cpuset='7'/>
|
||||
<emulatorpin cpuset='6-7'/>
|
||||
shares: 512
|
||||
memory: 2
|
||||
storage: 64
|
||||
data_storage:
|
||||
name: "vdb"
|
||||
pool: "backup"
|
||||
size: 1.75
|
||||
lan_mac: "0a:49:6e:4d:09:00"
|
||||
lan_net: "lan-net"
|
||||
lan_group: "vlan10-access"
|
||||
@@ -21,6 +21,6 @@ node:
|
||||
data_path: "{{ node['homelab_path'] }}/data"
|
||||
config_path: "{{ node['homelab_path'] }}/config"
|
||||
ssh_san: "{{ node['name'] }},{{ node['name'] }}.{{ domain['internal'] }}"
|
||||
ssh_users: "vmm,fw,infra,auth,app"
|
||||
ssh_users: "vmm,fw,bk,infra,auth,app"
|
||||
# add the hostname of wsl, it is needed to improve the sudo problem
|
||||
local_san: "localhost {{ node['name'] }} {{ node['name'] }}.{{ domain['internal'] }}"
|
||||
|
||||
@@ -28,75 +28,131 @@ vm:
|
||||
lan_group: "vlan-trunk"
|
||||
|
||||
# Network Factors
|
||||
# LLA is like MAC address for L3 (Network layer). Usually, subnet is used to separate network.
|
||||
network4:
|
||||
network:
|
||||
dns_serial: "{{ now().strftime('%Y%m%d') }}00"
|
||||
subnet:
|
||||
client: "192.168.1.0/24"
|
||||
server: "192.168.10.0/24"
|
||||
user: "192.168.20.0/24"
|
||||
wg: "192.168.99.0/24"
|
||||
lla: "169.254.0.0/16"
|
||||
# You can use "{{ hostvars['fw']['network4']['firewall'].values() | join(', ') }}" for all
|
||||
firewall:
|
||||
client: "192.168.1.1"
|
||||
server: "192.168.10.1"
|
||||
user: "192.168.20.1"
|
||||
wg: "192.168.99.1"
|
||||
ipv4:
|
||||
client: "192.168.1.0/24"
|
||||
server: "192.168.10.0/24"
|
||||
user: "192.168.20.0/24"
|
||||
wg: "192.168.99.0/24"
|
||||
lla: "169.254.0.0/16"
|
||||
ipv6:
|
||||
client: "fd00:1::/64"
|
||||
server: "fd00:10::/64"
|
||||
wg: "fd00:99::/64"
|
||||
lla: "fe80::/10"
|
||||
podman:
|
||||
ipv4:
|
||||
lla: "169.254.1.2"
|
||||
reverse_zone:
|
||||
ipv4:
|
||||
client: "1.168.192.in-addr.arpa"
|
||||
server: "10.168.192.in-addr.arpa"
|
||||
ipv6:
|
||||
client: "0.0.0.0.0.0.0.0.1.0.0.0.0.0.d.f.ip6.arpa"
|
||||
server: "0.0.0.0.0.0.0.0.0.1.0.0.0.0.d.f.ip6.arpa"
|
||||
fw:
|
||||
ipv4:
|
||||
client: "192.168.1.1"
|
||||
server: "192.168.10.1"
|
||||
user: "192.168.20.1"
|
||||
wg: "192.168.99.1"
|
||||
reverse: "1"
|
||||
ipv6:
|
||||
client: "fd00:1::1"
|
||||
server: "fd00:10::1"
|
||||
wg: "fd00:99::1"
|
||||
reverse: "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "ntp"
|
||||
- "crowdsec"
|
||||
blocky:
|
||||
server: "192.168.10.2"
|
||||
ipv4:
|
||||
server: "192.168.10.2"
|
||||
reverse: "2"
|
||||
ipv6:
|
||||
server: "fd00:10::2"
|
||||
reverse: "2.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
bind:
|
||||
server: "192.168.10.3"
|
||||
ipv4:
|
||||
server: "192.168.10.3"
|
||||
reverse: "3"
|
||||
ipv6:
|
||||
server: "fd00:10::3"
|
||||
reverse: "3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
console:
|
||||
client: "192.168.1.20"
|
||||
wg: "192.168.99.20"
|
||||
ipv4:
|
||||
client: "192.168.1.20"
|
||||
wg: "192.168.99.20"
|
||||
reverse: "20"
|
||||
ipv6:
|
||||
client: "fd00:1::20"
|
||||
wg: "fd00:99::20"
|
||||
reverse: "0.2.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
vmm:
|
||||
client: "192.168.1.10"
|
||||
server: "192.168.10.10"
|
||||
ipv4:
|
||||
client: "192.168.1.10"
|
||||
server: "192.168.10.10"
|
||||
reverse: "10"
|
||||
ipv6:
|
||||
client: "fd00:1::10"
|
||||
server: "fd00:10::10"
|
||||
reverse: "0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "init.vmm"
|
||||
bk:
|
||||
ipv4:
|
||||
server: "192.168.10.9"
|
||||
reverse: "9"
|
||||
ipv6:
|
||||
server: "fd00:10::9"
|
||||
reverse: "9.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "kopia"
|
||||
infra:
|
||||
server: "192.168.10.11"
|
||||
ipv4:
|
||||
server: "192.168.10.11"
|
||||
reverse: "11"
|
||||
ipv6:
|
||||
server: "fd00:10::11"
|
||||
reverse: "1.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "rustfs"
|
||||
- "ca"
|
||||
- "postgresql"
|
||||
- "mariadb"
|
||||
- "ldap"
|
||||
- "maddy"
|
||||
- "prometheus"
|
||||
- "loki"
|
||||
- "grafana"
|
||||
auth:
|
||||
server: "192.168.10.12"
|
||||
ipv4:
|
||||
server: "192.168.10.12"
|
||||
reverse: "12"
|
||||
ipv6:
|
||||
server: "fd00:10::12"
|
||||
reverse: "2.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "authelia"
|
||||
app:
|
||||
server: "192.168.10.13"
|
||||
ipv4:
|
||||
server: "192.168.10.13"
|
||||
reverse: "13"
|
||||
ipv6:
|
||||
server: "fd00:10::13"
|
||||
reverse: "3.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0"
|
||||
alias:
|
||||
- "*.app"
|
||||
switch:
|
||||
client: "192.168.1.2"
|
||||
nas:
|
||||
client: "192.168.1.11"
|
||||
ipv4:
|
||||
client: "192.168.1.2"
|
||||
reverse: "2"
|
||||
printer:
|
||||
client: "192.168.1.101"
|
||||
|
||||
network6:
|
||||
subnet:
|
||||
client: "fd00:1::/64"
|
||||
server: "fd00:10::/64"
|
||||
wg: "fd00:99::/64"
|
||||
lla: "fe80::/10"
|
||||
firewall:
|
||||
client: "fd00:1::1"
|
||||
server: "fd00:10::1"
|
||||
wg: "fd00:99::1"
|
||||
blocky:
|
||||
server: "fd00:10::2"
|
||||
bind:
|
||||
server: "fd00:10::3"
|
||||
console:
|
||||
client: "fd00:1::20"
|
||||
wg: "fd00:99::20"
|
||||
vmm:
|
||||
client: "fd00:1::10"
|
||||
server: "fd00:10::10"
|
||||
infra:
|
||||
server: "fd00:10::11"
|
||||
auth:
|
||||
server: "fd00:10::12"
|
||||
app:
|
||||
server: "fd00:10::13"
|
||||
switch:
|
||||
client: "fd00:1::2"
|
||||
nas:
|
||||
client: "fd00:1::11"
|
||||
printer:
|
||||
client: "fd00:1::101"
|
||||
ipv4:
|
||||
client: "192.168.1.101"
|
||||
reverse: "101"
|
||||
|
||||
# Suricata Factors
|
||||
# suricata_home_net: '[10.0.0.0/8,172.16.0.0/12,192.168.0.0/16]'
|
||||
|
||||
@@ -15,9 +15,9 @@ vm:
|
||||
cpu_pin: |
|
||||
<vcpupin vcpu='0' cpuset='2'/>
|
||||
<vcpupin vcpu='1' cpuset='3'/>
|
||||
<vcpupin vcpu='2' cpuset='6'/>
|
||||
<vcpupin vcpu='3' cpuset='7'/>
|
||||
<emulatorpin cpuset='6-7'/>
|
||||
<vcpupin vcpu='2' cpuset='8'/>
|
||||
<vcpupin vcpu='3' cpuset='9'/>
|
||||
<emulatorpin cpuset='8-9'/>
|
||||
shares: 2048
|
||||
memory: 6
|
||||
storage: 256
|
||||
|
||||
@@ -9,6 +9,7 @@ vmm ansible_host=vmm.ilnmors.internal ansible_user=vmm
|
||||
# --- Virtual Machines ---
|
||||
[vms]
|
||||
fw ansible_host=fw.ilnmors.internal ansible_user=fw
|
||||
bk ansible_host=bk.ilnmors.internal ansible_user=bk
|
||||
infra ansible_host=infra.ilnmors.internal ansible_user=infra
|
||||
auth ansible_host=auth.ilnmors.internal ansible_user=auth
|
||||
app ansible_host=app.ilnmors.internal ansible_user=app
|
||||
|
||||
+157
-42
@@ -78,6 +78,14 @@
|
||||
tags: ["init", "resolved"]
|
||||
tags: ["init", "resolved"]
|
||||
|
||||
- name: Set timesyncd
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_timesyncd"
|
||||
apply:
|
||||
tags: ["init", "timesyncd"]
|
||||
tags: ["init", "timesyncd"]
|
||||
|
||||
- name: Update and upgrade apt
|
||||
ansible.builtin.apt:
|
||||
upgrade: "dist"
|
||||
@@ -94,13 +102,31 @@
|
||||
- "jq"
|
||||
- "netcat-openbsd"
|
||||
- "dbus-user-session"
|
||||
- "ksmtuned"
|
||||
- "rsync"
|
||||
state: "present"
|
||||
become: true
|
||||
tags: ["init", "install-packages"]
|
||||
tags: ["init", "site", "install-packages"]
|
||||
|
||||
- name: Enable ksm.service
|
||||
ansible.builtin.systemd:
|
||||
name: "ksm.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
become: true
|
||||
tags: ["init", "site", "install-packages"]
|
||||
|
||||
- name: Disable ksmtuned.service
|
||||
ansible.builtin.systemd:
|
||||
name: "ksmtuned.service"
|
||||
state: "stopped"
|
||||
enabled: false
|
||||
become: true
|
||||
tags: ["init", "site", "install-packages"]
|
||||
|
||||
- name: Set data volume
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
name: "common"
|
||||
tasks_from: "node/set_data_volume"
|
||||
apply:
|
||||
tags: ["init", "raid"]
|
||||
@@ -114,14 +140,6 @@
|
||||
tags: ["init", "linger"]
|
||||
tags: ["init", "linger"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["init", "podman"]
|
||||
tags: ["init", "podman"]
|
||||
|
||||
- name: Set nftables
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -130,6 +148,14 @@
|
||||
tags: ["init", "nftables"]
|
||||
tags: ["init", "nftables"]
|
||||
|
||||
- name: Set alloy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_alloy"
|
||||
apply:
|
||||
tags: ["site", "alloy"]
|
||||
tags: ["site", "alloy"]
|
||||
|
||||
- name: Set crowdsec
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -138,14 +164,6 @@
|
||||
tags: ["site", "crowdsec"]
|
||||
tags: ["site", "crowdsec"]
|
||||
|
||||
- name: Set alloy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_alloy"
|
||||
apply:
|
||||
tags: ["init", "alloy"]
|
||||
tags: ["init", "alloy"]
|
||||
|
||||
- name: Set kopia
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -154,6 +172,14 @@
|
||||
tags: ["site", "kopia"]
|
||||
tags: ["site", "kopia"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["site", "podman"]
|
||||
tags: ["site", "podman"]
|
||||
|
||||
- name: Set caddy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -170,6 +196,14 @@
|
||||
tags: ["site", "vaultwarden"]
|
||||
tags: ["site", "vaultwarden"]
|
||||
|
||||
- name: Set snappymail
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_snappymail"
|
||||
apply:
|
||||
tags: ["site", "snappymail"]
|
||||
tags: ["site", "snappymail"]
|
||||
|
||||
- name: Set gitea
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
@@ -183,24 +217,24 @@
|
||||
name: "app"
|
||||
tasks_from: "services/set_immich"
|
||||
apply:
|
||||
tags: ["site", "immich"]
|
||||
tags: ["site", "immich"]
|
||||
|
||||
- name: Set paperless
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_paperless"
|
||||
apply:
|
||||
tags: ["site", "paperless"]
|
||||
tags: ["site", "paperless"]
|
||||
tags: ["site", "immich", "redis"]
|
||||
tags: ["site", "immich", "redis"]
|
||||
|
||||
- name: Set nextcloud
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_nextcloud"
|
||||
apply:
|
||||
tags: ["site", "nextcloud"]
|
||||
tags: ["site", "nextcloud"]
|
||||
tags: ["site", "nextcloud", "redis"]
|
||||
tags: ["site", "nextcloud", "redis"]
|
||||
|
||||
- name: Set groupoffice
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_groupoffice"
|
||||
apply:
|
||||
tags: ["site", "groupoffice"]
|
||||
tags: ["site", "groupoffice"]
|
||||
|
||||
- name: Set collabora
|
||||
ansible.builtin.include_role:
|
||||
@@ -210,37 +244,109 @@
|
||||
tags: ["site", "collabora"]
|
||||
tags: ["site", "collabora"]
|
||||
|
||||
- name: Set kaneo
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_kaneo"
|
||||
apply:
|
||||
tags: ["site", "kaneo"]
|
||||
tags: ["site", "kaneo"]
|
||||
|
||||
- name: Set sure
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_sure"
|
||||
apply:
|
||||
tags: ["site", "sure"]
|
||||
tags: ["site", "sure"]
|
||||
tags: ["site", "sure", "redis"]
|
||||
tags: ["site", "sure", "redis"]
|
||||
|
||||
- name: Set outline
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_outline"
|
||||
apply:
|
||||
tags: ["site", "outline"]
|
||||
tags: ["site", "outline"]
|
||||
tags: ["site", "outline", "redis"]
|
||||
tags: ["site", "outline", "redis"]
|
||||
|
||||
- name: Set memos
|
||||
- name: Set homebox
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_memos"
|
||||
tasks_from: "services/set_homebox"
|
||||
apply:
|
||||
tags: ["site", "memos"]
|
||||
tags: ["site", "memos"]
|
||||
tags: ["site", "homebox"]
|
||||
tags: ["site", "homebox"]
|
||||
|
||||
- name: Set mealie
|
||||
- name: Set mastodon
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_mealie"
|
||||
tasks_from: "services/set_mastodon"
|
||||
apply:
|
||||
tags: ["site", "mealie"]
|
||||
tags: ["site", "mealie"]
|
||||
tags: ["site", "mastodon", "redis"]
|
||||
tags: ["site", "mastodon", "redis"]
|
||||
|
||||
- name: Set papra
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_papra"
|
||||
apply:
|
||||
tags: ["site", "papra"]
|
||||
tags: ["site", "papra"]
|
||||
|
||||
- name: Set tandoor
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_tandoor"
|
||||
apply:
|
||||
tags: ["site", "tandoor"]
|
||||
tags: ["site", "tandoor"]
|
||||
|
||||
- name: Set bookstack
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_bookstack"
|
||||
apply:
|
||||
tags: ["site", "bookstack"]
|
||||
tags: ["site", "bookstack"]
|
||||
|
||||
- name: Set linkding
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_linkding"
|
||||
apply:
|
||||
tags: ["site", "linkding"]
|
||||
tags: ["site", "linkding"]
|
||||
|
||||
- name: Set llama
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_llama"
|
||||
apply:
|
||||
tags: ["site", "llama"]
|
||||
tags: ["site", "llama"]
|
||||
|
||||
- name: Set stablediffusion
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_stablediffusion"
|
||||
apply:
|
||||
tags: ["site", "stablediffusion"]
|
||||
tags: ["site", "stablediffusion"]
|
||||
|
||||
- name: Set openwebui
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_openwebui"
|
||||
apply:
|
||||
tags: ["site", "openwebui"]
|
||||
tags: ["site", "openwebui"]
|
||||
|
||||
- name: Set homepage
|
||||
ansible.builtin.include_role:
|
||||
name: "app"
|
||||
tasks_from: "services/set_homepage"
|
||||
apply:
|
||||
tags: ["site", "homepage"]
|
||||
tags: ["site", "homepage"]
|
||||
|
||||
- name: Flush handlers right now
|
||||
ansible.builtin.meta: "flush_handlers"
|
||||
@@ -255,10 +361,19 @@
|
||||
state: "present"
|
||||
become: true
|
||||
notify:
|
||||
- "notification_add_user_in_group"
|
||||
- "notification_update_initramfs"
|
||||
- "notification_reboot_app"
|
||||
tags: ["init"]
|
||||
handlers:
|
||||
- name: Add user in video, render group
|
||||
ansible.builtin.user:
|
||||
name: "{{ ansible_user }}"
|
||||
state: "present"
|
||||
groups: "video, render"
|
||||
append: true
|
||||
become: true
|
||||
listen: "notification_add_user_in_group"
|
||||
- name: Update initramfs
|
||||
ansible.builtin.command:
|
||||
update-initramfs -u
|
||||
|
||||
@@ -78,6 +78,14 @@
|
||||
tags: ["init", "resolved"]
|
||||
tags: ["init", "resolved"]
|
||||
|
||||
- name: Set timesyncd
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_timesyncd"
|
||||
apply:
|
||||
tags: ["init", "timesyncd"]
|
||||
tags: ["init", "timesyncd"]
|
||||
|
||||
- name: Update and upgrade apt
|
||||
ansible.builtin.apt:
|
||||
upgrade: "dist"
|
||||
@@ -106,14 +114,6 @@
|
||||
tags: ["init", "linger"]
|
||||
tags: ["init", "linger"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["init", "podman"]
|
||||
tags: ["init", "podman"]
|
||||
|
||||
- name: Set nftables
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -130,6 +130,14 @@
|
||||
tags: ["site", "crowdsec"]
|
||||
tags: ["site", "crowdsec"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["site", "podman"]
|
||||
tags: ["site", "podman"]
|
||||
|
||||
- name: Set caddy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
- name: Load secret values
|
||||
hosts: "console"
|
||||
gather_facts: false
|
||||
become: false
|
||||
tasks:
|
||||
- name: Load secret from secrets.yaml
|
||||
ansible.builtin.include_role:
|
||||
name: "console"
|
||||
tasks_from: "node/load_secret_vars"
|
||||
apply:
|
||||
tags: ["always"]
|
||||
tags: ["always"]
|
||||
|
||||
- name: Site bk
|
||||
hosts: "bk"
|
||||
gather_facts: false
|
||||
become: false
|
||||
pre_tasks:
|
||||
- name: Set become password
|
||||
ansible.builtin.set_fact:
|
||||
ansible_become_pass: "{{ hostvars['console']['sudo']['password']['bk'] }}"
|
||||
no_log: true
|
||||
tags: ["always"]
|
||||
|
||||
tasks:
|
||||
- name: Set timezone
|
||||
community.general.timezone:
|
||||
name: "{{ timezone }}"
|
||||
become: true
|
||||
tags: ["init", "timezone"]
|
||||
|
||||
- name: Deploy root_ca certificate
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/deploy_root_ca"
|
||||
apply:
|
||||
tags: ["init", "root_crt"]
|
||||
tags: ["init", "root_crt"]
|
||||
|
||||
- name: Deploy hosts file
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/deploy_hosts"
|
||||
apply:
|
||||
tags: ["init", "hosts"]
|
||||
tags: ["init", "hosts"]
|
||||
|
||||
- name: Create default directory
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/create_default_dir"
|
||||
apply:
|
||||
tags: ["init", "default_dir"]
|
||||
tags: ["init", "default_dir"]
|
||||
|
||||
- name: Set ssh host
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_ssh_host"
|
||||
apply:
|
||||
tags: ["init", "ssh_host"]
|
||||
tags: ["init", "ssh_host"]
|
||||
|
||||
- name: Set networkd
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_networkd"
|
||||
apply:
|
||||
tags: ["init", "networkd"]
|
||||
tags: ["init", "networkd"]
|
||||
|
||||
- name: Set resolved
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_resolved"
|
||||
apply:
|
||||
tags: ["init", "resolved"]
|
||||
tags: ["init", "resolved"]
|
||||
|
||||
- name: Set timesyncd
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_timesyncd"
|
||||
apply:
|
||||
tags: ["init", "timesyncd"]
|
||||
tags: ["init", "timesyncd"]
|
||||
|
||||
- name: Update and upgrade apt
|
||||
ansible.builtin.apt:
|
||||
upgrade: "dist"
|
||||
update_cache: true
|
||||
cache_valid_time: 3600
|
||||
become: true
|
||||
tags: ["init", "site", "upgrade-packages"]
|
||||
|
||||
- name: Install common packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "acl"
|
||||
- "curl"
|
||||
- "jq"
|
||||
- "netcat-openbsd"
|
||||
- "dbus-user-session"
|
||||
state: "present"
|
||||
become: true
|
||||
tags: ["init", "site", "install-packages"]
|
||||
|
||||
- name: Set data volume
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_data_volume"
|
||||
apply:
|
||||
tags: ["init", "raid"]
|
||||
tags: ["init", "raid"]
|
||||
|
||||
- name: Set linger
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_linger"
|
||||
apply:
|
||||
tags: ["init", "linger"]
|
||||
tags: ["init", "linger"]
|
||||
|
||||
- name: Set nftables
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_nftables"
|
||||
apply:
|
||||
tags: ["init", "nftables"]
|
||||
tags: ["init", "nftables"]
|
||||
|
||||
- name: Set crowdsec
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_crowdsec"
|
||||
apply:
|
||||
tags: ["site", "crowdsec"]
|
||||
tags: ["site", "crowdsec"]
|
||||
|
||||
- name: Set kopia
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_kopia"
|
||||
apply:
|
||||
tags: ["site", "kopia"]
|
||||
tags: ["site", "kopia"]
|
||||
|
||||
- name: Set rclone
|
||||
ansible.builtin.include_role:
|
||||
name: "bk"
|
||||
tasks_from: "services/set_rclone"
|
||||
apply:
|
||||
tags: ["site", "rclone"]
|
||||
tags: ["site", "rclone"]
|
||||
|
||||
- name: Set alloy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_alloy"
|
||||
apply:
|
||||
tags: ["site", "alloy"]
|
||||
tags: ["site", "alloy"]
|
||||
@@ -0,0 +1,223 @@
|
||||
---
|
||||
- name: Load secret values
|
||||
hosts: "console"
|
||||
gather_facts: false
|
||||
become: false
|
||||
tasks:
|
||||
- name: Load secret from secrets.yaml
|
||||
ansible.builtin.include_role:
|
||||
name: "console"
|
||||
tasks_from: "node/load_secret_vars"
|
||||
apply:
|
||||
tags: ["always"]
|
||||
tags: ["always"]
|
||||
|
||||
- name: Site console
|
||||
hosts: "console"
|
||||
gather_facts: false
|
||||
become: false
|
||||
tasks:
|
||||
- name: Create root CA
|
||||
tags: ["never", "root"]
|
||||
block:
|
||||
- name: Clean previous CA temporary directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
- name: Create ca directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
state: "directory"
|
||||
mode: "0700"
|
||||
- name: Get root CA password
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['password'] }}
|
||||
dest: "/run/user/{{ node['uid'] }}/ca/root_ca.password"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
no_log: true
|
||||
- name: Create root CA
|
||||
ansible.builtin.command: |
|
||||
step certificate create \
|
||||
"{{ domain['internal'] }} Root CA" \
|
||||
/run/user/{{ node['uid'] }}/ca/root_ca.crt \
|
||||
/run/user/{{ node['uid'] }}/ca/root_ca.key \
|
||||
--password-file /run/user/{{ node['uid'] }}/ca/root_ca.password \
|
||||
--profile root-ca \
|
||||
--not-after 87600h
|
||||
changed_when: true
|
||||
no_log: true
|
||||
- name: Update root CA
|
||||
environment:
|
||||
SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/ca/root_ca.crt" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["ca"]["root"]["crt"]'
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/ca/root_ca.key" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["ca"]["root"]["key"]'
|
||||
changed_when: true
|
||||
no_log: true
|
||||
always:
|
||||
- name: Clean temporary files
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
|
||||
- name: Get root CA and create intermediate CA
|
||||
tags: ["never", "intermediate"]
|
||||
block:
|
||||
- name: Clean previous CA temporary directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
- name: Create ca certificates directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
state: "directory"
|
||||
mode: "0700"
|
||||
- name: Get root key and cert and password
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root'][item] }}
|
||||
dest: "/run/user/{{ node['uid'] }}/ca/root_ca.{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
loop:
|
||||
- "key"
|
||||
- "crt"
|
||||
- "password"
|
||||
no_log: true
|
||||
- name: Get intermediate CA password
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['intermediate']['password'] }}
|
||||
dest: "/run/user/{{ node['uid'] }}/ca/intermediate_ca.password"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
no_log: true
|
||||
- name: Create intermediate CA
|
||||
ansible.builtin.command: |
|
||||
step certificate create \
|
||||
"{{ domain['internal'] }} intermediate CA" \
|
||||
/run/user/{{ node['uid'] }}/ca/intermediate_ca.crt \
|
||||
/run/user/{{ node['uid'] }}/ca/intermediate_ca.key \
|
||||
--password-file /run/user/{{ node['uid'] }}/ca/intermediate_ca.password \
|
||||
--profile intermediate-ca \
|
||||
--ca /run/user/{{ node['uid'] }}/ca/root_ca.crt \
|
||||
--ca-key /run/user/{{ node['uid'] }}/ca/root_ca.key \
|
||||
--ca-password-file /run/user/{{ node['uid'] }}/ca/root_ca.password \
|
||||
--not-after 43800h
|
||||
changed_when: true
|
||||
no_log: true
|
||||
- name: Update intermediate CA
|
||||
environment:
|
||||
SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/ca/intermediate_ca.crt" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["ca"]["intermediate"]["crt"]'
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/ca/intermediate_ca.key" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["ca"]["intermediate"]["key"]'
|
||||
changed_when: true
|
||||
no_log: true
|
||||
always:
|
||||
- name: Clean temporary files
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/ca"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
|
||||
- name: Get intermediate CA and create leaf cert
|
||||
tags: ["never", "leaf"]
|
||||
block:
|
||||
- name: Initialize self-cert services list
|
||||
ansible.builtin.set_fact:
|
||||
cert_services: []
|
||||
- name: Set self-cert services list
|
||||
ansible.builtin.set_fact:
|
||||
cert_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.cert', 'defined')
|
||||
| selectattr('value.dependency.cert', 'equalto', true)
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
- name: Clean previous leaf temporary directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/leaf"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
- name: Create leaf certificates directory
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/leaf"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
state: "directory"
|
||||
mode: "0700"
|
||||
- name: Get intermediate key and cert and password
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['intermediate'][item] }}
|
||||
dest: "/run/user/{{ node['uid'] }}/leaf/intermediate_ca.{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
loop:
|
||||
- "key"
|
||||
- "crt"
|
||||
- "password"
|
||||
no_log: true
|
||||
- name: Create leaf certificates
|
||||
ansible.builtin.command: |
|
||||
step certificate create \
|
||||
"{{ services[item]['domain']['internal'] }}.{{ domain['internal'] }}" \
|
||||
/run/user/{{ node['uid'] }}/leaf/{{ item }}.crt \
|
||||
/run/user/{{ node['uid'] }}/leaf/{{ item }}.key \
|
||||
--profile leaf \
|
||||
--san {{ services[item]['domain']['internal'] }}.{{ domain['internal'] }} \
|
||||
--ca /run/user/{{ node['uid'] }}/leaf/intermediate_ca.crt \
|
||||
--ca-key /run/user/{{ node['uid'] }}/leaf/intermediate_ca.key \
|
||||
--ca-password-file /run/user/{{ node['uid'] }}/leaf/intermediate_ca.password \
|
||||
--not-after 21900h \
|
||||
--insecure --no-password
|
||||
loop: "{{ cert_services }}"
|
||||
changed_when: true
|
||||
no_log: true
|
||||
- name: Update leaf keys and certificates
|
||||
environment:
|
||||
SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
|
||||
ansible.builtin.shell: |
|
||||
set -euo pipefail
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/leaf/{{ item }}.crt" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["{{ item }}"]["crt"]'
|
||||
jq -Rs . "/run/user/{{ node['uid'] }}/leaf/{{ item }}.key" \
|
||||
| sops set --value-stdin "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml" \
|
||||
'["{{ item }}"]["key"]'
|
||||
loop: "{{ cert_services }}"
|
||||
changed_when: true
|
||||
no_log: true
|
||||
always:
|
||||
- name: Clean temporary files
|
||||
ansible.builtin.file:
|
||||
path: "/run/user/{{ node['uid'] }}/leaf"
|
||||
state: "absent"
|
||||
no_log: true
|
||||
@@ -108,8 +108,8 @@
|
||||
ansible.builtin.get_url:
|
||||
url: "https://cdimage.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2"
|
||||
dest: "{{ node['data_path'] }}/images/debian-13-generic-amd64.qcow2"
|
||||
owner: "console"
|
||||
group: "svadmins"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
tags: ["init", "site", "cloud-init-image"]
|
||||
|
||||
|
||||
@@ -78,6 +78,14 @@
|
||||
tags: ["init", "resolved"]
|
||||
tags: ["init", "resolved"]
|
||||
|
||||
- name: Set timesyncd
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "node/set_timesyncd"
|
||||
apply:
|
||||
tags: ["init", "timesyncd"]
|
||||
tags: ["init", "timesyncd"]
|
||||
|
||||
- name: Update and upgrade apt
|
||||
ansible.builtin.apt:
|
||||
upgrade: "dist"
|
||||
@@ -106,14 +114,6 @@
|
||||
tags: ["init", "linger"]
|
||||
tags: ["init", "linger"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["init", "podman"]
|
||||
tags: ["init", "podman"]
|
||||
|
||||
- name: Set nftables
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -130,6 +130,22 @@
|
||||
tags: ["site", "crowdsec"]
|
||||
tags: ["site", "crowdsec"]
|
||||
|
||||
- name: Set kopia
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_kopia"
|
||||
apply:
|
||||
tags: ["site", "kopia"]
|
||||
tags: ["site", "kopia"]
|
||||
|
||||
- name: Set podman
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_podman"
|
||||
apply:
|
||||
tags: ["site", "podman"]
|
||||
tags: ["site", "podman"]
|
||||
|
||||
- name: Set ca
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
@@ -138,6 +154,14 @@
|
||||
tags: ["site", "ca"]
|
||||
tags: ["site", "ca"]
|
||||
|
||||
- name: Set rustfs
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
tasks_from: "services/set_rustfs"
|
||||
apply:
|
||||
tags: ["site", "rustfs"]
|
||||
tags: ["site", "rustfs"]
|
||||
|
||||
- name: Set postgresql
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
@@ -146,6 +170,14 @@
|
||||
tags: ["site", "postgresql"]
|
||||
tags: ["site", "postgresql"]
|
||||
|
||||
- name: Set mariadb
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
tasks_from: "services/set_mariadb"
|
||||
apply:
|
||||
tags: ["site", "mariadb"]
|
||||
tags: ["site", "mariadb"]
|
||||
|
||||
- name: Set caddy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -162,6 +194,14 @@
|
||||
tags: ["site", "ldap"]
|
||||
tags: ["site", "ldap"]
|
||||
|
||||
- name: Set maddy
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
tasks_from: "services/set_maddy"
|
||||
apply:
|
||||
tags: ["site", "maddy"]
|
||||
tags: ["site", "maddy"]
|
||||
|
||||
- name: Set x509 exporter
|
||||
ansible.builtin.include_role:
|
||||
name: "infra"
|
||||
@@ -201,11 +241,3 @@
|
||||
apply:
|
||||
tags: ["site", "grafana"]
|
||||
tags: ["site", "grafana"]
|
||||
|
||||
- name: Set kopia
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
tasks_from: "services/set_kopia"
|
||||
apply:
|
||||
tags: ["site", "kopia"]
|
||||
tags: ["site", "kopia"]
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
vars:
|
||||
valid_vm_names:
|
||||
- "fw"
|
||||
- "bk"
|
||||
- "infra"
|
||||
- "auth"
|
||||
- "app"
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
- name: Set raid
|
||||
ansible.builtin.include_role:
|
||||
name: "vmm"
|
||||
tasks_from: "node/set_raid"
|
||||
tasks_from: "node/set_disk"
|
||||
apply:
|
||||
tags: ["init", "raid"]
|
||||
tags: ["init", "raid"]
|
||||
@@ -143,6 +143,15 @@
|
||||
when: inventory_hostname != "vmm_init"
|
||||
tags: ["site", "crowdsec"]
|
||||
|
||||
- name: Set smartctl generator
|
||||
ansible.builtin.include_role:
|
||||
name: "vmm"
|
||||
tasks_from: "services/set_smart_metric_generator"
|
||||
apply:
|
||||
tags: ["site", "smart"]
|
||||
when: inventory_hostname != "vmm_init"
|
||||
tags: ["site", "smart"]
|
||||
|
||||
- name: Set alloy
|
||||
ansible.builtin.include_role:
|
||||
name: "common"
|
||||
@@ -169,6 +178,7 @@
|
||||
- python3-apt
|
||||
- python3-libvirt
|
||||
- python3-lxml
|
||||
- rsync
|
||||
state: "present"
|
||||
become: true
|
||||
when: "'init' is not in ansible_run_tags"
|
||||
|
||||
@@ -43,17 +43,6 @@
|
||||
listen: "notification_restart_immich-ml"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart paperless
|
||||
ansible.builtin.systemd:
|
||||
name: "paperless.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_paperless"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart nextcloud
|
||||
ansible.builtin.systemd:
|
||||
name: "nextcloud.service"
|
||||
@@ -103,24 +92,149 @@
|
||||
listen: "notification_restart_outline"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart memos
|
||||
- name: Restart homebox
|
||||
ansible.builtin.systemd:
|
||||
name: "memos.service"
|
||||
name: "homebox.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_memos"
|
||||
listen: "notification_restart_homebox"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart mealie
|
||||
- name: Restart homepage
|
||||
ansible.builtin.systemd:
|
||||
name: "mealie.service"
|
||||
name: "homepage.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_mealie"
|
||||
listen: "notification_restart_homepage"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart snappymail
|
||||
ansible.builtin.systemd:
|
||||
name: "snappymail.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_snappymail"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart mastodon
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
loop:
|
||||
- "mastodon-web.service"
|
||||
- "mastodon-worker.service"
|
||||
- "mastodon-streaming.service"
|
||||
changed_when: false
|
||||
listen: "notification_restart_mastodon"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart papra
|
||||
ansible.builtin.systemd:
|
||||
name: "papra.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_papra"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart tandoor
|
||||
ansible.builtin.systemd:
|
||||
name: "tandoor.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_tandoor"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart bookstack
|
||||
ansible.builtin.systemd:
|
||||
name: "bookstack.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_bookstack"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart linkding
|
||||
ansible.builtin.systemd:
|
||||
name: "linkding.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_linkding"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart openwebui
|
||||
ansible.builtin.systemd:
|
||||
name: "openwebui.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_openwebui"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart llama
|
||||
ansible.builtin.systemd:
|
||||
name: "llama.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_llama"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart stablediffusion
|
||||
ansible.builtin.systemd:
|
||||
name: "stablediffusion.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_stablediffusion"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart groupoffice
|
||||
ansible.builtin.systemd:
|
||||
name: "groupoffice.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_groupoffice"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart kaneo
|
||||
ansible.builtin.systemd:
|
||||
name: "kaneo.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_kaneo"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
- name: Create bookstack directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['bookstack']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/bookstack"
|
||||
- "data/containers/bookstack/public"
|
||||
- "data/containers/bookstack/storage"
|
||||
- "containers/bookstack"
|
||||
- "containers/bookstack/ssl"
|
||||
become: true
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/bookstack/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['bookstack']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_bookstack"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "BOOKSTACK_SECRET_KEY"
|
||||
value: "{{ hostvars['console']['bookstack']['secret_key'] }}"
|
||||
- name: "BOOKSTACK_DB_PASSWORD"
|
||||
value: "{{ hostvars['console']['mariadb']['password']['bookstack'] }}"
|
||||
- name: "BOOKSTACK_OIDC_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['bookstack']['oidc']['secret'] }}"
|
||||
notify: "notification_restart_bookstack"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/solidnerd/bookstack"
|
||||
tag: "{{ version['containers']['bookstack'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy bookstack.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/bookstack/bookstack.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/bookstack.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_bookstack"
|
||||
|
||||
- name: Enable bookstack.service
|
||||
ansible.builtin.systemd:
|
||||
name: "bookstack.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_solidnerd_bookstack_{{ version['containers']['bookstack'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/solidnerd/bookstack:{{ version['containers']['bookstack'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_solidnerd_bookstack_{{ version['containers']['bookstack'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_solidnerd_bookstack_{{ version['containers']['bookstack'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -1,4 +1,11 @@
|
||||
---
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/collabora/code"
|
||||
tag: "{{ version['containers']['collabora'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/collabora/collabora.container.j2"
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/gitea"
|
||||
- "data/containers/gitea/data"
|
||||
- "containers/gitea"
|
||||
- "containers/gitea/ssl"
|
||||
become: true
|
||||
@@ -33,6 +34,13 @@
|
||||
notify: "notification_restart_gitea"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/gitea/gitea"
|
||||
tag: "{{ version['containers']['gitea'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/gitea/gitea.container.j2"
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
---
|
||||
- name: Create groupoffice directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['groupoffice']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/groupoffice"
|
||||
- "data/containers/groupoffice/data"
|
||||
- "containers/groupoffice"
|
||||
- "containers/groupoffice/ssl"
|
||||
- "containers/groupoffice/config"
|
||||
become: true
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/groupoffice/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['groupoffice']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_groupoffice"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "GROUPOFFICE_DB_PASSWORD"
|
||||
value: "{{ hostvars['console']['mariadb']['password']['groupoffice'] }}"
|
||||
notify: "notification_restart_groupoffice"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy config files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/groupoffice/config/{{ item }}.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/groupoffice/config/{{ item }}"
|
||||
owner: "{{ services['groupoffice']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0640"
|
||||
loop:
|
||||
- "config.php"
|
||||
- "groupoffice-ca.ini"
|
||||
- "Connection.php"
|
||||
- "Authenticator.php"
|
||||
- "configfile.php"
|
||||
become: true
|
||||
notify: "notification_restart_groupoffice"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/intermesh/groupoffice"
|
||||
tag: "{{ version['containers']['groupoffice'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy groupoffice.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/groupoffice/groupoffice.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/groupoffice.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_groupoffice"
|
||||
|
||||
- name: Deploy groupoffice-cron service
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/groupoffice/services/{{ item }}"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "groupoffice-cron.service"
|
||||
- "groupoffice-cron.timer"
|
||||
|
||||
- name: Enable groupoffice.service
|
||||
ansible.builtin.systemd:
|
||||
name: "groupoffice.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Enable groupoffice-cron.timer
|
||||
ansible.builtin.systemd:
|
||||
name: "groupoffice-cron.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_intermesh_groupoffice_{{ version['containers']['groupoffice'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/intermesh/groupoffice:{{ version['containers']['groupoffice'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_intermesh_groupoffice_{{ version['containers']['groupoffice'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_intermesh_groupoffice_{{ version['containers']['groupoffice'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
- name: Create homebox directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/homebox"
|
||||
- "data/containers/homebox/data"
|
||||
- "containers/homebox"
|
||||
- "containers/homebox/ssl"
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/homebox/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
notify: "notification_restart_homebox"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "HBOX_AUTH_API_KEY_PEPPER"
|
||||
value: "{{ hostvars['console']['homebox']['api_secret'] }}"
|
||||
- name: "HBOX_DATABASE_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['homebox'] }}"
|
||||
- name: "HBOX_OIDC_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['homebox']['oidc']['secret'] }}"
|
||||
notify: "notification_restart_homebox"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/sysadminsmedia/homebox"
|
||||
tag: "{{ version['containers']['homebox'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy homebox.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/homebox/homebox.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/homebox.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_homebox"
|
||||
|
||||
- name: Enable homebox.service
|
||||
ansible.builtin.systemd:
|
||||
name: "homebox.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/sysadminsmedia/homebox:{{ version['containers']['homebox'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_sysadminsmedia_homebox_{{ version['containers']['homebox'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
- name: Set homepage services list
|
||||
ansible.builtin.set_fact:
|
||||
homepage_public_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.web', 'defined')
|
||||
| selectattr('value.dependency.web', 'in', ['infra-public', 'auth-public', 'app-public'])
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
homepage_internal_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.web', 'defined')
|
||||
| selectattr('value.dependency.web', 'in', ['infra-internal', 'auth-internal', 'app-internal'])
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Create homepage directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/homepage"
|
||||
- "containers/homepage/config"
|
||||
- "containers/homepage/images"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/gethomepage/homepage"
|
||||
tag: "{{ version['containers']['homepage'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy config files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/homepage/config/{{ item }}.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/homepage/config/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "settings.yaml"
|
||||
- "widgets.yaml"
|
||||
- "services.yaml"
|
||||
- "bookmarks.yaml"
|
||||
notify: "notification_restart_homepage"
|
||||
|
||||
- name: Deploy image directory
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/homepage/images/"
|
||||
dest: "{{ node['home_path'] }}/containers/homepage/images/"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/homepage/homepage.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/homepage.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_homepage"
|
||||
|
||||
- name: Enable homepage.service
|
||||
ansible.builtin.systemd:
|
||||
name: "homepage.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_gethomepage_homepage_{{ version['containers']['homepage'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/gethomepage/homepage:{{ version['containers']['homepage'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_gethomepage_homepage_{{ version['containers']['homepage'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_gethomepage_homepage_{{ version['containers']['homepage'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -43,14 +43,6 @@
|
||||
scope: "user"
|
||||
when: is_redis_conf.changed or is_redis_containerfile.changed # noqa: no-handler
|
||||
|
||||
- name: Add user in video, render group
|
||||
ansible.builtin.user:
|
||||
name: "{{ ansible_user }}"
|
||||
state: "present"
|
||||
groups: "video, render"
|
||||
append: true
|
||||
become: true
|
||||
|
||||
- name: Create immich directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
@@ -60,6 +52,7 @@
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/immich"
|
||||
- "data/containers/immich/data"
|
||||
- "containers/immich"
|
||||
- "containers/immich/ssl"
|
||||
- "containers/immich/ml"
|
||||
@@ -85,6 +78,22 @@
|
||||
notify: "notification_restart_immich"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ item.image }}"
|
||||
tag: "{{ item.tag }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
loop:
|
||||
- name: "immich_ml"
|
||||
image: "ghcr.io/immich-app/immich-machine-learning"
|
||||
tag: "{{ version['containers']['immich'] }}-openvino"
|
||||
- name: "immich"
|
||||
image: "ghcr.io/immich-app/immich-server"
|
||||
tag: "{{ version['containers']['immich'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
|
||||
- name: Deploy immich.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/immich/immich.container.j2"
|
||||
@@ -123,14 +132,17 @@
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
|
||||
loop:
|
||||
- image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
- name: "redis"
|
||||
image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
|
||||
- image: "ghcr.io/immich-app/immich-machine-learning:{{ version['containers']['immich'] }}-openvino"
|
||||
- name: "immich_ml"
|
||||
image: "ghcr.io/immich-app/immich-machine-learning:{{ version['containers']['immich'] }}-openvino"
|
||||
file: "ghcr.io_immich-app_immich-machine-learning_{{ version['containers']['immich'] }}-openvino"
|
||||
- image: "ghcr.io/immich-app/immich-server:{{ version['containers']['immich'] }}"
|
||||
- name: "immich"
|
||||
image: "ghcr.io/immich-app/immich-server:{{ version['containers']['immich'] }}"
|
||||
file: "ghcr.io_immich-app_immich-server_{{ version['containers']['immich'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.file }}"
|
||||
label: "{{ item.name }}"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
---
|
||||
- name: Create kaneo directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['kaneo']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/kaneo"
|
||||
- "containers/kaneo/ssl"
|
||||
become: true
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/kaneo/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['kaneo']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_kaneo"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "KANEO_AUTH_SECRET"
|
||||
value: "{{ hostvars['console']['kaneo']['secret_key'] }}"
|
||||
- name: "KANEO_DB_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['kaneo'] }}"
|
||||
- name: "KANEO_OIDC_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['kaneo']['oidc']['secret'] }}"
|
||||
- name: "KANEO_S3_SECRET_KEY"
|
||||
value: "{{ hostvars['console']['rustfs']['password']['kaneo'] }}"
|
||||
notify: "notification_restart_kaneo"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/usekaneo/kaneo"
|
||||
tag: "{{ version['containers']['kaneo'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy kaneo.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/kaneo/kaneo.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/kaneo.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_kaneo"
|
||||
|
||||
- name: Enable kaneo.service
|
||||
ansible.builtin.systemd:
|
||||
name: "kaneo.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_usekaneo_kane_{{ version['containers']['kaneo'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/usekaneo/kaneo:{{ version['containers']['kaneo'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_usekaneo_kane_{{ version['containers']['kaneo'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_usekaneo_kane_{{ version['containers']['kaneo'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
- name: Create linkding directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['linkding']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/linkding"
|
||||
- "data/containers/linkding/data"
|
||||
- "containers/linkding"
|
||||
- "containers/linkding/ssl"
|
||||
become: true
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/linkding/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['linkding']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_linkding"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "LINKDING_DB_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['linkding'] }}"
|
||||
- name: "LINKDING_OIDC_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['linkding']['oidc']['secret'] }}"
|
||||
notify: "notification_restart_linkding"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/sissbruecker/linkding"
|
||||
tag: "{{ version['containers']['linkding'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy linkding.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/linkding/linkding.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/linkding.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_linkding"
|
||||
|
||||
- name: Enable linkding.service
|
||||
ansible.builtin.systemd:
|
||||
name: "linkding.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_sissbruecker_linkding_{{ version['containers']['linkding'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/sissbruecker/linkding:{{ version['containers']['linkding'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_sissbruecker_linkding_{{ version['containers']['linkding'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_sissbruecker_linkding_{{ version['containers']['linkding'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
- name: Check model directory in data volume
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/containers/llama/models"
|
||||
file_type: "file"
|
||||
patterns: "*.gguf"
|
||||
hidden: true
|
||||
recurse: true
|
||||
register: llama_models
|
||||
|
||||
- name: Failure when models directory in data volume
|
||||
ansible.builtin.fail:
|
||||
msg: "There are no models in data directory, please ensure download some model files for llama.cpp"
|
||||
when: llama_models.matched == 0
|
||||
|
||||
- name: Create llama directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/llama"
|
||||
- "containers/llama/models"
|
||||
- "containers/llama/config"
|
||||
|
||||
- name: Sync model data (--delete=true)
|
||||
delegate_to: "{{ inventory_hostname }}"
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ node['home_path'] }}/data/containers/llama/models/"
|
||||
dest: "{{ node['home_path'] }}/containers/llama/models/"
|
||||
owner: true
|
||||
group: true
|
||||
perms: true
|
||||
delete: true
|
||||
notify: "notification_restart_llama"
|
||||
|
||||
- name: Deploy configuration file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/llama/config/models.ini.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/llama/config/models.ini"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0640"
|
||||
notify: "notification_restart_llama"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/ggml-org/llama.cpp"
|
||||
tag: "{{ version['containers']['llama'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/llama/llama.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/llama.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_llama"
|
||||
|
||||
- name: Enable llama.service
|
||||
ansible.builtin.systemd:
|
||||
name: "llama.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_ggml-org_llama.cpp_{{ version['containers']['llama'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/ggml-org/llama.cpp:{{ version['containers']['llama'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_ggml-org_llama.cpp_{{ version['containers']['llama'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_ggml-org_llama.cpp_{{ version['containers']['llama'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,276 @@
|
||||
---
|
||||
- name: Set redis service name
|
||||
ansible.builtin.set_fact:
|
||||
redis_service: "mastodon"
|
||||
|
||||
- name: Create redis_mastodon directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['redis']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/redis"
|
||||
- "containers/redis/{{ redis_service }}"
|
||||
- "containers/redis/{{ redis_service }}/data"
|
||||
become: true
|
||||
|
||||
- name: Deploy redis config file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/redis/redis.conf.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/redis/{{ redis_service }}/redis.conf"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
register: "is_redis_conf"
|
||||
|
||||
- name: Deploy redis container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/redis/redis.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/redis_{{ redis_service }}.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
register: "is_redis_containerfile"
|
||||
|
||||
- name: Enable (Restart) redis service
|
||||
ansible.builtin.systemd:
|
||||
name: "redis_{{ redis_service }}.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
when: is_redis_conf.changed or is_redis_containerfile.changed # noqa: no-handler
|
||||
|
||||
- name: Create mastodon directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['mastodon']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/mastodon"
|
||||
- "data/containers/mastodon/system"
|
||||
- "containers/mastodon"
|
||||
- "containers/mastodon/ssl"
|
||||
become: true
|
||||
|
||||
- name: Check data directory empty
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/data/containers/mastodon/.init"
|
||||
register: "is_mastodon_init"
|
||||
|
||||
- name: Check migrate file
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/data/containers/mastodon/.migrated_{{ version['containers']['mastodon'] }}"
|
||||
register: "is_mastodon_migrated"
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/mastodon/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['mastodon']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_mastodon"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "MASTODON_SECRET_KEY_BASE"
|
||||
value: "{{ hostvars['console']['mastodon']['secret_key'] }}"
|
||||
- name: "MASTODON_ENCRYPTION_PRIMARY_KEY"
|
||||
value: "{{ hostvars['console']['mastodon']['encryption']['primary_key'] }}"
|
||||
- name: "MASTODON_ENCRYPTION_DETERMINISTIC_KEY"
|
||||
value: "{{ hostvars['console']['mastodon']['encryption']['deterministic_key'] }}"
|
||||
- name: "MASTODON_ENCRYPTION_SALT"
|
||||
value: "{{ hostvars['console']['mastodon']['encryption']['salt'] }}"
|
||||
- name: "MASTODON_POSTGRES_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['mastodon'] }}"
|
||||
- name: "MASTODON_OIDC_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['mastodon']['oidc']['secret'] }}"
|
||||
- name: "MASTODON_VAPID_PRIVATE_KEY"
|
||||
value: "{{ hostvars['console']['mastodon']['vapid']['private_key'] }}"
|
||||
- name: "MASTODON_VAPID_PUBLIC_KEY"
|
||||
value: "{{ hostvars['console']['mastodon']['vapid']['public_key'] }}"
|
||||
notify: "notification_restart_mastodon"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ item }}"
|
||||
tag: "{{ version['containers']['mastodon'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
loop:
|
||||
- "ghcr.io/mastodon/mastodon"
|
||||
- "ghcr.io/mastodon/mastodon-streaming"
|
||||
|
||||
- name: Initialize mastodon
|
||||
when: not is_mastodon_init.stat.exists
|
||||
block:
|
||||
- name: Execute init command
|
||||
containers.podman.podman_container:
|
||||
name: "mastodon_init"
|
||||
image: "ghcr.io/mastodon/mastodon:{{ version['containers']['mastodon'] }}"
|
||||
command: "bundle exec rails db:prepare"
|
||||
state: "started"
|
||||
rm: true
|
||||
detach: false
|
||||
env:
|
||||
LOCAL_DOMAIN: "{{ services['mastodon']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
SAFETY_ASSURED: "1"
|
||||
DB_HOST: "{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
|
||||
DB_PORT: "{{ services['postgresql']['ports']['tcp'] }}"
|
||||
DB_NAME: "mastodon_db"
|
||||
DB_USER: "mastodon"
|
||||
DB_PASS: "{{ hostvars['console']['postgresql']['password']['mastodon'] }}"
|
||||
DB_SSLMODE: "verify-full"
|
||||
PGSSLROOTCERT: "/etc/ssl/mastodon/{{ root_cert_filename }}"
|
||||
REDIS_URL: "redis://host.containers.internal:{{ services['mastodon']['ports']['redis'] }}"
|
||||
SECRET_KEY_BASE: "{{ hostvars['console']['mastodon']['secret_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: "{{ hostvars['console']['mastodon']['encryption']['primary_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: "{{ hostvars['console']['mastodon']['encryption']['deterministic_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: "{{ hostvars['console']['mastodon']['encryption']['salt'] }}"
|
||||
volume:
|
||||
- "{{ node['home_path'] }}/containers/mastodon/ssl:/etc/ssl/mastodon:ro"
|
||||
- "{{ node['home_path'] }}/data/containers/mastodon/system:/mastodon/public/system:rw"
|
||||
no_log: true
|
||||
|
||||
- name: Create .init file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/containers/mastodon/.init"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
|
||||
- name: Create .migrated file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/containers/mastodon/.migrated_{{ version['containers']['mastodon'] }}"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
|
||||
- name: Migrate DB of mastodon
|
||||
when: not is_mastodon_migrated.stat.exists and is_mastodon_init.stat.exists
|
||||
block:
|
||||
- name: Stop the services
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: "stopped"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
loop:
|
||||
- "mastodon-web.service"
|
||||
- "mastodon-worker.service"
|
||||
- "mastodon-streaming.service"
|
||||
|
||||
- name: Execute migrate command
|
||||
containers.podman.podman_container:
|
||||
name: "mastodon_migrate"
|
||||
image: "ghcr.io/mastodon/mastodon:{{ version['containers']['mastodon'] }}"
|
||||
command: "bundle exec rails db:migrate"
|
||||
state: "started"
|
||||
rm: true
|
||||
detach: false
|
||||
env:
|
||||
LOCAL_DOMAIN: "{{ services['mastodon']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
DB_HOST: "{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}"
|
||||
DB_PORT: "{{ services['postgresql']['ports']['tcp'] }}"
|
||||
DB_NAME: "mastodon_db"
|
||||
DB_USER: "mastodon"
|
||||
DB_PASS: "{{ hostvars['console']['postgresql']['password']['mastodon'] }}"
|
||||
DB_SSLMODE: "verify-full"
|
||||
PGSSLROOTCERT: "/etc/ssl/mastodon/{{ root_cert_filename }}"
|
||||
REDIS_URL: "redis://host.containers.internal:{{ services['mastodon']['ports']['redis'] }}"
|
||||
SECRET_KEY_BASE: "{{ hostvars['console']['mastodon']['secret_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: "{{ hostvars['console']['mastodon']['encryption']['primary_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: "{{ hostvars['console']['mastodon']['encryption']['deterministic_key'] }}"
|
||||
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: "{{ hostvars['console']['mastodon']['encryption']['salt'] }}"
|
||||
volume:
|
||||
- "{{ node['home_path'] }}/containers/mastodon/ssl:/etc/ssl/mastodon:ro"
|
||||
- "{{ node['home_path'] }}/data/containers/mastodon/system:/mastodon/public/system:rw"
|
||||
no_log: true
|
||||
|
||||
- name: Create .migrated file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/containers/mastodon/.migrated_{{ version['containers']['mastodon'] }}"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
|
||||
- name: Deploy mastodon.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/mastodon/{{ item }}.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "mastodon-web.container"
|
||||
- "mastodon-worker.container"
|
||||
- "mastodon-streaming.container"
|
||||
notify: "notification_restart_mastodon"
|
||||
|
||||
- name: Enable mastodon.service
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ item }}"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
loop:
|
||||
- "mastodon-web.service"
|
||||
- "mastodon-worker.service"
|
||||
- "mastodon-streaming.service"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
|
||||
loop:
|
||||
- name: "redis"
|
||||
image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
|
||||
- name: "mastodon"
|
||||
image: "ghcr.io/mastodon/mastodon:{{ version['containers']['mastodon'] }}"
|
||||
file: "ghcr.io_mastodon_mastodon_{{ version['containers']['mastodon'] }}"
|
||||
- name: "mastodon-streaming"
|
||||
image: "ghcr.io/mastodon/mastodon-streaming:{{ version['containers']['mastodon'] }}"
|
||||
file: "ghcr.io_mastodon_mastodon-streaming_{{ version['containers']['mastodon'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "{{ item.item.image }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/{{ item.item.file }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
loop: "{{ container_archive_images.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.file }}"
|
||||
when: not item.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/{{ item.item.file }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
loop: "{{ container_archive_images.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.file }}"
|
||||
@@ -58,7 +58,7 @@
|
||||
- "containers/nextcloud/ini"
|
||||
become: true
|
||||
|
||||
- name: Check data directory empty
|
||||
- name: Check .init file
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/data/containers/nextcloud/.init"
|
||||
register: "is_nextcloud_init"
|
||||
@@ -78,7 +78,7 @@
|
||||
- name: Initialize nextcloud
|
||||
when: not is_nextcloud_init.stat.exists
|
||||
block:
|
||||
- name: Execute init command (Including pulling image)
|
||||
- name: Execute init command
|
||||
containers.podman.podman_container:
|
||||
name: "nextcloud_init"
|
||||
image: "docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}"
|
||||
@@ -90,7 +90,7 @@
|
||||
NEXTCLOUD_UPDATE: "1"
|
||||
NEXTCLOUD_ADMIN_USER: "{{ hostvars['console']['nextcloud']['admin']['id'] }}"
|
||||
NEXTCLOUD_ADMIN_PASSWORD: "{{ hostvars['console']['nextcloud']['admin']['password'] }}"
|
||||
POSTGRES_HOST: "{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
|
||||
POSTGRES_HOST: "{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
|
||||
POSTGRES_DB: "nextcloud_db"
|
||||
POSTGRES_USER: "nextcloud"
|
||||
POSTGRES_PASSWORD: "{{ hostvars['console']['postgresql']['password']['nextcloud'] }}"
|
||||
@@ -139,6 +139,13 @@
|
||||
- "upload.ini"
|
||||
notify: "notification_restart_nextcloud"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/library/nextcloud"
|
||||
tag: "{{ version['containers']['nextcloud'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy nextcloud.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/nextcloud/nextcloud.container.j2"
|
||||
@@ -150,7 +157,7 @@
|
||||
|
||||
- name: Deploy nextcloud-cron service
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/nextcloud/systemd/{{ item }}"
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/nextcloud/services/{{ item }}"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
@@ -179,12 +186,14 @@
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
|
||||
loop:
|
||||
- image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
- name: "redis"
|
||||
image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
|
||||
- image: "docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}"
|
||||
- name: "nextcloud"
|
||||
image: "docker.io/library/nextcloud:{{ version['containers']['nextcloud'] }}"
|
||||
file: "docker.io_library_nextcloud_{{ version['containers']['nextcloud'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.file }}"
|
||||
label: "{{ item.name }}"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
- name: Create openwebui directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/openwebui"
|
||||
- "data/containers/openwebui/data"
|
||||
- "containers/openwebui"
|
||||
- "containers/openwebui/ssl"
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/openwebui/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
notify: "notification_restart_openwebui"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "OPEN_WEBUI_SECRET_KEY"
|
||||
value: "{{ hostvars['console']['openwebui']['secret_key'] }}"
|
||||
- name: "OPEN_WEBUI_POSTGRES_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['openwebui'] }}"
|
||||
- name: "OPEN_WEBUI_OAUTH_CLIENT_SECRET"
|
||||
value: "{{ hostvars['console']['openwebui']['oidc']['secret'] }}"
|
||||
notify: "notification_restart_openwebui"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/open-webui/open-webui"
|
||||
tag: "{{ version['containers']['openwebui'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/openwebui/openwebui.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/openwebui.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_openwebui"
|
||||
|
||||
- name: Enable openwebui.service
|
||||
ansible.builtin.systemd:
|
||||
name: "openwebui.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_open-webui_open-webui_{{ version['containers']['openwebui'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/open-webui/open-webui:{{ version['containers']['openwebui'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_open-webui_open-webui_{{ version['containers']['openwebui'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_open-webui_open-webui_{{ version['containers']['openwebui'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -91,7 +91,7 @@
|
||||
force: true
|
||||
loop:
|
||||
- name: "OUTLINE_SECRET_KEY"
|
||||
value: "{{ hostvars['console']['outline']['session_secret'] }}"
|
||||
value: "{{ hostvars['console']['outline']['secret_key'] }}"
|
||||
- name: "OUTLINE_UTILS_SECRET"
|
||||
value: "{{ hostvars['console']['outline']['utils_secret'] }}"
|
||||
- name: "OUTLINE_DATABASE_PASSWORD"
|
||||
@@ -101,6 +101,13 @@
|
||||
notify: "notification_restart_outline"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/outlinewiki/outline"
|
||||
tag: "{{ version['containers']['outline'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy outline.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/outline/outline.container.j2"
|
||||
@@ -122,12 +129,14 @@
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
|
||||
loop:
|
||||
- image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
- name: "redis"
|
||||
image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
|
||||
- image: "docker.io/outlinewiki/outline:{{ version['containers']['outline'] }}"
|
||||
- name: "outline"
|
||||
image: "docker.io/outlinewiki/outline:{{ version['containers']['outline'] }}"
|
||||
file: "docker.io_outlinewiki_outline_{{ version['containers']['outline'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.file }}"
|
||||
label: "{{ item.name }}"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
- name: Create papra directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['papra']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/papra"
|
||||
- "data/containers/papra/data"
|
||||
- "data/containers/papra/backup"
|
||||
- "containers/papra"
|
||||
- "containers/papra/script"
|
||||
- "containers/papra/db"
|
||||
become: true
|
||||
|
||||
- name: Check backup file
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/data/containers/papra/backup/db.sqlite"
|
||||
register: "is_db_backup"
|
||||
|
||||
- name: Check database file
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/containers/papra/db/db.sqlite"
|
||||
register: "is_db"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/papra-hq/papra"
|
||||
tag: "{{ version['containers']['papra'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "PAPRA_AUTH_SECRET"
|
||||
value: "{{ hostvars['console']['papra']['secret_key'] }}"
|
||||
- name: "PAPRA_AUTH_PROVIDERS_CUSTOMS"
|
||||
value: |
|
||||
[
|
||||
{
|
||||
"providerId": "authelia",
|
||||
"providerName": "Authelia",
|
||||
"providerIconUrl": "https://www.authelia.com/images/branding/logo-cropped.png",
|
||||
"clientId": "papra",
|
||||
"clientSecret": "{{ hostvars['console']['papra']['oidc']['secret'] }}",
|
||||
"type": "oidc",
|
||||
"discoveryUrl": "https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration",
|
||||
"scopes": ["openid", "profile", "email"]
|
||||
}
|
||||
]
|
||||
notify: "notification_restart_papra"
|
||||
no_log: true
|
||||
|
||||
- name: Restore db file
|
||||
ansible.builtin.copy:
|
||||
src: "{{ node['home_path'] }}/data/containers/papra/backup/db.sqlite"
|
||||
remote_src: true
|
||||
dest: "{{ node['home_path'] }}/containers/papra/db/db.sqlite"
|
||||
owner: "{{ services['papra']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0660"
|
||||
become: true
|
||||
when:
|
||||
- is_db_backup.stat.exists
|
||||
- not is_db.stat.exists
|
||||
|
||||
- name: Deploy papra.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/papra/papra.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/papra.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
notify: "notification_restart_papra"
|
||||
|
||||
- name: Deploy papra-backup service
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/papra/services/{{ item }}"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "papra-backup.service"
|
||||
- "papra-backup.timer"
|
||||
|
||||
- name: Deploy papra script
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/papra/script/"
|
||||
dest: "{{ node['home_path'] }}/containers/papra/script/"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0755"
|
||||
|
||||
- name: Enable papra.service
|
||||
ansible.builtin.systemd:
|
||||
name: "papra.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Enable papra-backup.timer
|
||||
ansible.builtin.systemd:
|
||||
name: "papra-backup.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_papra-hq_papra_{{ version['containers']['papra'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/papra-hq/papra:{{ version['containers']['papra'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_papra-hq_papra_{{ version['containers']['papra'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_papra-hq_papra_{{ version['containers']['papra'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
- name: Create snappymail directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['snappymail']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/snappymail"
|
||||
- "data/containers/snappymail/data"
|
||||
- "containers/snappymail"
|
||||
- "containers/snappymail/ssl"
|
||||
- "containers/snappymail/configs"
|
||||
- "containers/snappymail/domains"
|
||||
become: true
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/snappymail/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ services['snappymail']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
become: true
|
||||
notify: "notification_restart_snappymail"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/the-djmaze/snappymail"
|
||||
tag: "{{ version['containers']['snappymail'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy config files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/snappymail/{{ item.src }}.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/snappymail/{{ item.dest }}"
|
||||
owner: "{{ services['snappymail']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- src: "configs/application.ini"
|
||||
dest: "configs/application.ini"
|
||||
- src: "domains/domain.ini"
|
||||
dest: "domains/{{ domain['internal'] }}.ini"
|
||||
loop_control:
|
||||
label: "{{ item.src | basename }}"
|
||||
become: true
|
||||
notify: "notification_restart_snappymail"
|
||||
|
||||
- name: Deploy snappymail.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/snappymail/snappymail.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/snappymail.container"
|
||||
owner: "{{ services['snappymail']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
become: true
|
||||
notify: "notification_restart_snappymail"
|
||||
|
||||
- name: Enable snappymail.service
|
||||
ansible.builtin.systemd:
|
||||
name: "snappymail.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_the-djmaze_snappymail_{{ version['containers']['snappymail'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/the-djmaze/snappymail:{{ version['containers']['snappymail'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_the-djmaze_snappymail_{{ version['containers']['snappymail'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_the-djmaze_snappymail_{{ version['containers']['snappymail'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,91 @@
|
||||
---
|
||||
- name: Check model directory in data volume
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/containers/stablediffusion/models"
|
||||
file_type: "file"
|
||||
patterns:
|
||||
- "*.gguf"
|
||||
- "*.safetensors"
|
||||
hidden: true
|
||||
recurse: true
|
||||
register: stablediffusion_models
|
||||
|
||||
- name: Failure when models directory in data volume
|
||||
ansible.builtin.fail:
|
||||
msg: "There are no models in data directory, please ensure download some model files for stable-diffusion.cpp"
|
||||
when: stablediffusion_models.matched == 0
|
||||
|
||||
- name: Create stablediffusion directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/stablediffusion"
|
||||
- "containers/stablediffusion/models"
|
||||
|
||||
- name: Sync model data (--delete=true)
|
||||
delegate_to: "{{ inventory_hostname }}"
|
||||
ansible.posix.synchronize:
|
||||
src: "{{ node['home_path'] }}/data/containers/stablediffusion/models/"
|
||||
dest: "{{ node['home_path'] }}/containers/stablediffusion/models/"
|
||||
owner: true
|
||||
group: true
|
||||
perms: true
|
||||
delete: true
|
||||
notify: "notification_restart_stablediffusion"
|
||||
|
||||
- name: Set active model
|
||||
ansible.builtin.set_fact:
|
||||
stabeldiffusion_active_model: "{{ services['stablediffusion']['dependency']['models']['active'] }}"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/leejet/stable-diffusion.cpp"
|
||||
tag: "{{ version['containers']['stablediffusion'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/stablediffusion/stablediffusion.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/stablediffusion.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_stablediffusion"
|
||||
|
||||
- name: Enable stablediffusion.service
|
||||
ansible.builtin.systemd:
|
||||
name: "stablediffusion.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Set stable-diffusion archive version
|
||||
ansible.builtin.set_fact:
|
||||
stablediffusion_archive_version: >-
|
||||
{{ version['containers']['stablediffusion'].split('@sha256:')[0] }}@{{ version['containers']['stablediffusion'].split('@sha256:')[1][0:7] }}
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/ghcr.io_leejet_stable-diffusion.cpp_{{ stablediffusion_archive_version }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "ghcr.io/leejet/stable-diffusion.cpp:{{ version['containers']['stablediffusion'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/ghcr.io_leejet_stable-diffusion.cpp_{{ stablediffusion_archive_version }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/ghcr.io_leejet_stable-diffusion.cpp_{{ stablediffusion_archive_version }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -78,7 +78,7 @@
|
||||
force: true
|
||||
loop:
|
||||
- name: "SURE_SECRET_KEY_BASE"
|
||||
value: "{{ hostvars['console']['sure']['session_secret'] }}"
|
||||
value: "{{ hostvars['console']['sure']['secret_key'] }}"
|
||||
- name: "SURE_POSTGRES_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['sure'] }}"
|
||||
- name: "SURE_OIDC_CLIENT_SECRET"
|
||||
@@ -86,6 +86,13 @@
|
||||
notify: "notification_restart_sure"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "ghcr.io/we-promise/sure"
|
||||
tag: "{{ version['containers']['sure'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy sure.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/sure/{{ item }}.j2"
|
||||
@@ -113,12 +120,14 @@
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/{{ item.file }}.tar"
|
||||
loop:
|
||||
- image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
- name: "redis"
|
||||
image: "docker.io/library/redis:{{ version['containers']['redis'] }}"
|
||||
file: "docker.io_library_redis_{{ version['containers']['redis'] }}"
|
||||
- image: "ghcr.io/we-promise/sure:{{ version['containers']['sure'] }}"
|
||||
- name: "sure"
|
||||
image: "ghcr.io/we-promise/sure:{{ version['containers']['sure'] }}"
|
||||
file: "ghcr.io_we-promise_sure_{{ version['containers']['sure'] }}"
|
||||
loop_control:
|
||||
label: "{{ item.file }}"
|
||||
label: "{{ item.name }}"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
- name: Create tandoor directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/tandoor"
|
||||
- "data/containers/tandoor/mediafiles"
|
||||
- "containers/tandoor"
|
||||
- "containers/tandoor/ssl"
|
||||
|
||||
- name: Deploy root certificate
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console']['ca']['root']['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/tandoor/ssl/{{ root_cert_filename }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
notify: "notification_restart_tandoor"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "TANDOOR_SECRET_KEY"
|
||||
value: "{{ hostvars['console']['tandoor']['secret_key'] }}"
|
||||
- name: "TANDOOR_POSTGRES_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['tandoor'] }}"
|
||||
- name: "TANDOOR_SOCIALACCOUNT_PROVIDERS"
|
||||
value: |
|
||||
{
|
||||
"openid_connect": {
|
||||
"SCOPE": ["openid", "profile", "email"],
|
||||
"OAUTH_PKCE_ENABLED": true,
|
||||
"APPS": [
|
||||
{
|
||||
"provider_id": "authelia",
|
||||
"name": "authelia",
|
||||
"client_id": "tandoor",
|
||||
"secret": "{{ hostvars['console']['tandoor']['oidc']['secret'] }}",
|
||||
"settings": {
|
||||
"server_url": "https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}/.well-known/openid-configuration",
|
||||
"token_auth_method": "client_secret_basic"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
notify: "notification_restart_tandoor"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/vabene1111/recipes"
|
||||
tag: "{{ version['containers']['tandoor'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy tandoor.container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/tandoor/tandoor.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/tandoor.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_tandoor"
|
||||
|
||||
- name: Enable tandoor.service
|
||||
ansible.builtin.systemd:
|
||||
name: "tandoor.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_vabene1111_recipes_{{ version['containers']['tandoor'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/vabene1111/recipes:{{ version['containers']['tandoor'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_vabene1111_recipes_{{ version['containers']['tandoor'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_vabene1111_recipes_{{ version['containers']['tandoor'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -8,6 +8,7 @@
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/vaultwarden"
|
||||
- "data/containers/vaultwarden/data"
|
||||
- "containers/vaultwarden"
|
||||
- "containers/vaultwarden/ssl"
|
||||
|
||||
@@ -34,11 +35,18 @@
|
||||
value: "{{ hostvars['console']['vaultwarden']['admin']['hash'] }}"
|
||||
- name: "VW_DATABASE_URL"
|
||||
value: "postgresql://vaultwarden:{{ hostvars['console']['postgresql']['password']['vaultwarden'] | urlencode | replace('/', '%2F') }}\
|
||||
@{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/vaultwarden_db?sslmode=verify-full&\
|
||||
@{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/vaultwarden_db?sslmode=verify-full&\
|
||||
sslrootcert=/etc/ssl/vaultwarden/{{ root_cert_filename }}"
|
||||
notify: "notification_restart_vaultwarden"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/vaultwarden/server"
|
||||
tag: "{{ version['containers']['vaultwarden'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/app/vaultwarden/vaultwarden.container.j2"
|
||||
|
||||
@@ -54,12 +54,19 @@
|
||||
- name: "AUTHELIA_JWKS_ES256"
|
||||
value: "{{ hostvars['console']['authelia']['jwk_es256'] }}"
|
||||
- name: "AUTHELIA_LDAP_PASSWORD"
|
||||
value: "{{ hostvars['console']['ldap']['password']['authelia'] }}"
|
||||
value: "{{ hostvars['console']['ldap']['password']['services']['authelia'] }}"
|
||||
- name: "POSTGRES_AUTHELIA_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['authelia'] }}"
|
||||
notify: "notification_restart_authelia"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/authelia/authelia"
|
||||
tag: "{{ version['containers']['authelia'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/auth/authelia/authelia.container.j2"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
- name: Install rclone
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "rclone"
|
||||
state: "present"
|
||||
become: true
|
||||
|
||||
- name: Create rclone config directory
|
||||
ansible.builtin.file:
|
||||
path: "/etc/secrets/{{ node['uid'] }}/rclone"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "root"
|
||||
mode: "0700"
|
||||
become: true
|
||||
|
||||
- name: Deploy rclone config
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/bk/rclone/config/rclone.config.j2"
|
||||
dest: "/etc/secrets/{{ node['uid'] }}/rclone/rclone.config"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy rclone backup service files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/bk/rclone/{{ item }}.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
validate: "/usr/bin/systemd-analyze verify %s"
|
||||
loop:
|
||||
- "rclone.service"
|
||||
- "rclone.timer"
|
||||
|
||||
- name: Enable rclone timer
|
||||
ansible.builtin.systemd:
|
||||
name: "rclone.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
@@ -99,3 +99,14 @@
|
||||
changed_when: false
|
||||
listen: "notification_restart_alloy"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart kopia server
|
||||
ansible.builtin.systemd:
|
||||
name: "kopia-server.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
changed_when: false
|
||||
listen: "notification_restart_kopia_server"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
+10
-10
@@ -1,16 +1,16 @@
|
||||
---
|
||||
- name: Check app data volume filesystem already exists
|
||||
ansible.builtin.command:
|
||||
cmd: "blkid /dev/{{ vm['data_storage']['name'] }}"
|
||||
register: is_app_data
|
||||
- name: Check data volume filesystem already exists
|
||||
ansible.builtin.command: |
|
||||
blkid /dev/{{ vm['data_storage']['name'] }}
|
||||
register: is_volume
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
become: true
|
||||
|
||||
- name: Create ext4 filesystem on app data raw
|
||||
ansible.builtin.command:
|
||||
cmd: "mkfs.ext4 -F /dev/{{ vm['data_storage']['name'] }}"
|
||||
when: is_app_data.rc != 0
|
||||
- name: Create ext4 filesystem on data raw
|
||||
ansible.builtin.command: |
|
||||
mkfs.ext4 -F /dev/{{ vm['data_storage']['name'] }}
|
||||
when: is_volume.rc != 0
|
||||
changed_when: true
|
||||
become: true
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
|
||||
- name: Mount app data volume
|
||||
- name: Mount data volume
|
||||
ansible.posix.mount:
|
||||
path: "{{ node['home_path'] }}/data"
|
||||
src: "/dev/{{ vm['data_storage']['name'] }}"
|
||||
@@ -31,7 +31,7 @@
|
||||
fstype: "ext4"
|
||||
become: true
|
||||
|
||||
- name: Set app data volume path permissions
|
||||
- name: Set data volume path permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data"
|
||||
state: "directory"
|
||||
@@ -1,19 +1,10 @@
|
||||
---
|
||||
- name: Check nftables installation
|
||||
ansible.builtin.shell: |
|
||||
command -v nft
|
||||
become: true # nftables is located in /usr/sbin, which means root permission is needed.
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_nftables_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install nftables
|
||||
ansible.builtin.apt:
|
||||
name: "nftables"
|
||||
name:
|
||||
- "nftables"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_nftables_installed.rc != 0
|
||||
|
||||
- name: Enable nftables.service
|
||||
ansible.builtin.systemd:
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
become: true
|
||||
|
||||
- name: Deploy timesyncd.conf.d/local-ntp.conf
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/node/common/timesyncd/local-ntp.conf"
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/node/common/timesyncd/local-ntp.conf.j2"
|
||||
dest: "/etc/systemd/timesyncd.conf.d/local-ntp.conf"
|
||||
owner: "root"
|
||||
group: "systemd-timesync"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
- name: Gather ystem facts (hardware)
|
||||
- name: Gather system facts (hardware)
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- hardware
|
||||
@@ -78,7 +78,7 @@
|
||||
- "{{ node['home_path'] }}"
|
||||
- "{{ node['home_path'] }}/data"
|
||||
become: true
|
||||
when: node['name'] == "app"
|
||||
when: node['name'] in ["bk", "app"]
|
||||
|
||||
- name: Enable alloy service
|
||||
ansible.builtin.systemd:
|
||||
@@ -88,9 +88,16 @@
|
||||
daemon_reload: true
|
||||
become: true
|
||||
|
||||
- name: Check alloy.deb on console
|
||||
delegate_to: "console"
|
||||
ansible.builtin.stat:
|
||||
path: "{{ hostvars['console']['node']['data_path'] }}/bin/alloy-{{ version['packages']['alloy'] }}.deb"
|
||||
register: is_console_alloy_deb
|
||||
|
||||
- name: Fetch deb bin file
|
||||
ansible.builtin.fetch:
|
||||
src: "/var/cache/apt/archives/alloy-{{ version['packages']['alloy'] }}.deb"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/bin/"
|
||||
flat: true
|
||||
when: not is_console_alloy_deb.stat.exists
|
||||
become: true
|
||||
|
||||
@@ -1,5 +1,48 @@
|
||||
---
|
||||
- name: Initialize Caddy services list
|
||||
ansible.builtin.set_fact:
|
||||
caddy_services: []
|
||||
|
||||
# infra, auth, app (vmm, fw has no podman in it)
|
||||
- name: Set Caddy infra services list
|
||||
ansible.builtin.set_fact:
|
||||
caddy_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.web', 'defined')
|
||||
| selectattr('value.dependency.web', 'in', ['infra-internal', 'infra-public'])
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
when: node['name'] == 'infra'
|
||||
|
||||
- name: Set Caddy auth services list
|
||||
ansible.builtin.set_fact:
|
||||
caddy_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.web', 'defined')
|
||||
| selectattr('value.dependency.web', 'in', ['auth-public', 'infra-public', 'app-public'])
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
when: node['name'] == 'auth'
|
||||
|
||||
- name: Set Caddy app services list
|
||||
ansible.builtin.set_fact:
|
||||
caddy_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.web', 'defined')
|
||||
| selectattr('value.dependency.web', 'in', ['app-internal', 'app-public'])
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
when: node['name'] == 'app'
|
||||
|
||||
- name: Create caddy directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers/{{ item }}"
|
||||
@@ -50,6 +93,8 @@
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0640"
|
||||
register: "is_caddy_containerfile"
|
||||
notify: "notification_restart_caddy"
|
||||
|
||||
- name: Deploy root crt for build
|
||||
ansible.builtin.copy:
|
||||
@@ -58,6 +103,8 @@
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0640"
|
||||
register: "is_caddy_root_crt"
|
||||
notify: "notification_restart_caddy"
|
||||
no_log: true
|
||||
|
||||
- name: Build caddy container image
|
||||
@@ -67,6 +114,7 @@
|
||||
tag: "{{ version['containers']['caddy'] }}"
|
||||
state: "build"
|
||||
path: "{{ node['home_path'] }}/containers/caddy/build"
|
||||
force: "{{ is_caddy_root_crt.changed or is_caddy_containerfile.changed }}"
|
||||
|
||||
- name: Prune caddy dangling images
|
||||
containers.podman.podman_prune:
|
||||
@@ -74,7 +122,7 @@
|
||||
|
||||
- name: Deploy caddyfile
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/common/caddy/etc/{{ node['name'] }}/Caddyfile.j2"
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/common/caddy/etc/Caddyfile.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/caddy/etc/Caddyfile"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
@@ -109,8 +157,8 @@
|
||||
- "{{ domain['internal'] }}/{{ node['name'] }}/caddy:{{ version['containers']['caddy'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/{{ domain['internal'] }}_{{ node['name'] }}_caddy_{{ version['containers']['caddy'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
force: "{{ is_caddy_root_crt.changed or is_caddy_containerfile.changed }}"
|
||||
when: not container_archive_images.stat.exists or is_caddy_root_crt.changed or is_caddy_containerfile.changed
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
|
||||
@@ -1,36 +1,18 @@
|
||||
---
|
||||
- name: Check crowdsec installed
|
||||
ansible.builtin.shell: |
|
||||
command -v crowdsec
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_crowdsec_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Check crowdsec bouncer installed
|
||||
ansible.builtin.shell: |
|
||||
command -v crowdsec-firewall-bouncer
|
||||
when: node['name'] == "fw"
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_crowdsec_bouncer_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install crowdsec
|
||||
ansible.builtin.apt:
|
||||
name: "crowdsec"
|
||||
name:
|
||||
- "crowdsec"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_crowdsec_installed.rc != 0
|
||||
|
||||
- name: Install crowdsec bouncers
|
||||
ansible.builtin.apt:
|
||||
name: "crowdsec-firewall-bouncer"
|
||||
name:
|
||||
- "crowdsec-firewall-bouncer"
|
||||
state: "present"
|
||||
become: true
|
||||
when:
|
||||
- node['name'] == "fw"
|
||||
- is_crowdsec_bouncer_installed.rc != 0
|
||||
when: node['name'] == "fw"
|
||||
|
||||
- name: Set acquis.d list for bouncer
|
||||
ansible.builtin.set_fact:
|
||||
@@ -120,8 +102,8 @@
|
||||
no_log: true
|
||||
|
||||
- name: Get existing machines list
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli machines list -o json"
|
||||
ansible.builtin.command: |
|
||||
cscli machines list -o json
|
||||
become: true
|
||||
changed_when: false
|
||||
register: "existing_crowdsec_machines_list"
|
||||
@@ -132,27 +114,27 @@
|
||||
|
||||
- name: Set goal machines' name
|
||||
ansible.builtin.set_fact:
|
||||
machines_name: ["fw", "vmm", "infra", "auth", "app"]
|
||||
machines_name: "{{ services['crowdsec']['sub']['machines'] | list }}"
|
||||
no_log: true
|
||||
|
||||
- name: Prune unknown (random) machines
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli machines delete {{ item }}"
|
||||
ansible.builtin.command: |
|
||||
cscli machines delete {{ item }}
|
||||
loop: "{{ existing_machines_name | difference(machines_name) }}"
|
||||
become: true
|
||||
changed_when: true
|
||||
|
||||
- name: Register crowdsec machines to LAPI server
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli machines add {{ item }} --password {{ hostvars['console']['crowdsec']['machine'][item] }} --force -f /dev/null"
|
||||
ansible.builtin.command: |
|
||||
cscli machines add {{ item }} --password {{ hostvars['console']['crowdsec']['machine'][item] }} --force -f /dev/null
|
||||
loop: "{{ machines_name }}"
|
||||
become: true
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Get existing bouncers list
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli bouncers list -o json"
|
||||
ansible.builtin.command: |
|
||||
cscli bouncers list -o json
|
||||
become: true
|
||||
register: "existing_crowdsec_bouncers_list"
|
||||
changed_when: false
|
||||
@@ -162,19 +144,19 @@
|
||||
existing_bouncers_name: "{{ existing_crowdsec_bouncers_list.stdout | from_json | map(attribute='name') | list }}"
|
||||
|
||||
- name: Flush bouncers
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli bouncers delete {{ item }}"
|
||||
ansible.builtin.command: |
|
||||
cscli bouncers delete {{ item }}
|
||||
loop: "{{ existing_bouncers_name }}"
|
||||
become: true
|
||||
changed_when: true
|
||||
|
||||
- name: Set bouncers' name
|
||||
ansible.builtin.set_fact:
|
||||
bouncers_name: ["fw", "caddy"]
|
||||
bouncers_name: "{{ services['crowdsec']['sub']['bouncers'] | list }}"
|
||||
|
||||
- name: Register Firewall Bouncer to LAPI
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli bouncers add {{ item }}-bouncer -k {{ hostvars['console']['crowdsec']['bouncer'][item] }}"
|
||||
ansible.builtin.command: |
|
||||
cscli bouncers add {{ item }}-bouncer -k {{ hostvars['console']['crowdsec']['bouncer'][item] }}
|
||||
loop: "{{ bouncers_name }}"
|
||||
become: true
|
||||
changed_when: true
|
||||
@@ -184,9 +166,15 @@
|
||||
- name: Set crowdsec bouncer
|
||||
when: node['name'] in acquisd_list
|
||||
block:
|
||||
- name: Update and upgrade crowdsec hub
|
||||
ansible.builtin.shell: |
|
||||
cscli hub update && cscli hub upgrade
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: Install crowdsec collection
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli collections install {{ item }}"
|
||||
ansible.builtin.command: |
|
||||
cscli collections install {{ item }}
|
||||
loop: "{{ acquisd_list[node['name']]['collection'] }}"
|
||||
become: true
|
||||
changed_when: "'overwrite' not in is_collection_installed.stderr"
|
||||
@@ -196,8 +184,8 @@
|
||||
register: "is_collection_installed"
|
||||
|
||||
- name: Install crowdsec parser
|
||||
ansible.builtin.command:
|
||||
cmd: "cscli parsers install {{ item }}"
|
||||
ansible.builtin.command: |
|
||||
cscli parsers install {{ item }}
|
||||
loop: "{{ acquisd_list[node['name']]['parser'] }}"
|
||||
become: true
|
||||
changed_when: "'overwrite' not in is_parser_installed.stderr"
|
||||
|
||||
@@ -5,55 +5,296 @@
|
||||
- hardware
|
||||
become: true
|
||||
|
||||
- name: Set console kopia
|
||||
when: node['name'] == 'console'
|
||||
- name: Set backup kopia repository server
|
||||
when: node['name'] == "bk"
|
||||
block:
|
||||
- name: Download kopia
|
||||
- name: Download kopia deb file (x86_64)
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
|
||||
kopia_{{ version['packages']['kopia'] }}_linux_{{ item }}.deb"
|
||||
dest: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-{{ item }}.deb"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
loop:
|
||||
- "amd64"
|
||||
- "arm64"
|
||||
|
||||
- name: Install kopia (x86_64)
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-amd64.deb"
|
||||
state: "present"
|
||||
kopia_{{ version['packages']['kopia'] }}_linux_amd64.deb"
|
||||
dest: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
become: true
|
||||
when: ansible_facts['architecture'] == "x86_64"
|
||||
|
||||
- name: Install kopia (aarch64)
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-arm64.deb"
|
||||
state: "present"
|
||||
- name: Download kopia deb file (aarch64)
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
|
||||
kopia_{{ version['packages']['kopia'] }}_linux_arm64.deb"
|
||||
dest: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
become: true
|
||||
when: ansible_facts['architecture'] == "aarch64"
|
||||
|
||||
- name: Connect console kopia server
|
||||
environment:
|
||||
KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users']['console'] }}"
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia repository connect server \
|
||||
--url=https://{{ services['kopia']['domain'] }}.{{ domain['internal'] }}:{{ services['kopia']['ports']['https'] }} \
|
||||
--override-username=console \
|
||||
--override-hostname=console.{{ domain['internal'] }}
|
||||
changed_when: false
|
||||
failed_when: is_kopia_connected.rc != 0
|
||||
register: "is_kopia_connected"
|
||||
- name: Create kopia directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ item.name }}"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "root"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- name: "/etc/kopia"
|
||||
mode: "0700"
|
||||
- name: "/etc/kopia/ssl"
|
||||
mode: "0700"
|
||||
- name: "/var/cache/kopia"
|
||||
mode: "0700"
|
||||
become: true
|
||||
no_log: true
|
||||
|
||||
- name: Set infra/app kopia
|
||||
when: node['name'] in ['infra', 'app']
|
||||
block:
|
||||
- name: Set kopia uid
|
||||
ansible.builtin.set_fact:
|
||||
kopia_uid: 951
|
||||
- name: Install kopia
|
||||
ansible.builtin.apt:
|
||||
deb: "/var/cache/apt/archives/kopia-{{ version['packages']['kopia'] }}.deb"
|
||||
state: "present"
|
||||
become: true
|
||||
notify: "notification_restart_kopia_server"
|
||||
|
||||
- name: Deploy kopia env
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/kopia.env.j2"
|
||||
dest: "/etc/secrets/{{ node['uid'] }}/kopia.env"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "root"
|
||||
mode: "0400"
|
||||
become: true
|
||||
notify: "notification_restart_kopia_server"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy kopia certificate and key
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ item.value }}
|
||||
dest: "/etc/kopia/ssl/{{ item.name }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- name: "kopia.crt"
|
||||
value: |
|
||||
{{ hostvars['console']['kopia']['crt'] | trim }}
|
||||
{{ hostvars['console']['ca']['intermediate']['crt'] }}
|
||||
mode: "0440"
|
||||
- name: "kopia.key"
|
||||
value: "{{ hostvars['console']['kopia']['key'] }}"
|
||||
mode: "0400"
|
||||
notify: "notification_restart_kopia_server"
|
||||
no_log: true
|
||||
|
||||
- name: Create repository directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/kopia/repository"
|
||||
state: "directory"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
|
||||
- name: Check repository directory empty
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/kopia/repository/"
|
||||
file_type: "any"
|
||||
hidden: true
|
||||
recurse: false
|
||||
register: "is_kopia_repository_empty"
|
||||
|
||||
- name: Create kopia repository
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia repository create filesystem \
|
||||
--path="{{ node['home_path'] }}/data/kopia/repository" \
|
||||
--description="{{ domain['internal'] }} kopia repository"
|
||||
when: is_kopia_repository_empty.matched == 0
|
||||
changed_when: true
|
||||
no_log: true
|
||||
|
||||
- name: Connect to kopia repository
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia repository connect filesystem \
|
||||
--path="{{ node['home_path'] }}/data/kopia/repository" \
|
||||
--override-username="il" \
|
||||
--override-hostname="{{ node['name'] }}.{{ domain['internal'] }}"
|
||||
when: is_kopia_repository_empty.matched > 0
|
||||
changed_when: false
|
||||
failed_when:
|
||||
- is_kopia_repository_empty.matched > 0
|
||||
- is_repository_connected.rc != 0
|
||||
register: "is_repository_connected"
|
||||
no_log: true
|
||||
|
||||
- name: Create kopia user
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia server users add \
|
||||
--user-password {{ item.password | quote }} \
|
||||
{{ item.name }}
|
||||
loop:
|
||||
- name: "console@console.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['console'] }}"
|
||||
- name: "infra@infra.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['infra'] }}"
|
||||
- name: "app@app.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['app'] }}"
|
||||
when: is_kopia_repository_empty.matched == 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Update kopia user
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia server users set \
|
||||
--user-password {{ item.password | quote }} \
|
||||
{{ item.name }}
|
||||
loop:
|
||||
- name: "console@console.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['console'] }}"
|
||||
- name: "infra@infra.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['infra'] }}"
|
||||
- name: "app@app.{{ domain['internal'] }}"
|
||||
password: "{{ hostvars['console']['kopia']['users']['app'] }}"
|
||||
when: is_kopia_repository_empty.matched > 0
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Set kopia console ACL
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia server acl add \
|
||||
--user console@console.{{ domain['internal'] }} \
|
||||
--target {{ item }} \
|
||||
--access FULL \
|
||||
--overwrite
|
||||
loop:
|
||||
- "type=snapshot"
|
||||
- "type=policy"
|
||||
- "type=user"
|
||||
- "type=acl"
|
||||
- "type=content"
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Set kopia infra ACL
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia server acl add \
|
||||
--user infra@infra.{{ domain['internal'] }} \
|
||||
--target {{ item.target }} \
|
||||
--access {{ item.access }} \
|
||||
--overwrite
|
||||
loop:
|
||||
- target: "type=snapshot"
|
||||
access: "FULL"
|
||||
- target: "type=policy"
|
||||
access: "READ"
|
||||
- target: "type=policy,username=infra,hostname=infra.{{ domain['internal'] }}"
|
||||
access: "FULL"
|
||||
- target: "type=content"
|
||||
access: "APPEND"
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Set kopia app ACL
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia server acl add \
|
||||
--user app@app.{{ domain['internal'] }} \
|
||||
--target {{ item.target }} \
|
||||
--access {{ item.access }} \
|
||||
--overwrite
|
||||
loop:
|
||||
- target: "type=snapshot"
|
||||
access: "FULL"
|
||||
- target: "type=policy"
|
||||
access: "READ"
|
||||
- target: "type=policy,username=app,hostname=app.{{ domain['internal'] }}"
|
||||
access: "FULL"
|
||||
- target: "type=content"
|
||||
access: "APPEND"
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Set kopia policy
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia policy set \
|
||||
{{ item.content }}
|
||||
loop:
|
||||
- content: |
|
||||
--global \
|
||||
--compression=zstd
|
||||
- content: |
|
||||
infra@infra.{{ domain['internal'] }} \
|
||||
--compression=zstd \
|
||||
--keep-latest=10 \
|
||||
--keep-hourly=0 \
|
||||
--keep-daily=14 \
|
||||
--keep-weekly=4 \
|
||||
--keep-monthly=6 \
|
||||
--keep-annual=1
|
||||
- content: |
|
||||
app@app.{{ domain['internal'] }} \
|
||||
--compression=none \
|
||||
--keep-latest=10 \
|
||||
--keep-hourly=0 \
|
||||
--keep-daily=14 \
|
||||
--keep-weekly=4 \
|
||||
--keep-monthly=6 \
|
||||
--keep-annual=1
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Set kopia parameters
|
||||
ansible.builtin.shell: |
|
||||
set -a
|
||||
. /etc/secrets/{{ node['uid'] }}/kopia.env
|
||||
set +a
|
||||
/usr/bin/kopia repository set-parameters \
|
||||
--max-pack-size-mb=100
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Deploy kopia server service file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/kopia-server.service.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/kopia-server.service"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
validate: "/usr/bin/systemd-analyze verify %s"
|
||||
become: true
|
||||
notify: "notification_restart_kopia_server"
|
||||
|
||||
- name: Enable kopia server service
|
||||
ansible.builtin.systemd:
|
||||
name: "kopia-server.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
scope: "user"
|
||||
daemon_reload: true
|
||||
|
||||
- name: Set infra/app backup kopia
|
||||
when: node['name'] in ["infra", "app"]
|
||||
block:
|
||||
- name: Download kopia deb file (x86_64)
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
|
||||
@@ -79,14 +320,14 @@
|
||||
- name: Create kopia group
|
||||
ansible.builtin.group:
|
||||
name: "kopia"
|
||||
gid: "{{ kopia_uid }}"
|
||||
gid: "{{ services['kopia']['uid'] }}"
|
||||
state: "present"
|
||||
become: true
|
||||
|
||||
- name: Create kopia user
|
||||
ansible.builtin.user:
|
||||
name: "kopia"
|
||||
uid: "{{ kopia_uid }}"
|
||||
uid: "{{ services['kopia']['uid'] }}"
|
||||
group: "kopia"
|
||||
shell: "/usr/sbin/nologin"
|
||||
password_lock: true
|
||||
@@ -120,14 +361,99 @@
|
||||
- name: Deploy kopia env
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/kopia.env.j2"
|
||||
dest: "/etc/secrets/{{ kopia_uid }}/kopia.env"
|
||||
owner: "{{ kopia_uid }}"
|
||||
dest: "/etc/secrets/{{ services['kopia']['uid'] }}/kopia.env"
|
||||
owner: "{{ services['kopia']['uid'] }}"
|
||||
group: "root"
|
||||
mode: "0400"
|
||||
become: true
|
||||
no_log: true
|
||||
|
||||
- name: Deploy kopia service files
|
||||
- name: Check data directory existance
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/data/"
|
||||
register: "is_data_dir"
|
||||
|
||||
- name: Delete lost+found directory on data directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/lost+found/"
|
||||
state: "absent"
|
||||
become: true
|
||||
when: is_data_dir.stat.exists
|
||||
|
||||
- name: Check data directory empty
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/"
|
||||
file_type: "any"
|
||||
hidden: true
|
||||
recurse: false
|
||||
register: "is_data_dir_empty"
|
||||
when: is_data_dir.stat.exists
|
||||
|
||||
- name: Connect kopia server
|
||||
environment:
|
||||
KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users'][node['name']] }}"
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia repository connect server \
|
||||
--url=https://{{ services['kopia']['domain']['internal'] }}.{{ domain['internal'] }}:443 \
|
||||
--override-username={{ node['name'] }} \
|
||||
--override-hostname={{ node['name'] }}.{{ domain['internal'] }}
|
||||
become: true
|
||||
when: (is_data_dir_empty.matched | default(1)) == 0
|
||||
changed_when: false
|
||||
failed_when: is_kopia_connected.rc != 0
|
||||
register: "is_kopia_connected"
|
||||
no_log: true
|
||||
|
||||
- name: Check whether Kopia snapshot exists
|
||||
environment:
|
||||
KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users'][node['name']] }}"
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia snapshot list \
|
||||
{{ node['name'] }}@{{ node['name'] }}.{{ domain['internal'] }}:{{ node['home_path'] }}/data \
|
||||
--json \
|
||||
--max-results=1
|
||||
become: true
|
||||
when: (is_kopia_connected.rc | default(1)) == 0
|
||||
changed_when: false
|
||||
failed_when: is_snapshot_exist.rc != 0
|
||||
register: "is_snapshot_exist"
|
||||
no_log: true
|
||||
|
||||
- name: Restore data directory
|
||||
environment:
|
||||
KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users'][node['name']] }}"
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia snapshot restore \
|
||||
--snapshot-time=latest \
|
||||
{{ node['name'] }}@{{ node['name'] }}.{{ domain['internal'] }}:{{ node['home_path'] }}/data \
|
||||
{{ node['home_path'] }}/data
|
||||
become: true
|
||||
when:
|
||||
- (is_data_dir_empty.matched | default(1)) == 0
|
||||
- (is_kopia_connected.rc | default(1)) == 0
|
||||
- (is_snapshot_exist.stdout |
|
||||
default('[]', true) |
|
||||
from_json |
|
||||
list |
|
||||
length
|
||||
) > 0
|
||||
changed_when: is_kopia_restored.rc == 0
|
||||
failed_when: is_kopia_restored.rc != 0
|
||||
register: "is_kopia_restored"
|
||||
no_log: true
|
||||
|
||||
- name: Disconnect kopia server
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia repository disconnect
|
||||
become: true
|
||||
when:
|
||||
- (is_data_dir_empty.matched | default(1)) == 0
|
||||
- (is_kopia_connected.rc | default(1)) == 0
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Deploy kopia backup service files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/common/kopia/{{ item }}.j2"
|
||||
dest: "/etc/systemd/system/{{ item }}"
|
||||
@@ -140,10 +466,52 @@
|
||||
- "kopia-backup.timer"
|
||||
become: true
|
||||
|
||||
- name: Enable auto kopia rules update
|
||||
- name: Enable Kopia backup timer
|
||||
ansible.builtin.systemd:
|
||||
name: "kopia-backup.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
become: true
|
||||
|
||||
- name: Set console kopia
|
||||
when: node['name'] == "console"
|
||||
block:
|
||||
- name: Download kopia
|
||||
ansible.builtin.get_url:
|
||||
url: "https://github.com/kopia/kopia/releases/download/v{{ version['packages']['kopia'] }}/\
|
||||
kopia_{{ version['packages']['kopia'] }}_linux_{{ item }}.deb"
|
||||
dest: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-{{ item }}.deb"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
loop:
|
||||
- "amd64"
|
||||
- "arm64"
|
||||
|
||||
- name: Install kopia (x86_64)
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-amd64.deb"
|
||||
state: "present"
|
||||
become: true
|
||||
when: ansible_facts['architecture'] == "x86_64"
|
||||
|
||||
- name: Install kopia (aarch64)
|
||||
ansible.builtin.apt:
|
||||
deb: "{{ node['data_path'] }}/bin/kopia-{{ version['packages']['kopia'] }}-arm64.deb"
|
||||
state: "present"
|
||||
become: true
|
||||
when: ansible_facts['architecture'] == "aarch64"
|
||||
|
||||
- name: Connect console kopia server
|
||||
environment:
|
||||
KOPIA_PASSWORD: "{{ hostvars['console']['kopia']['users']['console'] }}"
|
||||
ansible.builtin.shell: |
|
||||
/usr/bin/kopia repository connect server \
|
||||
--url=https://{{ services['kopia']['domain']['internal'] }}.{{ domain['internal'] }}:443 \
|
||||
--override-username={{ node['name'] }} \
|
||||
--override-hostname={{ node['name'] }}.{{ domain['internal'] }}
|
||||
changed_when: false
|
||||
failed_when: is_kopia_connected.rc != 0
|
||||
register: "is_kopia_connected"
|
||||
no_log: true
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
---
|
||||
- name: Check podman installation
|
||||
ansible.builtin.shell: |
|
||||
command -v podman
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_podman_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Create container directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers"
|
||||
@@ -15,14 +7,14 @@
|
||||
state: "directory"
|
||||
mode: "0700"
|
||||
|
||||
- name: Create container data directory for app
|
||||
- name: Create container data directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/data/containers"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
state: "directory"
|
||||
mode: "0770"
|
||||
when: node['name'] == "app"
|
||||
when: node['name'] in ["infra", "app"]
|
||||
|
||||
- name: Create container image archive directory
|
||||
ansible.builtin.file:
|
||||
@@ -35,23 +27,22 @@
|
||||
- "{{ node['home_path'] }}/archives"
|
||||
- "{{ node['home_path'] }}/archives/containers"
|
||||
|
||||
- name: Install podman and reset ssh connection for initiating
|
||||
when: is_podman_installed.rc != 0
|
||||
- name: Set subid scope (Overwrite)
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ ansible_user }}:100000:65536
|
||||
dest: "/etc/sub{{ item }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "uid"
|
||||
- "gid"
|
||||
become: true
|
||||
|
||||
- name: Install podman
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "podman"
|
||||
state: "present"
|
||||
become: true
|
||||
block:
|
||||
- name: Set subid scope (Overwrite)
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ ansible_user }}:100000:65536
|
||||
dest: "/etc/sub{{ item }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "uid"
|
||||
- "gid"
|
||||
- name: Install podman
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "podman"
|
||||
state: "present"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
environment:
|
||||
SOPS_AGE_KEY: "{{ hostvars['console']['age_key'] }}"
|
||||
ansible.builtin.command: |
|
||||
sops -d --output-type yaml {{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml
|
||||
sops -d --output-type yaml "{{ hostvars['console']['node']['config_path'] }}/secrets/secrets.yaml"
|
||||
changed_when: false
|
||||
register: "decrypted_secrets"
|
||||
run_once: true
|
||||
|
||||
@@ -1,29 +1,10 @@
|
||||
---
|
||||
- name: Check bind9 installation
|
||||
ansible.builtin.shell: |
|
||||
command -v named
|
||||
become: true # named is located in /usr/sbin, which means root permission is needed.
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_bind_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Set bind9 zone files
|
||||
ansible.builtin.set_fact:
|
||||
bind_zone_files:
|
||||
- "db.ilnmors.internal"
|
||||
- "db.ilnmors.com"
|
||||
- "db.1.168.192.in-addr.arpa"
|
||||
- "db.10.168.192.in-addr.arpa"
|
||||
- "db.1.00df.ip6.arpa"
|
||||
- "db.10.00df.ip6.arpa"
|
||||
|
||||
- name: Install bind9
|
||||
ansible.builtin.apt:
|
||||
name: "bind9"
|
||||
name:
|
||||
- "bind9"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_bind_installed.rc != 0
|
||||
|
||||
- name: Deploy acme.key
|
||||
ansible.builtin.copy:
|
||||
@@ -36,23 +17,64 @@
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy db files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/fw/bind/lib/{{ item }}"
|
||||
dest: "/var/lib/bind/{{ item }}"
|
||||
- name: Deploy forward zone files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/fw/bind/lib/{{ item.src }}.j2"
|
||||
dest: "/var/lib/bind/{{ item.dest }}"
|
||||
owner: "bind"
|
||||
group: "bind"
|
||||
mode: "0640"
|
||||
loop: "{{ bind_zone_files }}"
|
||||
loop:
|
||||
- src: "db.public"
|
||||
dest: "db.{{ domain['public'] }}"
|
||||
- src: "db.internal"
|
||||
dest: "db.{{ domain['internal'] }}"
|
||||
become: true
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy IPv4 reverse zone files
|
||||
vars:
|
||||
reverse_net: "{{ item.key }}"
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/fw/bind/lib/db.ipv4.rev.j2"
|
||||
dest: "/var/lib/bind/db.{{ item.key }}.ipv4.rev"
|
||||
owner: bind
|
||||
group: bind
|
||||
mode: "0644"
|
||||
loop: "{{ network['reverse_zone']['ipv4'] | dict2items }}"
|
||||
become: true
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy IPv6 reverse zones
|
||||
vars:
|
||||
reverse_net: "{{ item.key }}"
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/fw/bind/lib/db.ipv6.rev.j2"
|
||||
dest: "/var/lib/bind/db.{{ item.key }}.ipv6.rev"
|
||||
owner: bind
|
||||
group: bind
|
||||
mode: "0644"
|
||||
loop: "{{ network['reverse_zone']['ipv6'] | dict2items }}"
|
||||
become: true
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
|
||||
- name: Find BIND journal files
|
||||
ansible.builtin.find:
|
||||
paths: "/var/lib/bind"
|
||||
patterns: "*.jnl"
|
||||
file_type: file
|
||||
become: true
|
||||
register: bind_journal_files
|
||||
no_log: true
|
||||
|
||||
- name: Clean BIND journal files
|
||||
ansible.builtin.file:
|
||||
path: "/var/lib/bind/{{ item }}.jnl"
|
||||
path: "{{ item.path }}"
|
||||
state: absent
|
||||
loop: "{{ bind_zone_files }}"
|
||||
loop: "{{ bind_journal_files.files }}"
|
||||
become: true
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
@@ -67,7 +89,7 @@
|
||||
validate: "/usr/bin/named-checkconf -z %s"
|
||||
become: true
|
||||
notify: "notification_restart_bind"
|
||||
no_log: true
|
||||
|
||||
|
||||
- name: Create named.service.d
|
||||
ansible.builtin.file:
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
---
|
||||
- name: Check chrnoy installation
|
||||
ansible.builtin.shell: |
|
||||
command -v chronyc
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_chrony_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install chrony
|
||||
ansible.builtin.apt:
|
||||
name: "chrony"
|
||||
name:
|
||||
- "chrony"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_chrony_installed.rc != 0
|
||||
|
||||
- name: Deploy local acl file
|
||||
ansible.builtin.template:
|
||||
|
||||
@@ -1,20 +1,10 @@
|
||||
---
|
||||
- name: Check Kea dhcp4 installation
|
||||
ansible.builtin.shell: |
|
||||
command -v kea-dhcp4
|
||||
become: true # kea-dhcp4 is located in /usr/sbin, which means root permission is needed.
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_kea4_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install kea dhcp 4
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "kea-dhcp4-server"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_kea4_installed.rc != 0
|
||||
|
||||
- name: Deploy kea dhcp4 conf
|
||||
ansible.builtin.template:
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
---
|
||||
- name: Check suricata installation
|
||||
ansible.builtin.shell: |
|
||||
command -v suricata
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_suricata_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install suricata
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
@@ -14,7 +6,6 @@
|
||||
- "suricata-update"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_suricata_installed.rc != 0
|
||||
|
||||
- name: Deploy suricata-update service files
|
||||
ansible.builtin.copy:
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
---
|
||||
- name: Restart rustfs
|
||||
ansible.builtin.systemd:
|
||||
name: "rustfs.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
changed_when: false
|
||||
listen: "notification_restart_rustfs"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart ca
|
||||
ansible.builtin.systemd:
|
||||
name: "ca.service"
|
||||
@@ -12,7 +24,7 @@
|
||||
- name: Reload postgresql
|
||||
ansible.builtin.command:
|
||||
/usr/bin/podman exec -u postgres postgresql sh -c "pg_ctl reload"
|
||||
when: is_postgresql_init.stat.exists
|
||||
when: is_postgresql_init_marker.stat.exists
|
||||
changed_when: false
|
||||
listen: "notification_reload_postgresql"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
@@ -24,11 +36,23 @@
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
when: is_postgresql_init.stat.exists
|
||||
when: is_postgresql_init_marker.stat.exists
|
||||
changed_when: false
|
||||
listen: "notification_restart_postgresql"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart mariadb
|
||||
ansible.builtin.systemd:
|
||||
name: "mariadb.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
when: is_mariadb_init_marker.stat.exists
|
||||
changed_when: false
|
||||
listen: "notification_restart_mariadb"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart ldap
|
||||
ansible.builtin.systemd:
|
||||
name: "ldap.service"
|
||||
@@ -73,7 +97,7 @@
|
||||
listen: "notification_restart_grafana"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart x509-exporter.service
|
||||
- name: Restart x509-exporter
|
||||
ansible.builtin.systemd:
|
||||
name: "x509-exporter.service"
|
||||
state: "restarted"
|
||||
@@ -83,3 +107,14 @@
|
||||
changed_when: false
|
||||
listen: "notification_restart_x509-exporter"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
- name: Restart maddy
|
||||
ansible.builtin.systemd:
|
||||
name: "maddy.service"
|
||||
state: "restarted"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
changed_when: false
|
||||
listen: "notification_restart_maddy"
|
||||
ignore_errors: true # noqa: ignore-errors
|
||||
|
||||
@@ -24,16 +24,20 @@
|
||||
notify: "notification_restart_ca"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy ca config files
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/smallstep/step-ca"
|
||||
tag: "{{ version['containers']['ca'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy ca config file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ca/config/{{ item }}.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/ca/config/{{ item }}"
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ca/config/ca.json.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/ca/config/ca.json"
|
||||
owner: "{{ services['ca']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
loop:
|
||||
- "ca.json"
|
||||
- "defaults.json"
|
||||
become: true
|
||||
notify: "notification_restart_ca"
|
||||
|
||||
@@ -81,20 +85,20 @@
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['step'] }}.tar"
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['ca'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/smallstep/step-ca:{{ version['containers']['step'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['step'] }}.tar"
|
||||
- "docker.io/smallstep/step-ca:{{ version['containers']['ca'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['ca'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['step'] }}.tar"
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_smallstep_step-ca_{{ version['containers']['ca'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
- "grafana/etc"
|
||||
- "grafana/etc/provisioning"
|
||||
- "grafana/etc/provisioning/datasources"
|
||||
- "grafana/etc/provisioning/dashboards"
|
||||
- "grafana/etc/dashboards"
|
||||
- "grafana/ssl"
|
||||
become: true
|
||||
@@ -35,10 +36,10 @@
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "GF_LDAP_BIND_PASSWORD"
|
||||
value: "{{ hostvars['console']['ldap']['password']['services']['grafana'] }}"
|
||||
- name: "GF_DB_PASSWORD"
|
||||
value: "{{ hostvars['console']['postgresql']['password']['grafana'] }}"
|
||||
- name: "LDAP_BIND_PASSWORD"
|
||||
value: "{{ hostvars['console']['ldap']['password']['grafana'] }}"
|
||||
- name: "GF_ADMIN_PASSWORD"
|
||||
value: "{{ hostvars['console']['grafana']['admin']['password'] }}"
|
||||
notify: "notification_restart_grafana"
|
||||
@@ -58,16 +59,42 @@
|
||||
notify: "notification_restart_grafana"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy provisioing file
|
||||
- name: Deploy provisioing files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/grafana/etc/provisioning/datasources/datasources.yaml.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/grafana/etc/provisioning/datasources/datasources.yaml"
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/grafana/etc/provisioning/{{ item.file }}"
|
||||
dest: "{{ node['home_path'] }}/containers/grafana/etc/provisioning/{{ item.dest }}"
|
||||
owner: "{{ services['grafana']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
loop:
|
||||
- name: "datasource"
|
||||
file: "datasources/datasources.yaml.j2"
|
||||
dest: "datasources/datasources.yaml"
|
||||
- name: "dashboard"
|
||||
file: "dashboards/dashboards.yaml"
|
||||
dest: "dashboards/dashboards.yaml"
|
||||
loop_control:
|
||||
label: "{{ item.name }}"
|
||||
become: true
|
||||
notify: "notification_restart_grafana"
|
||||
|
||||
- name: Deploy dashboard files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/grafana/etc/dashboards/"
|
||||
dest: "{{ node['home_path'] }}/containers/grafana/etc/dashboards/"
|
||||
owner: "{{ services['grafana']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
become: true
|
||||
notify: "notification_restart_grafana"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/grafana/grafana"
|
||||
tag: "{{ version['containers']['grafana'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/grafana/grafana.container.j2"
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
# urlencode doesn't fix `/` as `%2F`. It needs replace
|
||||
- name: "LLDAP_DATABASE_URL"
|
||||
value: "postgres://ldap:{{ hostvars['console']['postgresql']['password']['ldap'] | urlencode | replace('/', '%2F') }}\
|
||||
@{{ services['postgresql']['domain'] }}.{{ domain['internal'] }}/ldap_db?sslmode=verify-full&sslrootcert=/etc/ssl/ldap/{{ root_cert_filename }}"
|
||||
@{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/\
|
||||
ldap_db?sslmode=verify-full&sslrootcert=/etc/ssl/ldap/{{ root_cert_filename }}"
|
||||
- name: "LLDAP_KEY_SEED"
|
||||
value: "{{ hostvars['console']['ldap']['seed_key'] }}"
|
||||
- name: "LLDAP_JWT_SECRET"
|
||||
@@ -58,13 +59,12 @@
|
||||
# The reason why this task doesn't use the way to check ".init" file is this tasks can override original database.
|
||||
# Absent of ".init" file cannot guarantee DB is empty.
|
||||
when: false
|
||||
become: true
|
||||
no_log: true
|
||||
block:
|
||||
- name: Register extra secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "LLDAP_LDAP_USER_PASSWORD"
|
||||
data: "{{ hostvars['console']['ldap']['password']['user'] }}"
|
||||
name: "LLDAP_LDAP_USER_PASS"
|
||||
data: "{{ hostvars['console']['ldap']['password']['services']['admin'] }}"
|
||||
state: "present"
|
||||
force: true
|
||||
# You must check the image version first (following container file on data/config/containers/infra/ldap/ldap.container)
|
||||
@@ -82,17 +82,26 @@
|
||||
- "LLDAP_DATABASE_URL,type=env"
|
||||
- "LLDAP_KEY_SEED,type=env"
|
||||
- "LLDAP_JWT_SECRET,type=env"
|
||||
- "LLDAP_LDAP_USER_PASSWORD,type=env"
|
||||
- "LLDAP_LDAP_USER_PASS,type=env"
|
||||
volumes:
|
||||
- "{{ node['home_path'] }}/containers/ldap/data:/data:rw"
|
||||
- "{{ node['home_path'] }}/containers/ldap/ssl:/etc/ssl/ldap:ro"
|
||||
etc_hosts:
|
||||
"{{ {} | combine({ services['postgresql']['domain']['internal'] ~ '.' ~ domain['internal']: 'host-gateway' }) }}"
|
||||
|
||||
always:
|
||||
- name: Clean extra secret value from podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "LLDAP_LDAP_USER_PASSWORD"
|
||||
name: "LLDAP_LDAP_USER_PASS"
|
||||
state: "absent"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/lldap/lldap"
|
||||
tag: "{{ version['containers']['ldap'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/ldap/ldap.container.j2"
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
loop:
|
||||
- "loki"
|
||||
- "loki/etc"
|
||||
- "loki/etc/rules"
|
||||
- "loki/etc/rules/{{ domain['internal'] }}"
|
||||
- "loki/data"
|
||||
- "loki/ssl"
|
||||
become: true
|
||||
@@ -24,6 +26,17 @@
|
||||
notify: "notification_restart_loki"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy loki rules file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/loki/etc/rules.yaml.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/loki/etc/rules/{{ domain['internal'] }}/rules.yaml"
|
||||
owner: "{{ services['loki']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
become: true
|
||||
notify: "notification_restart_loki"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy loki certificate and key
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
@@ -48,6 +61,13 @@
|
||||
notify: "notification_restart_loki"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/grafana/loki"
|
||||
tag: "{{ version['containers']['loki'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/loki/loki.container.j2"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
- name: Create maddy directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
state: "directory"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "containers/maddy"
|
||||
- "containers/maddy/ssl"
|
||||
- "data/containers/maddy"
|
||||
- "data/containers/maddy/data"
|
||||
|
||||
- name: Deploy maddy certificate and key
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ item.value }}
|
||||
dest: "{{ node['home_path'] }}/containers/maddy/ssl/{{ item.name }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- name: "{{ root_cert_filename }}"
|
||||
value: "{{ hostvars['console']['ca']['root']['crt'] }}"
|
||||
mode: "0440"
|
||||
- name: "maddy.crt"
|
||||
value: |
|
||||
{{ hostvars['console']['maddy']['crt'] | trim }}
|
||||
{{ hostvars['console']['ca']['intermediate']['crt'] }}
|
||||
mode: "0440"
|
||||
- name: "maddy.key"
|
||||
value: "{{ hostvars['console']['maddy']['key'] }}"
|
||||
mode: "0400"
|
||||
become: true
|
||||
notify: "notification_restart_maddy"
|
||||
no_log: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "{{ item.name }}"
|
||||
data: "{{ item.value }}"
|
||||
state: "present"
|
||||
force: true
|
||||
loop:
|
||||
- name: "MADDY_LDAP_BIND_PASSWORD"
|
||||
value: "{{ hostvars['console']['ldap']['password']['services']['maddy'] }}"
|
||||
- name: "MADDY_POSTGRES_URL"
|
||||
value: "postgresql://maddy:{{ hostvars['console']['postgresql']['password']['maddy'] | urlencode | replace('/', '%2F') }}\
|
||||
@{{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}/maddy_db?sslmode=verify-full&\
|
||||
sslrootcert=/etc/ssl/maddy/{{ root_cert_filename }}"
|
||||
notify: "notification_restart_maddy"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy configuration files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/maddy/data/maddy.conf.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/maddy/maddy.conf"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
notify: "notification_restart_maddy"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/foxcpp/maddy"
|
||||
tag: "{{ version['containers']['maddy'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/maddy/maddy.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/maddy.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_maddy"
|
||||
|
||||
- name: Enable maddy
|
||||
ansible.builtin.systemd:
|
||||
name: "maddy.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_foxcpp_maddy_{{ version['containers']['maddy'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/foxcpp/maddy:{{ version['containers']['maddy'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_foxcpp_maddy_{{ version['containers']['maddy'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_foxcpp_maddy_{{ version['containers']['maddy'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -0,0 +1,197 @@
|
||||
---
|
||||
- name: Initialize connected services list
|
||||
ansible.builtin.set_fact:
|
||||
connected_services: []
|
||||
|
||||
- name: Set connected services list
|
||||
ansible.builtin.set_fact:
|
||||
connected_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.db', 'defined')
|
||||
| selectattr('value.dependency.db', 'equalto', 'mariadb')
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Create mariadb directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['mariadb']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/mariadb/"
|
||||
- "data/containers/mariadb/backups"
|
||||
- "data/containers/mariadb/backups/sql"
|
||||
- "containers/mariadb"
|
||||
- "containers/mariadb/data"
|
||||
- "containers/mariadb/config"
|
||||
- "containers/mariadb/ssl"
|
||||
- "containers/mariadb/init"
|
||||
become: true
|
||||
|
||||
- name: Check mariadb .init marker
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/containers/mariadb/.init"
|
||||
register: "is_mariadb_init_marker"
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/library/mariadb"
|
||||
tag: "{{ version['containers']['mariadb'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy mariadb configuration files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/mariadb/config/mariadb.cnf.j2"
|
||||
dest: "{{ node['home_path'] }}/containers/mariadb/config/mariadb.cnf"
|
||||
owner: "{{ services['mariadb']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
become: true
|
||||
notify: "notification_restart_mariadb"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy mariadb certificate and key
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ item.value }}
|
||||
dest: "{{ node['home_path'] }}/containers/mariadb/ssl/{{ item.name }}"
|
||||
owner: "{{ services['mariadb']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "{{ item.mode }}"
|
||||
loop:
|
||||
- name: "{{ root_cert_filename }}"
|
||||
value: "{{ hostvars['console']['ca']['root']['crt'] }}"
|
||||
mode: "0440"
|
||||
- name: "mariadb.crt"
|
||||
value: |
|
||||
{{ hostvars['console']['mariadb']['crt'] | trim }}
|
||||
{{ hostvars['console']['ca']['intermediate']['crt'] }}
|
||||
mode: "0440"
|
||||
- name: "mariadb.key"
|
||||
value: "{{ hostvars['console']['mariadb']['key'] }}"
|
||||
mode: "0400"
|
||||
become: true
|
||||
notify: "notification_restart_mariadb"
|
||||
no_log: true
|
||||
|
||||
- name: Initiating mariadb
|
||||
when: not is_mariadb_init_marker.stat.exists
|
||||
block:
|
||||
- name: Check initiating SQL files
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/containers/mariadb/backups/sql/"
|
||||
file_type: "file"
|
||||
patterns:
|
||||
- "mariadb_*.sql"
|
||||
hidden: true
|
||||
recurse: false
|
||||
become: true
|
||||
register: "mariadb_init_sql_files"
|
||||
|
||||
- name: Set initiating SQL file lists
|
||||
ansible.builtin.set_fact:
|
||||
mariadb_init_sql_file_list: >-
|
||||
{{
|
||||
mariadb_init_sql_files.files
|
||||
| map(attribute='path')
|
||||
| map('basename')
|
||||
| map('regex_replace', '^mariadb_', '')
|
||||
| map('regex_replace', '[.]sql$', '')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Fail on invalid initiating SQL file set
|
||||
ansible.builtin.fail:
|
||||
when:
|
||||
- mariadb_init_sql_files.matched > 0
|
||||
- ((connected_services)
|
||||
| symmetric_difference(mariadb_init_sql_file_list)
|
||||
| length) > 0
|
||||
|
||||
- name: Remote copy the initiating SQL
|
||||
ansible.builtin.copy:
|
||||
src: "{{ node['home_path'] }}/data/containers/mariadb/backups/sql/mariadb_{{ item }}.sql"
|
||||
remote_src: true
|
||||
dest: "{{ node['home_path'] }}/containers/mariadb/init/{{ '%02d' | format(index_num) }}_mariadb_{{ item }}.sql"
|
||||
owner: "{{ services['mariadb']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
loop: "{{ connected_services }}"
|
||||
loop_control:
|
||||
index_var: index_num
|
||||
become: true
|
||||
when:
|
||||
- ((connected_services)
|
||||
| symmetric_difference(mariadb_init_sql_file_list)
|
||||
| length) == 0
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/mariadb/mariadb.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/mariadb.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_mariadb"
|
||||
|
||||
- name: Deploy backup service files
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/mariadb/services/{{ item }}"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ item }}"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "mariadb-data-backup@.service"
|
||||
- "mariadb-data-backup@.timer"
|
||||
|
||||
- name: Enable mariadb
|
||||
ansible.builtin.systemd:
|
||||
name: "mariadb.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Enable data backup timer
|
||||
ansible.builtin.systemd:
|
||||
name: "mariadb-data-backup@{{ item }}.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
loop: "{{ connected_services }}"
|
||||
|
||||
- name: Create .init file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers/mariadb/.init"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
when: not is_mariadb_init_marker.stat.exists
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_library_mariadb_{{ version['containers']['mariadb'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/library/mariadb:{{ version['containers']['mariadb'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_library_mariadb_{{ version['containers']['mariadb'] }}.tar"
|
||||
format: "oci-archive"
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_library_mariadb_{{ version['containers']['mariadb'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -1,19 +1,19 @@
|
||||
---
|
||||
- name: Initialize connected services list
|
||||
ansible.builtin.set_fact:
|
||||
connected_services: []
|
||||
|
||||
- name: Set connected services list
|
||||
ansible.builtin.set_fact:
|
||||
connected_services:
|
||||
- "ldap"
|
||||
- "grafana"
|
||||
- "authelia"
|
||||
- "vaultwarden"
|
||||
- "gitea"
|
||||
- "immich"
|
||||
- "paperless"
|
||||
- "nextcloud"
|
||||
- "sure"
|
||||
- "outline"
|
||||
- "memos"
|
||||
- "mealie"
|
||||
connected_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.db', 'defined')
|
||||
| selectattr('value.dependency.db', 'equalto', 'postgresql')
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Create postgresql directory
|
||||
ansible.builtin.file:
|
||||
@@ -23,7 +23,9 @@
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/postgresql/"
|
||||
- "data/containers/postgresql/backups"
|
||||
- "data/containers/postgresql/backups/sql"
|
||||
- "containers/postgresql"
|
||||
- "containers/postgresql/data"
|
||||
- "containers/postgresql/config"
|
||||
@@ -32,6 +34,11 @@
|
||||
- "containers/postgresql/build"
|
||||
become: true
|
||||
|
||||
- name: Check postgresql .init marker
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/containers/postgresql/.init"
|
||||
register: "is_postgresql_init_marker"
|
||||
|
||||
- name: Deploy containerfile for build
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/postgresql/build/postgresql.containerfile.j2"
|
||||
@@ -39,6 +46,8 @@
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0640"
|
||||
register: "is_postgresql_containerfile"
|
||||
notify: "notification_restart_postgresql"
|
||||
|
||||
- name: Build postgresql container image
|
||||
containers.podman.podman_image:
|
||||
@@ -47,6 +56,7 @@
|
||||
tag: "pg{{ version['containers']['postgresql'] }}-vectorchord{{ version['containers']['vectorchord'] }}"
|
||||
state: "build"
|
||||
path: "{{ node['home_path'] }}/containers/postgresql/build"
|
||||
force: "{{ is_postgresql_containerfile.changed }}"
|
||||
|
||||
- name: Prune postgresql dangling images
|
||||
containers.podman.podman_prune:
|
||||
@@ -90,45 +100,56 @@
|
||||
notify: "notification_reload_postgresql"
|
||||
no_log: true
|
||||
|
||||
- name: Check data directory empty
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/containers/postgresql/data/.init"
|
||||
become: true
|
||||
register: "is_postgresql_init"
|
||||
|
||||
- name: Prepare initiating DB
|
||||
when:
|
||||
- not is_postgresql_init.stat.exists
|
||||
- (connected_services | default([]) | length) > 0
|
||||
become: true
|
||||
- name: Initiating Postgresql
|
||||
when: not is_postgresql_init_marker.stat.exists
|
||||
block:
|
||||
# `init/pg_cluster.sql` should be fetched from postgresql's backup directory before running initiating
|
||||
- name: Deploy init cluster sql file
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/postgresql/init/pg_cluster.sql"
|
||||
dest: "{{ node['home_path'] }}/containers/postgresql/init/00_pg_cluster.sql"
|
||||
owner: "{{ services['postgresql']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
- name: Check initiating SQL files
|
||||
ansible.builtin.find:
|
||||
path: "{{ node['home_path'] }}/data/containers/postgresql/backups/sql/"
|
||||
file_type: "file"
|
||||
patterns:
|
||||
- "pg_*.sql"
|
||||
hidden: true
|
||||
recurse: false
|
||||
become: true
|
||||
register: "postgresql_init_sql_files"
|
||||
|
||||
- name: Deploy restoring data sql files
|
||||
- name: Set initiating SQL file lists
|
||||
ansible.builtin.set_fact:
|
||||
postgresql_init_sql_file_list: >-
|
||||
{{
|
||||
postgresql_init_sql_files.files
|
||||
| map(attribute='path')
|
||||
| map('basename')
|
||||
| map('regex_replace', '^pg_', '')
|
||||
| map('regex_replace', '[.]sql$', '')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Fail on invalid initiating SQL file set
|
||||
ansible.builtin.fail:
|
||||
when:
|
||||
- postgresql_init_sql_files.matched > 0
|
||||
- ((['cluster'] + connected_services)
|
||||
| symmetric_difference(postgresql_init_sql_file_list)
|
||||
| length) > 0
|
||||
|
||||
- name: Remote copy the initiating SQL
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/postgresql/init/pg_{{ item }}.sql"
|
||||
dest: "{{ node['home_path'] }}/containers/postgresql/init/{{ '%02d' | format(index_num + 1) }}_pg_{{ item }}.sql"
|
||||
src: "{{ node['home_path'] }}/data/containers/postgresql/backups/sql/pg_{{ item }}.sql"
|
||||
remote_src: true
|
||||
dest: "{{ node['home_path'] }}/containers/postgresql/init/{{ '%02d' | format(index_num) }}_pg_{{ item }}.sql"
|
||||
owner: "{{ services['postgresql']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0600"
|
||||
loop: "{{ connected_services }}"
|
||||
loop: "{{ ['cluster'] + connected_services }}"
|
||||
loop_control:
|
||||
index_var: index_num
|
||||
|
||||
- name: Create .init file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers/postgresql/data/.init"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
become: true
|
||||
when:
|
||||
- ((['cluster'] + connected_services)
|
||||
| symmetric_difference(postgresql_init_sql_file_list)
|
||||
| length) == 0
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
@@ -177,6 +198,15 @@
|
||||
scope: "user"
|
||||
loop: "{{ connected_services }}"
|
||||
|
||||
- name: Create .init file
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers/postgresql/.init"
|
||||
state: "touch"
|
||||
mode: "0644"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
when: not is_postgresql_init_marker.stat.exists
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/\
|
||||
@@ -192,8 +222,8 @@
|
||||
{{ domain['internal'] }}_{{ node['name'] }}_postgres_\
|
||||
pg{{ version['containers']['postgresql'] }}-vectorchord{{ version['containers']['vectorchord'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
force: "{{ is_postgresql_containerfile.changed }}"
|
||||
when: not container_archive_images.stat.exists or is_postgresql_containerfile.changed
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
|
||||
@@ -52,6 +52,13 @@
|
||||
notify: "notification_restart_prometheus"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/prom/prometheus"
|
||||
tag: "{{ version['containers']['prometheus'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/prometheus/prometheus.container.j2"
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
- name: Create rustfs directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/{{ item }}"
|
||||
state: "directory"
|
||||
owner: "{{ services['rustfs']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0770"
|
||||
loop:
|
||||
- "data/containers/rustfs"
|
||||
- "data/containers/rustfs/data"
|
||||
become: true
|
||||
|
||||
- name: Register secret value to podman secret
|
||||
containers.podman.podman_secret:
|
||||
name: "RUSTFS_SECRET_KEY"
|
||||
data: "{{ hostvars['console']['rustfs']['password']['rustfs'] }}"
|
||||
state: "present"
|
||||
force: true
|
||||
notify: "notification_restart_rustfs"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/rustfs/rustfs"
|
||||
tag: "{{ version['containers']['rustfs'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/rustfs/rustfs.container.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/containers/systemd/rustfs.container"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0644"
|
||||
notify: "notification_restart_rustfs"
|
||||
|
||||
- name: Enable rustfs
|
||||
ansible.builtin.systemd:
|
||||
name: "rustfs.service"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
scope: "user"
|
||||
|
||||
- name: Check container archive images
|
||||
ansible.builtin.stat:
|
||||
path: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar"
|
||||
register: container_archive_images
|
||||
|
||||
- name: Save container archive images
|
||||
containers.podman.podman_save:
|
||||
image:
|
||||
- "docker.io/rustfs/rustfs:{{ version['containers']['rustfs'] }}"
|
||||
dest: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar"
|
||||
format: "oci-archive"
|
||||
force: false
|
||||
when: not container_archive_images.stat.exists
|
||||
|
||||
- name: Fetch container archive images
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ node['home_path'] }}/archives/containers/docker.io_rustfs_rustfs_{{ version['containers']['rustfs'] }}.tar"
|
||||
dest: "{{ hostvars['console']['node']['data_path'] }}/images/containers/"
|
||||
flat: true
|
||||
@@ -1,4 +1,20 @@
|
||||
---
|
||||
- name: Initialize self-cert services list
|
||||
ansible.builtin.set_fact:
|
||||
cert_services: []
|
||||
|
||||
- name: Set self-cert services list
|
||||
ansible.builtin.set_fact:
|
||||
cert_services: >-
|
||||
{{
|
||||
services
|
||||
| dict2items
|
||||
| selectattr('value.dependency.cert', 'defined')
|
||||
| selectattr('value.dependency.cert', 'equalto', true)
|
||||
| map(attribute='key')
|
||||
| list
|
||||
}}
|
||||
|
||||
- name: Create x509-exporter directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ node['home_path'] }}/containers/{{ item }}"
|
||||
@@ -22,7 +38,7 @@
|
||||
become: true
|
||||
notify: "notification_restart_x509-exporter"
|
||||
|
||||
- name: Deploy certificates
|
||||
- name: Deploy CA certificates
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ item.value }}
|
||||
@@ -35,23 +51,31 @@
|
||||
value: "{{ hostvars['console']['ca']['root']['crt'] }}"
|
||||
- name: "intermediate.crt"
|
||||
value: "{{ hostvars['console']['ca']['intermediate']['crt'] }}"
|
||||
- name: "crowdsec.crt"
|
||||
value: "{{ hostvars['console']['crowdsec']['crt'] }}"
|
||||
- name: "blocky.crt"
|
||||
value: "{{ hostvars['console']['blocky']['crt'] }}"
|
||||
- name: "postgresql.crt"
|
||||
value: "{{ hostvars['console']['postgresql']['crt'] }}"
|
||||
- name: "ldap.crt"
|
||||
value: "{{ hostvars['console']['ldap']['crt'] }}"
|
||||
- name: "prometheus.crt"
|
||||
value: "{{ hostvars['console']['prometheus']['crt'] }}"
|
||||
- name: "loki.crt"
|
||||
value: "{{ hostvars['console']['loki']['crt'] }}"
|
||||
- name: "dsm.crt"
|
||||
value: "{{ hostvars['console']['dsm']['crt'] }}"
|
||||
become: true
|
||||
notify: "notification_restart_x509-exporter"
|
||||
no_log: true
|
||||
|
||||
- name: Deploy leaf certificates
|
||||
ansible.builtin.copy:
|
||||
content: |
|
||||
{{ hostvars['console'][item]['crt'] }}
|
||||
dest: "{{ node['home_path'] }}/containers/x509-exporter/certs/{{ item }}.crt"
|
||||
owner: "{{ services['x509-exporter']['subuid'] }}"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0440"
|
||||
loop: "{{ cert_services }}"
|
||||
become: true
|
||||
notify: "notification_restart_x509-exporter"
|
||||
no_log: true
|
||||
|
||||
- name: Pull image
|
||||
containers.podman.podman_image:
|
||||
name: "docker.io/enix/x509-certificate-exporter"
|
||||
tag: "{{ version['containers']['x509-exporter'] }}"
|
||||
state: "present"
|
||||
pull: true
|
||||
|
||||
|
||||
- name: Deploy container file
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/containers/infra/x509-exporter/x509-exporter.container.j2"
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
---
|
||||
- name: Install btrfs
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "btrfs-progs"
|
||||
state: "present"
|
||||
become: true
|
||||
|
||||
- name: Mount data disk
|
||||
block:
|
||||
- name: Set hard data disk path
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
ls -1 /dev/disk/by-id/ata-* | \
|
||||
grep -F -e "{{ hardware['disk']['data']['serials'] | join('" -e "') }}" | \
|
||||
grep -vE -- '-part[0-9]+$' | \
|
||||
sort
|
||||
changed_when: false
|
||||
register: "data_disk_path"
|
||||
|
||||
- name: Check vmm_hdd filesystem already exists
|
||||
ansible.builtin.command: |
|
||||
blkid -L {{ hardware['disk']['data']['fs']['label'] }}
|
||||
become: true
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_data_disk_fs"
|
||||
|
||||
- name: Check disk number
|
||||
ansible.builtin.fail:
|
||||
msg: "Below 2 disks for RAID, found {{ data_disk_path.stdout_lines | length }}"
|
||||
when: (data_disk_path.stdout_lines | length) < hardware['disk']['data']['fs']['btrfs']['min_devices']
|
||||
|
||||
- name: Set data btrfs volume
|
||||
ansible.builtin.shell: |
|
||||
mkfs.btrfs -f \
|
||||
-L {{ hardware['disk']['data']['fs']['label'] }} \
|
||||
-d {{ hardware['disk']['data']['fs']['btrfs']['data_profile'] }} \
|
||||
-m {{ hardware['disk']['data']['fs']['btrfs']['metadata_profile'] }} \
|
||||
{{ data_disk_path.stdout_lines | join(' ') }}
|
||||
become: true
|
||||
when:
|
||||
- is_data_disk_fs.rc != 0
|
||||
- (data_disk_path.stdout_lines | length) >= hardware['disk']['data']['fs']['btrfs']['min_devices']
|
||||
changed_when: is_mkfs.rc == 0
|
||||
register: "is_mkfs"
|
||||
|
||||
- name: Create mount volume
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Mount data btrfs volume
|
||||
ansible.posix.mount:
|
||||
path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
|
||||
src: "LABEL={{ hardware['disk']['data']['fs']['label'] }}"
|
||||
state: "mounted"
|
||||
fstype: "{{ hardware['disk']['data']['fs']['type'] }}"
|
||||
opts: "{{ hardware['disk']['data']['fs']['mount_opts'] | join(',') }}"
|
||||
become: true
|
||||
|
||||
- name: Set mounted btrfs volume permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['disk']['data']['fs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Mount backup disk
|
||||
block:
|
||||
- name: Set backup disk path
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
ls -1 /dev/disk/by-id/ata-* | \
|
||||
grep -F -e "{{ hardware['disk']['backup']['serials'] | join('" -e "') }}" | \
|
||||
grep -vE -- '-part[0-9]+$' | \
|
||||
sort
|
||||
changed_when: false
|
||||
register: "backup_disk_path"
|
||||
|
||||
- name: Check vmm_hdd filesystem already exists
|
||||
ansible.builtin.command: |
|
||||
blkid -L {{ hardware['disk']['backup']['fs']['label'] }}
|
||||
become: true
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_backup_disk_fs"
|
||||
|
||||
- name: Set backup btrfs volume
|
||||
ansible.builtin.shell: |
|
||||
mkfs.btrfs -f \
|
||||
-L {{ hardware['disk']['backup']['fs']['label'] }} \
|
||||
-d {{ hardware['disk']['backup']['fs']['btrfs']['data_profile'] }} \
|
||||
-m {{ hardware['disk']['backup']['fs']['btrfs']['metadata_profile'] }} \
|
||||
{{ backup_disk_path.stdout_lines | join(' ') }}
|
||||
become: true
|
||||
when:
|
||||
- is_backup_disk_fs.rc != 0
|
||||
- (backup_disk_path.stdout_lines | length) >= hardware['disk']['backup']['fs']['btrfs']['min_devices']
|
||||
changed_when: is_mkfs.rc == 0
|
||||
register: "is_mkfs"
|
||||
|
||||
- name: Create mount volume
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Mount backup btrfs volume
|
||||
ansible.posix.mount:
|
||||
path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
|
||||
src: "LABEL={{ hardware['disk']['backup']['fs']['label'] }}"
|
||||
state: "mounted"
|
||||
fstype: "{{ hardware['disk']['backup']['fs']['type'] }}"
|
||||
opts: "{{ hardware['disk']['backup']['fs']['mount_opts'] | join(',') }}"
|
||||
become: true
|
||||
|
||||
- name: Set mounted btrfs volume permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['disk']['backup']['fs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Verify data disk is mounted
|
||||
ansible.builtin.command: |
|
||||
mountpoint -q {{ hardware['disk']['data']['fs']['mount_point'] }}
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: Verify backup disk is mounted
|
||||
ansible.builtin.command: |
|
||||
mountpoint -q {{ hardware['disk']['backup']['fs']['mount_point'] }}
|
||||
become: true
|
||||
changed_when: false
|
||||
|
||||
- name: Deploy btrfs scrub service and timer
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/btrfs/btrfs-scrub-{{ item }}.j2"
|
||||
dest: "/etc/systemd/system/btrfs-scrub-{{ item }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "data.service"
|
||||
- "data.timer"
|
||||
- "backup.service"
|
||||
- "backup.timer"
|
||||
become: true
|
||||
|
||||
- name: Enable auto btrfs scrub
|
||||
ansible.builtin.systemd:
|
||||
name: "btrfs-scrub-{{ item }}.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
loop:
|
||||
- "data"
|
||||
- "backup"
|
||||
become: true
|
||||
@@ -13,7 +13,9 @@
|
||||
loop:
|
||||
- "images"
|
||||
- "seeds"
|
||||
- "data"
|
||||
- "disk"
|
||||
- "disk/data"
|
||||
- "disk/backup"
|
||||
register: "is_libvirt_dir"
|
||||
|
||||
- name: Create libvirt directory
|
||||
@@ -24,9 +26,10 @@
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
loop: "{{ is_libvirt_dir.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.item }}"
|
||||
when: not item.stat.exists
|
||||
become: true
|
||||
no_log: true
|
||||
|
||||
- name: Set LIBVIRT_DEFAULT_URI
|
||||
ansible.builtin.lineinfile:
|
||||
@@ -74,6 +77,7 @@
|
||||
- "images-pool"
|
||||
- "seeds-pool"
|
||||
- "data-pool"
|
||||
- "backup-pool"
|
||||
|
||||
- name: Start virtual storage pool
|
||||
community.libvirt.virt_pool:
|
||||
@@ -84,6 +88,7 @@
|
||||
- "images-pool"
|
||||
- "seeds-pool"
|
||||
- "data-pool"
|
||||
- "backup-pool"
|
||||
|
||||
- name: Autostart virtual storage pool
|
||||
community.libvirt.virt_pool:
|
||||
@@ -94,3 +99,4 @@
|
||||
- "images-pool"
|
||||
- "seeds-pool"
|
||||
- "data-pool"
|
||||
- "backup-pool"
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
---
|
||||
- name: Check btrfs installation
|
||||
ansible.builtin.shell: |
|
||||
command -v btrfs
|
||||
become: true # btrfs is located in /usr/sbin, which means root permission is needed.
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
register: "is_btrfs_installed"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Install btrfs
|
||||
ansible.builtin.apt:
|
||||
name: "btrfs-progs"
|
||||
state: "present"
|
||||
become: true
|
||||
when: is_btrfs_installed.rc != 0
|
||||
|
||||
- name: Set hard disk path
|
||||
ansible.builtin.shell: |
|
||||
set -o pipefail
|
||||
ls -1 /dev/disk/by-id/ata-* | \
|
||||
grep -F -e "{{ hardware['hdd']['data'].values() | join('" -e "') }}" | \
|
||||
grep -vE -- '-part[0-9]+$' | \
|
||||
sort
|
||||
changed_when: false
|
||||
register: "hdd_path_list"
|
||||
|
||||
- name: Check vmm_hdd filesystem already exists
|
||||
ansible.builtin.command: |
|
||||
blkid -L {{ hardware['btrfs']['label'] }}
|
||||
register: is_vmm_data
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
become: true
|
||||
|
||||
- name: Check disk number
|
||||
ansible.builtin.fail:
|
||||
msg: "Below 4 disks for RAID10, found {{ hdd_path_list.stdout_lines | length }}"
|
||||
when: (hdd_path_list.stdout_lines | length) < 4
|
||||
|
||||
- name: Set btrfs raid10 volume
|
||||
ansible.builtin.shell: |
|
||||
mkfs.btrfs -f \
|
||||
-L {{ hardware['btrfs']['label'] }} \
|
||||
-d {{ hardware['btrfs']['level'] }} \
|
||||
-m {{ hardware['btrfs']['level'] }} \
|
||||
{{ hdd_path_list.stdout_lines | join(' ') }}
|
||||
become: true
|
||||
when:
|
||||
- is_vmm_data.rc != 0
|
||||
- (hdd_path_list.stdout_lines | length) >= 4
|
||||
changed_when: is_mkfs.rc == 0
|
||||
register: "is_mkfs"
|
||||
|
||||
- name: Create mount volume
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['btrfs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Mount btrfs raid10 volume
|
||||
ansible.posix.mount:
|
||||
path: "{{ hardware['btrfs']['mount_point'] }}"
|
||||
src: "LABEL={{ hardware['btrfs']['label'] }}"
|
||||
state: "mounted"
|
||||
fstype: "btrfs"
|
||||
opts: "defaults,noatime,nodatacow,degraded,nofail"
|
||||
become: true
|
||||
|
||||
- name: Set mounted btrfs volume permissions
|
||||
ansible.builtin.file:
|
||||
path: "{{ hardware['btrfs']['mount_point'] }}"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Deploy btrfs scrub service and timer
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/btrfs/{{ item }}.j2"
|
||||
dest: "/etc/systemd/system/{{ item }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0644"
|
||||
loop:
|
||||
- "btrfs-scrub.service"
|
||||
- "btrfs-scrub.timer"
|
||||
become: true
|
||||
|
||||
- name: Enable auto btrfs scrub
|
||||
ansible.builtin.systemd:
|
||||
name: "btrfs-scrub.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
become: true
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
- name: Install smartmontools
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- "smartmontools"
|
||||
- "jq"
|
||||
state: "present"
|
||||
become: true
|
||||
|
||||
- name: Create SMART metric result directory
|
||||
ansible.builtin.file:
|
||||
path: "/etc/smartctl-exporter"
|
||||
state: "directory"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0755"
|
||||
become: true
|
||||
|
||||
- name: Deploy smart_metric_generator script
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/smart_metric/smart_metric_generator.sh"
|
||||
dest: "/usr/local/sbin"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0711"
|
||||
become: true
|
||||
|
||||
- name: Deploy smart_metric_generator service files
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/smart_metric/{{ item }}.j2"
|
||||
dest: "/etc/systemd/system/{{ item }}"
|
||||
owner: "root"
|
||||
group: "root"
|
||||
mode: "0600"
|
||||
validate: "/usr/bin/systemd-analyze verify %s"
|
||||
loop:
|
||||
- "smart_metric_generator.service"
|
||||
- "smart_metric_generator.timer"
|
||||
become: true
|
||||
|
||||
- name: Register smart_metric_generator timer
|
||||
ansible.builtin.systemd:
|
||||
name: "smart_metric_generator.timer"
|
||||
state: "started"
|
||||
enabled: true
|
||||
daemon_reload: true
|
||||
become: true
|
||||
@@ -49,8 +49,7 @@
|
||||
register: "is_seediso"
|
||||
|
||||
- name: Create seed.iso
|
||||
ansible.builtin.shell:
|
||||
cmd: |
|
||||
ansible.builtin.shell: |
|
||||
cloud-localds -N {{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/network-config \
|
||||
{{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/seed.iso \
|
||||
{{ hostvars['console']['node']['data_path'] }}/images/seeds/{{ target_vm }}/user-data \
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
become: true
|
||||
|
||||
- name: Check deployed cloud-init file info
|
||||
ansible.builtin.command:
|
||||
cmd: "qemu-img info {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 --output json"
|
||||
ansible.builtin.command: |
|
||||
qemu-img info {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 --output json
|
||||
changed_when: false
|
||||
failed_when:
|
||||
- deployed_cloudfile_info.rc != 0
|
||||
@@ -37,29 +37,29 @@
|
||||
register: "deployed_cloudfile_info"
|
||||
|
||||
- name: Resize deployed cloud-init file
|
||||
ansible.builtin.command:
|
||||
cmd: "qemu-img resize {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 {{ hostvars[target_vm]['vm']['storage'] }}G"
|
||||
ansible.builtin.command: |
|
||||
qemu-img resize {{ node['libvirt_path'] }}/images/{{ target_vm }}.qcow2 {{ hostvars[target_vm]['vm']['storage'] }}G
|
||||
when:
|
||||
- deployed_cloudfile_info.rc == 0
|
||||
- (deployed_cloudfile_info.stdout | from_json)['virtual-size'] < (hostvars[target_vm]['vm']['storage'] | int * 1024 * 1024 * 1024)
|
||||
changed_when: true
|
||||
|
||||
- name: Check app data raw image
|
||||
- name: Check bk/app raw image
|
||||
ansible.builtin.stat:
|
||||
path: "{{ hardware['btrfs']['mount_point'] }}/{{ target_vm }}.raw"
|
||||
path: "{{ hardware['disk'][hostvars[target_vm]['vm']['data_storage']['pool']]['fs']['mount_point'] }}/{{ target_vm }}.raw"
|
||||
get_checksum: false
|
||||
get_mime: false
|
||||
get_attributes: false
|
||||
when: target_vm == "app"
|
||||
when: target_vm in ["bk", "app"]
|
||||
register: "is_app_data"
|
||||
|
||||
- name: Create app data raw image
|
||||
ansible.builtin.command:
|
||||
# 3.5T
|
||||
cmd: "qemu-img create -f raw {{ hardware['btrfs']['mount_point'] }}/{{ target_vm }}.raw {{ hostvars[target_vm]['vm']['data_storage']['size'] }}T"
|
||||
- name: Create bk/app raw image
|
||||
ansible.builtin.command: |
|
||||
qemu-img create -f raw {{ hardware['disk'][hostvars[target_vm]['vm']['data_storage']['pool']]['fs']['mount_point'] }}/{{ target_vm }}.raw \
|
||||
{{ hostvars[target_vm]['vm']['data_storage']['size'] }}T
|
||||
become: true
|
||||
when:
|
||||
- target_vm == "app"
|
||||
- target_vm in ["bk", "app"]
|
||||
- not is_app_data.stat.exists
|
||||
changed_when: true
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
command: define
|
||||
|
||||
- name: Deploy VM systemd file
|
||||
ansible.builtin.copy:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/libvirt/services/{{ target_vm }}.service"
|
||||
ansible.builtin.template:
|
||||
src: "{{ hostvars['console']['node']['config_path'] }}/services/systemd/vmm/libvirt/services/{{ target_vm }}.service.j2"
|
||||
dest: "{{ node['home_path'] }}/.config/systemd/user/{{ target_vm }}.service"
|
||||
owner: "{{ ansible_user }}"
|
||||
group: "svadmins"
|
||||
group: "{{ node['group'] }}"
|
||||
mode: "0400"
|
||||
|
||||
- name: Register VM service
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#!/usr/sbin/nft -f
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network4']['auth']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network6']['auth']['server'] }}
|
||||
define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network']['auth']['ipv4']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network']['auth']['ipv6']['server'] }}
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_HTTP = 80
|
||||
define PORTS_HTTP_FORWARD = 2080
|
||||
define PORTS_HTTP_FORWARD = {{ services['caddy']['ports']['http'] }}
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_HTTPS_FORWARD = 2443
|
||||
define PORTS_HTTPS_FORWARD = {{ services['caddy']['ports']['https'] }}
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
#!/usr/sbin/nft -f
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_HTTP = 80
|
||||
define PORTS_HTTP_FORWARD = 2080
|
||||
define PORTS_HTTP_FORWARD = {{ services['caddy']['ports']['http'] }}
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_HTTPS_FORWARD = 2443
|
||||
define PORTS_HTTPS_FORWARD = {{ services['caddy']['ports']['https'] }}
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/sbin/nft -f
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_INFRA = {{ hostvars['fw']['network']['infra']['ipv4']['server'] }}
|
||||
define HOSTS6_INFRA = {{ hostvars['fw']['network']['infra']['ipv6']['server'] }}
|
||||
define HOSTS4_APP = {{ hostvars['fw']['network']['app']['ipv4']['server'] }}
|
||||
define HOSTS6_APP = {{ hostvars['fw']['network']['app']['ipv6']['server'] }}
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_KOPIA = {{ services['kopia']['ports']['https'] }}
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
tcp dport $PORTS_HTTPS dnat to :$PORTS_KOPIA comment "dnat https ports to $PORTS_KOPIA"
|
||||
}
|
||||
chain postrouting {
|
||||
|
||||
}
|
||||
chain output {
|
||||
type nat hook output priority dstnat; policy accept;
|
||||
oifname "lo" tcp dport $PORTS_HTTPS dnat to :$PORTS_KOPIA comment "dnat https ports to $PORTS_KOPIA out of LOCALHOST"
|
||||
}
|
||||
}
|
||||
|
||||
table inet filter {
|
||||
chain input {
|
||||
type filter hook input priority 0; policy drop;
|
||||
ct state invalid drop comment "deny invalid connection"
|
||||
ct state established, related accept comment "allow all connection already existing"
|
||||
iifname "lo" accept comment "allow local connection: BK > BK"
|
||||
meta l4proto { icmp, icmpv6 } accept comment "allow icmp connection: BK"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > BK"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > BK"
|
||||
ip saddr { $HOSTS4_CONSOLE, $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_KOPIA ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: > BK"
|
||||
ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_KOPIA ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: > BK"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
}
|
||||
chain output {
|
||||
type filter hook output priority 0; policy accept;
|
||||
}
|
||||
}
|
||||
+34
-37
@@ -1,37 +1,34 @@
|
||||
# localhost
|
||||
127.0.0.1 {{ node['local_san'] }}
|
||||
::1 {{ node['local_san'] }}
|
||||
{% if node['name'] == 'console' %}
|
||||
# Hosts IPv4
|
||||
{{ hostvars['fw']['network4']['firewall']['server'] }} fw.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['vmm']['client'] }} init.vmm.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['vmm']['server'] }} vmm.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['infra']['server'] }} infra.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['auth']['server'] }} auth.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['app']['server'] }} app.{{ domain['internal'] }}
|
||||
# Hosts IPv6
|
||||
{{ hostvars['fw']['network6']['firewall']['server'] }} fw.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['vmm']['client'] }} init.vmm.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['vmm']['server'] }} vmm.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['infra']['server'] }} infra.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['auth']['server'] }} auth.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['app']['server'] }} app.{{ domain['internal'] }}
|
||||
# kopia repository
|
||||
{{ hostvars['fw']['network4']['nas']['client'] }} nas.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['nas']['client'] }} nas.{{ domain['internal'] }}
|
||||
{% else %}
|
||||
# IPv4
|
||||
# Crowdsec, blocky, bind(fw)
|
||||
{{ hostvars['fw']['network4']['firewall']['server'] }} ntp.{{ domain['internal'] }} crowdsec.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['blocky']['server'] }} blocky.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network4']['bind']['server'] }} bind.{{ domain['internal'] }}
|
||||
# DB, LDAP, CA, Prometheus, Loki, mail (infra)
|
||||
{{ hostvars['fw']['network4']['infra']['server'] }} postgresql.{{ domain['internal'] }} ldap.{{ domain['internal'] }} prometheus.{{ domain['internal'] }} loki.{{ domain['internal'] }} mail.{{ domain['internal'] }} ca.{{ domain['internal'] }}
|
||||
# IPv6
|
||||
# Crowdsec, blocky, bind(fw)
|
||||
{{ hostvars['fw']['network6']['firewall']['server'] }} ntp.{{ domain['internal'] }} crowdsec.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['blocky']['server'] }} blocky.{{ domain['internal'] }}
|
||||
{{ hostvars['fw']['network6']['bind']['server'] }} bind.{{ domain['internal'] }}
|
||||
# DB, LDAP, CA, Prometheus, Loki, mail (infra)
|
||||
{{ hostvars['fw']['network6']['infra']['server'] }} postgresql.{{ domain['internal'] }} ldap.{{ domain['internal'] }} prometheus.{{ domain['internal'] }} loki.{{ domain['internal'] }} mail.{{ domain['internal'] }} ca.{{ domain['internal'] }}
|
||||
{% endif %}
|
||||
# Managed by Ansible
|
||||
# Bootstrap name resolution only.
|
||||
# Full service discovery is handled by BIND.
|
||||
|
||||
127.0.0.1 localhost
|
||||
::1 localhost
|
||||
|
||||
{% set net = hostvars['fw']['network'] %}
|
||||
{%
|
||||
set server_hosts = (
|
||||
net
|
||||
| dict2items
|
||||
| rejectattr('key', 'equalto', 'dns_serial')
|
||||
| rejectattr('key', 'equalto', 'subnet')
|
||||
| rejectattr('key', 'equalto', 'reverse_zone')
|
||||
| selectattr('value.ipv4.server', 'defined')
|
||||
| selectattr('value.ipv6.server', 'defined')
|
||||
| map(attribute='key')
|
||||
| list
|
||||
)
|
||||
%}
|
||||
# node canonical names
|
||||
{% for ip in ['ipv4', 'ipv6'] %}
|
||||
# {{ ip }}
|
||||
## vmm init
|
||||
{{ "%-36s" | format(net['vmm'][ip]['client']) }} init.vmm init.vmm.{{ domain['internal'] }}
|
||||
## console
|
||||
{{ "%-36s" | format(net['console'][ip]['client']) }} console console.{{ domain['internal'] }}
|
||||
## nodes
|
||||
{% for service in server_hosts %}
|
||||
{{ "%-36s" | format(net[service][ip]['server']) }} {{ service }} {{ service }}.{{ domain['internal'] }}{% for alias in net[service]['alias'] | default([]) %}{% if service in ['vmm', 'fw'] and alias != 'init.vmm' %} {{ alias }}.{{ domain['internal'] }}{% endif %}{% endfor %}{{ '' }}
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -3,11 +3,11 @@ Name=eth0
|
||||
|
||||
[Network]
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4'][target_vm]['server'] }}/24
|
||||
Gateway={{ hostvars['fw']['network4']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network'][target_vm]['ipv4']['server'] }}/24
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv4']['server'] }}
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
# IPv6
|
||||
IPv6AcceptRA=false
|
||||
Address={{ hostvars['fw']['network6'][target_vm]['server'] }}/64
|
||||
Gateway={{ hostvars['fw']['network6']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network'][target_vm]['ipv6']['server'] }}/64
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv6']['server'] }}
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Resolve]
|
||||
{% if node['name'] in ['vmm', 'fw'] %}
|
||||
{% if node['name'] in ["vmm", "fw"] %}
|
||||
DNS=1.1.1.2 1.0.0.2
|
||||
DNS=2606:4700:4700::1112 2606:4700:4700::1002
|
||||
{% endif %}
|
||||
cache=false
|
||||
Cache=false
|
||||
|
||||
@@ -9,8 +9,8 @@ IPv6AcceptRA=false
|
||||
VLAN=server
|
||||
VLAN=user
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['client'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['fw']['ipv4']['client'] }}/24
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['firewall']['client'] }}/64
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['fw']['ipv6']['client'] }}/64
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
|
||||
@@ -6,19 +6,19 @@ IPForward=true
|
||||
IPv6SendRA=false
|
||||
IPv6AcceptRA=false
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['server'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['fw']['ipv4']['server'] }}/24
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['firewall']['server'] }}/64
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['fw']['ipv6']['server'] }}/64
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network4']['blocky']['server'] }}/24
|
||||
Address={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}/24
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network4']['bind']['server'] }}/24
|
||||
Address={{ hostvars['fw']['network']['bind']['ipv4']['server'] }}/24
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network6']['blocky']['server'] }}/64
|
||||
Address={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}/64
|
||||
PreferredLifetime=0
|
||||
[Address]
|
||||
Address={{ hostvars['fw']['network6']['bind']['server'] }}/64
|
||||
Address={{ hostvars['fw']['network']['bind']['ipv6']['server'] }}/64
|
||||
PreferredLifetime=0
|
||||
|
||||
@@ -7,8 +7,8 @@ IPv6PrefixDelegation=true
|
||||
IPv6SendRA=true
|
||||
IPv6SendRAExtension=false
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['firewall']['user'] }}/24
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['fw']['ipv4']['user'] }}/24
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
|
||||
[IPv6PrefixDelegation]
|
||||
SubnetId=20
|
||||
@@ -22,4 +22,4 @@ Managed=false
|
||||
# O-Flag: Other information form DHCPv6
|
||||
OtherInformation=false
|
||||
EmitDNS=true
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
|
||||
@@ -9,48 +9,47 @@ define IF_SERVER = "server"
|
||||
define IF_USER = "user"
|
||||
define IF_WG = "wg0"
|
||||
|
||||
define NET4_CLIENT = {{ hostvars['fw']['network4']['subnet']['client'] }}
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET4_USER = {{ hostvars['fw']['network4']['subnet']['user'] }}
|
||||
define NET4_WG = {{ hostvars['fw']['network4']['subnet']['wg'] }}
|
||||
define NET4_LLA = {{ hostvars['fw']['network4']['subnet']['lla'] }}
|
||||
define NET4_CLIENT = {{ hostvars['fw']['network']['subnet']['ipv4']['client'] }}
|
||||
define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }}
|
||||
define NET4_USER = {{ hostvars['fw']['network']['subnet']['ipv4']['user'] }}
|
||||
define NET4_WG = {{ hostvars['fw']['network']['subnet']['ipv4']['wg'] }}
|
||||
define NET4_LLA = {{ hostvars['fw']['network']['subnet']['ipv4']['lla'] }}
|
||||
define NET4_RFC1918 = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
|
||||
|
||||
define NET6_CLIENT = {{ hostvars['fw']['network6']['subnet']['client'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define NET6_WG = {{ hostvars['fw']['network6']['subnet']['wg'] }}
|
||||
define NET6_LLA = {{ hostvars['fw']['network6']['subnet']['lla'] }}
|
||||
define NET6_CLIENT = {{ hostvars['fw']['network']['subnet']['ipv6']['client'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }}
|
||||
define NET6_WG = {{ hostvars['fw']['network']['subnet']['ipv6']['wg'] }}
|
||||
define NET6_LLA = {{ hostvars['fw']['network']['subnet']['ipv6']['lla'] }}
|
||||
|
||||
define HOSTS4_FW = { {{ hostvars['fw']['network4']['firewall'].values() | join(', ') }} }
|
||||
define HOSTS4_BLOCKY = {{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
define HOSTS4_BIND = {{ hostvars['fw']['network4']['bind']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS4_VMM = { {{ hostvars['fw']['network4']['vmm'].values() | join(', ') }} }
|
||||
define HOSTS4_INFRA = {{ hostvars['fw']['network4']['infra']['server'] }}
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network4']['auth']['server'] }}
|
||||
define HOSTS4_APP = {{ hostvars['fw']['network4']['app']['server'] }}
|
||||
define HOSTS4_NAS = {{ hostvars['fw']['network4']['nas']['client'] }}
|
||||
define HOSTS4_PRINTER = {{ hostvars['fw']['network4']['printer']['client'] }}
|
||||
define HOSTS4_FW = { {{ hostvars['fw']['network']['fw']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_BLOCKY = {{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
define HOSTS4_BIND = {{ hostvars['fw']['network']['bind']['ipv4']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_VMM = { {{ hostvars['fw']['network']['vmm']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_BK = {{ hostvars['fw']['network']['bk']['ipv4']['server'] }}
|
||||
define HOSTS4_INFRA = {{ hostvars['fw']['network']['infra']['ipv4']['server'] }}
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network']['auth']['ipv4']['server'] }}
|
||||
define HOSTS4_APP = {{ hostvars['fw']['network']['app']['ipv4']['server'] }}
|
||||
define HOSTS4_SWITCH = {{ hostvars['fw']['network']['switch']['ipv4']['client'] }}
|
||||
define HOSTS4_PRINTER = {{ hostvars['fw']['network']['printer']['ipv4']['client'] }}
|
||||
|
||||
define HOSTS6_FW = { {{ hostvars['fw']['network6']['firewall'].values() | join(', ') }} }
|
||||
define HOSTS6_BLOCKY = {{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
define HOSTS6_BIND = {{ hostvars['fw']['network6']['bind']['server'] }}
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_VMM = { {{ hostvars['fw']['network6']['vmm'].values() | join(', ') }} }
|
||||
define HOSTS6_INFRA = {{ hostvars['fw']['network6']['infra']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network6']['auth']['server'] }}
|
||||
define HOSTS6_APP = {{ hostvars['fw']['network6']['app']['server'] }}
|
||||
define HOSTS6_NAS = {{ hostvars['fw']['network6']['nas']['client'] }}
|
||||
define HOSTS6_FW = { {{ hostvars['fw']['network']['fw']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_BLOCKY = {{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
define HOSTS6_BIND = {{ hostvars['fw']['network']['bind']['ipv6']['server'] }}
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_VMM = { {{ hostvars['fw']['network']['vmm']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_BK = {{ hostvars['fw']['network']['bk']['ipv6']['server'] }}
|
||||
define HOSTS6_INFRA = {{ hostvars['fw']['network']['infra']['ipv6']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network']['auth']['ipv6']['server'] }}
|
||||
define HOSTS6_APP = {{ hostvars['fw']['network']['app']['ipv6']['server'] }}
|
||||
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_WEB = { 80, 443 }
|
||||
define PORTS_DHCP = { 67, 68, 546, 547 }
|
||||
define PORTS_DNS = 53
|
||||
define PORTS_NTP = 123
|
||||
define PORTS_VPN = 11290
|
||||
define PORTS_CROWDSEC = 8080
|
||||
define PORTS_NAS = { 5000, 5001 }
|
||||
define PORTS_KOPIA = 51515
|
||||
define PORTS_VPN = {{ services['wireguard']['ports']['udp'] }}
|
||||
define PORTS_CROWDSEC = {{ services['crowdsec']['ports']['https'] }}
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
@@ -113,13 +112,14 @@ table inet filter {
|
||||
jump global comment "set global condition"
|
||||
iifname "lo" accept comment "allow local connection: FW > FW"
|
||||
udp dport $PORTS_VPN accept comment "allow vpn connection: > FW"
|
||||
ip6 saddr $NET6_LLA meta l4proto icmpv6 accept comment "allow icmpv6 connection: ipv6 LLA > FW"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_USER, $IF_WG } meta l4proto { icmp, icmpv6 } accept comment "allow icmp, icmpv6 connection: CLIENT/SERVER/USER/WG > FW"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_WG } udp dport $PORTS_NTP accept comment "allow ntp connection: CLIENT/SERVER/USER/WG > FW"
|
||||
iifname { $IF_CLIENT, $IF_SERVER, $IF_WG } udp dport $PORTS_NTP accept comment "allow ntp connection: CLIENT/SERVER/WG > FW"
|
||||
# Global chain contains "WAN !> :SSH_PORT"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW"
|
||||
ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv4 crowdsec lapi connection: SERVER > FW"
|
||||
ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv6 crowdsec lapi connection: SERVER > FW"
|
||||
ip saddr { $HOSTS4_VMM, $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv4 crowdsec lapi connection: SERVER > FW"
|
||||
ip6 saddr { $HOSTS6_VMM, $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } tcp dport $PORTS_CROWDSEC accept comment "allow ipv6 crowdsec lapi connection: SERVER > FW"
|
||||
# Global chain contains "WAN !> :DNS_PORT"
|
||||
ip daddr $HOSTS4_BLOCKY udp dport $PORTS_DNS accept comment "allow ipv4 udp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
ip daddr $HOSTS4_BLOCKY tcp dport $PORTS_DNS accept comment "allow ipv4 tcp dns connection: !WAN > SERVER BLOCKY(FW)"
|
||||
@@ -140,17 +140,14 @@ table inet filter {
|
||||
# SSH connection
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv4 ssh connection: CONSOLE > FW >"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_SSH accept comment "allow ipv6 ssh connection: CONSOLE > FW >"
|
||||
# Reverse proxy (WAN)
|
||||
# Reverse proxy for all
|
||||
oifname $IF_SERVER ip daddr $HOSTS4_AUTH tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: > FW > SERVER AUTH"
|
||||
oifname $IF_SERVER ip6 daddr $HOSTS6_AUTH tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: > FW > SERVER AUTH"
|
||||
# Reverse proxy (SERVER)
|
||||
oifname $IF_SERVER ip saddr $HOSTS4_CONSOLE ip daddr { $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: CONSOLE > FW > SERVER INFRA/APP"
|
||||
oifname $IF_SERVER ip6 saddr $HOSTS6_CONSOLE ip6 daddr { $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: CONSOLE > FW > SERVER INFRA/APP"
|
||||
# Kopia/NAS Console > NAS
|
||||
oifname $IF_CLIENT ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv4 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr $HOSTS6_CONSOLE ip6 daddr $HOSTS6_NAS tcp dport { $PORTS_NAS, $PORTS_KOPIA } accept comment "allow ipv6 web connection (DSM, KOPIA): CONSOLE > FW > CLIENT NAS"
|
||||
# Reverse proxy (SERVER) and Kopia (SERVER) for CONSOLE
|
||||
oifname $IF_SERVER ip saddr $HOSTS4_CONSOLE ip daddr { $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_APP } tcp dport $PORTS_WEB accept comment "allow ipv4 web connection: CONSOLE > FW > SERVER BK/INFRA/APP"
|
||||
oifname $IF_SERVER ip6 saddr $HOSTS6_CONSOLE ip6 daddr { $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_APP } tcp dport $PORTS_WEB accept comment "allow ipv6 web connection: CONSOLE > FW > SERVER BK/INFRA/APP"
|
||||
# Printer
|
||||
oifname $IF_CLIENT ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_PRINTER accept comment "allow ipv4 printer connection: CONSOLE > FW > PRINTER"
|
||||
ip saddr $HOSTS4_CONSOLE ip daddr $HOSTS4_PRINTER accept comment "allow ipv4 printer connection: CONSOLE > FW > PRINTER"
|
||||
|
||||
iifname $IF_WAN jump wan comment "set WAN interface rules"
|
||||
iifname $IF_CLIENT jump client comment "set CLIENT interface rules"
|
||||
@@ -162,19 +159,13 @@ table inet filter {
|
||||
return
|
||||
}
|
||||
chain client {
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_CONSOLE, $HOSTS4_NAS } accept comment "allow ipv4 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
|
||||
oifname $IF_WAN ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_NAS } accept comment "allow ipv6 internet connection: CLIENT CONSOLE/NAS > FW > WAN"
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_PRINTER, $HOSTS4_SWITCH } drop comment "deny ipv4 internet connection: CLIENT PRINTER/SWITCH !> FW > WAN"
|
||||
oifname $IF_WAN accept comment "allow internet connection: CLIENT > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain server {
|
||||
# reverse proxy AUTH > NAS
|
||||
oifname $IF_CLIENT ip saddr $HOSTS4_AUTH ip daddr $HOSTS4_NAS tcp dport $PORTS_NAS accept comment "allow ipv4 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr $HOSTS6_AUTH ip6 daddr $HOSTS6_NAS tcp dport $PORTS_NAS accept comment "allow ipv6 web connection(DSM): SERVER AUTH > FW > CLIENT NAS"
|
||||
# Kopia INFRA, APP > NAS
|
||||
oifname $IF_CLIENT ip saddr { $HOSTS4_INFRA, $HOSTS4_APP } ip daddr $HOSTS4_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv4 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
|
||||
oifname $IF_CLIENT ip6 saddr { $HOSTS6_INFRA, $HOSTS6_APP } ip6 daddr $HOSTS6_NAS tcp dport $PORTS_KOPIA accept comment "allow ipv6 web connection(kopia): SERVER INFRA/APP > FW > CLIENT NAS"
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_VMM, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } accept comment "allow ipv4 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
|
||||
oifname $IF_WAN ip6 saddr { $HOSTS6_VMM, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } accept comment "allow ipv6 internet connection: SERVER VMM/INFRA/AUTH/APP > FW > WAN"
|
||||
oifname $IF_WAN ip saddr { $HOSTS4_VMM, $HOSTS4_BK, $HOSTS4_INFRA, $HOSTS4_AUTH, $HOSTS4_APP } accept comment "allow ipv4 internet connection: SERVER VMM/BK/INFRA/AUTH/APP > FW > WAN"
|
||||
oifname $IF_WAN ip6 saddr { $HOSTS6_VMM, $HOSTS6_BK, $HOSTS6_INFRA, $HOSTS6_AUTH, $HOSTS6_APP } accept comment "allow ipv6 internet connection: SERVER VMM/BK/INFRA/AUTH/APP > FW > WAN"
|
||||
return
|
||||
}
|
||||
chain user {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
Name=wg0
|
||||
Kind=wireguard
|
||||
[WireGuard]
|
||||
ListenPort=11290
|
||||
ListenPort={{ services['wireguard']['ports']['udp'] }}
|
||||
PrivateKey={{ hostvars['console']['wireguard']['server']['private_key'] }}
|
||||
[WireGuardPeer]
|
||||
PublicKey={{ hostvars['console']['wireguard']['console']['public_key'] }}
|
||||
PresharedKey={{ hostvars['console']['wireguard']['console']['preshared_key'] }}
|
||||
AllowedIPs={{ hostvars['fw']["network4"]["console"]["wg"] }}/32, {{ hostvars['fw']["network6"]["console"]["wg"] }}/128
|
||||
AllowedIPs={{ hostvars['fw']["network"]["console"]['ipv4']["wg"] }}/32, {{ hostvars['fw']["network"]["console"]['ipv6']["wg"] }}/128
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Match]
|
||||
Name=wg0
|
||||
[Network]
|
||||
Address={{ hostvars['fw']["network4"]["firewall"]["wg"] }}/24
|
||||
Address={{ hostvars['fw']["network6"]["firewall"]["wg"] }}/64
|
||||
Address={{ hostvars['fw']["network"]["fw"]['ipv4']["wg"] }}/24
|
||||
Address={{ hostvars['fw']["network"]["fw"]['ipv6']["wg"] }}/64
|
||||
IPForward=yes
|
||||
|
||||
@@ -3,21 +3,27 @@
|
||||
# iifname oifname saddr daddr proto dport ct state action / Ellipsis if you can something
|
||||
flush ruleset
|
||||
|
||||
define NET4_SERVER = {{ hostvars['fw']['network4']['subnet']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network6']['subnet']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define NET4_SERVER = {{ hostvars['fw']['network']['subnet']['ipv4']['server'] }}
|
||||
define NET6_SERVER = {{ hostvars['fw']['network']['subnet']['ipv6']['server'] }}
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS4_AUTH = {{ hostvars['fw']['network']['auth']['ipv4']['server'] }}
|
||||
define HOSTS6_AUTH = {{ hostvars['fw']['network']['auth']['ipv6']['server'] }}
|
||||
define PORTS_SSH = 22
|
||||
define PORTS_DB = 5432
|
||||
define PORTS_CA = 9000
|
||||
define PORTS_DB = { 5432, 3306 }
|
||||
define PORTS_CA = {{ services['ca']['ports']['https'] }}
|
||||
define PORTS_LDAPS = 636
|
||||
define PORTS_LDAPS_FORWARD = 6360
|
||||
define PORTS_LDAPS_FORWARD = {{ services['ldap']['ports']['ldaps'] }}
|
||||
define PORTS_HTTP = 80
|
||||
define PORTS_HTTP_FORWARD = 2080
|
||||
define PORTS_HTTP_FORWARD = {{ services['caddy']['ports']['http'] }}
|
||||
define PORTS_HTTPS = 443
|
||||
define PORTS_HTTPS_FORWARD = 2443
|
||||
define PORTS_PROMETHEUS = 9090
|
||||
define PORTS_LOKI = 3100
|
||||
define PORTS_HTTPS_FORWARD = {{ services['caddy']['ports']['https'] }}
|
||||
define PORTS_PROMETHEUS = {{ services['prometheus']['ports']['https'] }}
|
||||
define PORTS_LOKI = {{ services['loki']['ports']['https'] }}
|
||||
define PORTS_SMTP = 587
|
||||
define PORTS_SMTP_FORWARD = {{ services['maddy']['ports']['smtp'] }}
|
||||
define PORTS_IMAPS = 993
|
||||
define PORTS_IMAPS_FORWARD = {{ services['maddy']['ports']['imaps'] }}
|
||||
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
@@ -25,6 +31,8 @@ table inet nat {
|
||||
tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "DNAT http ports to $PORTS_HTTP_FORWARD"
|
||||
tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "DNAT https ports to $PORTS_HTTPS_FORWARD"
|
||||
tcp dport $PORTS_LDAPS dnat to :$PORTS_LDAPS_FORWARD comment "DNAT ldaps ports to $PORTS_LDAPS_FORWARD"
|
||||
tcp dport $PORTS_SMTP dnat to :$PORTS_SMTP_FORWARD comment "DNAT smtp ports to $PORTS_SMTP_FORWARD"
|
||||
tcp dport $PORTS_IMAPS dnat to :$PORTS_IMAPS_FORWARD comment "DNAT imaps ports to $PORTS_IMAPS_FORWARD"
|
||||
}
|
||||
chain postrouting {
|
||||
|
||||
@@ -34,6 +42,8 @@ table inet nat {
|
||||
oifname "lo" tcp dport $PORTS_HTTP dnat to :$PORTS_HTTP_FORWARD comment "DNAT http ports to $PORTS_HTTP_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_HTTPS dnat to :$PORTS_HTTPS_FORWARD comment "DNAT https ports to $PORTS_HTTPS_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_LDAPS dnat to :$PORTS_LDAPS_FORWARD comment "DNAT ldaps ports to $PORTS_LDAPS_FORWARD out of LOCALHOST"
|
||||
oifname "lo" tcp dport $PORTS_SMTP dnat to :$PORTS_SMTP_FORWARD comment "DNAT smtp ports to $PORTS_SMTP_FORWARD"
|
||||
oifname "lo" tcp dport $PORTS_IMAPS dnat to :$PORTS_IMAPS_FORWARD comment "DNAT imaps ports to $PORTS_IMAPS_FORWARD"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,16 +60,20 @@ table inet filter {
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_CA accept comment "allow ipv6 ca connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_DB accept comment "allow ipv4 db connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_DB accept comment "allow ipv6 db connection: SERVER > INFRA"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4 http connection: CONSOLE > INFRA"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv6 http connection: CONSOLE > INFRA"
|
||||
ip saddr $HOSTS4_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: CONSOLE > INFRA"
|
||||
ip6 saddr $HOSTS6_CONSOLE tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: CONSOLE > INFRA"
|
||||
ip saddr { $HOSTS4_CONSOLE, $HOSTS4_AUTH } tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv4 http connection: CONSOLE, AUTH > APP"
|
||||
ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_AUTH } tcp dport $PORTS_HTTP_FORWARD ct original proto-dst $PORTS_HTTP accept comment "allow ipv6 http connection: CONSOLE, AUTH > APP"
|
||||
ip saddr { $HOSTS4_CONSOLE, $HOSTS4_AUTH } tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv4 https connection: CONSOLE, AUTH > APP"
|
||||
ip6 saddr { $HOSTS6_CONSOLE, $HOSTS6_AUTH } tcp dport $PORTS_HTTPS_FORWARD ct original proto-dst $PORTS_HTTPS accept comment "allow ipv6 https connection: CONSOLE, AUTH > APP"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv4 ldaps connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_LDAPS_FORWARD ct original proto-dst $PORTS_LDAPS accept comment "allow ipv6 ldaps connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_PROMETHEUS accept comment "allow ipv4 prometheus connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_PROMETHEUS accept comment "allow ipv6 prometheus connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_LOKI accept comment "allow ipv4 loki connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_LOKI accept comment "allow ipv6 loki connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_SMTP_FORWARD ct original proto-dst $PORTS_SMTP accept comment "allow ipv4 smtp connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_SMTP_FORWARD ct original proto-dst $PORTS_SMTP accept comment "allow ipv6 smtp connection: SERVER > INFRA"
|
||||
ip saddr $NET4_SERVER tcp dport $PORTS_IMAPS_FORWARD ct original proto-dst $PORTS_IMAPS accept comment "allow ipv4 imaps connection: SERVER > INFRA"
|
||||
ip6 saddr $NET6_SERVER tcp dport $PORTS_IMAPS_FORWARD ct original proto-dst $PORTS_IMAPS accept comment "allow ipv6 imaps connection: SERVER > INFRA"
|
||||
}
|
||||
chain forward {
|
||||
type filter hook forward priority 0; policy drop;
|
||||
|
||||
@@ -3,26 +3,26 @@ Name=vlan1
|
||||
|
||||
[Network]
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['vmm']['client'] }}/24
|
||||
Address={{ hostvars['fw']['network']['vmm']['ipv4']['client'] }}/24
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['vmm']['client'] }}/64
|
||||
Address={{ hostvars['fw']['network']['vmm']['ipv6']['client'] }}/64
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From={{ hostvars['fw']['network4']['vmm']['client'] }}/32
|
||||
From={{ hostvars['fw']['network']['vmm']['ipv4']['client'] }}/32
|
||||
Table=1
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination={{ hostvars['fw']['network4']['subnet']['client'] }}
|
||||
Destination={{ hostvars['fw']['network']['subnet']['ipv4']['client'] }}
|
||||
Scope=link
|
||||
Table=1
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From={{ hostvars['fw']['network6']['vmm']['client'] }}/128
|
||||
From={{ hostvars['fw']['network']['vmm']['ipv6']['client'] }}/128
|
||||
Table=61
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination={{ hostvars['fw']['network6']['subnet']['client'] }}
|
||||
Destination={{ hostvars['fw']['network']['subnet']['ipv6']['client'] }}
|
||||
Scope=link
|
||||
Table=61
|
||||
|
||||
@@ -3,30 +3,30 @@ Name=vlan10
|
||||
[Network]
|
||||
RequiredForOnline=false
|
||||
# IPv4
|
||||
Address={{ hostvars['fw']['network4']['vmm']['server'] }}/24
|
||||
Gateway={{ hostvars['fw']['network4']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network4']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['vmm']['ipv4']['server'] }}/24
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv4']['server'] }}
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv4']['server'] }}
|
||||
# IPv6
|
||||
Address={{ hostvars['fw']['network6']['vmm']['server'] }}/64
|
||||
Gateway={{ hostvars['fw']['network6']['firewall']['server'] }}
|
||||
DNS={{ hostvars['fw']['network6']['blocky']['server'] }}
|
||||
Address={{ hostvars['fw']['network']['vmm']['ipv6']['server'] }}/64
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv6']['server'] }}
|
||||
DNS={{ hostvars['fw']['network']['blocky']['ipv6']['server'] }}
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From={{ hostvars['fw']['network4']['vmm']['server'] }}/32
|
||||
From={{ hostvars['fw']['network']['vmm']['ipv4']['server'] }}/32
|
||||
Table=2
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=0.0.0.0/0
|
||||
Gateway={{ hostvars['fw']['network4']['firewall']['server'] }}
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv4']['server'] }}
|
||||
Table=2
|
||||
|
||||
[RoutingPolicyRule]
|
||||
From={{ hostvars['fw']['network6']['vmm']['server'] }}/128
|
||||
From={{ hostvars['fw']['network']['vmm']['ipv6']['server'] }}/128
|
||||
Table=62
|
||||
Priority=100
|
||||
|
||||
[Route]
|
||||
Destination=::/0
|
||||
Gateway={{ hostvars['fw']['network6']['firewall']['server'] }}
|
||||
Gateway={{ hostvars['fw']['network']['fw']['ipv6']['server'] }}
|
||||
Table=62
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
# iifname oifname saddr daddr proto dport ct state action / Ellipsis if you can something
|
||||
flush ruleset
|
||||
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network4']['console'].values() | join(', ') }} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network6']['console'].values() | join(', ') }} }
|
||||
define HOSTS4_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv4'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define HOSTS6_CONSOLE = { {{ hostvars['fw']['network']['console']['ipv6'] | dict2items | rejectattr('key', 'equalto', 'reverse') | map(attribute='value') | join(', ')}} }
|
||||
define PORTS_SSH = 22
|
||||
|
||||
table inet filter {
|
||||
|
||||
+164
-68
@@ -7,11 +7,13 @@ sudo:
|
||||
console: ENC[AES256_GCM,data:RdvzU4VOU+ww1OVvLanD9KbCYom/yPHQ1DdjUBfG6l9nPHEapYqqvHpr6Oi3nDRfc2n5cR4R40i0DHCh01Eo,iv:X8RxKloim0jsDj8U/aY+rHARtrlTrvwNMqMcTmdPfes=,tag:eaMrWFdyU9jifh3SvBrE+A==,type:str]
|
||||
vmm: ENC[AES256_GCM,data:CqEAeHMgRkmsFYFGOyHic2TGYXlw/1VO4mMAaPSHqzGDoW6u6Gz29uho9EY=,iv:5fc0LkIQ/gVFTK7YEjnmA5ye2EEyh5/61VvTVarGOQA=,tag:yLwK2HchZvGZBFL4ZnxNaw==,type:str]
|
||||
fw: ENC[AES256_GCM,data:Iz9zt+M+ug6vxzjMAdGuSBSQ16+JrrXpfbsWUpoA184JEV+nC0xZi4eawLI=,iv:4lbQCgFdo5WzY5vFbn9dbkLN6iCoJNJ/5UXw74qOv7s=,tag:eCRh07yL5/D3Kzh6xgmDWg==,type:str]
|
||||
bk: ENC[AES256_GCM,data:mtpcOaoQzQzweKZG9toTXJ1C2wujyakkEP2axKCNXizKcQX575G42Ye3glU=,iv:SUZJFQbuxUoSB/fyk8NZZplCLG49dIFtnYqcxbXoJsg=,tag:Yy8yF/CwqLZP1cyOrTPJCA==,type:str]
|
||||
infra: ENC[AES256_GCM,data:2KEo16JyMbcySxkPUA1qvQZP5YnfKlT/lJS8FnFWSoXEL508dwiWslSDPfI=,iv:xLah1BYaNuMlSWUufhdWupzPaXbLVgVwVfXO7dKSCcY=,tag:wqkJdWNf2h5ecSBDf3T8xg==,type:str]
|
||||
auth: ENC[AES256_GCM,data:Gv73925NEyxQEXmVC3YImOfzj99ZVDH+Jt3iEl0yEN69E/1VeqH67uG5kyQ=,iv:+Dd4kY0nDZIBnB+Ft7e8GD1v9a9NjRjU/QnwnXJLJ/w=,tag:X/hOwq1fxHPPhp5VtENWbw==,type:str]
|
||||
app: ENC[AES256_GCM,data:/e7LF628qBL1+dPtfqV0myEp9MYBx4s1R6LG+HD9P/7LSsF2qG4eUl885GE=,iv:oU23xu+QTtYbT9/7Z8Q+CrCrpOJXs+Cgstvf8RASEZc=,tag:AvYzJuTKFt+dHm/uca+TGg==,type:str]
|
||||
hash:
|
||||
fw: ENC[AES256_GCM,data:cI7ZkkxkNypzTRtChxC0HVp0YxwUHXDlcs+Mm1A2OxuGekr4t2IoXnF3OieQVB8LfjH14iJDhBAQxAjww9O3dsaKy1QQx8zCZ5IabDmBfLEsdhJVGHxTBw6PJHzhlW4+1QAYnxXcWqH6Tg==,iv:s/A8I30BP4PYBf+5lBxBXySx2atYn1MYdclA1Cb/VOY=,tag:tKBs1udztZV0T3/UfAiL5A==,type:str]
|
||||
bk: ENC[AES256_GCM,data:tdZOY/Cyj0leqPpRqOpoudTLW00RQpzREz9gZ+wvwhcKR2tPA7IrDSSaJTt5EOYrfInwBL1x/Zq+JZ4b9+VWW/9+f8JWN0AW8IuCv+5aZ8b2/TKFM95P9a95n+JpkriwPp9Ca0ZQ8BdqpQ==,iv:NCXVJP0ZYQwNo7BmIeyKnHSIcQuUpQmccFLFRYZ+a1k=,tag:avOW/Xyy1tGSJbtp2vlvnw==,type:str]
|
||||
infra: ENC[AES256_GCM,data:Ifk0g0CZOIzyTeTgSVlOj5J0TsIBNQTtZYsM+MNsZ/BGhNb/NADotrBRwpgK7Lts13TQ9eNZtcm4VgWVyWVIcM2HJ+1hAKMHcgHsOlaZNZa3vbiGS/X6xvD01vFeNWC1P0A7GDsvNS0B0A==,iv:PbwSvKNl4EmLBJ/la3ePx7hzJodtLGn57XvgM3X3xtc=,tag:Qahp1EARyRqmWr2BZ/pLJw==,type:str]
|
||||
auth: ENC[AES256_GCM,data:ezk7MNsSRkF/dI8YhKB9CX+M8j876cRCkDqx64mZPaYNIWD7/tpbwqSTuTvoFsGJ9ikh3ZbNA4n3qMxMSsWstckHfcSgjUF56Bz9lCRvNqNCk/tDyj5aqxeHPXrbad4lwrgl0dPNFuPqxg==,iv:JEJnP+HnaxaLWpgsVmsLuTcxTMIA28l/ESCDnJcM1oQ=,tag:flDCxuD3L5IEfAX5BGu+YA==,type:str]
|
||||
app: ENC[AES256_GCM,data:xRr+kc1cvB2BK6DhQZQ21TvsgIgAxAJlWVMM7fbFTn9HObUIuz+a9MROGnduHKe8dp5bOkL97jlwZvk4qT8n51rYp4YvgKU/CQ7n89MqQO248hJp2MRMRWmom9Gh6HlzY4IHeMhceb/oYQ==,iv:BG4tPfwp5Qa9/H0h517fHjaE/ZIMy4vnAAQ4Fvqj2H8=,tag:meE8ZxXB8E4Pi/bS4dKMZA==,type:str]
|
||||
@@ -25,8 +27,8 @@ ca:
|
||||
crt: ENC[AES256_GCM,data:t+yAyGjsbGUFfa/3wKqAHVgV15trtFrFHXRgBN5y1iJNXvqsHzdt4OO07o/d8lT2bh/UXZEHQDmx0VW+gKSouVzr+ZF2ENgXAW+d1cWWup7cLW+oC2LOf22gP3js53dGNS4+qRhPTi5M7XZztsAJgaI3+LAiDMoxoZn8jZZ2OKOB2038w8ZHCDGMUmvCMXJkk5u4o9zf8qLggdPk/MoAtQ4g4/5Q/gJsf5v6+ufZbSXnWWfwtBce7FStb3Bg06RIGG3LtDGzBxvMFpDJe3z0bidJtOlYyAJhOZF/knOTUwVlEt/Jhd9KoxRKYCMETj0eKO88bIyxZx9gmli7OuETWRyK+A8Y7xAdAoZxgeDJZjX4kcPsMy3vkGKSGRKDg+FMwX/PGwUDQmG+UyfmGqZUyc5fJWHKI8eY55jZoHR2U47tRvV3DcRlvfq8x1Ror1aMtaHfAYcTtxmhQxaWTBhpEQDMSBfMS85UMtNATQd9FXaIh3L6NB1hXCEa/3Tb03ULjkV9Ij92l041CdVUGhRbgz7iC7gy2aGap8fK4PopuqPeEsz306S1Mc1+FLrBz0Y4+545k+cNcEueKRXkColtdsTGU0JhftF3tXxynmx8W0kGKfG3o12VAN4Q8+yYPvE4XtTNVoJtzPeC+ksCem+w57gIAP+PbSdmnaEjsM/GrfTfGzJzcuCUKVDtSl8jh3B8f7f6dk0GSXftMnofdHlSXcAq3rG8oHoqCzS+k/VMz8o22uqcVHTiE0HKVK9h0jghDkkEYcGyiBsLPMlUxmkBmE8uwA==,iv:FyUTqDvjMajaHljcwnQZ9usEaL46hpvGOjNvIVUTMEA=,tag:K3h0hZfr0yjVhxpaG6bi3Q==,type:str]
|
||||
password: ENC[AES256_GCM,data:ElXnqYyR9qAiBjPqR0HVsMcknp/qqCsBbs1zLfRVqYHSX68RkNVDWOWhrIo=,iv:xiBAV2J52aQbaA9VxdUvjiYg7JTnQyeuBukTFfDCjig=,tag:lZXVek8TSTcNtcu5VyUMUQ==,type:str]
|
||||
intermediate:
|
||||
key: ENC[AES256_GCM,data:xZB2VgzLgTleX/E27lie9Cy0Ham6iGZtSfmw/wfOqH/h/HBv754uYV5XPQyenj6Mst06WiiNl/gvzCZjNAoLiKPkGWvpWZeUjeclsb3QuWjIIArarjcOaA1XX0wxsizfAZ79FU4qjY+alJlN2EnWgiyYIq/bCdhMorYi9nn3z63Q2CetzDpMILfacv4aUzIqu6iX9sgJ4cwpzlAdl0vs7Q4jUZ1eNu00zb9Lbf3NSFUuafzDNSn4FFJ5H4nFqC/okLtFjfMrWv+XPXKR/EqA77cS2gW0g8bGtpZX51cNGYlIMdXj9Coet5tgj+UG4KzJSMoTFdiXHdR1jFAvmYUcFbX1wtbGtIqK3vKcVT1UBtkxQnj8dURzuetyj21qABR6WfPXVOfgIQrTdG4bUZEw1LZbEYd8w6L57NE=,iv:nspy2dXUIGvuyTkETzMxmeEPh0u4saxc5jHfsUMC93M=,tag:v7mMF2+asasRwqIyTSlgQQ==,type:str]
|
||||
crt: ENC[AES256_GCM,data:4RrGKeUS+9oZN08WINaW61C7yGs6Atu/vA/w9GNGhC21wMWHoB3FXl6sxDkNAO+qZn0YhINXW6MF6VvmPh0Lu2nQ5wdLlhsgFat1fXrWcatqvHoD08Q6pWSVTXwN9ZLM038ucOj26Xs4C2mBCl2wddII59YzCKRcXIYoK7GWF3m3x5uWY+sP+8IZ2fQiHEaITFX1hg9tNItmWoRh7gCQ15yec6KTOuM9Ph2HI32oP1Lm4h3fW2SvIcgJqHcFObtequGFXpvZbSedesdR3v+gNVSr5oTVsEGoGwyALt/gGpK3zptTDsavARzsQPUXu3+QILyuNYHXP653g+VnSLMwEMuFdeQJaBeG4TF0Zo76dPuy8lPSawhGK1BJsEgUb++23q87nW/O5UdJsUJ7gIejrQQpH266nq8cw1Thyskypk0TrsMdrTWwOniWOLSUVf+5GZi9mLqNse89Qe9xyJlvocTdpZg7Bl9kDVFjLRO2IC8+r7NqD8PeOjxT8ojJNYXG3iDbdqyQtHtpETjLUN4ZHCo8EOdGIBAqnutV0gAxnKIcran86gtk6QIeYL62x0AgkDDEClCrQMZEOIMbhzPMml+4Y0SdcoA8DErrFiPeufDxak5gNLRJxOT/okOBi5/QK4deJ2Cbx0lSxB79d69Ol9OAKUNW855o/lcGD+Tx3bNXYzN+EaFmpku3Sv8Bvl3QloVQ4832w0bbwcqEoviuB8hDMqsmWXZS8D+cqL9uYZVObRJS8rR8QGPfPkSPy8NePWsuR1vznlyBT35eyRcKwVp+qweDIjHHgAIcSvSAVPoQ3EYT01WCpRPsiTIxh4IbLIYeqImFrb6Vn7S6tMmv3E3eCnuL/LfxiV1t3Q==,iv:bUDkP5wRWEqi9n9QEN9ETHFeWdAiEk8GUwTD4X7asRA=,tag:xYYYPlGQfhcK97tSPtM7dQ==,type:str]
|
||||
key: ENC[AES256_GCM,data:a8KTCpX+JqANyXnD7aCAUYa+peHkJ+9NCFs7LUxbywINTQ6/wS/SL5jEWtw/7V6qOXbULXhv7DnBf4nydhTPDrN+Ej9JRGAVwJvrlai/41N5u/VZAHem6dihjQEEXiHMsOxMjEeyEgpw3F+D9ozLyp7KiN0C04bm8DH5GMcfQOPQMMCFT1RcpDtP44Yj/WZ2Xbjfv5NHLueSznmI5oiq6FP9Db5feumEv5bOpxZH4HRcX+wZHl0jVj9UH0KKXVbVYCowOqCwDSbzbXDcnVB3euS2rhgxf9ZpmxrcBNDdxN+y+RL3hdYtRnIjYdPp1VgO+AUHVwrG9+ewaVJQbc3VpC8JUGYPhJmApfd5AxAZV3f28dqCXxOTNG7OykdJWGq/2XUFaTc/qO95LHsPn3CLiJV4Ftd/9cWiU2U=,iv:OlGIpEZCS4glwwP/46HUOo6cYP68eDEhhym6ZPQFW64=,tag:WszdNLVTM7v1S+eQ3LJPlQ==,type:str]
|
||||
crt: ENC[AES256_GCM,data:GJVZ7a1B+OTzlwXEQLzlg6E48rrPe7mVhICRDjryN+PtxprlwcoFMPX+qByoSJg18qG2owfynrxMFhaLuuGMkgGS0MeQ9lsiN/Y6qAitK/Iz3LL2YMTXTu3P+VFiYyRTfidYrfzTNkb7wg8d64SeRo+rLA2xViObepaOSJmBO4jnKJCPVErg/BsZKcrHU4xG1AeMEKherpnw5JkiGyHFlBDyPSHG23Qnvn5YHiC+enwGUggi4ZrCI7c+VDKXAe2ATuEixE1yZOYtVbytZw+8JCgWQFF1EFnHvHh6vPbyP6ekJDx3xCh4nD9Il/g7HU5cMxKOmSuFINmWhgR+8UM/D6ZOIhX/G9tIyrCs6UDLHZuuGdNWICOIDaUTTh5D4c8RlsW0Xhu5EfN/ufEUY2EsaHv/RfL1EQdxSEEzLG6KENbZy5UEktAryD3hJUrIym84shsOoa8y54A7SrYSmcQIlMEAReRHKvbDWlUm1Gre/TseDpBbLRweqfenErq4pfnCt40iE7P22ZbAsexcjhbEkAcWkhIuxkyp9zXpyketPYoLT5jXnvOOBPQYvOYEa15eDWqKDOcGXP3HmwVQxTI1zd/+68U4jMoL69G/hyAMesNe3myZ/1jDZVzv7A6rBHAEVp0Y3XncsQdh/txnuNX/x/xS7BvSEI/2QF/LOTBy5JqgJ9hJUiqVb2mPtd+Z1EJCvL1xQOvE/Y+sV26QMjXWrhSSmGz+ynlBbYPX0teAoZk5q0HWxfxId12fwYBNYIVnok/rdHuSrVfypa4WOi7GMSXfqzV2Ny1LHeVFfYNWOlSvF9YTqVQFOOULq8UCENEjkQp8MmI+Yv1yY6MnM6LJggA1oNHAPGRR,iv:Y6bno4J3ltsapy9p7TfNHumlrkEJFA5U8qZN/CRO3yo=,tag:0Q2Su4pLFGC62ifDDSr8lA==,type:str]
|
||||
password: ENC[AES256_GCM,data:aijMXt3hTo19xVChh1gplU8sUQjmX4Y+dSjS69Kw2cEqmEJB/pelihLH96c=,iv:zP1yDLGsbL0sxJq2PF+qe3c8rNT7Knz6vKaGwMVB2xs=,tag:Oazypz0OfAYI/eptqgaINw==,type:str]
|
||||
acme_key: ENC[AES256_GCM,data:vir3SKMdU8FsZ3fBNoSMrev3vreFG4Vsex7R4hIR7Ty68x9wqsO/YpJSNkw=,iv:e7AqVbmCOkVIaje6xF8QzISU0E3JfyU4GM7/361ybdc=,tag:HC/kMa/jmVqBwCsvR31WHQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
@@ -58,6 +60,8 @@ wireguard:
|
||||
#
|
||||
#ENC[AES256_GCM,data:+kiy17Z7q3EiPgo4Ykk=,iv:vOi54XHHLNIO9U0ybpU9Cn68Ymj5W4vtQ2OhTkGAmRo=,tag:h3wdCo5UfNGlHqMpeeBf/A==,type:comment]
|
||||
kopia:
|
||||
key: ENC[AES256_GCM,data:7JTRJHzTCLOD68iXsPMvbgEapgYVG5iQ2RZnyNe5cgQvNOuCHVHyaEb0EKwPCyI1o8R32ygkKHzLRqojL2bBTXQN/diqNmL9PSOpkh7ZtFg/sioxEs0BjKLsrzi1gZQaB1Iyx4lrKy0L3QHH6KgjSJo/m5CyNVmLkFV545cdrU1TiHkgi90x0qcIH2YDN8VwtXyYwmzrPfx/0eHOdHbPcwI37KWf8auPBkx4UHzdbciz/mvr3AJiqs8g8CirnT5916jGS9HOGEkft2QJr2A+5PGjLJDZVHRukM6f+PSLHUKDzJY=,iv:0YcIIGbUWkcl8s+WSlW+IanQuIo+lCn92CIenid72ok=,tag:EG186gNnYIOnxCJ5EGP3+w==,type:str]
|
||||
crt: ENC[AES256_GCM,data:SOkD90wE+C2suQUzjeurp7R4En3RDpinxRcUXsr3c9RB46xL8Ryf3vFxvItl2hgefDmakjA919e6b0U4j2Z1OomvYGnoH7wk3LOvcCNqYwwYkGU9TOtn2rEuZ1jnJGx6PUEKmQPvNugnX3ZVFjEY3MSV/oGyoYYLgouPYGk5JJzcZMNUm47p9iFZW3NOpkrvcHOxQklXquJyMUDb0ZYp3KAs/+r+helqMFS45ZAWJz0yyxT75Ye+zBR8MQMyezuP4vd5BA11Q3KjJ0tcmxMcaQf+2PcOd/Ps7Z+F5SpuXsZFw8AYSftrtsUJvOxsnEO7MHH2KEUGwHCAvsNs80W9QrAm9zflperGlxmeu+ebZ/SqY7mAeMfwc4SHcPyBFcCfF7nYOPhye+A0SQ46lgKRD1ZoH3bP6O4bbvRLAU6d/1pDwyIgqL/YroQFJEjCD/JByYUJuechalZ/xcNbzy5TlcwdfoWCCaii10HDzdUcCczLvOBabarj0W8xkaKVUZtv7nbtVLoSks/TsG+1ipFIvKkCJ0yp4ycxXEGphQ1B0YvHAx+QDhtjJQuRpYEuwwa9mfRebrpVDy3G1zy85YyEE9btLQknOGmxkMrtAGZs8Qv5LF4xjWrFmfZk14mr86mXaNycVJstyzzd6Hsmkkw5WcDz9fYarUWDf/yY89LkVdCgjHWvD1GW5kD/o2kkWboMFsQPcNyZzEIQRmusi87xTSvaTUt0G0tAhOqsPty6T8A3VBbgku1dNLS2n2UQ/7iGSfyo0GLVl2cY1Db14nUmRP5Pk5JNlkAq1I0+Wsa4r91ljflhVbAuFN2hWuiS8S3R12jFHP3Bvda/B3sRSdghRpC8egB5dPMlMN+bFszxfwGb4KybFwtc0J367h6Zr+ekQ5WEQb0QR2jHMyIUuBovzbs5f7rpMKmhadT1ur9Mw7yX/YZlOftnpxY=,iv:IXj2HmxdN0QdhFd7k4KK6IMCYVF+u6KfOmMS13tHP84=,tag:yZ53WiOh6NWuDIaWHiQfyQ==,type:str]
|
||||
repository: ENC[AES256_GCM,data:16V50bVVtecbF+TJcXHCx46ZPGNMgAhUOA0YbZHVTsCrOWQvTvcK2k8Iq3E=,iv:/wNbrE5GaFiQPNEp8wZ0JehbXkmah/gPm5ywNE6WVVM=,tag:vW82KTKtJ44++tqXON/SYw==,type:str]
|
||||
users:
|
||||
console: ENC[AES256_GCM,data:v1QY7h6vMmzYq/PTmnLg3M5Iwc/Ljr/1M3nJGuUJMfPN2ATY+GIMUyhYu+0=,iv:32c4YrZfTiu7sv/c9tDItmAE8G1lvc1sm6JD1GRkYr0=,tag:kj1a32+bMUsRdusadoXDvg==,type:str]
|
||||
@@ -66,15 +70,26 @@ kopia:
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:OK1SKcHWst0rO4MCrEU/,iv:1z4/DaZoVTfQtM/dtKUNHjMmv0UDYayyYwv2yoE1YXQ=,tag:2emhffuIuwdlP/xUYk4bbA==,type:comment]
|
||||
rclone:
|
||||
google_drive:
|
||||
oidc:
|
||||
id: ENC[AES256_GCM,data:Z4LnW6WMwBbVf1n1sD6GWCQXUSuPe3PcKhSb3aJ7UhtzCaD9DUNn5m/2f+WaTbkv6EhrCDeGrQBnfxoSGvniE8VZ2BltSeDu,iv:CjcP+E4wyOWcghjcSHGPhbKcxfTD97uhVzRTUJVq75U=,tag:TpCr3eApSE2MsanJ5pu72w==,type:str]
|
||||
secret: ENC[AES256_GCM,data:n81fc7PwTP9BSxjplwlf+A7tXhwkToHv6lDuav+fleBMC1o=,iv:ndFJpWINRVCL7wcZZ8KjEgs1YPgR6wtWig+3VR4Okgo=,tag:HGOTF4i5mhA4mr4Xnf0UTA==,type:str]
|
||||
refresh_token: ENC[AES256_GCM,data:EEE8ExDhoBqPNM/t+q07ng0UYTU2AGNJEWL3ydZ5A10yOrHrdjMC0YtblQzlsA6tdkLCemaUZQXz9kEIHfTQr901AQALkfb5C9OoEnlXz579OXhDnuv9BJUi7tv+Hny5z5DEeVm/Fw==,iv:LyTHhKqzmO530zFqB0+dKlgi+/NEE/WaJw1CdMTLFls=,tag:nJVszyqv3kEQ7ehlBDe44w==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:gfsEXIOqhoTsiCI4uDjDeEY=,iv:SfJwBdIFY8Z4Nt2CxjuSY8PYKebQvKcg9n2xL3w7rsU=,tag:yrTNPBjrvnxydGK2X32Zlg==,type:comment]
|
||||
crowdsec:
|
||||
key: ENC[AES256_GCM,data:C7bMfJikh20PFQTe7UtP48SDUlSKKDMOul7dt9USZIVKq7LLBJV83vqbOc3xbteqPzwIYqBEndfqypSevpy/cLAPstQXL634fQGbel6trqbCApq/xjucUvnaqRKyUjk/TH3oRP9qXG8XDsgQ1o+I4b4E1alxLljMPN12wd2KIHfDGp+TURcC9DkK+NESIyQMLQg40cBaps1HcxXvg7FB1oJImM6AjqP9iybDfgkCaNAqUHxLyCHJI4rdYFflALHFkorl8jaQTazqWfuSu70x8j5tUJREksOS8arN3YIwXp4UGHQ=,iv:sbF2ZD6xS3Z3EYc6/5m3oKMghkR1q/IDzVwBX0OuTTI=,tag:NIuO8x3rP47oE/Y0EiNOvw==,type:str]
|
||||
crt: ENC[AES256_GCM,data:0Olvh8chXMx0tri9NeiWhka/bl5XRwdAQf55EwhVa2kTedETOBIjdgDqdsXhoREhannWK/1cXcxP7vpvRFMt5e06FsmPh8mSuuyRboVs9ys5p8KPYQcnlOZxfBU1J6DzE8Zq/tOf9cpdlcUVpPJ038tI7cokqhBvPGZIR2Q4/2BKWQnL8d0GvQoEfXOpNw63qQDynSvaSs/asfZf7yeYH6v3Tc4tNRBB5nl8sCq8GjTvm4xleRWax9qS0oroB/uY7S+5OCGLtJFo0A4eweOcEwWuqvpGqsOgs6s8bToeaSmPOUgsCQ2abiMtBWnyCxMxMCFNB+79lpByasf1iGRWlrhjQeUpIoWWAWU6oUbd4pMRy+j+rKV1/Cq4wF7cc7kSTh8BlFAK3Yr8DIDppiUUo53utPAl179ZkycNUzHY5Auh/jA9ZU1UZRbtIOBlIN6mVr/Y53EzigtVYlZRQ6aaQFutM8jGBnegfPhp3m+XY2WanYk1GKKj46Wh11g1YqIWVYpk5hlR1RdQoPsgZPf0yChblbdfQ14iRJqw/0pVPBvX6bKS6P2OaDHpCIBSpTE98VSEjXTkK0XU0Mu5YzyUWxIe5/BoRiF9gRFGHEDWwFWprTuFk3eUEaEZ9qoyWr0igmX73Be7y8Bre0jX1xSMjepSLV/0dSUnimhfAvT1TlhwNlxq+FGR0ZMsu8QmbYp1CqLcH93rQxoloHIs2T1+KfKAENwsjm2PshdqmOOoUkzANUmdilYCelkbXyUKXkLqFb8qnSV0jK6hG/ZVeXTzZPnODJ9Tow9bXKdxOwk16XpuMSHjCoIol2E0yD/0YKVBHAnYuz/Uz8Dl/ko//3+OaDD4TudV/nRyy4Ge4JI/kckiovMLma4dJSmADgOAXa+Ao+3N/vfUMF1F1DyRXUXsqHMygtlZZpGiswabq/MrjEvBPomzFWUmu9clWiPJ,iv:SQrBnbzApJscyGuNPE40uKsUdQCf4W73uUwanfyCGbU=,tag:KK+a0tLB+mmn4YWl5Yc0tQ==,type:str]
|
||||
key: ENC[AES256_GCM,data:XEA7VSw4ZYQYeeUv8dywRDicb5edmIYuMPFMlZBhZxXIcCaM/6lntB/GiQMcj+rAmrWz8RD/BRx+UMxpDlXMHsQLhdqgJf/UdToRsdUWs17IRyoH0+ihbeZjK3CtgYol/lJLvBJMDetUaajHtC3sNKi5vMnmTaSLih8RBwG1h1vX+btp7rie8xZTAzaTlGyQuBUc0A5JJyMQa76x1cKXoc8c+qCz1C5d2Zpc8H86np/mSb2HeMEk6uYbEzXg8a5vldl2+ClYG71POo6lygi/L/POLYHJ3yZKeA+t+yNOHQvfzdw=,iv:z0lZ9TrRymVjS40Q8vJYEGmXUJQVepyG+2wNEb1JDmw=,tag:BCUM6oPpLihYFFpDuus5jw==,type:str]
|
||||
crt: ENC[AES256_GCM,data:Ij59/dP/LVJgCH4YfwUwthXe8xe4CFCQTac/4cqP+AJvfYMR6KzMODlNZ/eokxLN6eGqyUfheK60ustVBkKMRWcre5fIEJ5e8YhN7MUlVdyHJjL1je3AtKSm7Pp19bUtzYdwHeEOuRJhpz//Ulp5Y1lqSa/GL/QKmLZhmWKlwGG/+cp5bH+9zc3MwyAFjMigZU+M3mEJghO6jmy+jTKI4bwJRlhhS//fhsO/f0N1je9bSwmng15BKkMoAzoxoAVmawSonax30iLRNbkd5MvIILgzBNTIHtG+wK3fKJwf6XSFJvFzwmNt3QGBVHHMy0R5wCeicsq6BtOmJHkvE5DXFTqpPnKEbGMgjj7t7ehHBScP40fp+00a1V7ubWi/V2lv1Q+4N2ldDDHjgr3m2K8I7JinxVebZpkeFCzir+BSTbk2rwzjxhsX65S0UmDSYRGA6w2ROWLNUHk7vR54qv+zwtRQLK9r41exVVLdXjJ+MIgbPSQEUmOaqqy1euWWYIintU6xiDkpFIodK8xJXdmJ/82DORXz/gK0yLSF4Cc2DYXurlMCj9hrW0k3QlTv8c9xYSTh0tpkXRsOtYAQVwFnPI2SB/H+q06/VCK93adhvgzJriQ08VKz7dP8gVNhWPiPENkhBKqlX6kWcK0fPdUg/UBYZBLKJAzr93CCpEJbnR/cCE8sZFf1QoV03CrZKCaZTuRne22Ppzm3cNZJysqDc4fsjymk/PMx11ZjlyNw4nREb3nQ1mNLGE8uYlIV645WGo2kWo1GnoANzPdQ5BCXF5wS5qfxLF2YvKYm7Y3Eqc43Dv4ayx0dNk6XoUSPj5Ttp8033tweK3PRnUrAfvDdyxMe9D2igkY7lSioM2XLU7xfxfbgp0czlJieD47Fi8oZwPu58UebSxP7V7c435W3zU3/rL7JP4dEbmtvQnxhI8a28B9hfetoyeaKDj2ly3WkDA==,iv:NVGOUpfjT9lfEMpq+3jm1zuCmceP4QhgOEpnXB0wTu0=,tag:0MMkBBfTNjkKLspWEcS9mg==,type:str]
|
||||
bouncer:
|
||||
fw: ENC[AES256_GCM,data:wplc8z6YNuQi7bN6r27wSOmx7alVDWUBgU+pgvnH0exmRhHCHjbS9zX+4P0=,iv:fbBg0AlqOtbKgYjbiSPopJ0QwEryAEXfcc+YaUWI6xI=,tag:Ul5+MwKZyMevBIyvZH/hAQ==,type:str]
|
||||
caddy: ENC[AES256_GCM,data:fRyTH9/7OZ7oaz2n3o7DtXJCnH5l89fGSZtM3FH8sWzw8Iqj14t/qXsX5Vs=,iv:YQbozgWTmU+facWKeC+2ab2fvm47CwLbrprRiWKDRyg=,tag:Ki3hGXPJ4lWMXJYaDF0kaA==,type:str]
|
||||
machine:
|
||||
vmm: ENC[AES256_GCM,data:CF49CU6iwC8LiUMPaGMFMNGjF0n9gpSplnGkkJNk14qEkvYFTgfoUPqc964=,iv:Qi6cTieniO++EltyUkabXqsPAEb0AEmdR1ramlisthI=,tag:G85rEh6STS9pDr1zbuNUdg==,type:str]
|
||||
bk: ENC[AES256_GCM,data:+paUsZrY/lPv6xTcPMCeTOL4aIpTsnNHo1jVL6LyXky8UyDtsrt5xr6xQ0g=,iv:oI4BoR40rZN3jHFCx3jANdyVMAeO2Kt4EonUdIixveo=,tag:x/sHdgx7S0Aus0+QiopEyw==,type:str]
|
||||
fw: ENC[AES256_GCM,data:uA3AfA394F8b0a2jGjU8ABHvKGNTsZM0O1woQc7gLdHte5Cn8SgfuyNgWu0=,iv:TCZ4NwJuTVPAbiWn6QWM7cRta2uXODHb/41Q1qslJsU=,tag:A7fGrietJuxyEUik3eVZLQ==,type:str]
|
||||
infra: ENC[AES256_GCM,data:rNpo77YAdoRedzJonScaT6Fhr18+T6u6/bKEzC7PYOIzEpuKh/MqzIS6Np4=,iv:D8QND39D2eqBG0USHhcc2UCxpTSuGn4SCpTCOBO0RAE=,tag:1X8IK8DNsD2m6DdtxMQTyA==,type:str]
|
||||
auth: ENC[AES256_GCM,data:neUWugEoUU+LrXijmUjd6063pvtyMuvBhiLtKR0BdAqkl126LN776x4cibs=,iv:OSu3S3AQNqk0PRR2kITKgLcniEsNhrNbpPIix3UIwDw=,tag:5OpA77ayasIQAYx7tYFD9Q==,type:str]
|
||||
@@ -97,65 +112,96 @@ bind:
|
||||
#
|
||||
#ENC[AES256_GCM,data:FNnIRyidUh2urEgGgM85,iv:w6Z7/VLY9BtH4CNqchc/3GkWb4ez2Nb0TxdZF6RdND4=,tag:14vEc2qpBoOApdnci8ZTug==,type:comment]
|
||||
blocky:
|
||||
key: ENC[AES256_GCM,data:3hIpfdbwUzIvFhhVOl9TYoLvVLtFS0jdKSC9FGT2dSmYJP9f0qqrKEtH9+52GF3YUXvf0fkPoqAxxDf3iNh2ynAS7PMBOth3LS5mnY+NpRCZuod8PkyQOWCzkAeVla/JeAD3n3da4f8layWHY47u37XgeojQpyijCWKifEnpbjJdXVBKi440mSaFaORgDJkvSMRGcgF1o1HWz8/YricUIfv3xniQA3Ke8gg4/L9gHHFAqAZiKUBDDppHzuY5ua82FDWTgipPtoNdi+9xyeTmNdunrVAF3OrHwkNQqfLJrGOfrhU=,iv:TGbO2lfqjnsu6ZzcO5qAeQKSgE5qr2lQZi+3YuAlAGs=,tag:tE8bTnPpBXwDXYyB9YsOPA==,type:str]
|
||||
crt: ENC[AES256_GCM,data:vvT9evMqMW8isY3N0tvQCW0XFWIW98vVz0aO0o3habCbLJlB5wjF6TMA1u1xbJ9zQWX8kHTt62BxBngCHXtKFnnVN2q1hNFK/sGFpAJz/WXD/sJW8kHOAv00dwGl2/r1josB9hFmn52omxpryY2h3ZTgqLxoCpzYPoB1LvJzPKo0bS4ig+/qYbAyPe9pNbTmPzGjXutoGbOKXKAQvfZg0YNsR/nbdd0Y5eEdHL+0syH2wEZZ1ZBBNxnd9wiEmRoQHDDkDJ6VHAWfcgZcuX47jKak6LFBAOfj2lVIza78o7MSQsCT1M5DJMZu/K5mV9jJhftljnZ8MB9rX3rFcApHnFX9luLn5b7pHRwieWCNHM71gy3wHS9DFZXjYRpFqFTiXmAxtKxgL3wDIu7M3Ajrc1o1JMlsWMGVUa/InfF73NIMJMKrAPgSWXb4JgwF9HmGjbO5GiSAjRXvuFFmQBArvA7NRn6XFaRyHsig8T/5nQ4t+E0C1HjCkzMFVnUwq5C/3aEJij+cv2YaT5jVTZ5tvX/x0lykMLxd5Psy2Mqvw1++NjS1eOBmg/4q0Pero6zOl+s83fyoSCiXD+K8XHHe24M2IBITABC/Wf4L4yNrwE5S8qn7M6vbFZns1C4BpnIUqbtGeMbAx5reM30nXTWO9pI8Xl5zAPrb4gd7zdl5c6HLge3k8wdNqw2kBD/z4EDCNCPar3g4f1XMhcA1aB3FrHuLvHOkCkCmNbvZ4D4+Nams8HDQ7aNNStshLGt2Rdh8fzQ/KlQslJvgk0oLupnGuZzNWP+TO4tuR4DC/pfX9Uw3+1SDeeTFH/X4iaoSJJxqwC0D3pTvu4SUXilZ+MBE+mDEkB+PbNTuyuFkbUi9OyRFy3W175Mbr9BAdlSIAd70SpUiARqn7k3S5twV5pomxYyOaK+cuAJub/Gp8I0Y102P2rNqcASmA/Ocnogp,iv:m3r2kOi1XUVzLcKo/x9gWT22IDrnOlDYFaGxY2wd6Oo=,tag:6qOgMHBC4mrOTRJ61jhGAQ==,type:str]
|
||||
key: ENC[AES256_GCM,data:hbHEU0PtTH9lcupz7u8NMQRkugvrWMkFcJ81d8NeiY/SA7tm9jVvmOhXEzfxUiOV6s+xzu+F0jzuXmW8CHpkqFJVly3wYNvAUwy5QaLd0khe3VgEA2nCNgJpWQzba1obt5WTwjTJnHNp7T9wR7Bk0NNdDfugwK7+Fm3ox6M2U5Cj3f9OQLPkekSM6ezVWQMlslxc1hMQ1ay+w7J3g/Zb5+99VQlkKhkiA9vlRWAZdvItw4OJhb/SGEkVa41gV6N8Q9JJTs6Hr1YgQ3Qqjl7JpWIUVoWdY4gQMrwfpZGlLlDo6NI=,iv:13AdT/hqc1AH1OJl75KsT25HeZlRdGfu6OL7YE1LT7w=,tag:VndwMppICahMH6QsFKNWyg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:NPFunJfR6r5EgCKnnWkPvNO5AEmzpoTwL8e2B21Wdb1pFiol4hFrCQQKJYlKUTkV/E41Ug6jzRpDAT9mp2/j9HsuRc6LFMti2xLhq0tDu+PaVVs46E/impsL5wLiuRLwoDtmQiAySwGTHO2hzBABvBINTW3RkAg0FHu/6/JLt5xG55TpCb/S/DdYCqBMOI/c2AQn8L6M6MHnKV+lJUK6LM3ZBMtAxCuIzzA15PSTNausXgkle5A2EzjD/wE9tifNLulVHIAH/a+um5S9QCvp2J002aoQ+Op8qlzzTiezs8Mbg+Hp6w+OcqMwBEX2znZFoJpZDNst/nJbQMD6ulmEzxnEcn1uAczG7J5uo55dFTqLc+0860aWTlFsWaF8SKLauYQVfPRCEUTLG9vbfmemxFosI9JGYKHqyNWldfhfkSfqniTAiEMTHkK6E5zZwomeAnje4TyFOoZUQp73kKNj7GigdUWBMmb+YWpDE5J1DJztbKlJKSwVwbFRuMA0QjQfhTGTBWJE4cnU3uyHb1KTiUK3lOFSgR/8IzQ5jwRJ59KbZ/68iiZr5xKY97dRumYg2j6eVHQwIozUfg4ey1y5PfvUIjGBoh6eSXe8tqwUTOyr/kKXRR6eavnc1G2Igw8A/Rkmyrk9AKNqanZZ9vajUQVhnt1rZN6UNRtU7GKONMEtlaRQ32qLBAtk+JtsC5cKOaeca/tE4oneZ8nlazFD6WJ2AovBXew51unJbVypXoyLACcESlHX4qhSQerd33S5iiIRGYNXXNrUniRYajH7oShgzN/z/qtfdOjvpHvJRgFZBwjs86i4m+8jsCdF1VSi9cbp++IV9vqKxD+M/4m46GNbjcMajZflGTuWtZpUAcA477NxMUYKXDtuNFIzHTZ3lrn0i65nHUAVufQl7xpFSh4d66oeOL8mZPFf35uIKAZwvNcPRkLkCnk=,iv:fAqUAiv5WkQacbQWNUnfKC3lLjFj1nBwPPpesQve/3c=,tag:o7qnb/p1ZXgbYkSJlTZ3Cg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:YRIwmRi2hfDb9s4RDy4C,iv:HkpZSROqRaWH/m4dq3Yo9p+n4QJDRbkb29Wcd7OJpXc=,tag:sjnNSWS84DdCIPkGxzFCyQ==,type:comment]
|
||||
rustfs:
|
||||
password:
|
||||
rustfs: ENC[AES256_GCM,data:Wrhw7iW6oPdXXMRq6E/AL+PEM/smak9313eAgwtzrt6fzcSYtdCaVkwNG2Q=,iv:CM5hjpusS9qPoGd96QhHPMTAXpEzZFQEamNRJXVHwjQ=,tag:squNCCytd1BB/91jPSVnng==,type:str]
|
||||
kaneo: ENC[AES256_GCM,data:15kcZRVhZwrU0znXqc8pJX2+/zEIsHWKttkEZGKlhkthNIRCjK28zi4l/Ns=,iv:3c0s9UCPlP+OqRgugGK27LGyZk8sZjigFfPtET50Hps=,tag:qQa8zVicVHGEwj5HrrXEOg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:xUxguG12uiQAzJGMXaaqdgTfCw==,iv:kh2nqSVtBXaAhEywAdDPbbG0p2ljX4mtjVKYXCNL20c=,tag:XGaBtxPBHSaLRYZa97+kmw==,type:comment]
|
||||
postgresql:
|
||||
key: ENC[AES256_GCM,data:XCBWU7Y/BG5kOeKqmNpqwyjePWrMzXUW2RUc+d3r8kfTMqVT2Hxe3Hh8qSCilsZOKoeEfraDKCMKBLmmaX/WGXtjnhOF87Y43i11jDPeMv4g0b3f3oh+ekckxG43pFpPUR8/IW3xB3otTdrp7Sw93xh1s6BcYVutL+opOVLwdB6JNlnx6ZAi+ppjmlHxinEa1UpnOkLC0JNIyp0i5xp5KMizNs4iNcduI3eWWZmj1z/lW1Q7dkH6rPIjtNQt0Ce8wpdsuJvPaZHHAZZ31KkSj/6n/sNhSQsgAvJNYBIsqZRG5lw=,iv:/1keHEeQzFuxaZD/Pw51IBIaBy3J/5fK7BcgF+A41Mc=,tag:Cx2AX0sPTwkmHODbuZNu3A==,type:str]
|
||||
crt: ENC[AES256_GCM,data:cnvAtbrzS3xpa+RQKhSO72xsPLAiloQZrbUL5asql6Zf2B4aNzepfZa9vlTObd4pG/nw1lIFIY4N1oh+L22j9snDXRX4BX5tANJBCiZrnqhvfDkT97xaK/86D9J6kyWmIYjlQ6bXBkvDhDII0eqigV3A/NDl8V9YApGHyAMuryWB69I4wjvVnlok2HSOgZxq0F/3Epp4hk8BuUTNvAcSeIAfpWePVHYtHRk0X3IT3KhR+Q16Ahm3fqDXFkAhs86NBaCl+kEFunGLyBqxecU8uYuU7gmofISqSDytI5ZGVt+oygHSkcQKrW/NBxY2yYs++8m5N0sLPfmtE8NFIMktpjHrUGEKnZmdUEjg7sFFRGhvpGyo77x8TPC3bD1rZJVgDwYCmKjyCO3VT9jPonV66rVOq5S8svm4pQlaT+BDPZXIqDQn4UHD7grKOdUA+zgvdBuVsUnngR/D34cPPm0Y2x4CLPmz4PBGZQu5Q4sCU+8vq/n8kNX1z2T1K/d40YBPlSunOZIZk6H5XMoy4Njftty2sIjraVy7udYEwqmUwfm9XlYqBa6QeofoxY7BaUrRjVUIcPrKLUZ13qddOoPV//gLtEDwcD37kyLw5ZbPKVdR/5rU48ENvP1UPFC47HDyhtA9/FzYweEZ1jEXSuxr6r5xJVcH5/2eyhW3Eo6ewwWeT26oVPj0zm6faeY6WVPXJX3fhMwNonAtTHzkfZCfFlDgizMtSMsMadzzTut8rlziEea9cuMS0EacIdzafoZgQsYq2ZrRhsYDbQNGAE/DzK3Hkrtp8eqJDNyRyCIsn1+B0A0ci8hADSHPS3q4tQD2JPb5zj6/0PNt0oIIBRcYuXgJW1nathtP718i3Hhi+cmqvZtza7XKUkxNYNYLO9hGnVTNY+mHD8HW94QdAQ8ikfF8tSBv0N4/ebyVIkaS9Nes8MyOQJbzfGhmmpeuo8jineQsf6w=,iv:6gXqS7C8lypzUvjExURswSwnUXG1bTC2+BxUkK0D36w=,tag:cd6URiL6TxM8GxyYirvYDw==,type:str]
|
||||
key: ENC[AES256_GCM,data:uULX8NVo7hBS0RMMlTwBtv61brsZfKN+IQeifjCUogqgsDzNbYVFa7lartuM5u9opvJsrwgVJqTTWI71SB2cCAPTK6fVvdCAvtwHD2NwtHYu0gPsFKyxotvyWF2SNLNFF89ntz2wyPIvZhiTY4QwN6BbHpt9a/aYzZU3mQ2CFtquUPWH8caI38c2Kvj8wcRqR3+adXoF5VA5JOf+bZla78/QkGG3ty93luQz9ygXPwjYtqaHy/mpKOymX5hA/jz33ciShOxVBwe9xwxKwyV7KONTd1IudbRoqe0QC1hrMa/HJ7M=,iv:4WiN/fQgCPuve5lXOttcmRos6e04f7fLYSLYte7mfmw=,tag:3ZkhRr1MGeiGu8HZnoVXcg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:DqAjRk0ccrxqDt2diu2i5jjLDUY0/LG5tGdlEBHohvkXsOG+072z/GbxYtMy7SfZ95SeMUsUsJLMpPjLWg6srsMP8w1T3vUgKTjfdrLhDL+Eh+OpbW7fvYwpHIRmSc/F/u1tqz5gr9cZSvF6XvpZO0TBAiN0BPl2/0mOWB1MbzHf9ZhmrDPaQYlDVlLjIf3v96qeImq/38A9rVxq/Dj/hMSieUg8mjzjUXZ/SarwxtbxVRvqFC19CwxPnvpEaPFf6oLzztry5u9XTiiEbkas/dS6EjGR34Utcpe8jCa6bO5tqRETS0nqTky85fvvPZKukdpFo0/2ydni9Yr0MhN3hZWz1EozZUmzODSg4BoA1lAE+aJWo9WpUwIxVsvRRKBQXppkkzI/GjN1ctSg5bB6UvWZWgbUt2vaVeIMiFfzdyyJNJwz1LvyFHZkVOAANAosqauZg7Hhw1M7jLSItMWreGPzKPlOQwosdusWZMD77b0wBsKtciTQk5/u1ip0tIuHYy8LU8bbnlqq9cSk1bxC2s/toeZ430iTJjhFjvhNufkX0EdHyXTSwLrJSLkDs45j0Lha9foRwubPsIjz4vuzup9Hjt0pJjFZuIoSzPbjkWvqLOaAKHC59XIjlrysetqmWiSilEsmIFv/FeGzsKp1bxMh43HTWpI5aZ1uuqyGzL8I5exIfytIaFYgUKZ34taCM1jxHNHQyfhkcekUwCWSrMCyf0IHCIJua+fUK/0iiVp8RMfWNPLqbdkN3mzQKFa6WKmGxLz6fMYdfSk+4tytiyveYNN7no/tSPd3hOzlBT55mBG+kQxWAdXesAoUlBzBmTPDu1GFjaKG+0faZYc/ecIl64vrz8hWOf+KW9fukzhYUurbaGdfIT+BI1EOs2bxXnfucrHxu7O21hIag8GYXyk4NnzL8FcQY1NGfUra4yOzu0WocvxWweTOLyuHWk5yOr/aCFY=,iv:kCNYR1LyB8YAwFmZdy7T2wyCIWhH9UKEDhneqH5FuHc=,tag:WMUPajsBA8lNJa7fOfN2FQ==,type:str]
|
||||
#ENC[AES256_GCM,data:Zu3CNVkCUlW6BKGh/rhTTqrGv/7H2BG7,iv:vW4cAVvla/Ya0S89DTvo9k3do9517F+AHMLb36Ey19A=,tag:neDpBA97R77p88Im92xn8w==,type:comment]
|
||||
password:
|
||||
postgres: ENC[AES256_GCM,data:XlpsKT0/3VgNesMdifvHlYZ2dh7mlMEnxi0MJpQZiQ+1tZ0/3zMxQ7+vwec=,iv:akcPRmDZQfFLxelG7V87UnNB8ez28PPLCmY1MYfzStU=,tag:14jvIKP7Htfh+/oMwLYC2Q==,type:str]
|
||||
alloy: ENC[AES256_GCM,data:ifgJH2e7MTAJ/+ppdWHEmLC3DAsKHWNi8j4w1ZVjUh4tN1cDLDJR3EvJTl0=,iv:rDYUkVe6idIf5Si5E9V+mvBaIdYQTJJCB2rOV0Suvr0=,tag:xDCL25NwuTp6H1DOGTIm4w==,type:str]
|
||||
ldap: ENC[AES256_GCM,data:mJrxIhXynHxJhncw3upHpOkXIw+Ka9bmDBJwkDjYl+D9Pg4RDvL6WzBjthw=,iv:y8MUYo6VhgTzbWh/+n7/hf1Jw+L2KcdxKvulPJ67xn8=,tag:4ZFpj1UdOwXmaZjYvC/s3A==,type:str]
|
||||
maddy: ENC[AES256_GCM,data:D8cFa65up8DVGBiIAXvh/2BdYoeZ9X4wPZmCU6aQ6p37+4edBhsl6VWYhH4=,iv:AORId0QsAkeIQH2IMcI+HKFKW7NLrZ0GXi0yCn2NK5Y=,tag:RtI/Vn8WydkjIiNZB9om/w==,type:str]
|
||||
grafana: ENC[AES256_GCM,data:P9okJ7bcsqmeGstkSwbDq/RgnG+lFrgAOvcj8A5lOTpmHaSlXGiKG+ybXa0=,iv:Di1ghnxIbAb/u7uo/mJCC3QYVjdweTHaQDZmXTx8OG4=,tag:DT3a1zgU9sTr0BXpyoZ/SQ==,type:str]
|
||||
authelia: ENC[AES256_GCM,data:OqyloAADO6KKEaBjGLsJc9GTe77wn6IvA1VCD2dfCWxx+zgzUYh87fK1XX8=,iv:QIOHNTdNnzcY/f3Co8dPdNHykhBnYRhm43nt35hbALM=,tag:DLQq58GrZd+Ul7MSn6s9uQ==,type:str]
|
||||
vaultwarden: ENC[AES256_GCM,data:BPj5eFo54DTZ82n3yTIqEbm7kb/jWT0n2kZY//oV5q48eRch3C2RBuxn/Ko=,iv:DGC4ipHMyVs25gc4sNMt8LN1RsHjiR/b303vgiFoxMY=,tag:k1eb4DoRPLKvvMstSI1faQ==,type:str]
|
||||
gitea: ENC[AES256_GCM,data:l+pBCzyQa3000SE9z1R4htD0V0ONsBtKy92dfgsVYsZ3XlEyVJDIBOsugwM=,iv:5t/oHW1vFAmV/s2Ze/cV9Vuqo96Qu6QvZeRbio7VX2s=,tag:4zeQaXiXIzBpy+tXsxmN7Q==,type:str]
|
||||
immich: ENC[AES256_GCM,data:11jvxTKA/RL0DGL6y2/X092hnDohj6yTrYGK4IVojqBd1gCOBnDvUjgmx14=,iv:oBfHxsx9nxhyKY/WOuWfybxEX2bf+lHEtsaifFRS9lg=,tag:tAfkBdgQ8ZEkLIFcDICKDw==,type:str]
|
||||
paperless: ENC[AES256_GCM,data:6VBrBbjVoam7SkZCSvoBTdrfkUoDghdGTiBmFLul04X/okXOHeC5zusJffY=,iv:iZumcJ3TWwZD77FzYx8THwCqC+EbnXUBrEKuPh3zgV8=,tag:u2m8SppAdxZ/duNdpuS3oQ==,type:str]
|
||||
nextcloud: ENC[AES256_GCM,data:ROsximNuWYMTZktmLJPx7W1Qol/uT+APgwoCtFO/6ZYYc3KxKvlk344eqEc=,iv:4d+MrfIHjJKAcwhvZ3g4go66uZcieuL7lngKErJd+fg=,tag:QbWOtxeCbiu62GyrE2atXg==,type:str]
|
||||
sure: ENC[AES256_GCM,data:FULJ2gjJ2gZC3s324itW+CjGRBHIP9RnOqw5TT1UaiUhb7UHAPm1na+LsZk=,iv:c0GnVZkxprJUzPPq3TCQaZvAes9QQuvDXqgVLLaiQIg=,tag:uDxy/Lkd2hNK4AWwMNMslw==,type:str]
|
||||
outline: ENC[AES256_GCM,data:0eJFCfHgS4olWXHOnUPixs4Dl5PoxJa+2H1mk3YgC4GUv+nX8gTPmzKTMVM=,iv:HGxX7aLODUc2nVLC8YXdet9qphU/wxMapWhk93YmHDM=,tag:6/2uckW/a24LgVFRH6E85Q==,type:str]
|
||||
memos: ENC[AES256_GCM,data:BaNTnZFZH4oMTnDkgrf2/fMTkO43rc9bSsgnDWrHJ/Z6+MZdMitpIMkrMN4=,iv:JsG3B0YweZYO96MW9NmoSsIG++gFq+jRUsozwJtWl3M=,tag:orLTUiW0inOJdD4YSp4baQ==,type:str]
|
||||
mealie: ENC[AES256_GCM,data:XbYHQv6HBWCXUBRmcbQZN5Y1Gw+V+Wra28Mp+m+ZGl8VRXsKMu5507vGHQM=,iv:zp4ZarqG9KshiBV8F8UksfI2QXmXHwqPw631r/5bYy8=,tag:jvsvXrUsCvpQGIbLV9jTYQ==,type:str]
|
||||
homebox: ENC[AES256_GCM,data:EhNnltOBwLai5vEMt7Dih5Ug6h3ojrdbwhq4Vr0tg/p/0nqI9L7O/Le0B4w=,iv:14oyl916t0inr+W/lztQCjYiSQ0vIIwC9NmbezDuvvY=,tag:IiXZd3NU+dUvDrHpxJXFew==,type:str]
|
||||
mastodon: ENC[AES256_GCM,data:hq1ETBK9iUI7kWFO+9pZwMQMbmyLExGk7/VzBwDdLFbzptXL2KEi6oYRCS0=,iv:hF1C8lsnP2i3LxDIuOA6op4qKXQKjJ7gqznDst7hVAU=,tag:maR7Jvsv3DJGrO77EzmBDA==,type:str]
|
||||
tandoor: ENC[AES256_GCM,data:+5g/jzRMQoxocZntoE+1BU0MS00yEp0tyVNxriEIJ0pW2V1bsLhUAkwQ748=,iv:feNbpOhkdjmKS7Ovy0KGioOTyjQ4sflfH+50niP7Y8Y=,tag:51/u+EE3Pp5o7jnlj0AWIw==,type:str]
|
||||
linkding: ENC[AES256_GCM,data:+diOqVjK5RkDOpxCrb0M0sLWEufXEwhTNo0x5qH4FkteN8zaUAZfO8lD13I=,iv:jHQANXC1tamiphm33RpTKpEB3niLFx6IKzcdq8/KNCg=,tag:NwkkmUPOS9K0IKtUBVRWqg==,type:str]
|
||||
openwebui: ENC[AES256_GCM,data:QNeBJjdLIzoI2h9e3me6A/xZ03YpBeLpKK0Yya5Wi5vryv1ZwnHHZwOjmuA=,iv:qLpsxlwpE+V+qACkfOee/ExFIyVV+KsXzuT3VDiJ/w4=,tag:YsmBhmEkqYcSmIIX7R2nTw==,type:str]
|
||||
kaneo: ENC[AES256_GCM,data:Q2rg4/0wAgWDzB8Aj5B6i851FZN3eGR7BbX2l3Y5+Ij47//TtKGzdq6cxNg=,iv:Mbp/S7Lc0tLJAT+QFMVB3a86S+mqoQmZDZQ7Agf8rU8=,tag:BkerNmfeeOicsQAwUo4dtQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:n2lt/VhdDjqfcwYN5OUjTg==,iv:QidjK4AzjisEzaDmXhYZKWyx/BrHOsgGcxxcirQOlQo=,tag:0ViayyRFg5E3kQ5vPgV5fA==,type:comment]
|
||||
mariadb:
|
||||
key: ENC[AES256_GCM,data:8KxZ+u5DJo72OFEv4mNSlkgp5Qj6KvABmV1JPw2uvGmkBI9dv6zxjYMjNx9xqf2T2rK+omBtQHIQLoFfLQUvBmws5B51pYdoyPujKYduEMW8kw8x7mb+lgzJthN9A6iTGUQnAkgDxt8g/t2c46lLd5vOecUXygxrS/HLEm3QcOFVBI4qIfZ+NyeNK5CFQPBjB8RoAfXX6dryhcdiCGN0CjzXMMY7rhuYNSaB3xrNvkeW43zOv3GFAGx4WjA1VL6B2M/m+Xrkh0/8rkmp68SQgadA0U8SX8s5kH3DKZ8QJAqnhPU=,iv:5H5hrlDbhsklmKZup+mK0mSlp5e3jhtZWWSiezX+Ztc=,tag:E+pYEiG3qnKmob20+21G1g==,type:str]
|
||||
crt: ENC[AES256_GCM,data:aCrAXf5n6vIyEIbpwyrmVvjPa6gmVrAU213SnqHO3/Mem4MgfDjmh9Q1tQbvXKSJT4tcecp08sCY1Y+AKN26lvqFd1Y8b50dNVLXuBRd0saLDwyvi2/w7a9B5sinKLCtKfvOc2JOdoYVHQKcyQXG6uHxSpZPf2+j8s7KUrgTNAjKM6aOQaUYydbxcD0pQ9BgJxCCM88+que+HtX0FdLYr/ImF+dvpMRE5RlvWlWB4bae6A/xPRWH8ZHj4ZwO4uMSQARu5w3kWDngcE/CnEhC1JQvKLJ1gKzkaUF3/Vn8kkxIITGddw0+2kQyGCJ9a5ZXpzr+AJX1OuFE83YDZRRXbhmEuSZiNQmLaw7ImSjNI5uZ4MNyKUuq9t+xqSgBj64dhn4egHaAb9fzZo9lV9/2kAchnidWBzn9EtAacYsO0lf7i7OYuSwCjKaTBvO8DwPudSsWi3CYYx2NlQXP5PvElJi/7aasWcF3ohmhMUew0ATBdgxMKvl3MENzi66WuTb2uzcryMQf5M6lIceXYa3RLQQzJXkBUe4vBg5aQBiKAYqURvxmvgb+j/YMLHrXGj8bkkV/iTdiI5oyeE9+si6Tw+f6Gj/E++KUWSR8AIrNbAHgJ1dtPd/oHt8CW8X9USJd56L3tOAA0r5SDnHhnZ/sfumuyz3H34RYjPxfKu0FCQhsEofDrDc4DnypD6s1RgzJM+esvHRLb2k4+X1CN5Lf04pTis+GshRtWxRClycrwLjcyaCZ/JN5+4sAHazr2nEQ8C+RQ9NuVRK2enFVcfTCf+2Sk6pN8ltHcmrYH1Xx1B88gsAPL8eWmeGLiTbzCqRAkkZ2EvbOAu4qZteLC0qRan1jYQs3C8zjwfQKf8QpEY1EYqNYaNkqDPpZcxeRMoNX5vlS9n5W3qoX+qyBxUKKNl6O3WH6JNnODkJMwnFhaSE8HSTr7rbBjqc1XaM0,iv:lCxYy8LkovdX1dIIoS0NXe5YbUT/ctPK1eS1pSU1z9c=,tag:Pads/Okb8YVZH19ODUThHw==,type:str]
|
||||
password:
|
||||
bookstack: ENC[AES256_GCM,data:kFQ47qbE+D89Pjr4B6WMAcCHQ8deCyzaPmNspI5TvqwvN5RIaKOWU1uT4jU=,iv:3OiYzBod2xxKMt/5Q9uazalld1NkUNun+DJipC3Ts+w=,tag:orCNWYMAZ/5yi7c6apXVJg==,type:str]
|
||||
groupoffice: ENC[AES256_GCM,data:s4jO9jrn15tPcStDYUTNLgvCJvtlfp641nU3EzYmPvIzk4sQIQZRuGsODaU=,iv:OBpzPkW0bMWL9da2/vL7GgOTqaKSvYamapaK5AMZeZE=,tag:CYuoBHO5Wt0VBL32YKrd5A==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:VuOcF5INAvCNDvXhcAc=,iv:zdTFTKaII606RjjDJbdUyv8jGba8abL7lJNTsPH5C74=,tag:cYSefZHKIuvHmAzoxierQg==,type:comment]
|
||||
ldap:
|
||||
key: ENC[AES256_GCM,data:OCje8b2x62vVQDV2DXvy28UxY9IIMtRoSLyXVFwNe+sRWA5prW67Vp0XcwwL00nP6hagkXGNRxy0eXx0VYXiktQBeQQe7TC5bUpzJlDCyGmi9BsbDhzShSoSM0v/TxX4UYZ16PbdVxyEIxlD5J/SpbQdg/VvVA6oJgLU4SfZCYmKRZ/gC3I4cKGzFJAT7NLAnC74/Wngz2nE6ipzXiQaDHnSuitLHF/RGoAgE5XyelyXag5wGaB8EAUgmuM8woI5g7RES9885bPOdt/Q1MUNNmEz7jIBH4AVGo8stxRioYmAcZ0=,iv:6Fi0DyvzmrQN+OVclRFZZyXCW8v1nfizj0saGkV7qTY=,tag:AkMtsUaRIgxNKZG1oYPTTg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:1SJlTokgS71mW3rEQG1fTLs1cp1Mraww58stg87Bf2PryFsKw88va4HB+bsKzkCRgykQoj8iDSqM7tc7Wze1HWz+bgFTgIqluRQpZtbcmfYVlqefdIUcJPAntqe/eEaA8Hj3ozTNMlKFspv13vPwjSJHGrHcektwlcEI58+S3lhu/IrIfdxryBm97E2UQczznRE3zuP3MiBYUV0oj9Bcm8KWDKqa3DLwudp5wwyw/OG6DGg48isEvNxaMJhuEkiMwMNR+zZXgAvYcYteMaW0p1UXNFHzxMpOWshU1zYL6U9vZkKfpVMoMoTPW3+SO+vxlJVafevStEipUFd48XmOo31uMQH9zWh/hbLM8j/fiTaW+kY89XwkQ9ZUOx8+YXgcfBb04FAbtLEXMbC/eF0meVdjAHv0TEBPF1a/F4m9Kqv1GkJ4RA8jHKFng7vWsRGl7WhmxrCxjrJrYu9ptP7iMvbaaqMWG1YOSwwZUe2HvrM7WTlJxeRukwvW3rOglAUdFODJhsWbATpobuu716fKLqDcprKa+vA5l7VMghqLf7tWRGXmT3O3RgTGDwqjokx0q0+4ib10cgzrRCkwuTBDiLYRdxd2eZFWumLOlKKQyVAMJ9YZmUnH2VNULazcN7Tznpqm3vdA8pC6Em7ELTxYTUvkaye27jRVyilkZvoX8oLiWyEpMpPAajoVntmPnGTF5ppChQ0EmyuFXlv0tsU3K+bxmM5VYVNy4S+1cMOvEwGDuSGJ9nZfS0BFm8NXDp+BbEIAa/DVc6yOjVEwi1Wh0khxbplkW9feWfkLqrdlxF2khNOTePIyEDMzs5/CRq+kzLy0U+7BeyX28jleRpeAQL6nlOZ6Ha3AyQUhxC1/KVOK/kgAlGVi0gyaxZy0yuF4whFKN7+oXB+CrJoCyX3mjrOVqQIOeNIK6tLac3hW/cATu43uDQ==,iv:BmdsX6o02n/ekhnTQrpTUgM3lqXCyQNYtMbexI1Ziho=,tag:7AI4lOFSXDxR7n1zoqcE1g==,type:str]
|
||||
seed_key: ENC[AES256_GCM,data:q6kodsHzwDuf0UHPSk9VbEI9pCwePJWcA7o6dQiZqyM=,iv:EbozH0UpLThEXjmWkNhkpHQxabH/K3/lJ8xki3lLGZo=,tag:rKO8csevxpH5kzzFWQoang==,type:str]
|
||||
jwt_secret: ENC[AES256_GCM,data:AfPcqKAwdsHfiYHrZ6yKqOxD93gBcLEvZ4N3M8nhWMQ=,iv:awfSXZbc7Tzg8sRqUkp71TXivLb663ZjaxNkskE1Heg=,tag:e541/ejk7x+GOhJeoUPMGA==,type:str]
|
||||
key: ENC[AES256_GCM,data:ziQ38fhTghKl29cy7zB2f7uhLgCDwnA2rAw0npf3Xf4DCOPY9gYj7bjbA8mJP7IXHroD19HtoMVZQjGW8PlbBCMRPVtCJzZ7I4tRH+w3eGbj7L6kAcbxyoONFWGTZgjNm3u5qaj03hnYXcDXJmn6kqgug7JUYX67n0BDzNnGZSqIqvqDHXxQgsDQoN2M6lonLsAxJSQgtTzwT+XpP9dIpi8l2owUbpwKG8UAO/Ma/LZO3X2adsef7x9prRXft4VVbUJhY7Liyi84lutjHxXGpF759OFCZUhEVrYngRVN8sqXrbU=,iv:VbOCUz3AAwSpYPpaqKbK/jfNMJ93yu3Oqz0YGeSUlF4=,tag:ltTKZQZ7yZYuV3+xazVL3w==,type:str]
|
||||
crt: ENC[AES256_GCM,data:LuUFkvvmHunulUa76e6Q5jbloqbvLoNsD90sZw4kXvTf6SLzYpWSuo2F6gmAgQwN4IFtPtSGEay0sjryqHrQpp+Z6o6LTESd06PEMxgNPsVS9CcU1wJ8KV0oyciQEwcAIrYgwhvEE9kw8PdpAmcXMW0Dcenu3yuqql/z8zMQvoweaT7x5UJQYZuJ2v5QIyMx6PsA6X/+O2Rcza3zXTBW/Z4AnybQvcx2Gew9pIWsWZ8f4plAnFpsrS/SUbDs1sxwlx+hgxmD8+2kRLlAvktx5fvVET3UfC9BpuMsM2lgu37UhVGR1egOZdLR/w49O86wDVVO35bDU9XKBXh3N7eig82k6Sj18cS69gtYSIJWypSJ9Qp1F/LM0HGq3HPvKt7S60OBu/zzgn0RakRF50Bl/9/OqJu62Ny4y0JFt4C/LJh5okVKW1egLJG00wBmUCON6tQkU/CYTFHsvB0Y3uxrc0jdx5Lw2t1mx/lmrDmN8mHIo8bRrP0E2Po8MetvZNwuoo1tZ8K8AAZ0AVJDovkMjZPX0PEfX/fKPbFKYVjma/zKK58bSU53QQVBWOn7kc4tNbLI16jECWJGayAvU5v4BkRhAqxssZs5vn9MnkPwwXMFDbKLzH+yp/jMY+IZPMr7gZ1QFcURp+DmNFpO3akSsvAK8znNGBlQsLIuVOIGbpSNWX/b90Nm6ak9qxQyavfKOF5DdjxZTvOFi2T5U8Rr6V2WrhxPpP0i5xpDH7vdXUARSzATHWJYvCtZ0ZA0FOcQRnLugUCI9QePqIK5loBPdnVo4loE7hm5WGqZYTb0Y1R3sUO5xip+P5fPvySn8R0YiBqVHOUnnCzfIpexP1M42DJuE0qA02QeXz9lBfJPru8dp1HEAk/EG/ssKHPdrEXWjWTlT4mgZc7K9giJutqlVTlt4R6KRqkwHAr5dh0a9An7V0Uodg==,iv:TBggCu/Z56xUH8kkEcVjawiO/PfpzaXGq+5+OB/Cds8=,tag:K99JW4Ur0qDbLqnmY9xsgg==,type:str]
|
||||
seed_key: ENC[AES256_GCM,data:1hv0p1uhHoJQduFLu/mJ3QvnFJUsjkeclnW4TXAszT411ceN4i5V8NIXImI=,iv:vf/lDc+A7wXX4MlXvfKSYzUUYuai4j8qlGQhA5CR85M=,tag:o8MQzkImlDLOPvO+7o440Q==,type:str]
|
||||
jwt_secret: ENC[AES256_GCM,data:m3wA70WxYPGWxrcsHpFcbK+M4EkntA2ySWWS/chV/CoSa9fx4jHqgW4kiuA=,iv:VYCga9S19s7SsXt1KoTR2El7aOtADymNNUR57g6+sHA=,tag:eUUF1nPV8STOWGI3WaVB/g==,type:str]
|
||||
#ENC[AES256_GCM,data:/5Po+8hjJg74ZBepaNWTzZy7JrTjiwo2DNFT76hZTUFKEdchNd4sfdy3tbVwL5y9QPC/kC3kvBZL2oA0+WzcUmd51Ht4/xS6CnUCpodBrSWNHu4H+ohdmz/jMplREeJVWAFHuTZROqB9v3hw3rYJ5Gb+5XROAuzT4pKfrPoJ1B+ysGUpuvybhrC1O5Tg6IPs5fvIiR3yExGcIFuywZBiiA==,iv:gupWDnXb2TD1N8GhHwpiYuz0sDciLX8V0ww9cFKtFNI=,tag:7eDx5RZOrNXOUshvdijV5w==,type:comment]
|
||||
#ENC[AES256_GCM,data:+Q0n+z/P2NwlY6/aOzMNe2yZaoN7uSctcH8DlTUR6dYgNTnZlGQNNFAHs416XVMcYHyBqPwkSvdQLGl5TcJReZLm+8ESeYeQhjWgHZWKnGJK0e46cdMhznXKjQ==,iv:dayGt24JAY3+LV3OS0JUxM7vxfOUAoTl7O33d6y4wVI=,tag:KcfHxeqjmyAUfNDELBfx/w==,type:comment]
|
||||
#ENC[AES256_GCM,data:6AE31A6F6mflPwwac4jVxY5kJPYaKlYzNjtUC9/VmCPeS8iuvoFmxHNQ9cwxLa20Nw==,iv:N7tQ9RyBYvSCKzbLGWgH8NgyKCJpNM5cupGK9e9pQbM=,tag:nAduK50DDywtkkQ03psKRA==,type:comment]
|
||||
#ENC[AES256_GCM,data:o4Uc0IfSKbSCHAh00aHkN1g/+FoK/Ffm26iT//ZGc9WTncusMdZslfX9AQWXXOtRwOP9hjpw7KZA5FWsYEGzyIJNcvq0nayEgwBmCB1RmmDVcvVT2jEjKLGCIqYMHT10ZUdFuls+SSKtE6Kk6GMrrV/MEGzn7rKIHSlflv3+Iav8p2cblRoEFqAxrbNgbvcMzSDpWH9XCInhD0Sw5ABViNvBc6CVb0ZfZEuyoBF4EhQ=,iv:bs9iS3fmJtb0K5fc/DXKYWho9+1GBWmN8jOBEhGr8Bw=,tag:Ry77miT/7UKA2pLE3kMcag==,type:comment]
|
||||
password:
|
||||
user: ENC[AES256_GCM,data:DT9h51o6z70A4QeoKvCbUo98JFxILgB5tkHeX60CZuCl0GHTa//mRpIUEvo=,iv:Pa9iqXeKDHHBz524zeRImYEkXmY50s7Z+Z4KYt3sNT4=,tag:UTS5VIqbRA66UVDrDXwuPQ==,type:str]
|
||||
authelia: ENC[AES256_GCM,data:G8ZGsLKqEmMzQ5NMAgirF5BQraHNqixtI6dyyaeNhTdXebjJZML52xL36p4=,iv:ZtHAsFYmrQxr+qoQLPW/eme0+nsT148KRsXmW/LNLlU=,tag:Pvjs/eylkgxJpmGBsRmjcw==,type:str]
|
||||
grafana: ENC[AES256_GCM,data:vWmU3ZKcolETWAY74C3OMD8gMXDeYk+DqssACL0xefIPi5IkbrhYWmnWAnA=,iv:wcRms3Zp8kPM4USRPVa0UHpCTK36SWhK9C8yHSWu2Cs=,tag:gU5S/6fdMZVd/ih3Yd5uJA==,type:str]
|
||||
users:
|
||||
il: ENC[AES256_GCM,data:9b9OU4Nt60/XdUrwnhJh,iv:7ZqOYqM2aibgcFRxw1ZvOdBJMZUfOVbNa+2sMzrXAns=,tag:x87IG/HETASiC9/HwyW1Ig==,type:str]
|
||||
morsalin: ENC[AES256_GCM,data:rERjBNLZXSKT,iv:VuD8ZGfrd0wQ/5TCgLhLN459ZHPepcZyv8Kdl7TsMc4=,tag:Xp/fjve1xn0Wjk7ExShCLw==,type:str]
|
||||
services:
|
||||
admin: ENC[AES256_GCM,data:xMBoPycO/5wDae2AMZlgomoXjB98BpCOQkxek3W7t7Wk+az1GMqJhdB0osY=,iv:E6nNmNNKlJoNC7KwE0PaDIB8QyGM0MuNutQty3bi1Pc=,tag:yc8nlegBUOX2hfaMBoNaCw==,type:str]
|
||||
authelia: ENC[AES256_GCM,data:1hHNPWgiRte/TJr4gBuwFt3zMHPivgRp7Z2kurYG+bT96HWmwk1+4iKSQVM=,iv:cpV2P14daWabaDuQ9KgrGs8bN+4pc7sXbAUE2mjWQL0=,tag:lsLgHkkhgSPfwxC6vu5JEg==,type:str]
|
||||
grafana: ENC[AES256_GCM,data:42rnv/NMwmvHdyWW6PZj1Lto5mRDTHp6h55OuRYd9xMOtmenX5zBJzGMvnE=,iv:jUKuPisxa/S9erKjXHl3y0zJR+Tfe36O85/BdGmN+gE=,tag:h1InzKaa+bWjlmIq9OZRpw==,type:str]
|
||||
maddy: ENC[AES256_GCM,data:+E8ggJax1s7Nwdc8EpAWHnVuM0ceJqpW++z4UGeTpPN0DYDPqNSBi/7rW6s=,iv:n+iMKOBjuyeVNRLZQTr+3/Fuu3KEYolLjCXLZ9lTBvk=,tag:B5NZO7zKxh+7nN29vvE1Jw==,type:str]
|
||||
users:
|
||||
il: ENC[AES256_GCM,data:GcOsUe7yJFLdhPp2H7i2,iv:T4NGNvYe5beYbxr+ezfT86aS5lCBa/TG3bUWuUrCZ+A=,tag:rrdHtLyZI7pdTGq5qmptYw==,type:str]
|
||||
morsalin: ENC[AES256_GCM,data:86+imwqNJ5Xg,iv:Lgt1I12gtDsjvE1yMjiyed0sZEeExQZoJPD+xKzHBqk=,tag:YiQgczFZnzh7p1t+KIzM6Q==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:6RVyF1gPUfKEvkV3RQ==,iv:0MTKlm5kE0kZi3E013Kk/Wo642BizBRmcHXR+Zwf/W8=,tag:SaQJ7lvFUuALxXWf41C24A==,type:comment]
|
||||
maddy:
|
||||
key: ENC[AES256_GCM,data:GlzNzjI31rpuVYocSQHnExbIQRprqJasX9nXc116o2Xr78h+Qz2djB8CnpCC9posjTKx/h8AlK15GFw8UeI09BQt9Io6j4ROywYPxC6riqlGrBxRhXL7NTwtFASKs64s5oKujTBH8jegRPvDMNf/OAnC4R3AtgPw1SwnhcEgoe6aGp5xeTOXpiblaK955SZTeDyBvLMWYTe5zmCupp0XprLK3yrdfi/aUQ5EpjV782l4yN/G3W7ruF33YmLMd/haAIFUMlFTYo7fQEE0NEvvkKldmv15Dy7TNckHxVHRKoEuh2g=,iv:ac821nuHLBkz/BoSseknWJeHae0d3TYUYLVo7L9RXGs=,tag:CFDLTufZoEjW0Cg9/oCRZQ==,type:str]
|
||||
crt: ENC[AES256_GCM,data:ANefptHaB25E2wl3ddFAfEtRPPBq1KyLWi3jxwyFIYE4oIebR0t6RQodWBfvRvG8IHVM3L3ciadu542fLgRBfaSr4hlP2QgN0prAVt4gFmZfkQ3tZJBHAyRTVHWx+q5NYPdILNtZWVfFZykym87X4xqtRuKmtbF+2NB+sb/oR5rWMqTYGP7ryveT28lcVKxlVzCC6XY1Kk9m8i5x8KO1eon5xDkbDnK5qlGx7/6OyM9dWsm3xxUGhQqHOR5XwjH9+iRG32B30Sw1r+f75nGYRDku+XQn4mTWoBeb8BdkgUdUOlKiElkk0nQvEdwLk8MkYOMzO9zAAwQfkTtgDLAOP9LaO9ykZry/1+cwMbyzXsWRJI/lL0RumYWJi6GqvtZa8TIIzzAT0HKplui1A9LZ9bHtJHJwwUWtiuFu+sAWr5DrUhvbx8CNM1MNqEmTxHCgEKi888GGsPAcWW/m2NMMeR6Pu6RvBkUNyAMfV9ak3K8QotPh6QS2gVcpuRmfczFqyjIQ6/mT63gFAs71Zh/891pSdenOcJ5MVTOSv/LgBZ5IPCO9wq4KSjksmU309ykPUdym0XpwGgWKirZAQQg4cuapemIhm+FNnhRTFQJrQtYwBGStx3vAF0HkdDAzKP/K+58b94F05V9TjKrG6FWK6/U9bg4ePSJ7V6Slm2yeBwnQvAU7zNxSJ6gf9STk2mtBoM+bdHVUi/LKiLx7LJZUSAYXVsrpeXNz5DWht/lCr4m8aIvUEjpp+w41/HV5LGdRtgSpTAOGwyvuAnmJUush8OSANOvcybr5IBnx/vnmzIhAeJt3P8KUE7Q639kBDTqlzpQB47sx0gUW8kl01bWY5uLmh28FwtfMPnZozXAWXTcUOakWB3aNHG0jCSA683DI8ch3bQD+yhuSTbKMhdsh35/ResjyOXwuoAqL9NlBp77p6zhVPB8v3t4=,iv:gyKP2MJ+DikuFJ4Ocrn6zvS31j6MSLgMZTqoxR2sraM=,tag:NUztgGwtKalzyIyvBdUQiQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:NronfCPkbPQLilb38VmliNn0Yg==,iv:AbC7xk46CJ5dqU55IbyPX+OZVEROz+OGnJfxoZmaKwE=,tag:GEsziOOFhDF16Vjqx59SNw==,type:comment]
|
||||
prometheus:
|
||||
key: ENC[AES256_GCM,data:MNmUv4J5qVRB2NH3vFcIPGsx8ZB7ggYLK/4HyI2hBE+KhBGgh/9GeIauN6VDxO0xPqVe6xsY41vMDE8K5wmQyvTOi2fyXzL6LDxPHKVZVUKMjRgiYKJJh9hghzVeQwKwTjfZ+eXFgSKf+ENpSgh4+zbFqm0eVhhZy6EQ38494IlwS/UsojC831xg0OeeHNF5QrE7rIG8zo+rjsntpWZbJzSM9BgzFAAfW38Ywi03lstbJi8IEq/gFmZjQxU3CFHicD0X/jKY/uBxZB8lu8Km2ZevGDLFGwGX3zpcYxou3667m9M=,iv:1Px2X4RKD1sbQ9NhFW9rf0Q8cu0ex8P2RjmR5wUmFbA=,tag:rKkYDav55LfUwUueaA9Qfg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:0eNafjanGCWtqCiavj5vAQKi9nczPShx0w9dfULmP03sPZTh74FCZwZvu2vQ8i0GbKNZdHMKYAP/Utyd1XdttaVr4Kvf6ggkQXj5a0AOakRmTOjkO2WhZtWUVd/fJSfcsifa1gG+x5O32yVZXx4pWSVtcV57g+BnksTyt5JBnPz+u5pEBK0VZKRSjIjlvanLM+l/Dp1tyrmKarFX+28bCDUxB3I6wZUEnF35wUNbu6pVMcR8JofQG6KrmsjixMWPRDz+u1w8b/+nTGOXyykUUjxH7a6wEf7/RTGNBwT44CrSACxybJMCed2MBjY42jA0Lm4ISwE8epvOkpptu7NRyEgMiVke5mNSH9ZGaUe6mCBpbUVkL+tUQG5rwclsL6ijaCyqsWSD5bb2i6wGhmPe5/ERKxmLjOWNeAQSf1HiJc/bSXOSpt15DuGgwwJ4jfebOqdshUy7CMc7KclQj7ppqhTYhRHbM1mJwCJr6QGVDh5xSzFDSH1qbCRdeXkPEkm7WxRJbAtzY73UmO4eqhsp5n6+PtiFNNqQg66mOGF8N7PlEKh2vcoxgtjnTTVHVlgiAHuT2TMWNuhO3qwJeF6G3zApFSPuJWcEH7PGAeezL+qUF2TzHVthOHQMUNFr1m8i4ms/hCE9DGSv5oo+X7YKO6xcIe00xNQEzMNk+HqmAKed9pl/eBHhD62UvQNZh66e1VjWpOE/ig0hP6vgKSwyQL6xUtJWWzYl184KcWokw+O9Vyw2FCR++0iu+Zn+PIYYQg4Vwpqd5VM0cj0tIB7W1+aLz8hGIOgQKDjQUshWeMxEjESILgb3+7lNyZkKT/y48ocHL/dedHRLXuxUcSQ6ZUGhWf33so7763Gimo2hK3jmIaprnx4LGyiBKPPxkSl+Bt7seUiFJ041olDmO+fUDvi0ko166CA+3mUxeoeNRh74J2RPHR8dmy1okp1NLEQztyHw4Ps=,iv:14bMOT+Fn8j2kFDQxTuwtsTyYnp4fIF0WRpQntz4afE=,tag:fWnktLbiQzG8UExa3nspUA==,type:str]
|
||||
key: ENC[AES256_GCM,data:MNjb/avV1H8i5SFmpohIX2Z0GL96U5LdAHkN5pOs2wrPcadM/Sw3HCS9t2q72CRjjeSiuWCUTQNZ4nFc6NeLeIX7oN86dhsDOoykuR0MCavC9O4DW5LHTOZPhmgq7YVaa4vE9dxhLKmlhEv65SZ4G3iZzTzOorgbuD8W6qNyHMxDVMo15qtY+O76l797hk3xnCmUqlgKlkx3MjmyrArXnks8u6tXFBjlxXxdlxfx4K/xnHd+EBoDKMUzvlrTgXoXUciE/FNLcXo3yPGjkp8A8SuZtsf6Ea9RINWx22uMHBW/1RE=,iv:bOMy4gvISMvYph3kmtDoQhcs2t1z1uLLXjXo9r2tOzI=,tag:ZorqLjIlthQx+684yNnUMQ==,type:str]
|
||||
crt: ENC[AES256_GCM,data:ZLtk6fUIhInTm/Kc4LfFLYeOxPBLkJuYc3UpGlejsHwdYwKWKC+YBcUbQ106CUfkNCWYjEJfptUQ+YQ5E6QpNnLPgbXASrNgIVWEWMdo2SH/lFSzg6HczklC52RsVTw+Kc4CSHL8rkdRo1PnHgCwyRlDCD8H4LUBs/TVlr8BnIrjAiGnLflYG7cJcpjpJbIxnfrt/NPevq2f9eGdvkzgC7vqpHO9FYPFqDxvFnT5KVdjKmDUtHSiOizAzoGfLF39+fngCvhjpHVT15CrlHMbsdFdLqEVeAaPACCqewd8eqOtkKmJs2IVnMO5wtLvpYSN8Ug6VSicn1QH/YAajciIReTrSWjvJZ8DhvJyLWEkh5ryEgDoSO7sLs5zYXL9HEqmV2uapV9rp0RjUZtIrf0Lrq5Znfg//exClN4IRIqEJ7c/D/aNeGHSUHb7c79E6Q7TDETVjf+n1aakxc0WiamElqP2bksPVhomq6VinJl4mQp07/bfzo4wxESYehfyZHhzOiHBQqnQbxfNUI9nnv9oP6SESKVZtW2AXGSnyan1iZRMHExaUZdzSoSwnwh4E3NcYJQuIHPVsm/02aQIWGFeb7dCUcOHV22bNIbFCoksLem522mqhIbRzpxQ/DE41eH9QS25uohKopIQp+HO97bBBg/dbuTjCENXDIMlE1KetKR5bsES8AQe8LcC0UAQbmCKfpgnWrWoHAvTviywOfm7/UQaPSIJspFpRAqWjbJwGw66eMfwIh3nerU3fra0AzemF4b5XshlgBwGPtAEO4R+KBHxXLw4+WJbdqcKGoetxkSGm3/qZ21B3GgZv411yJeniKpwahmUQPfZDWBwpq8NEPqQjA8YzqY8Mu0KwCYFPjzRmjz1qHhSxYFhyz1osZ5D+ul/gTH4N1JsGqfGp3v8InpXPsjmv1EJjDUyzwLykSQH95kQgWIiXjxezdt9xkcKVu4DN9QVQUv1,iv:TCO6Dr0MVSzj3JXYpw1/pV7gGTCfAExicosHTe8XSlo=,tag:4b69wqEAcEsvvKfUoimlpg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:8Pk3De3AWQPtW+o18w==,iv:O05B1JyftUqN/0/pCi5HReEOltp5jJ6GRER5+NXkoMY=,tag:Tl4duRnv+EoZ4xWVwMfEWA==,type:comment]
|
||||
loki:
|
||||
key: ENC[AES256_GCM,data:gtQ3j59WJd3YxreCMoR70VZBJubaR8UfoeAEYgZR8KGIYkEGPnBCMEmBlu/L4qZO0fHg0DLSN/ixLbmvbOluTMNF1rbj/5W4F0O79YI2RztXZ3oxrtYf4dRPxIoCuOQi9PtD5VrduBUGGhvDW9yae9QxzQ+Ca7KwMHgOLu/5+VW6YdQRBdgEQycSDsdMvRTmFwnQuSxuQhWxhu9GqR2WGx3cinQIZ8ewr147aOiZNgUjnHLfYjtzRXqQtK0HEvjNVKBWPuOWLYRa+h10TQlKMQMZn7x7QJlDZhsF/aRqVRNwYc0=,iv:0vVdSLKOgFTwvUbW1uU2vINYwnXMIYIzOl+2BqsJ7Vk=,tag:nm34OwNXseUTzO/KUmT2Vg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:O1if/oi5wJQNhHftNEwRhSvdnloaiE8EIJ0dlY9DO2Lml1rz5+2LfwGnN/mHGFOkIZri2AhizPUqXios5kKYgdh7ib4jD2C4DC8crKO9XiNiiChzqE0WqP/sda9UJL9zzmmm3WtkGljcL1iyr4zuCvH0uuIMX6W+NohIu19JT9wqamwMHBCEYuQ6gFAVOBnsz5Rsa6v2LBsIsUBadAzngUcrIztT1UO0cHiplBq5s+TkC96wWrlAUiaV1Lcf1aABDrI6o2u4uv6Vwv/d4AQrEpaNvH1N3un/M3lOIek53atwMYw598/BAioJfZXRTQ4qeqcv9+WxFJSpG6XrWxx941St6N3ITJcAMVmKQFfupj257oyazHF4oqyJKsgXQBTXlMdLPDLH/HTRVfv5k1qD5RQ6AXJrMy4NQrE4BlLBPkLU1wxyg2REqd6eKMgw1PQdqTeZHZrQCGzxWeY+rv/0v5jwSFzC/YY+hOZRz3BRpfufWC9mZQZpNoH8yccVhPybVT22YMMVljLUEg/0BICm9Q4mSMpc9hEJ7VwHZo5pT4DuNiVjComTpcnnrEgK3yYGBB6jsAAkU+zNmOZ6AkCvKAma2DVbOhwUx1ZuBruc4GsfJcHGWqWogr4zBpgDg9FOtLF28yQpfKDWZEdx1eq1Bu9gFhK1FoBxrzd7mX5ADn0XeRbFDn/G+C24ShA+D+rmhARAdCtz6M4uk5IZ3w+L8NA/qWyZ+bgaXX8KrpDOV+/7KFStD4FXkVk20+IaMpb6OSYskqPq1ICI0MIFsONajO8gCd026B6WD/hLsGvkLL/58IwtAd+bRBceXHgoqXeTjyqNgKhhiqmKejZUphzrIsMx+GWdP70GOdcj41I5PSN0GbMnXQTRPGJo/GYN4pP3TbtmVrEvs5rMuGe0WiDiXQGM2hAreGMnt43Ge7DjyB+BPAx6ZA==,iv:1E1u18aWSRZFKewRnH+pJKN9xCpFUcJ0Dy4kq4yMprY=,tag:nmI9X0IrT545vUWhoIdhHg==,type:str]
|
||||
key: ENC[AES256_GCM,data:MexqK8ZDQEsMMJ5lbNBZJ+ql2dXMArFJ+gSHR/VwqlwF3f1YzXSp5XPRYvejMk6XiHP+xam8BMAbyfD2wGpAbXvQZveCqViJPZLzBi+AsjIU/tjgtD6yNMuKv0Eaw7noC4i7P1avtTm8TNCAXFCAhgbnAQnT0REbb1LjOdjXiJ/Q3lW3Gf7sHsufgl9gfz41NGgxK/a42GCSxx/wk9ZCq3UMdQMoWsZI9wShj5wCZH42YX95VRVdUW3oNsb9M1FUj83HhhDZnj/L5Zhf239NMYB/j4tOJIHTQsr7YLIUfhhd0aM=,iv:oFrOJUet+9ggE/w1vyRVCYaWSoSqm+U3GBXWZDbTc80=,tag:2gErGt32d2PCsZ+cpWz5kg==,type:str]
|
||||
crt: ENC[AES256_GCM,data:X18uFhTDpRamTspa6avrXA/xPTOnlHsHg7Z0DI/Kahk99uIXLMjh/biUkivcz8Y3FBd2YsrndM7ZIdbq50f8kUI/tRcidy18GbHb/equnshenIYEth2Vk3ulh45TnJ2OPO0jbgDYZZXqHRSXSTiymYYlDFAgiv+X8SH19o2J+J4FTI/pWbauEevSsYgxRPHLGd6Q5jBzQsS/epUpo88mWXo+dugcIPiRbPlRxBdFPsPtqn8eQ2w1Lt9dXHTSZ8AFy5r5uc1ue/pIwg40yMayO9rvPHvxBcsz9LF6/WQ4Q0e/EtvvAv9Sy3QNiJ5jj/+5VBjsCDgAvA0wI7SU31SOyNAUGo1kq7wUeEGOSlqqX2kpcN/3OrGhExHXB0HZ7pzsec5JtBR5FyRzGb2JWvJ7gucRUKsJ4+5gIDINrJg9jNnzKYjv1Q7No3yMFecUDXkoiWsvb3mISzeilZXy6XQN64Ly4L1VbnAQNXYmY7dMQijVdyJtS2GlD0+Btv9Wwg09s6m8WBcH1oYxzE6kTpSM7VBmzsd3RAT9M3YVzlptsw/c5dANlQI11bf2bvXHpgBFcMb1XR21Wh+aElqG1UvQsuFD2YIHc75iaG/g4OW1KbXoDpKXvCIKzyyAJRELx6ha2ufEqN7zIxcadq+TKm7DgSP8twCpxEI9NJbKnhrp3v+i05jPUnInOgv8qzm9VUBDZT//Se3CS4brlllW4hWD6Fdj6EHxslbAcZCULgDhdYxy+rYNvzZgFizJLxkmFkB2grH6uJkTNx26JWMuooxLWhnXYvEk0OTGzyqSr3N6SABdviUgezfCKvvN/NlLaLHPtEzN7auAzt5rv0bTFNiNMHdLioe9elo/k9qg8kMbqdUQ1crXajEsxh7+gWDTo9hpEVCP2krirGAqzlsuIgqccfnBIuxen+5p3evE8sBcqbzQtx6PrQ==,iv:j11bZWXHN8J1oKVvs9UYHup4KREQ5AD7kT3jV3zA2Ew=,tag:UG7zbcb9dyGVNwXztOshuw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
@@ -169,9 +215,9 @@ grafana:
|
||||
#
|
||||
#ENC[AES256_GCM,data:k+Y8/BDL9G+C1EnnJjy7gz4=,iv:IU/ZlXVvtX+zaeU7Zcz5baYk8ceDz95dZgzpl5/L9lg=,tag:t0OzLQCM+Up0wLkc3B/R/Q==,type:comment]
|
||||
authelia:
|
||||
jwt_secret: ENC[AES256_GCM,data:NOsbV8poM41bodRZeNJ6vnRYIl7vGKXm2BpBNeXWVeE=,iv:1G4PnaoopJMIt7D+8x0x3ui5tefMPRnSI5KJRv4IuTo=,tag:EkEHgeJ3ta4htrgOCnYldg==,type:str]
|
||||
session_secret: ENC[AES256_GCM,data:tPudIXLrAKMhR3VPFj8U1g/+FRvYgBo0wXLNf/a72x0=,iv:atfRSZNUYEYFK92+0WOvsD5Gi4tMEKv+dwsFcRDrEtM=,tag:cJu5G4EYQ9EnYOQ4w1OSpA==,type:str]
|
||||
storage_secret: ENC[AES256_GCM,data:g3Z8t/2xFZJMz4baIfY7pGoAOdoKsr+Xn4POBl1lQCk=,iv:i9Owc4w76qC1rFSUXLv4NuW6/Y2rmgSoTr/EnZuRVE0=,tag:zitZ/UAgXiUSuyWDhvHa9A==,type:str]
|
||||
jwt_secret: ENC[AES256_GCM,data:YwMsvOqmukD/UyLZZOxHyN7VCy9yT6ZIkWHCtRdb3Qh12/5QFMUrsuy9HC0=,iv:yg3dTjGAKpBCLT2ixfF99mqnKj+OMogs3uU748ouLwk=,tag:AeGAfyIfGY2FxCvJfHUd0w==,type:str]
|
||||
session_secret: ENC[AES256_GCM,data:PPO8MhdI9EgfXFJsu7/FsCa+cudZ+34bq2lP709NDFdzLK4Svdy9JkhZqsE=,iv:Zfq/NDpbPtEgt7fmv9Z0kIL/nQUGALAJ5bEVaMPD8tA=,tag:FG2Nii5QeJY8rREKAtmdZQ==,type:str]
|
||||
storage_secret: ENC[AES256_GCM,data:uORmJjre1o1JjjEzuI3qdLPW8Vgld1bwp5lrzrfLMhce35Iw9wm1UM0WkW8=,iv:ajDOHOo6AXI3r+32nd8nj+PK/pLb9BXkExIYkN90C4g=,tag:OOdraFk6SudP1GEn0Eox9Q==,type:str]
|
||||
hmac_secret: ENC[AES256_GCM,data:c6Xn0QceaQWIFDCFr6UAQcr9M/Np2aGCkcNiXJfM79vFakT5L8q27+38Mvs=,iv:QSpnN/ZVYNogHfFq10E1rR8jXnI/qLs3Z7k2qKHFt4A=,tag:N6Wx52yCmGx2kJlyQXl7bQ==,type:str]
|
||||
jwk_rs256: ENC[AES256_GCM,data:e0rbiDCUadbuRL3dFZ//LMMYimQ3THJtZo1OqkKntwayh10DbvdNrEhs6HF0VAMtVh5nkAaL69V3tqZnwLUadSg0Oomum8v9GkTE527iupAMjWRrXzAR/nsjvjI8gPUL3NJk++v0VA6ew/Gb9WfGlhUlmkf3K72Ab+gGiD8+xfAFeqRE/k7vHkTxkNwD1hRFnE+XhkUa4Q021nSd7xrW80sHwBWTKKUqA08xuouQN8Gkbjj22NgicT5rhy4VJiV8OnLCERLWc8F6LmDM9vLrTiPBvsGn1eX09fvVRtw40Wo0VSgklm9+REQtjefBhXuVxVDR3DXNzPliLNL3MOrvlcweDU8uxFVuml23FBBkJypJLJwbWvxwFQk1OWjiQ9jPel9+9gYu1xHg/dKeEsDf8GyMVJz60BDEQH5YnEwI1R6rPnJLZnmZVhRtoxmKRE8/oE3lP30tvOVKwRL/f3rXCyB1PYDR/2NsWtj61inzgn1BuMDl/tHDKjGhsCu2+ECThD756p6cjQnGftSSoGlwhmMCqA8I+6WUjMPqEsqietWKbMCRk000ufLp57wU4i7BvUVPSpiVO58lf6n/zs6hHBYDWNfoxEa2gha4csmCTkhCrzf+N+UJQmoMDOIQe/gSqPNcwcW/+q8K8zr2b4cMIyLbwZIyiez0RvPRnM/KuM9UmFAKfW1xdtyxalNLMOBjpqeZFnCIPFRQy6COP/dZNA9xUQX4TXXsL+qTk0vlU41/gcORgw9HQFRkLiRtrnqvRUMXipIDU6SIRipbBJ1GawH5nPTdHdbjdr7Wh0s2RUjIzLNvT0Lz0VRii2dlVRdURbtFl8R8frijuE9LG9xKY2Z4f/ojo71h6HcJvrvMOGm4iE8V5+cdthlwn4Hpyl8nLinJWLyVjhc4bzmIlo+VZvbq9o/keSfCb3wrI39L3Wy/bpoKzXx/U3eTVIIXRDrBpK+4fmYeSEi2JRJjAHHvs8De7c0wKLq9qOctIFvELwueisDIkyNGYykX1+JXa4YbuTYaOSLJNbk9B6UE17Vbr6FD9N/8n5JveXzfd2dTROQBbWmHyKa0qR7MC9foPdyUVImj1Z06w91OwRyAi+/GBiUE8ivKD9AmnTjrvX1uZhp9qGSzP9f3RkCd6lFDQ0YhSCVHQAYOrDsdBX50zqqmZEPPevIXXPnaJpSgIaOCamBLIHqrxX9KOFM3ApicE2BhXX4xN2QWFl8HGu2cVD1e9bINKrpLGqR+rQQE822OQqMqw3kZsi7lo46YPOrpXLsetxPJlLftQ7bdaCPONZk3M18xvxESYclDeGk7LJ8Lp5CjtBterF3Ka/0r7cY4OxWusTypOY3jmVDILZTMlVOKoYiJgjIHxwXFdoqbtGMeGi83CY2/SfoHn7BSrU2669O3liX0L7hzGOLerkiVozbmC3TPq+JxGNw7dA79mXCqRDQEeqAjeha6J3wmvTvdmkuPIbO7ryFtDg9VwbULfgl07WzkES5nVyQDeamKv76ERRF/EIjQGgiWRY5MDyXAhVnzy9ATEbOnBTXeks6863CTKa/3lhhtDUGeo+9tTXcEUqLPkq1jh9xYo80OUp99J1483n5iE7EEBfB13McRwsJPufViyMWIQX9KDmRZmbCjhe/Jrj6joapQcY1Fw5MaZJgfIIfzz83GnekgTG9sz7Vfq2p4qiPDONLhY6qL9ENl8Cm/tWq/Xjvk+v/gaT65L9uvGLtkYKv7OpbPtTzieGHtYmddLZNr34Ly06PHxajLL+X6LeB5wmeC7jvanLh9vW6VqwNRn6kstS9reM4kHRhYTNKlDB9pOOz/cK0p0wcNzVvqetoYtZAX9TgPcYumhZQUPsXYsuC2Gdo88seihGKND9jtepvu2OwKRT3raSpsG+rum86Q95ulRsE/rhg4BvBXs8U62E16gL1KamtRkPcjXT/2aO1t0gh6JiBbQAYemnOaJCanycbnQcZal5oSvqPLAxzFpcjTkPNVFhYyiGe0ekcaYkCs9PYuM3hqP+qNAwjQmK7bfpK+eZNGT1gwikmlUtokTvRvQjmFynfbQ5oUoOHQuxuqWOa8KLi2NwMMmaJ4LXuzozUY8KD2EXmlmrxteCZBtQNfa7BxulUMlPRHG5bqKsBc9l380I1XU+aR2qmqHxdrd9698sIXxVK5zM1vhwI0fb6V61u86iYIAdSoitzhRQu8lK8prJXxcZWOQWehV03wvDnqkU4F2Qm/XYCXJgTx8PJyGKP2w90K7TtkW1YMWrBXmnwr,iv:av1JOLQd7WoZr4O8e9PU8nEZlaf+Bs7LLbGZs/4hm88=,tag:sZ8zyjRmhyYRdwntXTOfPg==,type:str]
|
||||
jwk_rs256_public: ENC[AES256_GCM,data:2IP+w7X5ZfYUH+upr7qtjno45RXXUT71hG9Xs/VMY9aWOv6KGLpK17OEo7hVUaXwmOWOzAQl0V79bGZjIowabAoba15+IEi38L973i6F44kM9pb4N29Z2LjmLoZ/blNpl82C0ZIO/+OQ+OCRxVV8b9eZ+E1ckpvEk24NmOV2o9H2E1EU6QBOQGmYt39mnD/tQKNtE0/Q0+HbW2bz9dWqTScjH6CcwBwhtn3dhU/kbXjLc27XG6pxMKInKLo6GZmjLA3PDRQY9O2cYnFN1nDRKdOqHpbEnAPU4DiUSronJZGq6R6Z+3JGkWXH2OUTXaP8itLpXYBioY8BKH02QA+YVxnzxC0cBooNW9BxFb/GQdeLqFawNZ2lH9+743svXIRjjKp3jyn1Bn0TnDxgirZSfmvBdrgOy1fKl0qpMBYrBVLaAP1+T4MxNNa1kQqnmt9wke7aYrjVroi3/33TE9oU/xW6SW6Y+3lLEB6kJIGYb/m+qhwksOrqXRDom8G5hocUqMX3Q1fkiv8Jt/qvmuz8oSFNsjVF/4AZFESacfAF9pyerPUemyti6Y+rVjeY1yUv3+BHGgu8OiF7lqlIUm5O7NGhNQ==,iv:41P+xnnSOQK4H1dm5EohB5FmXsuaKXfSOFr+ROgoTWw=,tag:7a0+DsaDDK1DlkggQQd6vQ==,type:str]
|
||||
@@ -221,18 +267,6 @@ immich:
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:McPUAbIUvtC1gdPaxTgAxAMCMWcLfg==,iv:Tp6idRf7he3sYzo8LW596C905JAaoTIhIoDUzSyRT0k=,tag:4mZQ0Swu1X9uuwjsRNhr2A==,type:comment]
|
||||
paperless:
|
||||
session_secret: ENC[AES256_GCM,data:siwCs2noeVpg9DCEZybnmo/oz11BdrHSTnHciMOu/6g=,iv:XVjhu10TIujIdUopN9+TVVqRade9EvItDWxym6YXnZs=,tag:TxLYm+4Bo7IMaTQBtMg9pQ==,type:str]
|
||||
admin:
|
||||
id: ENC[AES256_GCM,data:8uo=,iv:f/qtpDb1Xe0M6Gd2VFP2vXULCd7WOn7TCxLlaK1dDbA=,tag:eNRMPJtLlA3Vjj79bSFxuA==,type:str]
|
||||
password: ENC[AES256_GCM,data:TAA+TRTYRUSw47nE7oPDQmOtCBZpf2WyxUIIzftWq16wQhseODhH0R74X+Q=,iv:V0tzSvW5iYzEUgcxempmyD9ermVAqg673liiysT4jJ4=,tag:GuxtZ7EvgwvlFWwg+C6Jsg==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:wjRDVCJsINM4z5946a6uZD+6bhN5BChLMdRzgMEJFGRGFNcXd7A1p2Iqn4I=,iv:Y4QDA09L8ULKr4hhvoiduzCD8Hifo1gAnpzjCr8e520=,tag:R0RvGxYnXo3zwykXJykRug==,type:str]
|
||||
hash: ENC[AES256_GCM,data:pali6WwPNhJA+6QL4O+tKv42PnpGqmojb8JQUZLqxGizv1bJSCgdUN8upCy5Ke0DYZs5P+JY5vh23xfMZFnHduGxGwOuPX6J5lYgvJRV58LqS3/+yIBBprTJyro3MwsurTTEWesgKMr8/2H9lirhaLjWUOSPxAmQ6e4wPNpHycDVyj4=,iv:cg2trI7t1MfIcMo1/M+IY6JEl2msDoKRGgAx/Y5nyGk=,tag:gnOq7sBq9z5zrRY0yhIabg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:PZS7EbvMHqHGorNUGAWj4dk1,iv:vOE+djRAvBTMM51kHi6kG5Arw3uPXlJt1d/BpcEaD0c=,tag:AuoCHLQz42CYvVVdKFWu1Q==,type:comment]
|
||||
nextcloud:
|
||||
admin:
|
||||
@@ -246,7 +280,7 @@ nextcloud:
|
||||
#
|
||||
#ENC[AES256_GCM,data:Fsqc2JDp9dvfgiCjdQ==,iv:3DALKKEXaP8hzXRvxD4CgfFpOiPPsOa16OB94n8WKp8=,tag:K+FF3zGrc0YLXWK/R2L3Ow==,type:comment]
|
||||
sure:
|
||||
session_secret: ENC[AES256_GCM,data:InHsz/jld8E9TwI8MWpxk9x2I7dxlIsY9R6jtDK2pBA=,iv:HY5yXEC2Dce26e9/vXTIWELvVd9ZjhcCwFD0jhz5pPw=,tag:LLSJovZ0RH3CUK+se7R4Ag==,type:str]
|
||||
secret_key: ENC[AES256_GCM,data:95YY5PQXvNkHLhzpgO+av+J+f+ttN/adfRr5kspNXy5CNl44sh7F9OcHmXM=,iv:c25O1a4yrPaPQ9CTCS74UWGAAiijkAASKoaPQBOBstY=,tag:LHQilc4NfLjLTVytGM+pUQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:9BSvpcU9BJctSN9bkPIAsRxg8JNHTWvOKdpJFhm//CUDm/Xc7oC/ANHf5no=,iv:JVQLl/rp65kZSK/4SpVXxtiac3Z35XNkxWm2+lEdq/c=,tag:WgfaORiNlrO+wHSdnl4CWQ==,type:str]
|
||||
hash: ENC[AES256_GCM,data:EjJ+1fP7/9wG2jG0Jv2hxMLtErqxjHBstRjru79dd5ZXhqwT7S+jpLfl9WpZU9qi20ps9YP4qe7G08p6NJNXjYhQj852GQxEORRh/9StAZsPt3p8w+ePZSVbivPQH+FpPKWYxoH0VR7y3TnL66R0tKRLh1fNTc5jRy5rU5r1bfs1jZ0=,iv:0y9FxW4QdD7qHz3bPRWlwHFpvOsvlYhVrOItB6BzaE8=,tag:Wc7MZhP3QRYmvZcjpoEWtQ==,type:str]
|
||||
@@ -255,7 +289,7 @@ sure:
|
||||
#
|
||||
#ENC[AES256_GCM,data:H6BtfLuevnDCEpHSmf6pxQ==,iv:9Jw0UZwVwS2It7c4e1rAN/BEiqDKp9DHD4W9xdpJ/Vs=,tag:Xj8HKvxgCA260CXBVK2S1A==,type:comment]
|
||||
outline:
|
||||
session_secret: ENC[AES256_GCM,data:A26j8/ghGA9MjDiuq+H84iTFXkHZp3l3LbGKO9w+Cgv+u1dkTF5q4zuBnOSBi+Tnz+2Y4jIoxsac+CS0dguRMg==,iv:NzJiJxVxOvud3e4mP8urnHrqugE8SmjFVnZtwfzrUzs=,tag:YR/jexb3G0HfC2qHpn6fPA==,type:str]
|
||||
secret_key: ENC[AES256_GCM,data:0kfEulDNslLfm8aNSPaWci2qmWiEHU+RF1pyAddcFJjhV0Rj8WduJjIwEQkp8pmAt2QE76yAi4Flksj0VgMNJA==,iv:XvRgWkhfsLofms5M4Y+3M3ycgNzB8ZmDnDWklB8ZwvM=,tag:ccADOhrpmiDjK64JA3tkmw==,type:str]
|
||||
utils_secret: ENC[AES256_GCM,data:ACI+NZzqHBsYeb4WwTJ1nfJcy6zNwJn2hBqA93aM5cgNWQ4KtQHDXgmS6UTwmSpxrteiaH25J3Np03H3eQoVeA==,iv:nitwxxwTPQvoQXGLVMnk2zsdC7M+JIXkTY4zJdQ3DFo=,tag:IQewG7EE9IgQk+Rfz7M5Iw==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:zR6sN205C51BIiQxLYOwC4ZbTYGr2AveiPeEbdadairmfnNJkGOtm0zT4Gg=,iv:uyYoJYuAuH/Gy2dlLr2SkkLYq+lMdwBgmzUsEj1EAKc=,tag:uhgvE6BagvPPKf7Y3NaGfA==,type:str]
|
||||
@@ -263,19 +297,96 @@ outline:
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:Fis0K+QOQwUfHItGI5U=,iv:kRmt4WhV6bBwN7Xl2xLrbxnKuLKTBC5nI9ZnQSIgIwo=,tag:whb1oOEX+fry9GS1+RlPrA==,type:comment]
|
||||
memos:
|
||||
#ENC[AES256_GCM,data:b74wua/tFSoef2fq5jZhNQ==,iv:RDtz7Y6eFQKiVVnNvoLAfzE4xo8t7RFiKjLTbd0xo80=,tag:iUS7ofvuVj6ZTsy8zA6KSg==,type:comment]
|
||||
homebox:
|
||||
api_secret: ENC[AES256_GCM,data:BT6m0D9Xwa1tnQQRzpUnEF4bjLFne297oS3p8HM8Q/1Vakrf+uFcfS0C4MU=,iv:5WeWyfe8kt+AWwsV3YXxfLVuSEE8lYmNFxrXyRZzISc=,tag:cYd6U3BxqyGst+UsMpRypA==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:+rX8znej0jjXybmUjoI7DkybNkNeg15Py7bav665Uej48I5ZAZbUiKwccNo=,iv:UzcCqXxvweosRL8afhyRBB2ERm1PNs+tuxeDwL7Mcu8=,tag:+gJWSAq2BpSlSw/iwhIbpA==,type:str]
|
||||
hash: ENC[AES256_GCM,data:D7+37XTpDFRabT5YEh9nfxO1Q9Sdc98jAxPsjkPzj7bthn1H0dlLYZSJ2Fy8Ye4vjIFO+TZ6HWx8N4cSwHTfgls3EYFh1TW0FUnyCY1kYd/+ljfZB9Y6M+i5zb5nEIBHI32Sk7/B20cGnr0SUb3EKU+SmnACgZ0fjKKyUpSzGu75MH8=,iv:3RkTpgy85JPJqu6AEKrw8RY2O+L/CldPuPpN9ln54u8=,tag:Nl0DL5tVenA/fdRNOGyPkA==,type:str]
|
||||
secret: ENC[AES256_GCM,data:26flutXrbmP4UqyfQs4PmROQGwrJhmkTw2Ujro0jg+q5nfy1mN5i5zKcnAg=,iv:a/fwjeE7MVByIG/L8Tq2ORjF4aSOwWSusER0c3ySBV8=,tag:kkx4hAlfff42Qghe+l9uLg==,type:str]
|
||||
hash: ENC[AES256_GCM,data:CRdr7WWotsMujhH5PFEFNNF/y0xLjLu6TZc93/eIZyzFZPp9kdHcVyMs8pnyQTMT5r3ynWRsT17N8s7X84uZNqPCu1o4KGvNR5UioiSecHdov1LoJbE1mYCCm2H34PEFwpjSMP013ipz0ybuaYqMTASOn1B/lOUt2bP6yj9NnlBVPUg=,iv:K4iH1ZykdgcL9a0eqCB6PPCU/8jGpX9NEt3yljbOVpY=,tag:EpWG3NEwioRietOi/IbvmA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:ATLTbBi1RsBr2ldHDDH4,iv:RFbPz/46BIGYv9Wo5Jxw5Swi4Xo2JgIEI4IsO4rCQoQ=,tag:i7/2ItQSFurrmdNaBWwWAA==,type:comment]
|
||||
mealie:
|
||||
#ENC[AES256_GCM,data:3vSrCbjgdJF8gQ429r/xMCE=,iv:b7+xc6VGoCBttqUFb7tk4qTYvqdIT4U2+EjVZgPqB6c=,tag:60uoeIZEkQk+h2MkzGK60g==,type:comment]
|
||||
mastodon:
|
||||
secret_key: ENC[AES256_GCM,data:nyymxkVxZK2Lr7QHtX5A/C+18/xHJj8B3EYbqy133reQMxGPyt1ROvnuKSU=,iv:htu8aWqS1ANJeAt6K/wa4x7F7tBqmqLMLPucOZbEaLQ=,tag:jVEsKh7yi9dzXtN58VXKcQ==,type:str]
|
||||
encryption:
|
||||
primary_key: ENC[AES256_GCM,data:MJqoZmeQzB7o6XNS5/KK5GZrJp70bXe8m8M/aSVs0RFHn/Mb4Bzk0yfdATU=,iv:7bszcxnK0V40Fm2krbuYe4bpuKzJDwsn5D68HWpzGGk=,tag:n4Ij8DQli4JfyMdxaYGiXA==,type:str]
|
||||
deterministic_key: ENC[AES256_GCM,data:fREH+pLeWPVzycTHp9raSu5EqNnO/zjBmUCe8Df2/2hjDrf2f1OjQpI2w7Y=,iv:4v/Cwh+lqRLtpO6ymZ0jLUhJIOwukS+Ng4pK3qeZh8A=,tag:ylAhb0GvVIx36dvJTYdjNg==,type:str]
|
||||
salt: ENC[AES256_GCM,data:NC4iHNcL+M5tl1W4dKqz9TlvYKY4TN83YCxJbbMDJrvBurnJJtFDqRsmK28=,iv:zIiPcgDCY6stDhZsQRhhJstmh+/Z9oSpVRRfuLBxVSE=,tag:2FajPSyZiFRPUWGj/RpvEQ==,type:str]
|
||||
vapid:
|
||||
private_key: ENC[AES256_GCM,data:t4weu5P492pFSpTlHGeEaHhssjReSx2jgE2CdlYcHqgembiv30CpYyVj71c=,iv:V5rLMV4dyjfCgIpcZAuijPDuPTEaRyR5kqR1Pico17Y=,tag:cvfQbl8sJynuw8gbZ0/9Fg==,type:str]
|
||||
public_key: ENC[AES256_GCM,data:DOzTSCIJkwGoFk2lymMwTeZpnV8RIX1xbFff3SdHu6/Rvtyj6GxVPlRo2IADXUBB5vA5BlORxSsQCmkzjPI/6Rq/WKtHEgLi2ZWtvt83j6LHkwqISuNZ/A==,iv:jgCSaAmsoDxtb5Voxx1b5oRyKH2Yb0oje4Mg14lT+is=,tag:YImmQEuzVxfcWe3L3u8KCg==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:ldsfwWnexNNM4r+aP2h+woQROwbp9MpxAz8E/o1Q53GxcEwtixqvP6QZGoo=,iv:6M/lfuDU3IOd0nxLi2l02OD5FopErhSCp6AhxBGTI1k=,tag:3w0p+wi9T1PqNmgoM59gug==,type:str]
|
||||
hash: ENC[AES256_GCM,data:YmziHxsFPJ93uMNG6/EUiPEfMvvAZM8/S5854GJ/fPPTMvXj9cM2sovkSrcNd7H0ac5KDJIcJoD9SC5lWKCAbjKzxHvI6CdI63SM8bExrDL2PVSGAf29VLU/cz8rQtZS39GWz2v5GWlpk67Emy0T115vruIGfDlan8zgQKK7YIWyVMs=,iv:xmnBYjBIWq6P2g5DyMh+wYskmJRcVDREGL/yYhJHyRs=,tag:qMWXHiLmAy5UvWFvv3Ct8g==,type:str]
|
||||
secret: ENC[AES256_GCM,data:dAnoQbB0YyS3Uj4AcM9h0RkGjseFWfiGllYGGUnjc8LXsruTqIPjYuM6NR0=,iv:l4fy6uD4NosdKq/JqrQbIIzjB6o9rkyH5OLL50uRUjY=,tag:AXohLv42vQo6Kmo4tDAbhQ==,type:str]
|
||||
hash: ENC[AES256_GCM,data:1iISp93pXT21Cn+7+aiZDdXs7jb562IjLS926xseKfTZszFeqlXktal1RiPllTvwoVzB7PC4WcdiJHma8yJock8oXMEQa5/IAm+Wr3sfFkOEBiQtNieJXdWdBffqtrg4dxYz6Silc+NB4Sifs2SaSrUJjn5FuItl/bNW9jk8Tzq3Yd8=,iv:oxqHOowZIPJDtIscOLByyY1OpQPiZAEm+4iRwwFUirI=,tag:R4w+qlwUDiWnKeEZwF3ixg==,type:str]
|
||||
#ENC[AES256_GCM,data:9YYxY6yRWdykN6mhtAtD2XE5HDwMvg9YZzcvP0lzq6ts8zX6usOg1SVgIKG+lezv5fgFgKB3xP7uNqbQRIdvFY1YgSW/ZcNlkcKQ,iv:Qd+p0c7qRw2hYR+i2sCjuY1zd1XW52m1VoglO7VlIzM=,tag:bY4ZXqnVHrfnDcGd0E0xyA==,type:comment]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:BmZppA02YtiTykTtUnk=,iv:zV2x6W1yWhMegE+h7zdQNRxVrN7C16Lq4xpDkkZPcBw=,tag:MPGH1vjS1IYuZo2qf30qwA==,type:comment]
|
||||
papra:
|
||||
secret_key: ENC[AES256_GCM,data:AoqqUS2OUb11UwWNteZHqU6FF1eJVbmvANfZRvcwnvU+/cbYtPC8cHyRcBQ=,iv:6eWM/9NDApVMpTviYw2X1p91VItG3qlkGocjrkLyBq8=,tag:STXAVUqQEHGW+ijRQOZLrA==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:a019OZyi6HSP4t4IcDVOATKnrwIHooq9nh3g5mzq4x9fpcbM5o6UW3kCNlE=,iv:7ibp5/fCq/qGM3RcVbpl94OjGjuXL+Y1qvsx9t693aw=,tag:Sv2K89OBPGQFkag0vXenxw==,type:str]
|
||||
hash: ENC[AES256_GCM,data:bHVmhaBo49OHH7ZGRdZvRcOyRZrorTFk+63H5esDwUAqZfXJfTVML9naOtoeYElPnh+Zx0EX06ozHwuqgK9ZcGVAi3hoxnWQeImKfVvlifazGIcVK8omNguPd8n5PhooqS6AiFixiizvTM6iLp1TvKLTCb8QywOVq7RxykJPu3XXDAA=,iv:/EsPo3bMtVYoGtyHydW96o404ZRI2Tqop76XozEZlhw=,tag:HlWGa096oG61Ua7Fr1OjPA==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:7nupd3g2GlsjuxZFFdXiyw==,iv:vdwhjZTOhHPp14Z0oGdZV9zs9IAebjrxuE7ih66mgr8=,tag:lzbMg8K/yYEuUD+Q9OgbWw==,type:comment]
|
||||
tandoor:
|
||||
secret_key: ENC[AES256_GCM,data:RZc91Ji9x7A2PQF+lw47B6tlczWO7e8hRfUJIlNd0BtkPIacDvztR7/VbCc=,iv:IlpZcvR70XvNc46KrrNls5RbndnWeobU0k9qQMIhA0Q=,tag:d0weqGUUFa5bH5tEDzPDYg==,type:str]
|
||||
admin:
|
||||
id: ENC[AES256_GCM,data:N8TQU9gwDUe5Roc=,iv:dPikeLm98iB5JMXv5xTePZcbz7bUdRUfQRUkBmU4aqQ=,tag:2EJ5N51bYi2uOhOtnVbLUA==,type:str]
|
||||
password: ENC[AES256_GCM,data:888/eGiNJVc7HppIBnefmEpZXcmZntKtJgB3Gigvld44kubx9n9exWQ1JPQ=,iv:eebNRxHJScFtoEcp4QEKWH0k1oQRKb1tGvRD9B3KQmw=,tag:LGi/nxTSRi/5Zqm4po9KFQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:w3Md+8XEJ+VMP9WGcyA3o/Hy55xvMDSyOM+PxUBPnXen/IFkTYoBRnyAxtc=,iv:5ZfNmM/fBEaSpw8SD7gXph1czdXOYvBrr19MRaPjYRE=,tag:MeuWc/KuSUyIeavakjqIbw==,type:str]
|
||||
hash: ENC[AES256_GCM,data:IsEmqlacmA+SO4QkobJBMDnaEF19/EWnzhKUgjekhF02E4teOKEI5DRosoe3AFz5sB9qg+1DO6y6nvHDaTP5WKGJcaonu3UOO6jMPOAHudJsTrOb+6cM4govT9VITnF0RbwImqrwOutzQe0IRyGDxZ7TkZTmdlwCs9DiLfyf918nMgg=,iv:d/Kb5tPeYVIbYQxWBwVZ485WCZfTxwPabx4+NLMBP2M=,tag:i9VtcCeoL5r11Q7F/Secpw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:yiiJIGjYsvXc/Gswhbn4wI4v,iv:YrG8oCVLYDi+ERDYMjcWqSblelPFgCpYCmxL+BUC8sE=,tag:Z9r6kk6CgodIzRDXaY33Mg==,type:comment]
|
||||
bookstack:
|
||||
secret_key: ENC[AES256_GCM,data:O8OkaNnD/J241SGKKJU9k8cocTXyQ/I2Q0IXtaBh4SR0pjQeZbpeU6q79T70U92or3Wj,iv:5sU2wonIFkymuMLSsU8x1ma2yv0Wf/Z3S5RDuIcGdn0=,tag:n0EhWB97MK8ZxBBeOlm+Jw==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:9GoEgOV+0PyT4A8hrEBzSg+fveSyFDYPCmrkQA48nIRP73kq2nZoznnxhSg=,iv:ues0Gu7aJio9lk+IiYP9wKJ0r73sc5snxbqPIZ1qyzM=,tag:QZP3NHJpgniC6sAEz6Fa7A==,type:str]
|
||||
hash: ENC[AES256_GCM,data:5DBNQc7ooU5aRyK4O0j6f3OLpR12LniAvWEUd4IMltMhLvsEi64QkSst2Fur588v0Jv0P78M49LbqYiXYHl0oLfrCGEQafoqAY4IEpbbNm5aTb0ekQ1GDoshfp7wIO4NtkeOHeiozohi0UQK01PN2zM4GVihgFXZupsooeIoOo9i3i8=,iv:vVcC2gkky/DQ2rY62eZJYj9yhk6IXWr0TRDipOpFDYI=,tag:ZBGgF2iL5Qe+98LlHz98/Q==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:YSPB2SN7qm10qtJTDf1aI5k=,iv:Q1xcZboMd3zyDfpgNG+MzOAUwWY0iKP2uXo6oN4kbfI=,tag:p+DNn5p5SwXFvCWj++74xg==,type:comment]
|
||||
linkding:
|
||||
admin:
|
||||
password: ENC[AES256_GCM,data:f3i2LGaDbC+qAVXouPL3odRCRxNjYayBMqY4IXkRm7WMCz/AtM+/C/4uOOE=,iv:FZVx42qbcb9neoVuS0wzXGJdHlkYOCG7A6I4vQFNdXI=,tag:OY5onMh0ia0CvlJNJS5XEQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:Z+990MZgGw0kFLZNz97dZzdN2azGHSBe1QMB+81xRz+7kqA9dyYmnrMRZK4=,iv:t2BN7kSKhA1DOMqEcXzDAoVnywC9yJWxfWG31W11Y9M=,tag:Cybo+cTgPc/hgT3rKeFl1A==,type:str]
|
||||
hash: ENC[AES256_GCM,data:0XBUGG83pACnTxKgqh0ehNL2vupNxDJ3aD46sEbBNwetZdWHvTwG+WA5Y04o1CBEqR3PqTuvSageNzKGPAvPeI+Tf12dKuwEqjaqy69EbszVFTFA45JosDzUHEdF6HmOFRAOWZVqeMKYEZqql/gpzrEXBYYmsdCrCy8yzeC/ozfvcnU=,iv:ytR01gmnOCdkmjNKcmcXSVLirilsSkN2hkFrwbX/SQM=,tag:Mqa2Mv+Jbut4nKg/UIqAXQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:aFaqLiw+m7M5KEBCH06w2Cgasw==,iv:Yq1tY7lNxW6UuY+77OQEmWwzW9vnJpaZL/bI650wg18=,tag:e9Fozat8Pf3h/BXUNZ0fHQ==,type:comment]
|
||||
openwebui:
|
||||
secret_key: ENC[AES256_GCM,data:dAUmbxfOGo684M7Mk7VAv+mZTLT2qi83Nvf6fOR6M/Ale/2n1D4Q8jIl0C4=,iv:uNNQmXTIUACVyguvPBhLzv9ir3WXlPFacgqMhrNScKM=,tag:h3plKpikh7UqHIUO9fyZiQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:1PZgSzT28FMuClh7W21j9zjHn/YAPiY7iBF8Hid2FCDMzC2jHaObQdXM5H4=,iv:mhNxP0So9JjG1Hgtvt8OpdzIcfp7SZZGPiX0wj0ZP20=,tag:xvKiHjeVJDz0uSkZXpuKcA==,type:str]
|
||||
hash: ENC[AES256_GCM,data:XIHS9JJVGy3qKFiBIPETou+79vMV4wjYXW9Grv4Hx1zqjqZ4onJ/JiMVcYmtBm5CAp2hsrouIdw9gjW344pnjVg5DORMz6P+/95Yu3OlYmOEj+Cl1iLqgN/q5qc3XAXzQaOylwdbp6UMR+z7PmqJzY+z1h/qMqlSIYGtRAVo4BgNBng=,iv:sK8HTn0z/kzYB8Db+zrKmlk2DxcH3DcoQkPRJtlIvSY=,tag:5hmbItxT4bRlGaM5z2kQkg==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:AzckMweK6MUIX9VYy96juNpiGfU=,iv:4/j/5QgJy9OsxZ1dNN16TKR93/9mCmOuaqLrab3ymLo=,tag:4wrv96l2BI09Afc7HaQiRA==,type:comment]
|
||||
groupoffice:
|
||||
admin:
|
||||
id: ENC[AES256_GCM,data:WafJHpvJ3MmpfA8=,iv:i9KbnMoMG8EnaryPAQ+3xYvUwFYKQDnzGmMkSOKllTs=,tag:uH/ksrBdK1M++rVyMvxcRQ==,type:str]
|
||||
email: ENC[AES256_GCM,data:AfAQUHankHwMGutLM/LZWJEimCiDFzyDp+GsPg==,iv:atCWo/TTshDGGwtu42ZddILK45eMIg5oYy82m4TAzUU=,tag:0X+bhJ05/1b7DS9wb22A9w==,type:str]
|
||||
password: ENC[AES256_GCM,data:V0CJ8KAoHguWrW9+/j12xjbqqn/5nKAqbYYHZ1UxqAubpD0fQDLTjrZRTuQ=,iv:MJinVDkLBaSNAwM8qCj0WaWl26vTYDoHQqcmdlyNjR4=,tag:7P1UQZd197aJlFREiJP2ow==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:zEb2WvNmwVIqKcKesJk=,iv:G/CP+ZrjF9uJNTRC0CVY1cRM1gPL8Ud2GHAmHkkSM78=,tag:lXIH+YF2dCdIzI/ImhQRig==,type:comment]
|
||||
kaneo:
|
||||
secret_key: ENC[AES256_GCM,data:SeMvcW+SZABzQKnTsd1dOFbKklfqqTEDM6q9pqd1SS9hig/XuW4lDzS8q0k=,iv:3Djzn0VGasdxyoZo8zMx4G8sIOGBhRt/1cq3LuabUzA=,tag:FCbSB7A/PowGPz8URFm/eA==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:AFjQeEv3DMFZCpObgOR69i/Tavp3lcYUsaUqZ/X4pQYcXCNAE1gRHwkk//8=,iv:nEsQOT5AZnHHHMfrfcCIClw3Dwg+O2ykPFjIlcl8Wrc=,tag:J+E50bmw6pEXSVkAOwfuWQ==,type:str]
|
||||
hash: ENC[AES256_GCM,data:47WzIRYnXn/Jz01BwSVjtff2cTl16vVWh1YypJLmg/GJjXNj+XcghAnw4j7hFf8YhIyyCgWHHm0wkgqxpjPXN03wDIP8Djxg3K5ubUPXZJZWYVTdwcc1Ebdi/3x/DijMLqSJxbRATYSXijBF1o6t1uv0GfGHXTt7M50vdsB8MNjBkds=,iv:MRj+G3gpr8tQdwAxxZlojknUeQ67WY17OAbu04v2sxY=,tag:avz6caNLAi/bGvkfheGJCw==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
@@ -284,21 +395,6 @@ switch:
|
||||
admin:
|
||||
password: ENC[AES256_GCM,data:cwBJRIO3eUgezyN60dU=,iv:Ab+EpURW+MYT7RTcPHi4FvQiv4m6TDhAb1/xexkIHCE=,tag:JEWZ3cqoAfAPfwXz7KmINQ==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
#ENC[AES256_GCM,data:UfrFHblh4F20kzKZ,iv:+gouH3z5BXLnALq1Fcs0H6SQ8Gnz6noeeRhltWSgzJQ=,tag:JXqIQjRZGtnx4y+/83CFFA==,type:comment]
|
||||
dsm:
|
||||
key: ENC[AES256_GCM,data:jxQRPNuioZbznadJa7sdhbntABsi+nc6Y5TJsyMXwKRvVUbQw8p3snp75d9WVmOfq4uj8wBGen0noa/6xtWo4ZiHsIg1Svh/5xAN37zueB6NmK/z+BW2y8HaIkNhjcinusnT2SWE2ahguizMNM90FpXgmTt9Zv7wVwRkifDLWpH+rs5zmyMWPtpT2RN3+k7tVh8XWVevek/DxG4h+jtoYhTVzndMC5oe/A60MHBJCj6kaksGlX3vIDbRo5A0FEKX8uWI6k6U2osFc4SHIvpljYmPagj3EwPaTc3mbl8IJsXFVH4=,iv:7O5oQa1fELjIt6f3nQ+fWDFirAexgioS36/Nozh656o=,tag:t1RHmY8QC6mE9PVPJg426Q==,type:str]
|
||||
crt: ENC[AES256_GCM,data:N32+8CItiwbW8drpnL65weS35SY8uP8vcw9wBDFOxGFQjs6EyEwsMUVh1ndMpmDSUKWz7c7ji0HisC710RqnZw9l2NMg6R57DeXR/WsLW4LiAT7sFuDBcqorTB+6Nk0K9wLLdnsKpUQgl8oV9ffnWXZdfI5skKCDMNB40WJAYY/3wx9iT3wDQWaunq/1NT0SZHrtXXTj1JYiLbfDaTwTvkuqqUv1cXvOjonL2Cp4aNT/zjwK6c/TRbKdhIs/7tnUUE/lJx74eARfrMQy/3y6h2xK9pgruASuJxMw9Tyaj6Ya0FMNMIezO3GPQbFCE/IRfmCE6vX2RXUjVqX8wd/d4m4KNuMsN3hbwC3vQ6r+DcYdaTUfGIu96xfKSiSax/ZPQ4JhTyqthkGgpE0Ob67aVELrZkyhc/kvvSxafVSvP63C/nHPQnXMgitdRddYFq7487Vbq03frxiyID1WkqeUavc+Tn3dyA8c7aqVvbW6vZCAwUzbKD0nwPuBUtKZQpJKxHvtx2390PW7a214zkPLcw5LH3FnNacopiNfs6dNEeW/UsGysYkoBRXfrAPMX4UL53TvUTrpuCBhthJ4rgqjhgTfq9GtomP7piuf/tnMAO33qSHPM3w2ocLWeLyOiqYESFmXoBAsiu33LVzuVryFVw75pgrGAsc2wwKhcu4JC0cNgUE44ENIIjffVQX/mcvPvHxuI05vtzM0N8kOFPwG7iAVrO1eUEpwUjZwUwkk8QRsuIhZ6W7aYx7TLdPDpjmy6XCYGNHZgHg6jU7v18KkPep1YarAnsVYFzHQwfZIMOzW7DHlHq38NJW8lWq7zkg+kY6JDVy0nttlAUSskWNeCHdI5Xy3Rz3t7V6t1+UxkSy3roQCZOYjiaknwrXSctsgqucKaJCq4w0Tty36kaIXwOQYVm9JqDIztOmer4fW8Es7OEbLwA==,iv:26fGb288JEbtA0UcAmiYcN+UunrUOw2S6fKjGMetgwE=,tag:GmUJb9LJ186HNOF4AhfmLg==,type:str]
|
||||
admin:
|
||||
id: ENC[AES256_GCM,data:/Js=,iv:GyEcag6KxEHy6xApfzEo+dZF9NOtkOoYaJZEzPa8ing=,tag:W/4zaDxdw42Ap4DVE9ogAQ==,type:str]
|
||||
password: ENC[AES256_GCM,data:/rgn1Eogw3F2EqArMJXL8Ri4y1W04hGzxy4w1Ct5/ysBjjHGgRbxd9tXSf0=,iv:PISJ0a113rlEL0z0yo+nBYNQNU6Ht0PgFWZzooxIgi0=,tag:UZl0EiVcaVPq1v0MtNCXFQ==,type:str]
|
||||
oidc:
|
||||
secret: ENC[AES256_GCM,data:IXJNy9PmMPn9uowSMMrNPYqaW5PZ13JTeu1t7eNlapxmnV3EAl3I3xbMK5A=,iv:UcG2E6zgoKkPfUiHr0A+gvnApCkBJG2GROfacwD634Q=,tag:nSFn9yaCadJGlGy/aCvc2A==,type:str]
|
||||
hash: ENC[AES256_GCM,data:Y2/FNYbID0trRS5UpP2MX6UcLWxlRoXu9VLeU9DU9whEwNLbf4gYrxI7Q7etQe6HidBuoIJNxKajf3t0fI0ptbXnJaxzMh/v/CsiDg2p568o3KIyfB1PruGRKUrTuJneREUHg5jRXMYCwcRUQ4C5WgAyjd2spGlTQO0OLEqh0wkTtvs=,iv:YTYoaBy3QwlSrmx/K5woiXAHrh0RkawF+uQ4rQuP7WU=,tag:Ej6ZjTFvKjw6BrXbd0lf0g==,type:str]
|
||||
#ENC[AES256_GCM,data:ODXFUxxxdQ==,iv:s9zJVx6wo6x517tbNvC+FZ0dFzqbjqeLI6rXBq72hQA=,tag:bXoV2I3LbpmQyddJrtS3Qg==,type:comment]
|
||||
#
|
||||
#
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
@@ -310,7 +406,7 @@ sops:
|
||||
k+uyWPPi+enFkVaceSwMFrA66uaWWrwAj11sXEB7yzvGFPrnAGezjQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age120wuwcmsm845ztsvsz46pswj5je53uc2n35vadklrfqudu6cxuusxetk7y
|
||||
lastmodified: "2026-06-12T13:44:23Z"
|
||||
mac: ENC[AES256_GCM,data:FMOY7qMDSCzvOUL44zmwLwUVAXfYkat1JbiNeBVQFuUrC4lAwuukxW9MCPs5plj84LOAUMVgMofyudFJh5VKTR6Y0EnB5ft0NnbGgwMwzQnQn7d9Mcg9xPca3ccSbSGNx0UrC+8lTjXuzhoawMQ5ZXZ3ZK0k7JrFQ2El7UUwxEA=,iv:+oj0bvsDo8gidUn6m0FOeWsJOxIXPHhzvtiIbQ1VgcY=,tag:8xLcthizKqWjqg2eQvJlRA==,type:str]
|
||||
lastmodified: "2026-09-15T10:12:55Z"
|
||||
mac: ENC[AES256_GCM,data:694Pf1d/O64CCv+l72zugmlk+XOiFi27UJ7nrqtIArdgOZsNbRKGwM2kcsbcHiJsqh6erLCJPEaN7pb+cZ3OEBz1pK7veZ+px4yBvDntfZB0ZuSUgiKuebChVRY2ljTMPtQWYHN8R/ij3uXWmSNIA8Kws0fKKZ9yOGTtUUCAbbU=,iv:zdlTeNrImqna2Fsv+mq2W3Mb4mpIsx8IDRIHTXWTHZU=,tag:A95RmZJwRZ06MkHfgGwtKw==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.13.1
|
||||
version: 3.13.2
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=Bookstack
|
||||
|
||||
[Container]
|
||||
Image=docker.io/solidnerd/bookstack:{{ version['containers']['bookstack'] }}
|
||||
|
||||
ContainerName=bookstack
|
||||
HostName=bookstack
|
||||
|
||||
PublishPort={{ services['bookstack']['ports']['http'] }}:8080/tcp
|
||||
|
||||
# Volumes
|
||||
Volume=%h/data/containers/bookstack/public:/var/www/bookstack/public/uploads:rw
|
||||
Volume=%h/data/containers/bookstack/storage:/var/www/bookstack/storage/uploads:rw
|
||||
Volume=%h/containers/bookstack/ssl:/etc/ssl/bookstack:ro
|
||||
|
||||
# General
|
||||
Environment="TZ={{ timezone }}"
|
||||
Environment="APP_ENV=production"
|
||||
Environment="APP_DEBUG=false"
|
||||
Environment="APP_URL=https://{{ services['bookstack']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
# 169.254.1.2 is podman pasta APIPA ip address to communicate the other container in the same host
|
||||
Environment="APP_PROXIES={{ hostvars['fw']['network']['podman']['ipv4']['lla'] }},{{ hostvars['fw']['network']['auth']['ipv4']['server'] }},{{ hostvars['fw']['network']['auth']['ipv6']['server'] }}"
|
||||
|
||||
# Secrets
|
||||
Secret=BOOKSTACK_SECRET_KEY,type=env,target=APP_KEY
|
||||
|
||||
# Database (MariaDB)
|
||||
Environment="DB_HOST={{ services['mariadb']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['mariadb']['ports']['tcp'] }}"
|
||||
Environment="DB_DATABASE=bookstack_db"
|
||||
Environment="DB_USERNAME=bookstack"
|
||||
Environment="MYSQL_ATTR_SSL_CA=/etc/ssl/bookstack/{{ root_cert_filename }}"
|
||||
Secret=BOOKSTACK_DB_PASSWORD,type=env,target=DB_PASSWORD
|
||||
|
||||
# OIDC
|
||||
Environment="AUTH_METHOD=oidc"
|
||||
Environment="AUTH_AUTO_INITIATE=false"
|
||||
Environment="OIDC_NAME=Authelia"
|
||||
Environment="OIDC_ISSUER=https://{{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
Environment="OIDC_ISSUER_DISCOVER=true"
|
||||
Environment="OIDC_CLIENT_ID=bookstack"
|
||||
Environment="OIDC_ADDITIONAL_SCOPES=groups"
|
||||
Environment="OIDC_DISPLAY_NAME_CLAIMS=name"
|
||||
Environment="OIDC_GROUPS_CLAIM=groups"
|
||||
Environment="OIDC_USER_TO_GROUPS=true"
|
||||
Environment="OIDC_REMOVE_FROM_GROUPS=true"
|
||||
Environment="OIDC_END_SESSION_ENDPOINT=false"
|
||||
Secret=BOOKSTACK_OIDC_CLIENT_SECRET,type=env,target=OIDC_CLIENT_SECRET
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/nc -zv {{ services['mariadb']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['mariadb']['ports']['tcp'] }}
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -13,13 +13,15 @@ PublishPort={{ services['collabora']['ports']['http'] }}:9980/tcp
|
||||
|
||||
Environment="TZ={{ timezone }}"
|
||||
Environment="aliasgroup1=https://{{ services['nextcloud']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
Environment="aliasgroup2=https://{{ services['groupoffice']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
# Environment="aliasgroup2=other_server_FQDN"
|
||||
Environment="extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:server_name={{ services['collabora']['domain']['public'] }}.{{ domain['public'] }} --o:admin_console.enable=false"
|
||||
|
||||
[Service]
|
||||
MemoryKSM=yes
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
WantedBy=default.target
|
||||
|
||||
@@ -15,15 +15,17 @@ HostName=gitea
|
||||
|
||||
PublishPort={{ services['gitea']['ports']['http'] }}:3000/tcp
|
||||
|
||||
Volume=%h/data/containers/gitea:/data:rw
|
||||
Volume=%h/data/containers/gitea/data:/data:rw
|
||||
Volume=%h/containers/gitea/ssl:/etc/ssl/gitea:ro
|
||||
|
||||
# General
|
||||
Environment="TZ={{ timezone }}"
|
||||
Environment="GITEA__server__DISABLE_SSH=true"
|
||||
Environment="GITEA__server__REVERSE_PROXY_LIMIT=2"
|
||||
Environment="GITEA__server__REVERSE_PROXY_TRUSTED_PROXIES={{ hostvars['fw']['network']['podman']['ipv4']['lla'] }},{{ hostvars['fw']['network']['auth']['ipv4']['server'] }},{{ hostvars['fw']['network']['auth']['ipv6']['server'] }}"
|
||||
# Database
|
||||
Environment="GITEA__database__DB_TYPE=postgres"
|
||||
Environment="GITEA__database__HOST={{ services['postgresql']['domain'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
|
||||
Environment="GITEA__database__HOST={{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }}:{{ services['postgresql']['ports']['tcp'] }}"
|
||||
Environment="GITEA__database__NAME=gitea_db"
|
||||
Environment="GITEA__database__USER=gitea"
|
||||
Secret=GITEA__database__PASSWD,type=env
|
||||
@@ -34,7 +36,7 @@ Environment="GITEA__oauth2_client__ACCOUNT_LINKING=auto"
|
||||
# OIDC configuration
|
||||
Environment="GITEA__openid__ENABLE_OPENID_SIGNIN=false"
|
||||
Environment="GITEA__openid__ENABLE_OPENID_SIGNUP=true"
|
||||
Environment="GITEA__openid__WHITELISTED_URIS={{ services['authelia']['domain'] }}.{{ domain['public'] }}"
|
||||
Environment="GITEA__openid__WHITELISTED_URIS={{ services['authelia']['domain']['public'] }}.{{ domain['public'] }}"
|
||||
# automatic create user via authelia
|
||||
Environment="GITEA__service__DISABLE_REGISTRATION=false"
|
||||
Environment="GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=true"
|
||||
@@ -42,7 +44,7 @@ Environment="GITEA__service__SHOW_REGISTRATION_BUTTON=false"
|
||||
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
|
||||
ExecStartPre=/usr/bin/nc -zv {{ services['postgresql']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['postgresql']['ports']['tcp'] }}
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
@@ -0,0 +1,519 @@
|
||||
<?php
|
||||
|
||||
namespace go\modules\community\imapauthenticator\model;
|
||||
|
||||
use Exception;
|
||||
use go\core\auth\PrimaryAuthenticator;
|
||||
use go\core\imap\Connection;
|
||||
use go\core\model\User;
|
||||
use GO\Email\Model\Account;
|
||||
use function GO;
|
||||
|
||||
class Authenticator extends PrimaryAuthenticator
|
||||
{
|
||||
public static function id(): string
|
||||
{
|
||||
return "imap";
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a login name into a Group-Office username and e-mail address.
|
||||
*
|
||||
* Full e-mail:
|
||||
* foo@example.com
|
||||
* -> username = foo
|
||||
* -> email = foo@example.com
|
||||
*
|
||||
* Short username:
|
||||
* foo
|
||||
* -> allowed only when exactly one concrete IMAP domain is configured
|
||||
* -> username = foo
|
||||
* -> email = foo@configured-domain
|
||||
*
|
||||
* Wildcard (*) domains are not used for short-name inference.
|
||||
*
|
||||
* @param string $login
|
||||
* @return array{username:string,email:string}|null
|
||||
*/
|
||||
private static function resolveIdentity(string $login): ?array
|
||||
{
|
||||
$login = trim($login);
|
||||
|
||||
if($login === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$atPos = strpos($login, '@');
|
||||
|
||||
if($atPos !== false) {
|
||||
if($atPos === 0 || $atPos === strlen($login) - 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'username' => substr($login, 0, $atPos),
|
||||
'email' => $login
|
||||
];
|
||||
}
|
||||
|
||||
/*
|
||||
* For a short username, infer the mail domain from the
|
||||
* configured IMAP authenticator domains.
|
||||
*
|
||||
* This is only unambiguous when exactly one concrete
|
||||
* domain is configured.
|
||||
*/
|
||||
$stmt = go()->getDbConnection()->query(
|
||||
"SELECT DISTINCT `name`
|
||||
FROM `imapauth_server_domain`
|
||||
WHERE `name` <> '*'
|
||||
AND `name` <> ''
|
||||
ORDER BY `name`"
|
||||
);
|
||||
|
||||
$domains = $stmt->fetchAll(\PDO::FETCH_COLUMN);
|
||||
|
||||
if(count($domains) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'username' => $login,
|
||||
'email' => $login . '@' . $domains[0]
|
||||
];
|
||||
}
|
||||
|
||||
public static function isAvailableFor(string $username): bool
|
||||
{
|
||||
$identity = static::resolveIdentity($username);
|
||||
|
||||
if(!$identity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Existing Group-Office users with a local password must be
|
||||
* authenticated locally.
|
||||
*
|
||||
* This keeps local/break-glass administrator accounts such as
|
||||
* "local_admin" out of the IMAP authentication flow.
|
||||
*
|
||||
* IMAP-managed users have their local password cleared after
|
||||
* successful IMAP authentication, so they continue to use IMAP.
|
||||
*/
|
||||
$localUser = User::find()
|
||||
->where([
|
||||
'username' => $identity['username']
|
||||
])
|
||||
->single();
|
||||
|
||||
if($localUser && $localUser->hasPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return static::findServer($identity['email']) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the IMAP authentication server for an e-mail address.
|
||||
*
|
||||
* @param string $email
|
||||
* @return Server|boolean
|
||||
*/
|
||||
private static function findServer($email)
|
||||
{
|
||||
$atPos = strpos($email, '@');
|
||||
|
||||
if(!$atPos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$domain = substr($email, $atPos + 1);
|
||||
|
||||
return Server::find()
|
||||
->join(
|
||||
'imapauth_server_domain',
|
||||
'd',
|
||||
's.id = d.serverId'
|
||||
)
|
||||
->where([
|
||||
'd.name' => $domain
|
||||
])
|
||||
->orWhere([
|
||||
'd.name' => '*'
|
||||
])
|
||||
->single();
|
||||
}
|
||||
|
||||
public function authenticate(
|
||||
string $username,
|
||||
string $password
|
||||
): bool|User
|
||||
{
|
||||
$this->fireEvent(
|
||||
'beforeauthenticate',
|
||||
[$username]
|
||||
);
|
||||
|
||||
$identity = static::resolveIdentity($username);
|
||||
|
||||
if(!$identity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$localUsername = $identity['username'];
|
||||
$email = $identity['email'];
|
||||
|
||||
$server = static::findServer($email);
|
||||
|
||||
if(!$server) {
|
||||
return false;
|
||||
}
|
||||
|
||||
go()->debug(
|
||||
"Attempting IMAP authentication on " .
|
||||
$server->imapHostname
|
||||
);
|
||||
|
||||
$connection = new Connection();
|
||||
|
||||
if(!$connection->connect(
|
||||
$server->imapHostname,
|
||||
$server->imapPort,
|
||||
$server->imapEncryption == 'ssl',
|
||||
10,
|
||||
!$server->imapValidateCertificate
|
||||
)) {
|
||||
throw new Exception(
|
||||
"Could not connect to IMAP server"
|
||||
);
|
||||
}
|
||||
|
||||
if($server->imapEncryption == 'tls') {
|
||||
if(!$connection->startTLS()) {
|
||||
throw new Exception(
|
||||
"Could not enable TLS on " .
|
||||
$server->imapHostname .
|
||||
" at port " .
|
||||
$server->imapPort
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Username sent to the IMAP server.
|
||||
*
|
||||
* Remove domain from username = No
|
||||
* -> foo@example.com
|
||||
*
|
||||
* Remove domain from username = Yes
|
||||
* -> foo
|
||||
*/
|
||||
$imapUsername = $server->removeDomainFromUsername
|
||||
? $localUsername
|
||||
: $email;
|
||||
|
||||
if(!$connection->authenticate(
|
||||
$imapUsername,
|
||||
$password
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Group-Office username is the local-part.
|
||||
*/
|
||||
$user = User::find()
|
||||
->where([
|
||||
'username' => $localUsername
|
||||
])
|
||||
->single();
|
||||
|
||||
/*
|
||||
* Prevent the same short username from being associated
|
||||
* with two different e-mail addresses.
|
||||
*/
|
||||
if(
|
||||
$user &&
|
||||
strcasecmp(
|
||||
(string) $user->email,
|
||||
$email
|
||||
) !== 0
|
||||
) {
|
||||
throw new Exception(
|
||||
"Username '" .
|
||||
$localUsername .
|
||||
"' already belongs to another e-mail address"
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Migrate an account previously created by the stock
|
||||
* IMAP authenticator:
|
||||
*
|
||||
* username = foo@example.com
|
||||
* email = foo@example.com
|
||||
*
|
||||
* to:
|
||||
*
|
||||
* username = foo
|
||||
* email = foo@example.com
|
||||
*
|
||||
* The existing User ID is preserved.
|
||||
*/
|
||||
if(!$user) {
|
||||
$user = User::find()
|
||||
->where([
|
||||
'username' => $email
|
||||
])
|
||||
->single();
|
||||
|
||||
if(!$user) {
|
||||
$user = User::find()
|
||||
->where([
|
||||
'email' => $email
|
||||
])
|
||||
->single();
|
||||
}
|
||||
|
||||
if($user) {
|
||||
$user->username = $localUsername;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$user) {
|
||||
$user = $this->createUser(
|
||||
$localUsername,
|
||||
$email
|
||||
);
|
||||
} elseif($user->hasPassword()) {
|
||||
$user->clearPassword();
|
||||
}
|
||||
|
||||
foreach($server->groups as $group) {
|
||||
$user->addGroup($group->groupId);
|
||||
}
|
||||
|
||||
if($user->isModified()) {
|
||||
if(!$user->save()) {
|
||||
throw new Exception(
|
||||
"Could not save user"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronize the user's actual Email Account with the
|
||||
* global IMAP Authenticator server profile on every
|
||||
* successful login.
|
||||
*/
|
||||
$this->setEmailAccount(
|
||||
$imapUsername,
|
||||
$password,
|
||||
$email,
|
||||
$server,
|
||||
$user
|
||||
);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Group-Office user.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function createUser(
|
||||
string $username,
|
||||
string $email
|
||||
): User
|
||||
{
|
||||
$user = new User();
|
||||
|
||||
$user->displayName = $username;
|
||||
$user->username = $username;
|
||||
$user->email = $email;
|
||||
$user->recoveryEmail = $email;
|
||||
|
||||
if(!$user->save()) {
|
||||
throw new Exception(
|
||||
"Could not save user after successful IMAP login"
|
||||
);
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize the user's Email Account with the global
|
||||
* IMAP Authenticator server profile on every successful login.
|
||||
*
|
||||
* The following settings are authoritative:
|
||||
*
|
||||
* - IMAP host
|
||||
* - IMAP port
|
||||
* - IMAP encryption
|
||||
* - IMAP certificate validation
|
||||
* - IMAP username
|
||||
* - IMAP password
|
||||
* - SMTP host
|
||||
* - SMTP port
|
||||
* - SMTP encryption
|
||||
* - SMTP certificate validation
|
||||
* - SMTP authentication credentials
|
||||
*
|
||||
* User-specific mailbox, alias and other unrelated settings
|
||||
* are preserved.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function setEmailAccount(
|
||||
$username,
|
||||
$password,
|
||||
$email,
|
||||
Server $server,
|
||||
User $user
|
||||
) {
|
||||
if(!$user->hasModule('legacy', 'email')) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find all existing e-mail accounts belonging to this user.
|
||||
*
|
||||
* Do not use the configured IMAP hostname as an identifier.
|
||||
* The administrator may change the global hostname later,
|
||||
* and in that case we want to update the existing account
|
||||
* instead of creating a duplicate.
|
||||
*/
|
||||
$accounts = Account::model()
|
||||
->findByAttributes([
|
||||
'user_id' => $user->id
|
||||
])
|
||||
->fetchAll();
|
||||
|
||||
$account = null;
|
||||
|
||||
/*
|
||||
* Prefer an account whose IMAP username matches either
|
||||
* the current IMAP login username or the full e-mail
|
||||
* address.
|
||||
*/
|
||||
foreach($accounts as $candidate) {
|
||||
if(
|
||||
$candidate->username === $username ||
|
||||
$candidate->username === $email
|
||||
) {
|
||||
$account = $candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If this user has exactly one e-mail account, treat that
|
||||
* account as the one managed by the IMAP authenticator.
|
||||
*
|
||||
* This allows changes to username/hostname configuration
|
||||
* without accidentally creating a duplicate account.
|
||||
*/
|
||||
if(!$account && count($accounts) === 1) {
|
||||
$account = $accounts[0];
|
||||
}
|
||||
|
||||
$wasNew = false;
|
||||
|
||||
if(!$account) {
|
||||
$account = new Account();
|
||||
$account->user_id = $user->id;
|
||||
$account->mbroot = "";
|
||||
|
||||
$wasNew = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* IMAP Authenticator server profile is authoritative.
|
||||
*
|
||||
* Refresh IMAP configuration on every successful login.
|
||||
*/
|
||||
$account->host =
|
||||
$server->imapHostname;
|
||||
|
||||
$account->port =
|
||||
$server->imapPort;
|
||||
|
||||
$account->username =
|
||||
$username;
|
||||
|
||||
$account->password =
|
||||
$password;
|
||||
|
||||
$account->imap_encryption =
|
||||
$server->imapEncryption ?? "";
|
||||
|
||||
$account->imap_allow_self_signed =
|
||||
!$server->imapValidateCertificate;
|
||||
|
||||
/*
|
||||
* Refresh SMTP configuration from the same global
|
||||
* authentication server profile.
|
||||
*/
|
||||
$account->smtp_host =
|
||||
$server->smtpHostname;
|
||||
|
||||
$account->smtp_port =
|
||||
$server->smtpPort;
|
||||
|
||||
$account->smtp_encryption =
|
||||
$server->smtpEncryption ?? "";
|
||||
|
||||
$account->smtp_allow_self_signed =
|
||||
!$server->smtpValidateCertificate;
|
||||
|
||||
/*
|
||||
* SMTP authentication.
|
||||
*/
|
||||
if($server->smtpUseUserCredentials) {
|
||||
/*
|
||||
* Use the same credentials that successfully
|
||||
* authenticated against IMAP.
|
||||
*/
|
||||
$account->smtp_username =
|
||||
$username;
|
||||
|
||||
$account->smtp_password =
|
||||
$password;
|
||||
} else {
|
||||
/*
|
||||
* Use static SMTP credentials configured in the
|
||||
* global IMAP Authenticator server profile.
|
||||
*/
|
||||
$account->smtp_username =
|
||||
$server->smtpUsername;
|
||||
|
||||
$account->smtp_password =
|
||||
$server->getSmtpPassword();
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the resulting IMAP configuration while saving.
|
||||
*/
|
||||
$account->checkImapConnectionOnSave = true;
|
||||
|
||||
if(!$account->save(true)) {
|
||||
throw new Exception(
|
||||
"Could not save e-mail account: " .
|
||||
implode(
|
||||
"\n",
|
||||
$account->getValidationErrors()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if($wasNew) {
|
||||
$account->addAlias(
|
||||
$email,
|
||||
$user->displayName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,736 @@
|
||||
<?php
|
||||
|
||||
namespace go\core\db;
|
||||
|
||||
use Exception;
|
||||
use go\core\App;
|
||||
use go\core\orm\Property;
|
||||
use LogicException;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
use PDOStatement;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* The database connection object. It uses PDO to connect to the database.
|
||||
*
|
||||
* The app instance of this connection is available by calling:
|
||||
*
|
||||
* ````````````````````````````````````````````````````````````````````````````
|
||||
* \go\core\App::get()->getDbConnection();
|
||||
* ````````````````````````````````````````````````````````````````````````````
|
||||
*
|
||||
* @copyright (c) 2014, Intermesh BV http://www.intermesh.nl
|
||||
* @author Merijn Schering <mschering@intermesh.nl>
|
||||
* @license http://www.gnu.org/licenses/agpl-3.0.html AGPLv3
|
||||
*/
|
||||
class Connection {
|
||||
|
||||
private $dsn;
|
||||
private $username;
|
||||
private $password;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var PDO
|
||||
*/
|
||||
private $pdo;
|
||||
|
||||
/**
|
||||
* Output all SQL to the debugger
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $debug = false;
|
||||
|
||||
public function __construct($dsn, $username, $password) {
|
||||
|
||||
$initCmd = "SET character_set_client = utf8mb4,
|
||||
character_set_connection = utf8mb4,
|
||||
character_set_results = utf8mb4,
|
||||
sql_mode = 'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION',
|
||||
time_zone = '+00:00',
|
||||
lc_messages = 'en_US'";
|
||||
|
||||
$this->dsn = $dsn;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
$this->options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_PERSISTENT => false, // Unit test on closing DB connection fails. We need this to work for long running processes
|
||||
PDO::ATTR_EMULATE_PREPARES => false, //for native data types int, bool etc.
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
||||
];
|
||||
|
||||
if(version_compare(PHP_VERSION, '8.5.0') >= 0) {
|
||||
$this->options[PDO\Mysql::ATTR_USE_BUFFERED_QUERY] = true;
|
||||
$this->options[PDO\Mysql::ATTR_INIT_COMMAND] = $initCmd;
|
||||
} else {
|
||||
$this->options[PDO::MYSQL_ATTR_USE_BUFFERED_QUERY] = true;
|
||||
$this->options[PDO::MYSQL_ATTR_INIT_COMMAND] = $initCmd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Database TLS
|
||||
*
|
||||
* SSL attributes must be passed when PDO is constructed.
|
||||
*/
|
||||
if (defined('GO_DB_SSL_CA') && GO_DB_SSL_CA !== '') {
|
||||
|
||||
$verifyServerCert =
|
||||
defined('GO_DB_SSL_VERIFY_SERVER_CERT')
|
||||
? GO_DB_SSL_VERIFY_SERVER_CERT
|
||||
: true;
|
||||
|
||||
if(version_compare(PHP_VERSION, '8.5.0') >= 0) {
|
||||
$this->options[PDO\Mysql::ATTR_SSL_CA] =
|
||||
GO_DB_SSL_CA;
|
||||
|
||||
$this->options[PDO\Mysql::ATTR_SSL_VERIFY_SERVER_CERT] =
|
||||
$verifyServerCert;
|
||||
} else {
|
||||
$this->options[PDO::MYSQL_ATTR_SSL_CA] =
|
||||
GO_DB_SSL_CA;
|
||||
|
||||
$this->options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] =
|
||||
$verifyServerCert;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getDsn() {
|
||||
return $this->dsn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global database connection object.
|
||||
*
|
||||
* {@link http://php.net/manual/en/pdo.construct.php}
|
||||
*
|
||||
* @return PDO Database connection object
|
||||
*/
|
||||
public function getPDO(): PDO
|
||||
{
|
||||
if (!isset($this->pdo)) {
|
||||
$this->setPDO();
|
||||
}
|
||||
return $this->pdo;
|
||||
}
|
||||
|
||||
private $database;
|
||||
|
||||
/**
|
||||
* Get the database instance
|
||||
*
|
||||
* @return Database
|
||||
*/
|
||||
public function getDatabase(): Database
|
||||
{
|
||||
if(!isset($this->database)) {
|
||||
$this->database = new Database($this);
|
||||
}
|
||||
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the database connection. Beware that all active PDO statements must be set to null too
|
||||
* in the current scope.
|
||||
*
|
||||
* Weird things happen when using fsockopen. This test case leaves the conneciton open. When removing the fputs call it seems to work.
|
||||
*
|
||||
*
|
||||
|
||||
$settings = \GO\Sync\Model\Settings::model()->findForUser(\go\core\App::get()->user());
|
||||
$account = \GO\Email\Model\Account::model()->findByPk($settings->account_id);
|
||||
|
||||
|
||||
$handle = stream_socket_client("tcp://localhost:143");
|
||||
$login = 'A1 LOGIN "admin@intermesh.dev" "admin"'."\r\n";
|
||||
fputs($handle, $login);
|
||||
fclose($handle);
|
||||
$handle=null;
|
||||
|
||||
echo "Test\n";
|
||||
|
||||
\go\core\App::get()->unsetDbConnection();
|
||||
sleep(10);
|
||||
*/
|
||||
public function disconnect(): void
|
||||
{
|
||||
$this->pdo = null;
|
||||
|
||||
Property::clearCachedRelationStmts();
|
||||
Property::$lastDeleteStmt = null;
|
||||
self::$cachedStatements = [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if connection still exists
|
||||
*
|
||||
* @param int $id
|
||||
* @return bool
|
||||
* @throws DbException
|
||||
*/
|
||||
public static function exists(int $id) : bool {
|
||||
|
||||
$dsn = go()->getDbConnection()->getDsn();
|
||||
$config = go()->getConfig();
|
||||
|
||||
$watchConn = new Connection(
|
||||
$dsn, $config['db_user'], $config['db_pass']
|
||||
);
|
||||
$processes = $watchConn->query("SHOW PROCESSLIST")->fetchAll(\PDO::FETCH_ASSOC);
|
||||
|
||||
foreach($processes as $process) {
|
||||
if($process['Id'] == $id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static array $cachedStatements = [];
|
||||
|
||||
/**
|
||||
* Register a cached statement that will be unset when we want to disconnect from the database.
|
||||
* If you don't unset these statement the connection will be kept open.
|
||||
* @param string $name
|
||||
* @param Statement $statement
|
||||
* @return void
|
||||
*/
|
||||
public function cacheStatement(string $name, Statement $statement): void
|
||||
{
|
||||
self::$cachedStatements[$name] = $statement;
|
||||
}
|
||||
|
||||
public function getCachedStatment(string $name) : ?Statement {
|
||||
return self::$cachedStatements[$name] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set's a new PDO object base on the current connection settings
|
||||
*/
|
||||
private function setPDO() {
|
||||
$this->pdo = null;
|
||||
$this->pdo = new PDO($this->dsn, $this->username, $this->password, $this->options);
|
||||
// go()->debug("PDO Driver: " . $this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION));
|
||||
// if (strpos($this->pdo->getAttribute(PDO::ATTR_CLIENT_VERSION), 'mysqlnd') !== false) {
|
||||
// echo 'PDO MySQLnd enabled!';
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get MySQL connection ID
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getId() : int {
|
||||
return (int) $this->query("select connection_id()")->fetch(PDO::FETCH_COLUMN, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an SQL string
|
||||
*
|
||||
* Should be properly escaped!
|
||||
* {@link http://php.net/manual/en/pdo.query.php}
|
||||
*
|
||||
* @param string $sql
|
||||
* @return PDOStatement
|
||||
* @throws DbException
|
||||
*/
|
||||
public function query(string $sql): PDOStatement
|
||||
{
|
||||
if($this->debug) {
|
||||
go()->getDebugger()->debug($sql, 1 ,false);
|
||||
}
|
||||
try {
|
||||
return $this->getPdo()->query($sql);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
throw new DbException($e, $sql);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an SQL statement and return the number of affected rows
|
||||
* <p><b>PDO::exec()</b> executes an SQL statement in a single function call, returning the number of rows affected by the statement.</p><p><b>PDO::exec()</b> does not return results from a SELECT statement. For a SELECT statement that you only need to issue once during your program, consider issuing <code>PDO::query()</code>. For a statement that you need to issue multiple times, prepare a PDOStatement object with <code>PDO::prepare()</code> and issue the statement with <code>PDOStatement::execute()</code>.</p>
|
||||
* @param string $sql <p>The SQL statement to prepare and execute.</p> <p>Data inside the query should be properly escaped.</p>
|
||||
* @return int <p><b>PDO::exec()</b> returns the number of rows that were modified or deleted by the SQL statement you issued. If no rows were affected, <b>PDO::exec()</b> returns <i>0</i>.</p><p><b>Warning</b></p><p>This function may return Boolean <b><code>FALSE</code></b>, but may also return a non-Boolean value which evaluates to <b><code>FALSE</code></b>. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.</p><p>The following example incorrectly relies on the return value of <b>PDO::exec()</b>, wherein a statement that affected 0 rows results in a call to <code>die()</code>:</p> <code> <?php<br>$db->exec() or die(print_r($db->errorInfo(), true)); // incorrect<br>?> </code>
|
||||
* @link http://php.net/manual/en/pdo.exec.php
|
||||
*
|
||||
* @throws DbException
|
||||
*/
|
||||
public function exec(string $sql): int
|
||||
{
|
||||
if($this->debug) {
|
||||
go()->getDebugger()->debug($sql, 1, true);
|
||||
}
|
||||
try {
|
||||
return $this->getPdo()->exec($sql);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
throw new DbException($e, $sql);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* UNLOCK TABLES explicitly releases any table locks held by the current session
|
||||
*/
|
||||
public function unlockTables(): bool
|
||||
{
|
||||
return $this->getPdo()->exec("UNLOCK TABLES") !== false;
|
||||
}
|
||||
|
||||
private $transactionSavePointLevel = 0;
|
||||
|
||||
/**
|
||||
* Start a database transation
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function beginTransaction(): bool
|
||||
{
|
||||
if($this->transactionSavePointLevel == 0) {
|
||||
$ret = $this->getPdo()->beginTransaction();
|
||||
|
||||
}else
|
||||
{
|
||||
$ret = true;
|
||||
}
|
||||
|
||||
$this->transactionSavePointLevel++;
|
||||
|
||||
if($this->debug) {
|
||||
go()->debug("beginTransaction " . $this->transactionSavePointLevel, 1);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private $resumeLevels = 0;
|
||||
|
||||
public function isPaused(): bool
|
||||
{
|
||||
return $this->resumeLevels > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits the transaction but remembers the nesting of transaction nesting level. Must be resumed with resumeTransactions().
|
||||
* This is used by custom fields that do database structure changes. MySQL commits transactions automatically when the database
|
||||
* structure changes.
|
||||
*
|
||||
*/
|
||||
public function pauseTransactions() {
|
||||
if($this->isPaused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->resumeLevels = $this->transactionSavePointLevel;
|
||||
while($this->transactionSavePointLevel > 0) {
|
||||
$this->commit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see pauseTransactions()
|
||||
*/
|
||||
public function resumeTransactions() {
|
||||
while($this->resumeLevels > 0) {
|
||||
$this->beginTransaction();
|
||||
$this->resumeLevels--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rollback the DB transaction
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function rollBack(): bool
|
||||
{
|
||||
if($this->transactionSavePointLevel == 0) {
|
||||
throw new LogicException("Not in transaction!");
|
||||
}
|
||||
|
||||
$this->transactionSavePointLevel--;
|
||||
|
||||
if($this->debug) {
|
||||
go()->warn("ROLLBACK DB TRANSACTION " . $this->transactionSavePointLevel, 1);
|
||||
}
|
||||
|
||||
if($this->transactionSavePointLevel == 0) {
|
||||
return $this->getPdo()->rollBack();
|
||||
}else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the database transaction
|
||||
*
|
||||
* @return boolean
|
||||
* @throws PDOException
|
||||
*/
|
||||
public function commit(): bool
|
||||
{
|
||||
if($this->transactionSavePointLevel == 0) {
|
||||
throw new PDOException("Not in transaction!");
|
||||
}
|
||||
|
||||
$this->transactionSavePointLevel--;
|
||||
|
||||
if($this->debug) {
|
||||
go()->debug("COMMIT DB TRANSACTION " . $this->transactionSavePointLevel, 1);
|
||||
}
|
||||
|
||||
|
||||
if($this->transactionSavePointLevel == 0) {
|
||||
return $this->getPdo()->commit();
|
||||
}else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a transaction is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function inTransaction(): bool
|
||||
{
|
||||
return $this->getPdo()->inTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the table of this model and also for the 't' alias.
|
||||
*
|
||||
* The locks array should be indexed by model name and the value is an array with two optional values.
|
||||
* THe first is a boolean that enables a write-lock and the second is a table alias.
|
||||
*
|
||||
* @param array $locks eg. [go\cores\Users\Model\User::tableName() => [true, 't']]
|
||||
*
|
||||
* @throws PDOException
|
||||
*/
|
||||
public function lock(array $locks)
|
||||
{
|
||||
$sql = "LOCK TABLES ";
|
||||
|
||||
foreach ($locks as $tableName => $lockInfo) {
|
||||
$sql .= $tableName . " ";
|
||||
|
||||
if (isset($lockInfo[1])) {
|
||||
$sql .= ' AS ' . $lockInfo[1] . ' ';
|
||||
}
|
||||
$sql .= empty($lockInfo[0]) ? 'READ' : 'WRITE';
|
||||
|
||||
$sql .= ', ';
|
||||
}
|
||||
|
||||
$sql = rtrim($sql, ', ');
|
||||
|
||||
App::get()->getDbConnection()->exec($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a delete statement
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param Query|array|string|null $query
|
||||
* @return Statement
|
||||
* @example
|
||||
* ```
|
||||
* $success = App::get()
|
||||
* ->getDbConnection()
|
||||
* ->delete("test_a", ['id' => 1])
|
||||
* ->execute();
|
||||
* ```
|
||||
*/
|
||||
public function delete(string $tableName, $query = null): Statement
|
||||
{
|
||||
$query = Query::normalize($query);
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildDelete($tableName, $query);
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an insert statement
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param array|Query $data Key value array, a numeric array with key value arrays or select query
|
||||
* @param string[] $columns If $data is a query object then you can supply the
|
||||
* selected columns with this parameter. If not given all columns must be
|
||||
* selected in the correct order.
|
||||
*
|
||||
* @return Statement
|
||||
* @throws PDOException
|
||||
* @example Single record
|
||||
* ```
|
||||
* $data = [
|
||||
* "propA" => "string 1",
|
||||
* "createdAt" => new \DateTime(),
|
||||
* "modifiedAt" => new \DateTime()
|
||||
* ];
|
||||
*
|
||||
* $result = App::get()
|
||||
* ->getDbConnection()
|
||||
* ->insert("test_a", $data)
|
||||
* ->execute();
|
||||
* ```
|
||||
*
|
||||
* Get the ID if it has an auto increment column:
|
||||
* ```
|
||||
* $id = App::get()->getDbConnection()->getPDO()->lastInsertId();
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @example Multiple records
|
||||
* ```
|
||||
* $data = [[
|
||||
* "propA" => "string 1",
|
||||
* "createdAt" => new \DateTime(),
|
||||
* "modifiedAt" => new \DateTime()
|
||||
* ],[
|
||||
* "propA" => "string 2",
|
||||
* "createdAt" => new \DateTime(),
|
||||
* "modifiedAt" => new \DateTime()
|
||||
* ]];
|
||||
*
|
||||
* $result = App::get()
|
||||
* ->getDbConnection()
|
||||
* ->insert("test_a", $data)
|
||||
* ->execute();
|
||||
* ```
|
||||
*
|
||||
* Or with an expression:
|
||||
*
|
||||
* ```
|
||||
* App::get()->getDbConnection()
|
||||
* ->update("core_state", new \go\core\db\Expression("highestModSeq = highestModSeq + 1"), $query);
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
public function insert(string $tableName, $data, array $columns = []): Statement
|
||||
{
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildInsert($tableName, $data, $columns);
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert data in the database and ignore if the records exist
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param array|Query $data Key value array or select query
|
||||
* @param string[] $columns If $data is a query object then you can supply the
|
||||
* selected columns with this parameter. If not given all columns must be
|
||||
* selected in the correct order.
|
||||
*
|
||||
* @return Statement
|
||||
* @throws DbException
|
||||
* @see insert()
|
||||
*/
|
||||
public function insertIgnore(string $tableName, Query|array $data, array $columns = []): Statement
|
||||
{
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildInsert($tableName, $data, $columns, "INSERT IGNORE");
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace data in the database
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param array|Query $data Key value array, array of key value arrays for multi insert or select query
|
||||
* @param string[] $columns If $data is a query object then you can supply the
|
||||
* selected columns with this parameter. If not given all columns must be
|
||||
* selected in the correct order.
|
||||
*
|
||||
* @return Statement
|
||||
* @throws Throwable
|
||||
* @see insert()
|
||||
*/
|
||||
public function replace(string $tableName, Query|array $data, array $columns = []): Statement
|
||||
{
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildInsert($tableName, $data, $columns, "REPLACE");
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an update statement
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param $data
|
||||
* @param Query|string|array|null $query {@see Query::normalize()}
|
||||
* @return Statement
|
||||
* @throws PDOException
|
||||
* @example with join
|
||||
* ```
|
||||
* go()->getDbConnection()->update(
|
||||
* 'core_acl',
|
||||
* [
|
||||
* 'acl.entityTypeId' => $entityTypeId,
|
||||
* 'acl.entityId' => new Expression('ab.id')], // Use go\core\db\Expression for references to tables
|
||||
* (new Query())
|
||||
* ->tableAlias('acl') // set alias for core_acl table
|
||||
* ->join('addressbook_addressbook, 'ab', 'ab.aclId = acl.id'))
|
||||
* ->execute();
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* $data = [
|
||||
* "propA" => "string 3",
|
||||
* "count" => new \go\core\db\Expression('count + 1'), //Example for expression
|
||||
* ];
|
||||
*
|
||||
* $stmt = App::get()->getDbConnection()->update("test_a", $data, ['id' => 1]);
|
||||
* $stmt->execute();
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
public function update(string $tableName, $data, Criteria|array|string|null $query = null): Statement
|
||||
{
|
||||
$query = Query::normalize($query);
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildUpdate($tableName, $data, $query);
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update but with ignore
|
||||
*
|
||||
* @param $tableName
|
||||
* @param $data
|
||||
* @param Criteria|array|string|null $query
|
||||
* @return Statement
|
||||
* @throws Exception
|
||||
* @see update()
|
||||
*/
|
||||
public function updateIgnore($tableName, $data, Criteria|array|string|null $query = null): Statement
|
||||
{
|
||||
$query = Query::normalize($query);
|
||||
|
||||
$queryBuilder = new QueryBuilder($this);
|
||||
$build = $queryBuilder->buildUpdate($tableName, $data, $query, "UPDATE IGNORE");
|
||||
|
||||
return $this->createStatement($build);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a select statement.
|
||||
*
|
||||
* @param string|string[] $select
|
||||
* @return Query
|
||||
* @example
|
||||
* ```
|
||||
* $query = go()->getDbConnection()
|
||||
* ->select('*')
|
||||
* ->from('test_a')
|
||||
* ->where('id', '=', 1);
|
||||
*
|
||||
* $stmt = $query->execute();
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* @see Query
|
||||
*/
|
||||
public function select(array|string $select = "*"): Query
|
||||
{
|
||||
$query = new Query();
|
||||
return $query->setDbConnection($this)->select($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a single column or count(*) for example.
|
||||
*
|
||||
* Shortcut for:
|
||||
* $query->fetchMode(\PDO::FETCH_COLUMN,0)->select($select)
|
||||
*
|
||||
* @param string $select
|
||||
* @return Query
|
||||
*/
|
||||
public function selectSingleValue(string $select): Query
|
||||
{
|
||||
$query = new Query();
|
||||
return $query->setDbConnection($this)->selectSingleValue($select);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a statement from a QueryBuilder result.
|
||||
*
|
||||
* For internal use of the API.
|
||||
*
|
||||
* @param array $build
|
||||
* @return Statement
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createStatement(array &$build): Statement
|
||||
{
|
||||
try {
|
||||
if($this->debug) {
|
||||
$build['start'] = go()->getDebugger()->getMicroTime();
|
||||
}
|
||||
|
||||
$pdoStmt = $this->getPDO()->prepare($build['sql']);
|
||||
|
||||
$stmt = new Statement($pdoStmt);
|
||||
$stmt->setBuild($build);
|
||||
|
||||
for ($i =0, $l = count($build['params']); $i < $l; $i++) {
|
||||
$stmt->bindValue($i + 1, $build['params'][$i]['value'], $build['params'][$i]['pdoType']);
|
||||
}
|
||||
|
||||
return $stmt;
|
||||
} catch(PDOException $e) {
|
||||
throw new DbException($e, go()->getDebugger()->enabled ? QueryBuilder::debugBuild($build) : null);
|
||||
} catch(Exception $e) {
|
||||
if(go()->getDebugger()->enabled) {
|
||||
go()->debug(QueryBuilder::debugBuild($build));
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get or set foreign key checks
|
||||
*
|
||||
* @param bool|null $value Provide to set new value
|
||||
* @return bool The current or old value
|
||||
* @throws DbException
|
||||
*/
|
||||
public function foreignKeyChecks(bool|null $value = null): bool
|
||||
{
|
||||
$stmt = $this->query("SELECT @@SESSION.foreign_key_checks");
|
||||
$current = !!$stmt->fetch(PDO::FETCH_COLUMN, 0);
|
||||
|
||||
if(isset($value) && $value != $current) {
|
||||
$this->exec("set foreign_key_checks = " . ($value ? "1" : "0") . ";");
|
||||
}
|
||||
|
||||
return $current;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
require "docker-config.php";
|
||||
|
||||
$config['db_port'] = 3306;
|
||||
|
||||
/*
|
||||
* Database TLS
|
||||
*/
|
||||
$config['db_ssl_ca'] = "/etc/ssl/groupoffice/{{ root_cert_filename }}";
|
||||
$config['db_ssl_verify_server_cert'] = true;
|
||||
|
||||
/*
|
||||
* Connection.php is instantiated while the application is being initialized.
|
||||
* Export DB TLS settings as constants to avoid calling App::get() recursively
|
||||
* from the Connection constructor.
|
||||
*/
|
||||
if (!defined('GO_DB_SSL_CA')) {
|
||||
define('GO_DB_SSL_CA', $config['db_ssl_ca']);
|
||||
}
|
||||
|
||||
if (!defined('GO_DB_SSL_VERIFY_SERVER_CERT')) {
|
||||
define(
|
||||
'GO_DB_SSL_VERIFY_SERVER_CERT',
|
||||
$config['db_ssl_verify_server_cert']
|
||||
);
|
||||
}
|
||||
|
||||
$config['file_storage_path'] = "/var/lib/groupoffice";
|
||||
$config['tmpdir'] = "/tmp/groupoffice";
|
||||
$config['debug'] = false;
|
||||
$config['business'] = array (
|
||||
'studio' =>
|
||||
array (
|
||||
'package' => 'studio',
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
require('../vendor/autoload.php');
|
||||
use go\core\App;
|
||||
use go\core\fs\Folder;
|
||||
use go\core\util\IniFile;
|
||||
|
||||
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
|
||||
|
||||
$dbConnectError = null;
|
||||
$pdo = null;
|
||||
/**
|
||||
*
|
||||
* @global PDO $pdo
|
||||
* @param type $config
|
||||
* @return PDO
|
||||
*/
|
||||
function dbConnect($config){
|
||||
global $pdo, $dbConnectError;
|
||||
if(isset($pdo)) {
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
$dsn = go()->createDsn($config['db_name'] ?? "groupoffice", $config);
|
||||
/*
|
||||
* Database TLS
|
||||
*/
|
||||
$options = [];
|
||||
|
||||
if (!empty($config['db_ssl_ca'])) {
|
||||
$verifyServerCert =
|
||||
$config['db_ssl_verify_server_cert'] ?? true;
|
||||
|
||||
if (version_compare(PHP_VERSION, '8.5.0') >= 0) {
|
||||
$options[PDO\Mysql::ATTR_SSL_CA] =
|
||||
$config['db_ssl_ca'];
|
||||
|
||||
$options[PDO\Mysql::ATTR_SSL_VERIFY_SERVER_CERT] =
|
||||
$verifyServerCert;
|
||||
} else {
|
||||
$options[PDO::MYSQL_ATTR_SSL_CA] =
|
||||
$config['db_ssl_ca'];
|
||||
|
||||
$options[PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT] =
|
||||
$verifyServerCert;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
$pdo = new PDO(
|
||||
$dsn,
|
||||
$config['db_user'],
|
||||
$config['db_pass'],
|
||||
$options
|
||||
);
|
||||
}
|
||||
/*
|
||||
* Database TLS
|
||||
*/
|
||||
catch(Exception $e){
|
||||
$dbConnectError = "Could not connect to the database with DSN = '" . $dsn . "' with username '" . ($config['db_user'] ?? "groupoffice") . " and " . (empty($config['db_pass']) ? "NOT using password" : "USING a password") . ". The database returned this error:<br />".$e->getMessage();
|
||||
}
|
||||
|
||||
if($pdo) {
|
||||
$clientVersion = $pdo->getAttribute(PDO::ATTR_CLIENT_VERSION);
|
||||
if (strpos($clientVersion, 'mysqlnd') === false) {
|
||||
$dbConnectError = "PDO is not using the mysqlnd driver. Please make sure PDO uses mysqlnd. It's now using: " . $clientVersion;
|
||||
$pdo = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $pdo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
$configFile = App::findConfigFile();
|
||||
if(!$configFile) {
|
||||
$configFile = '/etc/groupoffice/config.php';
|
||||
} else
|
||||
{
|
||||
require($configFile);
|
||||
}
|
||||
|
||||
$mustSave = false;
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] != 'POST')
|
||||
{
|
||||
|
||||
$config['file_storage_path'] = $config['file_storage_path'] ?? "/var/lib/groupoffice";
|
||||
$config['tmpdir'] = $config['tmpdir'] ?? "/tmp/groupoffice";
|
||||
|
||||
//check if config.ini is already prefilled with usable data (Docker)
|
||||
$tmpFolder = new Folder($config['tmpdir']);
|
||||
$dataFolder = new Folder($config['file_storage_path']);
|
||||
if(!$dataFolder->isWritable() && isset($_SERVER['DOCUMENT_ROOT'])) {
|
||||
$dataFolder = new Folder(dirname($_SERVER['DOCUMENT_ROOT']) . '/groupoffice');
|
||||
$mustSave = true;
|
||||
}
|
||||
|
||||
if(dbConnect($config) && $dataFolder->isWritable() && $tmpFolder->isWritable() && !$mustSave) {
|
||||
header("Location: install.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$_POST['dbPort'] = $config['db_port'] ?? 3306;
|
||||
$_POST['dbHostname'] = $config['db_host'] ?? 'localhost';
|
||||
$_POST['dbName'] = $config['db_name'] ?? "groupoffice";
|
||||
|
||||
$_POST['dbUsername'] = $config['db_user'] ?? "groupoffice";
|
||||
//$_POST['dbPassword'] = $config['db']['password'];
|
||||
} else
|
||||
{
|
||||
// $config['general']['dataPath'] = $_POST['dataPath'];
|
||||
// $config['general']['tmpPath'] = $_POST['tmpPath'];
|
||||
// $config['db']['dsn'] = 'mysql:host='.$_POST['dbHostname'].';port='.$_POST['dbPort'].';dbname='.$_POST['dbName'];
|
||||
// $config['db']['username'] = $_POST['dbUsername'];
|
||||
// $config['db']['password'] = $_POST['dbPassword'];
|
||||
|
||||
$config['file_storage_path'] = $_POST['dataPath'];
|
||||
$config['tmpdir'] = $_POST['tmpPath'];
|
||||
$config['db_host'] =$_POST['dbHostname'];
|
||||
$config['db_name'] =$_POST['dbName'];
|
||||
$config['db_user'] =$_POST['dbUsername'];
|
||||
$config['db_pass'] =$_POST['dbPassword'];
|
||||
$config['db_port'] =$_POST['dbPort'];
|
||||
|
||||
$tmpFolder = new Folder($config['tmpdir']);
|
||||
$dataFolder = new Folder($config['file_storage_path']);
|
||||
|
||||
|
||||
if($dataFolder->isWritable() && $tmpFolder->isWritable() && dbConnect($config)) {
|
||||
$cFile = new \go\core\fs\File($configFile);
|
||||
|
||||
if(!$cFile->putContents("<?php\n\n\$config = ".var_export($config, true) .";\n\n")) {
|
||||
$configError = "Could not write config.php";
|
||||
} else
|
||||
{
|
||||
if(function_exists("opcache_invalidate")) {
|
||||
opcache_invalidate($cFile->getPath());
|
||||
}
|
||||
|
||||
header('Location: install.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
require('header.php');
|
||||
?>
|
||||
|
||||
<?php
|
||||
try {
|
||||
$isWritable = is_writable($configFile);
|
||||
} catch(Throwable $e) {
|
||||
//open basedir restriction
|
||||
$isWritable = false;
|
||||
}
|
||||
if(!$isWritable):
|
||||
|
||||
?>
|
||||
|
||||
<section>
|
||||
<fieldset>
|
||||
<h2><?= go()->t("Config file"); ?></h2>
|
||||
<p class="error">Please create a writeable config.php file here: <?= $configFile; ?>.</p>
|
||||
</fieldset>
|
||||
</section>
|
||||
|
||||
|
||||
<?php endif ?>
|
||||
|
||||
<section>
|
||||
<form method="POST" action="" onsubmit="submitButton.disabled = true;">
|
||||
|
||||
|
||||
<fieldset>
|
||||
<h2>Data storage</h2>
|
||||
|
||||
<p>
|
||||
Please create a folder for storing Group-Office files and a temporary files folder and make sure the webserver user can write to these folders.
|
||||
</p>
|
||||
|
||||
<?php
|
||||
if(!$dataFolder->isWritable()) {
|
||||
echo '<p class="error">Not writable</p>';
|
||||
}
|
||||
?>
|
||||
|
||||
<p>
|
||||
<input type="text" name="dataPath" value="<?= htmlspecialchars($dataFolder->getPath()) ?>" placeholder="" required />
|
||||
<label>Data folder</label>
|
||||
</p>
|
||||
|
||||
|
||||
<?php
|
||||
if(!$tmpFolder->isWritable()) {
|
||||
echo '<p class="error">Not writable</p>';
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<input type="text" name="tmpPath" value="<?= htmlspecialchars($config['tmpdir']); ?>" placeholder="Temp folder" required />
|
||||
<label>Temp folder</label>
|
||||
</p>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<h2>Configure the database</h2>
|
||||
|
||||
<?php
|
||||
if(isset($config['db_host']) && !dbConnect($config)) {
|
||||
echo '<p class="error">'.$dbConnectError.'</p>';
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label>Database user</label>
|
||||
<input type="text" name="dbUsername" value="<?= htmlspecialchars($_POST['dbUsername'] ?? "groupoffice"); ?>" required />
|
||||
</p>
|
||||
<p>
|
||||
<label>Database password</label>
|
||||
<input type="password" name="dbPassword" value="<?= htmlspecialchars($_POST['dbPassword'] ?? "");?>" required />
|
||||
</p>
|
||||
<p>
|
||||
<label>Database name</label>
|
||||
<input type="text" name="dbName" value="<?= htmlspecialchars($_POST['dbName'] ?? "groupoffice");?>" required />
|
||||
</p>
|
||||
<p>
|
||||
<label>Database hostname</label>
|
||||
<input type="text" name="dbHostname" value="<?= htmlspecialchars($_POST['dbHostname'] ?? "localhost");?>" required />
|
||||
</p>
|
||||
<p>
|
||||
<label>Database port</label>
|
||||
<input type="text" name="dbPort" value="<?= htmlspecialchars($_POST['dbPort'] ?? 3306); ?>" required />
|
||||
</p>
|
||||
|
||||
<button class="primary right" name="submitButton"><?= go()->t('Continue'); ?></button>
|
||||
</fieldset>
|
||||
|
||||
|
||||
</form>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<?php require('footer.php'); ?>
|
||||
@@ -0,0 +1,2 @@
|
||||
openssl.cafile=/etc/ssl/groupoffice/{{ root_cert_filename }}
|
||||
openssl.capath=/etc/ssl/certs
|
||||
@@ -0,0 +1,41 @@
|
||||
[Quadlet]
|
||||
DefaultDependencies=false
|
||||
|
||||
[Unit]
|
||||
Description=GroupOffice
|
||||
|
||||
[Container]
|
||||
Image=docker.io/intermesh/groupoffice:{{ version['containers']['groupoffice'] }}
|
||||
|
||||
ContainerName=groupoffice
|
||||
HostName=groupoffice
|
||||
|
||||
PublishPort={{ services['groupoffice']['ports']['http'] }}:80/tcp
|
||||
|
||||
Volume=%h/data/containers/groupoffice/data:/var/lib/groupoffice:rw
|
||||
Volume=%h/containers/groupoffice/ssl/{{ root_cert_filename }}:/etc/ssl/groupoffice/{{ root_cert_filename }}:ro
|
||||
# Keep the official image intact.
|
||||
Volume=%h/containers/groupoffice/config/config.php:/etc/groupoffice/config.php:ro
|
||||
Volume=%h/containers/groupoffice/config/groupoffice-ca.ini:/usr/local/etc/php/conf.d/99-groupoffice-ca.ini:ro
|
||||
Volume=%h/containers/groupoffice/config/Authenticator.php:/usr/local/share/groupoffice/go/modules/community/imapauthenticator/model/Authenticator.php:ro
|
||||
Volume=%h/containers/groupoffice/config/db_Connection.php:/usr/local/share/groupoffice/go/core/db/Connection.php:ro
|
||||
Volume=%h/containers/groupoffice/config/configfile.php:/usr/local/share/groupoffice/install/configfile.php:ro
|
||||
|
||||
Environment="TZ={{ timezone }}"
|
||||
|
||||
# GroupOffice official Docker DB configuration
|
||||
Environment="MYSQL_HOST={{ services['mariadb']['domain']['internal'] }}.{{ domain['internal'] }}"
|
||||
Environment="MYSQL_DATABASE=groupoffice_db"
|
||||
Environment="MYSQL_USER=groupoffice"
|
||||
Secret=GROUPOFFICE_DB_PASSWORD,type=env,target=MYSQL_PASSWORD
|
||||
|
||||
[Service]
|
||||
ExecStartPre=/usr/bin/nc -zv {{ services['mariadb']['domain']['internal'] }}.{{ domain['internal'] }} {{ services['mariadb']['ports']['tcp'] }}
|
||||
ExecStartPre=/usr/bin/nc -zv {{ services['maddy']['domain']['internal'] }}.{{ domain['internal'] }} 993
|
||||
ExecStartPost=-/usr/bin/podman exec -u www-data groupoffice php /usr/local/share/groupoffice/cli.php core/System/upgrade
|
||||
Restart=always
|
||||
RestartSec=10s
|
||||
TimeoutStopSec=120
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user