From 283b8d98635a6427cbeecdb175e2f7a47293c968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Fra=C3=9F?= Date: Thu, 9 Oct 2025 01:36:32 +0200 Subject: [PATCH 01/11] [add] tool:cfg-man --- tools/cfg-man | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100755 tools/cfg-man diff --git a/tools/cfg-man b/tools/cfg-man new file mode 100755 index 0000000..6aa543b --- /dev/null +++ b/tools/cfg-man @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 + +import os as _os +import sys as _sys +import json as _json +import argparse as _argparse + + +def convey( + x, + fs +): + y = x + for f in fs: + y = f(y) + return y + + +def file_read( + path +): + handle = open(path, "r") + content = handle.read() + handle.close() + return content + + +class interface_option(object): + def is_filled(self): + raise NotImplementedError() + def cull(self): + raise NotImplementedError() + def propagate(self, function): + raise NotImplementedError() + + +class class_option_empty(interface_option): + def __init__(self): + pass + def is_filled(self): + return False + def cull(self): + raise ValueError("cull from empty") + def propagate(self, function): + return class_option_empty() + + +class class_option_filled(interface_option): + def __init__(self, value): + self.value = value + def is_filled(self): + return True + def cull(self): + return self.value + def propagate(self, function): + return function(self.value) + + +def generate_defaults( + schema_node +): + if ("anyOf" in schema_node): + ## todo: o'rly? + return generate_defaults(schema_node["anyOf"][0]) + else: + if (not ("type" in schema_node)): + raise ValueError(":?") + else: + if (not (schema_node["type"] == "object")): + if (not ("default" in schema_node)): + return class_option_empty() + else: + return class_option_filled(schema_node["default"]) + else: + result = {} + for (key, value, ) in schema_node["properties"].items(): + sub_result = generate_defaults(value) + if (not sub_result.is_filled()): + pass + else: + result[key] = sub_result.cull() + return class_option_filled(result) + + +def generate_overrides( + schema_node +): + if ("anyOf" in schema_node): + ## todo: o'rly? + return generate_overrides(schema_node["anyOf"][0]) + else: + if (not ("type" in schema_node)): + raise ValueError(":?") + else: + if (not (schema_node["type"] == "object")): + if ("default" in schema_node): + return class_option_empty() + else: + if ("enum" in schema_node): + return class_option_filled(schema_node["enum"][0]) + else: + if (schema_node.get("nullable", False)): + return class_option_filled(None) + else: + if (schema_node["type"] == "boolean"): + return class_option_filled(False) + elif (schema_node["type"] == "integer"): + return class_option_filled(0) + elif (schema_node["type"] == "number"): + return class_option_filled(0) + elif (schema_node["type"] == "string"): + return class_option_filled("") + else: + raise ValueError("unhandled type: %s" % schema_node["type"]) + else: + result = {} + for (key, value, ) in schema_node["properties"].items(): + sub_result = generate_overrides(value) + if (not sub_result.is_filled()): + pass + else: + result[key] = sub_result.cull() + return ( + class_option_empty() + if (len(result) <= 0) else + class_option_filled(result) + ) + + +def role_name_derive( + role_name +): + return role_name.replace("-", "_") + + +def main( +): + ## args + argument_parser = _argparse.ArgumentParser() + argument_parser.add_argument( + "action", + type = str, + choices = [ + "defaults", + "overrides", + ], + metavar = "", + ) + argument_parser.add_argument( + "role", + type = str, + metavar = "", + ) + args = argument_parser.parse_args() + + ## exec + cfg_schema = convey( + args.role, + [ + lambda x: _os.path.join("roles", x, "cfg.schema.json"), + file_read, + _json.loads, + ] + ) + if args.action == "defaults": + raw = generate_defaults(cfg_schema) + key = ("cfg_%s_defaults" % (role_name_derive(args.role))) + result = {key: (raw.cull() if raw.is_filled() else {})} + _sys.stdout.write(_json.dumps(result, indent = "\t") + "\n") + elif args.action == "overrides": + raw = generate_overrides(cfg_schema) + key = ("cfg_%s_overrides" % (role_name_derive(args.role))) + result = {key: (raw.cull() if raw.is_filled() else {})} + _sys.stdout.write(_json.dumps(result, indent = "\t") + "\n") + else: + raise ValueError("invalid action: %s" % args.action) + + +main() From 5d1b1908a5d45d2cd8ccd0773874621ef9edf808 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:41:40 +0200 Subject: [PATCH 02/11] [task-406] tlscert_selfsigned --- roles/tlscert_selfsigned/cfg.schema.json | 14 ++++++++++++ roles/tlscert_selfsigned/defaults/main.json | 3 ++- roles/tlscert_selfsigned/tasks/main.json | 25 +++++++++++++-------- 3 files changed, 32 insertions(+), 10 deletions(-) create mode 100644 roles/tlscert_selfsigned/cfg.schema.json diff --git a/roles/tlscert_selfsigned/cfg.schema.json b/roles/tlscert_selfsigned/cfg.schema.json new file mode 100644 index 0000000..c06145c --- /dev/null +++ b/roles/tlscert_selfsigned/cfg.schema.json @@ -0,0 +1,14 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "domain": { + "nullable": false, + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "domain" + ] +} diff --git a/roles/tlscert_selfsigned/defaults/main.json b/roles/tlscert_selfsigned/defaults/main.json index 06c1a9a..9fe02ee 100644 --- a/roles/tlscert_selfsigned/defaults/main.json +++ b/roles/tlscert_selfsigned/defaults/main.json @@ -1,3 +1,4 @@ { - "var_tlscert_selfsigned_domain": "foo.example.org" + "cfg_tlscert_selfsigned_defaults": { + } } diff --git a/roles/tlscert_selfsigned/tasks/main.json b/roles/tlscert_selfsigned/tasks/main.json index bed8255..cbe8ea6 100644 --- a/roles/tlscert_selfsigned/tasks/main.json +++ b/roles/tlscert_selfsigned/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_tlscert_selfsigned" + } + }, { "name": "install packages", "become": true, @@ -28,19 +35,19 @@ "name": "csr | generate private key", "become": true, "community.crypto.openssl_privatekey": { - "path": "/etc/ssl/private/{{var_tlscert_selfsigned_domain}}.pem" + "path": "/etc/ssl/private/{{cfg_tlscert_selfsigned.domain}}.pem" } }, { "name": "csr | execute", "become": true, "community.crypto.openssl_csr": { - "privatekey_path": "/etc/ssl/private/{{var_tlscert_selfsigned_domain}}.pem", - "common_name": "{{var_tlscert_selfsigned_domain}}", + "privatekey_path": "/etc/ssl/private/{{cfg_tlscert_selfsigned.domain}}.pem", + "common_name": "{{cfg_tlscert_selfsigned.domain}}", "subject_alt_name": [ - "DNS:{{var_tlscert_selfsigned_domain}}" + "DNS:{{cfg_tlscert_selfsigned.domain}}" ], - "path": "/etc/ssl/csr/{{var_tlscert_selfsigned_domain}}.pem" + "path": "/etc/ssl/csr/{{cfg_tlscert_selfsigned.domain}}.pem" }, "register": "temp_csr" }, @@ -48,17 +55,17 @@ "name": "generate certificate", "become": true, "community.crypto.x509_certificate": { - "privatekey_path": "/etc/ssl/private/{{var_tlscert_selfsigned_domain}}.pem", - "csr_path": "/etc/ssl/csr/{{var_tlscert_selfsigned_domain}}.pem", + "privatekey_path": "/etc/ssl/private/{{cfg_tlscert_selfsigned.domain}}.pem", + "csr_path": "/etc/ssl/csr/{{cfg_tlscert_selfsigned.domain}}.pem", "provider": "selfsigned", - "path": "/etc/ssl/certs/{{var_tlscert_selfsigned_domain}}.pem" + "path": "/etc/ssl/certs/{{cfg_tlscert_selfsigned.domain}}.pem" } }, { "name": "compose fullchain", "become": true, "ansible.builtin.shell": { - "cmd": "cat /etc/ssl/certs/{{var_tlscert_selfsigned_domain}}.pem > /etc/ssl/fullchains/{{var_tlscert_selfsigned_domain}}.pem" + "cmd": "cat /etc/ssl/certs/{{cfg_tlscert_selfsigned.domain}}.pem > /etc/ssl/fullchains/{{cfg_tlscert_selfsigned.domain}}.pem" } } ] From fb931da668a3107d171889d46d8d098744d1d9d7 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:42:26 +0200 Subject: [PATCH 03/11] [task-406] nginx --- roles/nginx/cfg.schema.json | 28 +++++++ roles/nginx/defaults/main.json | 6 +- roles/nginx/tasks/main.json | 81 ++++++++++++--------- roles/nginx/templates/ssl-hardening.conf.j2 | 20 +++++ 4 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 roles/nginx/cfg.schema.json create mode 100644 roles/nginx/templates/ssl-hardening.conf.j2 diff --git a/roles/nginx/cfg.schema.json b/roles/nginx/cfg.schema.json new file mode 100644 index 0000000..13a8fcb --- /dev/null +++ b/roles/nginx/cfg.schema.json @@ -0,0 +1,28 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "auto_reload_interval": { + "nullable": true, + "type": "integer", + "description": "in hours", + "default": null + }, + "dhparam_size": { + "nullable": true, + "type": "integer", + "default": null + }, + "improved_security": { + "nullable": false, + "type": "boolean", + "default": false + } + }, + "additionalProperties": false, + "required": [ + "auto_reload_interval", + "dhparam_size", + "improved_security" + ] +} diff --git a/roles/nginx/defaults/main.json b/roles/nginx/defaults/main.json index 997702e..e59898d 100644 --- a/roles/nginx/defaults/main.json +++ b/roles/nginx/defaults/main.json @@ -1,3 +1,7 @@ { - "var_nginx_auto_reload_interval": null + "cfg_nginx_defaults": { + "auto_reload_interval": null, + "dhparam_size": null, + "improved_security": false + } } diff --git a/roles/nginx/tasks/main.json b/roles/nginx/tasks/main.json index 9748e6d..b03c46c 100644 --- a/roles/nginx/tasks/main.json +++ b/roles/nginx/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_nginx" + } + }, { "name": "install packages", "become": true, @@ -12,9 +19,10 @@ }, { "name": "generate dhparams file", + "when": "cfg_nginx.dhparam_size != None", "become": true, "ansible.builtin.command": { - "cmd": "openssl dhparam -out /etc/nginx/dhparam 4096" + "cmd": "openssl dhparam -out /etc/nginx/dhparam {{cfg_nginx.dhparam_size | string}}" }, "args": { "creates": "/etc/nginx/dhparam" @@ -23,49 +31,54 @@ { "name": "place hardening config", "become": true, - "ansible.builtin.copy": { - "src": "ssl-hardening.conf", + "ansible.builtin.template": { + "src": "ssl-hardening.conf.j2", "dest": "/etc/nginx/ssl-hardening.conf" } }, { - "name": "ufw | check", - "become": true, - "check_mode": true, - "community.general.ufw": { - "state": "enabled" - }, - "register": "ufw_enable_check" - }, - { - "name": "ufw | allow port 80", - "when": "not ufw_enable_check.changed", - "become": true, - "community.general.ufw": { - "rule": "allow", - "port": "80", - "proto": "tcp" - } - }, - { - "name": "ufw | allow port 443", - "when": "not ufw_enable_check.changed", - "become": true, - "community.general.ufw": { - "rule": "allow", - "port": "443", - "proto": "tcp" - } + "name": "ufw", + "block": [ + { + "name": "check", + "become": true, + "check_mode": true, + "community.general.ufw": { + "state": "enabled" + }, + "register": "ufw_enable_check" + }, + { + "name": "allow port 80", + "when": "not ufw_enable_check.changed", + "become": true, + "community.general.ufw": { + "rule": "allow", + "port": "80", + "proto": "tcp" + } + }, + { + "name": "allow port 443", + "when": "not ufw_enable_check.changed", + "become": true, + "community.general.ufw": { + "rule": "allow", + "port": "443", + "proto": "tcp" + } + } + ] }, { "name": "auto reload", - "when": "var_nginx_auto_reload_interval == None", + "when": "cfg_nginx.auto_reload_interval == None", "become": true, "ansible.builtin.cron": { "name": "nginx_auto_reload", "disabled": true, "minute": "0", - "hour": "*/{{var_nginx_auto_reload_interval | string}}", + "hour": "*/{{cfg_nginx.auto_reload_interval | string}}", "day": "*", "month": "*", "weekday": "*", @@ -74,13 +87,13 @@ }, { "name": "auto reload", - "when": "var_nginx_auto_reload_interval != None", + "when": "cfg_nginx.auto_reload_interval != None", "become": true, "ansible.builtin.cron": { "name": "nginx_auto_reload", "disabled": false, "minute": "0", - "hour": "*/{{var_nginx_auto_reload_interval | string}}", + "hour": "*/{{cfg_nginx.auto_reload_interval | string}}", "day": "*", "month": "*", "weekday": "*", diff --git a/roles/nginx/templates/ssl-hardening.conf.j2 b/roles/nginx/templates/ssl-hardening.conf.j2 new file mode 100644 index 0000000..26d4e15 --- /dev/null +++ b/roles/nginx/templates/ssl-hardening.conf.j2 @@ -0,0 +1,20 @@ +ssl_session_timeout 1d; +ssl_session_cache shared:MozSSL:10m; # about 40000 sessions +ssl_session_tickets off; + +# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam +{% if cfg_nginx.dhparam_size != None %} +ssl_dhparam /etc/nginx/dhparam; +{% endif %} + +# intermediate configuration +ssl_protocols TLSv1.2 TLSv1.3; +ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; +ssl_prefer_server_ciphers off; + +# HSTS (ngx_http_headers_module is required) (63072000 seconds) +add_header Strict-Transport-Security "max-age=63072000" always; + +# OCSP stapling +ssl_stapling on; +ssl_stapling_verify on; From e0f485e556925ec7a10234039451c1b637749221 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:43:49 +0200 Subject: [PATCH 04/11] [task-406] authelia --- roles/authelia/cfg.schema.json | 449 +++++++++++++++++++++ roles/authelia/defaults/main.json | 80 ++-- roles/authelia/tasks/main.json | 216 +++++----- roles/authelia/templates/conf-main.json.j2 | 75 ++-- roles/authelia/vardef.json | 169 -------- 5 files changed, 651 insertions(+), 338 deletions(-) create mode 100644 roles/authelia/cfg.schema.json delete mode 100644 roles/authelia/vardef.json diff --git a/roles/authelia/cfg.schema.json b/roles/authelia/cfg.schema.json new file mode 100644 index 0000000..30ca12f --- /dev/null +++ b/roles/authelia/cfg.schema.json @@ -0,0 +1,449 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "listen_address": { + "nullable": false, + "type": "string", + "default": "0.0.0.0" + }, + "domain": { + "nullable": false, + "type": "string" + }, + "session_domain": { + "nullable": false, + "type": "string" + }, + "redirect_url": { + "nullable": false, + "type": "string" + }, + "jwt_secret": { + "nullable": false, + "type": "string" + }, + "session_secret": { + "nullable": false, + "type": "string" + }, + "storage_encryption_key": { + "nullable": false, + "type": "string" + }, + "users_file_path": { + "nullable": false, + "type": "string", + "default": "/var/authelia/users.yml" + }, + "log_file_path": { + "nullable": false, + "type": "string", + "default": "/var/authelia/log.jsonl" + }, + "storage": { + "anyOf": [ + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["sqlite"], + "default": "sqlite" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "path": { + "nullable": false, + "type": "string", + "default": "/var/authelia/state.db" + } + }, + "additionalProperties": false, + "required": [ + "path" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ], + "default": { + } + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["postgresql"] + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "host": { + "nullable": false, + "type": "string", + "ddefault": "localhost" + }, + "port": { + "nullable": false, + "type": "integer", + "default": 5432 + }, + "username": { + "nullable": false, + "type": "string", + "default": "authelia_user" + }, + "password": { + "nullable": false, + "type": "string" + }, + "schema": { + "nullable": false, + "type": "string", + "default": "authelia" + } + }, + "additionalProperties": false, + "required": [ + "host", + "port", + "username", + "password", + "schema" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ], + "default": { + } + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["mariadb"] + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "host": { + "nullable": false, + "type": "string", + "ddefault": "localhost" + }, + "port": { + "nullable": false, + "type": "integer", + "default": 3306 + }, + "username": { + "nullable": false, + "type": "string", + "default": "authelia_user" + }, + "password": { + "nullable": false, + "type": "string" + }, + "schema": { + "nullable": false, + "type": "string", + "default": "authelia" + } + }, + "additionalProperties": false, + "required": [ + "host", + "port", + "username", + "password", + "schema" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ], + "default": { + } + } + ] + }, + "ntp_server": { + "nullable": false, + "type": "string", + "default": "time.cloudflare.com:123" + }, + "password_reset": { + "nullable": false, + "type": "object", + "properties": { + "enabled": { + "nullable": false, + "type": "boolean", + "default": false + }, + "custom_url": { + "nullable": true, + "type": "string", + "default": null + } + }, + "additionalProperties": false, + "required": [ + "enabled", + "custom_url" + ], + "default": { + } + }, + "notification": { + "anyOf": [ + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["file"], + "default": "file" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "path": { + "nullable": false, + "type": "string", + "default": "/var/authelia/notifications" + } + }, + "additionalProperties": false, + "required": [ + "path" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ], + "default": { + } + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["smtp"], + "default": "smtp" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "host": { + "nullable": false, + "type": "string" + }, + "port": { + "nullable": false, + "type": "integer", + "default": 465 + }, + "username": { + "nullable": false, + "type": "string", + "default": "authelia" + }, + "password": { + "nullable": false, + "type": "string" + }, + "sender": { + "nullable": false, + "type": "string", + "default": "authelia@example.org" + } + }, + "additionalProperties": false, + "required": [ + "host", + "port", + "username", + "password", + "sender" + ] + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ], + "default": { + } + } + ] + }, + "oidc": { + "nullable": false, + "type": "object", + "properties": { + "hmac_secret": { + "nullable": false, + "type": "string" + }, + "lifespan": { + "nullable": false, + "type": "object", + "properties": { + "default": { + "nullable": false, + "type": "object", + "properties": { + "access_token": { + "nullable": false, + "type": "string", + "default": "1h" + }, + "refresh_token": { + "nullable": false, + "type": "string", + "default": "1m" + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }, + "custom": { + "nullable": false, + "type": "object", + "properties": { + }, + "additionalProperties": { + "nullable": false, + "type": "object", + "properties": { + "access_token": { + "nullable": false, + "type": "string" + }, + "refresh_token": { + "nullable": false, + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "access_token", + "refresh_token" + ] + }, + "required": [ + ], + "default": { + "long": { + "access_token": "2d", + "refresh_token": "3d" + } + } + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }, + "cors_endpoints": { + "nullable": true, + "type": "array", + "items": { + "nullable": false, + "type": "string", + "enum": [ + "authorization", + "pushed-authorization-request", + "token", + "revocation", + "introspection", + "userinfo" + ] + }, + "default": [ + "authorization", + "token", + "revocation", + "introspection", + "userinfo" + ] + } + }, + "additionalProperties": false, + "required": [ + "hmac_secret", + "lifespan", + "cors_endpoints" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "listen_address", + "domain", + "session_domain", + "redirect_url", + "jwt_secret", + "session_secret", + "storage_encryption_key", + "users_file_path", + "log_file_path", + "storage", + "ntp_server", + "notification", + "oidc" + ], + "default": { + } +} diff --git a/roles/authelia/defaults/main.json b/roles/authelia/defaults/main.json index 04a1f7f..6b9e1f9 100644 --- a/roles/authelia/defaults/main.json +++ b/roles/authelia/defaults/main.json @@ -1,39 +1,45 @@ { - "var_authelia_version": "4.37.5", - "var_authelia_architecture": "amd64", - "var_authelia_listen_address": "0.0.0.0", - "var_authelia_jwt_secret": "REPLACE_ME", - "var_authelia_users_file_path": "/var/authelia/users.yml", - "var_authelia_log_file_path": "/var/authelia/log.jsonl", - "var_authelia_domain": "authelia.example.org", - "var_authelia_redirect_url": "https://example.org", - "var_authelia_session_domain": "example.org", - "var_authelia_session_secret": "REPLACE_ME", - "var_authelia_storage_encryption_key": "REPLACE_ME", - "var_authelia_storage_kind": "sqlite", - "var_authelia_storage_data_sqlite_path": "/var/authelia/state.db", - "var_authelia_storage_data_postgresql_host": "localhost", - "var_authelia_storage_data_postgresql_port": 5432, - "var_authelia_storage_data_postgresql_username": "authelia_user", - "var_authelia_storage_data_postgresql_password": "REPLACE_ME", - "var_authelia_storage_data_postgresql_schema": "authelia", - "var_authelia_storage_data_mariadb_host": "localhost", - "var_authelia_storage_data_mariadb_port": 3306, - "var_authelia_storage_data_mariadb_username": "authelia_user", - "var_authelia_storage_data_mariadb_password": "REPLACE_ME", - "var_authelia_storage_data_mariadb_schema": "authelia", - "var_authelia_ntp_server": "time.cloudflare.com:123", - "var_authelia_password_reset_enabled": false, - "var_authelia_password_reset_custom_url": null, - "var_authelia_notification_mode": "smtp", - "var_authelia_notification_file_path": "/var/authelia/notifications", - "var_authelia_notification_smtp_host": "smtp.example.org", - "var_authelia_notification_smtp_port": 465, - "var_authelia_notification_smtp_username": "authelia", - "var_authelia_notification_smtp_password": "REPLACE_ME", - "var_authelia_notification_smtp_sender": "authelia@example.org", - "var_authelia_oidc_hmac_secret": "REPLACE_ME", - "var_authelia_oidc_lifespan_access_token": "1h", - "var_authelia_oidc_lifespan_refresh_token": "1m", - "var_authelia_oidc_cors_endpoints": null + "cfg_authelia_defaults": { + "listen_address": "0.0.0.0", + "users_file_path": "/var/authelia/users.yml", + "log_file_path": "/var/authelia/log.jsonl", + "storage": { + "kind": "sqlite", + "data": { + "path": "/var/authelia/state.db" + } + }, + "ntp_server": "time.cloudflare.com:123", + "password_reset": { + "enabled": false, + "custom_url": null + }, + "notification": { + "kind": "file", + "data": { + "path": "/var/authelia/notifications" + } + }, + "oidc": { + "lifespan": { + "default": { + "access_token": "1d", + "refresh_token": "1h" + }, + "custom": { + "long": { + "access_token": "2d", + "refresh_token": "3d" + } + } + }, + "cors_endpoints": [ + "authorization", + "token", + "revocation", + "introspection", + "userinfo" + ] + } + } } diff --git a/roles/authelia/tasks/main.json b/roles/authelia/tasks/main.json index 3ae8267..6502607 100644 --- a/roles/authelia/tasks/main.json +++ b/roles/authelia/tasks/main.json @@ -1,45 +1,57 @@ [ { - "name": "packages | prerequisites", - "become": true, - "ansible.builtin.apt": { - "update_cache": true, - "pkg": [ - "apt-transport-https", - "ca-certificates", - "gpg" - ] + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_authelia" } }, { - "name": "packages | keys", - "become": true, - "ansible.builtin.get_url": { - "url": "https://www.authelia.com/keys/authelia-security.gpg", - "dest": "/usr/share/keyrings/authelia-security.gpg" - } - }, - { - "name": "packages | repository", - "become": true, - "ansible.builtin.shell": { - "cmd": "echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/authelia-security.gpg] https://apt.authelia.com stable main\" > /etc/apt/sources.list.d/authelia.list", - "creates": "/etc/apt/sources.list.d/authelia.list" - } + "name": "packages", + "block": [ + { + "name": "prerequisites", + "become": true, + "ansible.builtin.apt": { + "update_cache": true, + "pkg": [ + "apt-transport-https", + "ca-certificates", + "gpg" + ] + } + }, + { + "name": "keys", + "become": true, + "ansible.builtin.get_url": { + "url": "https://www.authelia.com/keys/authelia-security.gpg", + "dest": "/usr/share/keyrings/authelia-security.gpg" + } + }, + { + "name": "repository", + "become": true, + "ansible.builtin.shell": { + "cmd": "echo \"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/authelia-security.gpg] https://apt.authelia.com stable main\" > /etc/apt/sources.list.d/authelia.list", + "creates": "/etc/apt/sources.list.d/authelia.list" + } - }, - { - "name": "packages | installation", - "become": true, - "ansible.builtin.apt": { - "update_cache": true, - "pkg": [ - "openssl", - "python3-cryptography", - "python3-yaml", - "authelia" - ] - } + }, + { + "name": "installation", + "become": true, + "ansible.builtin.apt": { + "update_cache": true, + "pkg": [ + "openssl", + "python3-cryptography", + "python3-yaml", + "authelia" + ] + } + } + ] }, { "name": "generate private key for signing OIDC JWTs", @@ -53,74 +65,88 @@ "register": "temp_tls_result" }, { - "name": "configuration | compose script", - "become": true, - "ansible.builtin.copy": { - "src": "conf-compose.py", - "dest": "/usr/bin/authelia-conf-compose", - "mode": "0700" - } - }, - { - "name": "configuration | directories", - "become": true, - "loop": [ - "/etc/authelia/conf.d", - "/etc/authelia/conf.d/clients" - ], - "ansible.builtin.file": { - "state": "directory", - "path": "{{item}}" - } - }, - { - "name": "configuration | main", - "become": true, - "ansible.builtin.template": { - "src": "conf-main.json.j2", - "dest": "/etc/authelia/conf.d/main.json" - } - }, - { - "name": "configuration | compose", - "become": true, - "ansible.builtin.command": { - "cmd": "/usr/bin/authelia-conf-compose --main-file-path=/etc/authelia/conf.d/main.json --clients-directory-path=/etc/authelia/conf.d/clients --output-format=yaml --output-path=/etc/authelia/configuration.yml" - } + "name": "configuration", + "block": [ + { + "name": "configuration | compose script", + "become": true, + "ansible.builtin.copy": { + "src": "conf-compose.py", + "dest": "/usr/bin/authelia-conf-compose", + "mode": "0700" + } + }, + { + "name": "configuration | directories", + "become": true, + "loop": [ + "/etc/authelia/conf.d", + "/etc/authelia/conf.d/clients" + ], + "ansible.builtin.file": { + "state": "directory", + "path": "{{item}}" + } + }, + { + "name": "configuration | main", + "become": true, + "ansible.builtin.template": { + "src": "conf-main.json.j2", + "dest": "/etc/authelia/conf.d/main.json" + } + }, + { + "name": "configuration | compose", + "become": true, + "ansible.builtin.command": { + "cmd": "/usr/bin/authelia-conf-compose --main-file-path=/etc/authelia/conf.d/main.json --clients-directory-path=/etc/authelia/conf.d/clients --output-format=yaml --output-path=/etc/authelia/configuration.yml" + } + } + ] }, { "name": "setup log directory", "become": true, "ansible.builtin.file": { "state": "directory", - "path": "{{var_authelia_log_file_path | dirname}}" + "owner": "authelia", + "group": "authelia", + "path": "{{cfg_authelia.log_file_path | dirname}}" } }, { - "name": "users | directory", - "become": true, - "ansible.builtin.file": { - "state": "directory", - "path": "{{var_authelia_users_file_path | dirname}}" - } - }, - { - "name": "users | initial file", - "become": true, - "ansible.builtin.template": { - "src": "users.yml.j2", - "dest": "{{var_authelia_users_file_path}}", - "force": false - } - }, - { - "name": "users | management script", - "become": true, - "ansible.builtin.copy": { - "src": "user-manage.py", - "dest": "/usr/bin/authelia-user-manage", - "mode": "0700" - } + "name": "users", + "block": [ + { + "name": "directory", + "become": true, + "ansible.builtin.file": { + "state": "directory", + "owner": "authelia", + "group": "authelia", + "path": "{{cfg_authelia.users_file_path | dirname}}" + } + }, + { + "name": "initial file", + "become": true, + "ansible.builtin.template": { + "src": "users.yml.j2", + "dest": "{{cfg_authelia.users_file_path}}", + "force": false + } + }, + { + "name": "management script", + "become": true, + "ansible.builtin.copy": { + "src": "user-manage.py", + "dest": "/usr/bin/authelia-user-manage", + "mode": "0700" + } + } + ] }, { "name": "apply", diff --git a/roles/authelia/templates/conf-main.json.j2 b/roles/authelia/templates/conf-main.json.j2 index 84a4214..eee90ef 100644 --- a/roles/authelia/templates/conf-main.json.j2 +++ b/roles/authelia/templates/conf-main.json.j2 @@ -2,12 +2,12 @@ "theme": "auto", "identity_validation": { "reset_password": { - "jwt_secret": "{{var_authelia_jwt_secret}}" + "jwt_secret": "{{cfg_authelia.jwt_secret}}" } }, "default_2fa_method": "totp", "server": { - "address": "{{var_authelia_listen_address}}:9091", + "address": "{{cfg_authelia.listen_address}}:9091", "endpoints": { "enable_pprof": false, "enable_expvars": false @@ -17,7 +17,7 @@ "log": { "level": "info", "format": "json", - "file_path": "{{var_authelia_log_file_path}}", + "file_path": "{{cfg_authelia.log_file_path}}", "keep_stdout": false }, "telemetry": { @@ -43,7 +43,7 @@ "user_verification": "preferred" }, "ntp": { - "address": "{{var_authelia_ntp_server}}", + "address": "{{cfg_authelia.ntp_server}}", "version": 4, "max_desync": "3s", "disable_startup_check": false, @@ -51,16 +51,16 @@ }, "authentication_backend": { "password_reset": { -{% if var_authelia_password_reset_enabled %} +{% if cfg_authelia.password_reset.enabled %} "disable": false, {% else %} "disable": true, {% endif %} - "custom_url": "{{var_authelia_password_reset_custom_url}}" + "custom_url": {{cfg_authelia.password_reset.custom_url | to_json}} }, "refresh_interval": "5m", "file": { - "path": "{{var_authelia_users_file_path}}", + "path": "{{cfg_authelia.users_file_path}}", "watch": true, "search": { "email": false, @@ -121,15 +121,15 @@ "session": { "name": "authelia_session", "same_site": "lax", - "secret": "{{var_authelia_session_secret}}", + "secret": "{{cfg_authelia.session_secret}}", "expiration": "1h", "inactivity": "5m", "remember_me": "1M", "cookies": [ { - "domain": "{{var_authelia_session_domain}}", - "authelia_url": "https://{{var_authelia_domain}}/", - "default_redirection_url": "{{var_authelia_redirect_url}}" + "domain": "{{cfg_authelia.session_domain}}", + "authelia_url": "https://{{cfg_authelia.domain}}/", + "default_redirection_url": "{{cfg_authelia.redirect_url}}" } ] }, @@ -139,44 +139,44 @@ "ban_time": "5m" }, "storage": { - "encryption_key": "{{var_authelia_storage_encryption_key}}", -{% if var_authelia_storage_kind == "sqlite" %} + "encryption_key": "{{cfg_authelia.storage_encryption_key}}", +{% if cfg_authelia.storage.kind == "sqlite" %} "local": { - "path": "{{var_authelia_storage_data_sqlite_path}}" + "path": "{{cfg_authelia.storage.data.path}}" } {% endif %} -{% if var_authelia_storage_kind == "postgresql" %} +{% if cfg_authelia.storage.kind == "postgresql" %} "postgres": { - "address": "{{var_authelia_storage_data_postgresql_host}}:{{var_authelia_storage_data_postgresql_port | string}}", + "address": "{{cfg_authelia.storage.data.host}}:{{cfg_authelia.storage.data.port | string}}", "schema": "public", - "username": "{{var_authelia_storage_data_postgresql_username}}", - "password": "{{var_authelia_storage_data_postgresql_password}}", - "database": "{{var_authelia_storage_data_postgresql_schema}}" + "username": "{{cfg_authelia.storage.data.username}}", + "password": "{{cfg_authelia.storage.data.password}}", + "database": "{{cfg_authelia.storage.data.schema}}" } {% endif %} -{% if var_authelia_storage_kind == "mariadb" %} +{% if cfg_authelia.storage.kind == "mariadb" %} "mysql": { - "host": "{{var_authelia_storage_data_mariadb_host}}", - "port": {{var_authelia_storage_data_mariadb_port | string}}, - "username": "{{var_authelia_storage_data_mariadb_username}}", - "password": "{{var_authelia_storage_data_mariadb_password}}", - "database": "{{var_authelia_storage_data_mariadb_schema}}" + "host": "{{cfg_authelia.storage.data.host}}", + "port": {{cfg_authelia.storage.data.port | string}}, + "username": "{{cfg_authelia.storage.data.username}}", + "password": "{{cfg_authelia.storage.data.password}}", + "database": "{{cfg_authelia.storage.data.schema}}" } {% endif %} }, "notifier": { "disable_startup_check": true, -{% if var_authelia_notification_mode == "file" %} +{% if cfg_authelia.notification.kind == "file" %} "filesystem": { - "filename": "{{var_authelia_notification_file_path}}" + "filename": "{{cfg_authelia.notification.data.path}}" } {% endif %} -{% if var_authelia_notification_mode == "smtp" %} +{% if cfg_authelia.notification.kind == "smtp" %} "smtp": { - "address": "{{var_authelia_notification_smtp_host}}:{{var_authelia_notification_smtp_port | string}}", - "username": "{{var_authelia_notification_smtp_username}}", - "password": "{{var_authelia_notification_smtp_password}}", - "sender": "{{var_authelia_notification_smtp_sender}}", + "address": "{{cfg_authelia.notification.data.host}}:{{cfg_authelia.notification.data.port | string}}", + "username": "{{cfg_authelia.notification.data.username}}", + "password": "{{cfg_authelia.notification.data.password}}", + "sender": "{{cfg_authelia.notification.data.sender}}", "disable_require_tls": false, "disable_html_emails": false, "tls": { @@ -187,7 +187,7 @@ }, "identity_providers": { "oidc": { - "hmac_secret": "{{var_authelia_oidc_hmac_secret}}", + "hmac_secret": "{{cfg_authelia.oidc.hmac_secret}}", "jwks": [ { "algorithm": "RS256", @@ -195,14 +195,15 @@ } ], "lifespans": { - "access_token": "{{var_authelia_oidc_lifespan_access_token}}", - "refresh_token": "{{var_authelia_oidc_lifespan_refresh_token}}" + "access_token": "{{cfg_authelia.oidc.lifespan.default.access_token}}", + "refresh_token": "{{cfg_authelia.oidc.lifespan.default.refresh_token}}", + "custom": {{cfg_authelia.oidc.lifespan.custom | to_json}} }, "cors": { "allowed_origins_from_client_redirect_uris": true -{% if var_authelia_oidc_cors_endpoints == None %} +{% if cfg_authelia.oidc.cors_endpoints == None %} {% else %} - ,"endpoints": {{var_authelia_oidc_cors_endpoints | to_json}} + ,"endpoints": {{cfg_authelia.oidc.cors_endpoints | to_json}} {% endif %} }, "clients": [ diff --git a/roles/authelia/vardef.json b/roles/authelia/vardef.json deleted file mode 100644 index 9b651a1..0000000 --- a/roles/authelia/vardef.json +++ /dev/null @@ -1,169 +0,0 @@ -{ - "version": { - "type": "string", - "mandatory": false - }, - "architecture": { - "type": "string", - "mandatory": false - }, - "listen_address": { - "type": "string", - "mandatory": false - }, - "jwt_secret": { - "type": "string", - "mandatory": true - }, - "users_file_path": { - "type": "string", - "mandatory": false - }, - "log_file_path": { - "type": "string", - "mandatory": false - }, - "domain": { - "type": "string", - "mandatory": false - }, - "redirect_url": { - "type": "string", - "mandatory": false - }, - "session_domain": { - "type": "string", - "mandatory": false - }, - "session_secret": { - "type": "string", - "mandatory": true - }, - "storage_encryption_key": { - "type": "string", - "mandatory": true - }, - "storage_kind": { - "type": "string", - "mandatory": false - }, - "storage_data_sqlite_path": { - "type": "string", - "mandatory": false - }, - "storage_data_postgresql_host": { - "type": "string", - "mandatory": false - }, - "storage_data_postgresql_port": { - "type": "integer", - "mandatory": false - }, - "storage_data_postgresql_username": { - "type": "string", - "mandatory": false - }, - "storage_data_postgresql_password": { - "type": "string", - "mandatory": false - }, - "storage_data_postgresql_schema": { - "type": "string", - "mandatory": false - }, - "storage_data_mariadb_host": { - "type": "string", - "mandatory": false - }, - "storage_data_mariadb_port": { - "type": "integer", - "mandatory": false - }, - "storage_data_mariadb_username": { - "type": "string", - "mandatory": false - }, - "storage_data_mariadb_password": { - "type": "string", - "mandatory": false - }, - "storage_data_mariadb_schema": { - "type": "string", - "mandatory": false - }, - "ntp_server": { - "type": "string", - "mandatory": false - }, - "password_reset_enabled": { - "type": "boolean", - "mandatory": false - }, - "password_reset_custom_url": { - "nullable": true, - "type": "string", - "mandatory": false - }, - "notification_mode": { - "type": "string", - "mandatory": false, - "options": [ - "file", - "smtp" - ] - }, - "notification_file_path": { - "type": "string", - "mandatory": false - }, - "notification_smtp_host": { - "type": "string", - "mandatory": false - }, - "notification_smtp_port": { - "type": "integer", - "mandatory": false - }, - "notification_smtp_username": { - "type": "string", - "mandatory": false - }, - "notification_smtp_password": { - "type": "string", - "mandatory": false - }, - "notification_smtp_sender": { - "type": "string", - "mandatory": false - }, - "oidc_hmac_secret": { - "type": "string", - "mandatory": true - }, - "oidc_lifespan_access_token": { - "nullable": true, - "type": "string", - "mandatory": false - }, - "oidc_lifespan_refresh_token": { - "nullable": true, - "type": "string", - "mandatory": false - }, - "oidc_cors_endpoints": { - "nullable": true, - "type": "array", - "items": { - "type": "string", - "enum": [ - "authorization", - "pushed-authorization-request", - "token", - "revocation", - "introspection", - "userinfo" - ] - }, - "mandatory": false - } -} From 59510fb415b40b04b3413be2aca97d4c7763d51b Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:44:12 +0200 Subject: [PATCH 05/11] [task-406] nginx --- roles/nginx/vardef.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 roles/nginx/vardef.json diff --git a/roles/nginx/vardef.json b/roles/nginx/vardef.json deleted file mode 100644 index c03ddc6..0000000 --- a/roles/nginx/vardef.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "auto_reload_interval": { - "description": "in hours", - "nullable": true, - "type": "integer", - "mandatory": false - } -} From df9f32ad02da9d70813b27449ad077d1e95265ba Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:45:22 +0200 Subject: [PATCH 06/11] [task-406] hedgedoc --- roles/hedgedoc/cfg.schema.json | 248 +++++++++++++++++++++++ roles/hedgedoc/defaults/main.json | 39 ++-- roles/hedgedoc/tasks/main.json | 46 ++++- roles/hedgedoc/templates/config.json.j2 | 48 ++--- roles/hedgedoc/templates/systemd-unit.j2 | 4 +- roles/hedgedoc/vardef.json | 87 -------- 6 files changed, 333 insertions(+), 139 deletions(-) create mode 100644 roles/hedgedoc/cfg.schema.json delete mode 100644 roles/hedgedoc/vardef.json diff --git a/roles/hedgedoc/cfg.schema.json b/roles/hedgedoc/cfg.schema.json new file mode 100644 index 0000000..d2dc549 --- /dev/null +++ b/roles/hedgedoc/cfg.schema.json @@ -0,0 +1,248 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "user_name": { + "nullable": false, + "type": "string", + "default": "hedgedoc" + }, + "directory": { + "nullable": false, + "type": "string", + "default": "/opt/hedgedoc" + }, + "version": { + "nullable": false, + "type": "string", + "default": "1.10.3" + }, + "domain": { + "nullable": false, + "type": "string" + }, + "session_secret": { + "nullable": false, + "type": "string" + }, + "database": { + "anyOf": [ + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["sqlite"], + "default": "sqlite" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "path": { + "nullable": false, + "type": "string", + "default": "/var/hedgedoc/data.sqlite" + } + }, + "additionalProperties": false, + "required": [ + "path" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["postgresql"], + "default": "postgresql" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "host": { + "nullable": false, + "type": "string", + "default": "localhost" + }, + "port": { + "nullable": false, + "type": "integer", + "default": 5432 + }, + "username": { + "nullable": false, + "type": "string", + "default": "hedgedoc_user" + }, + "password": { + "nullable": false, + "type": "string" + }, + "schema": { + "nullable": false, + "type": "string", + "default": "hedgedoc" + } + }, + "additionalProperties": false, + "required": [ + "host", + "port", + "username", + "password", + "schema" + ] + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + } + ] + }, + "authentication": { + "anyOf": [ + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["internal"], + "default": "internal" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "nullable": false, + "type": "string", + "enum": ["authelia"], + "default": "authelia" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "url_base": { + "nullable": false, + "type": "string" + }, + "client_id": { + "nullable": false, + "type": "string", + "default": "hedgedoc" + }, + "client_secret": { + "nullable": false, + "type": "string" + }, + "provider_name": { + "nullable": false, + "type": "string", + "default": "Authelia" + } + }, + "additionalProperties": false, + "required": [ + "url_base", + "client_id", + "client_secret", + "provider_name" + ] + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + } + ] + }, + "guest_allow_create": { + "nullable": false, + "type": "boolean", + "default": false + }, + "guest_allow_change": { + "nullable": false, + "type": "boolean", + "default": false + }, + "free_names_mode": { + "nullable": false, + "type": "string", + "enum": [ + "never", + "authed", + "always" + ], + "default": "authed" + }, + "log_level": { + "nullable": false, + "type": "string", + "enum": [ + "debug", + "verbose", + "info", + "warn", + "error" + ], + "default": "error" + } + }, + "additionalProperties": false, + "required": [ + "user_name", + "directory", + "version", + "domain", + "session_secret", + "database", + "authentication", + "guest_allow_create", + "guest_allow_change", + "free_names_mode", + "log_level" + ] +} diff --git a/roles/hedgedoc/defaults/main.json b/roles/hedgedoc/defaults/main.json index 5dc2820..9f2da1f 100644 --- a/roles/hedgedoc/defaults/main.json +++ b/roles/hedgedoc/defaults/main.json @@ -1,21 +1,22 @@ { - "var_hedgedoc_user_name": "hedgedoc", - "var_hedgedoc_directory": "/opt/hedgedoc", - "var_hedgedoc_version": "1.9.9", - "var_hedgedoc_session_secret": "REPLACE_ME", - "var_hedgedoc_database_kind": "sqlite", - "var_hedgedoc_database_data_sqlite_path": "/var/hedgedoc/data.sqlite", - "var_hedgedoc_database_data_postgresql_host": "localhost", - "var_hedgedoc_database_data_postgresql_port": 5432, - "var_hedgedoc_database_data_postgresql_username": "hedgedoc_user", - "var_hedgedoc_database_data_postgresql_password": "REPLACE_ME", - "var_hedgedoc_database_data_postgresql_schema": "hedgedoc", - "var_hedgedoc_domain": "hedgedoc.example.org", - "var_hedgedoc_authentication_kind": "internal", - "var_hedgedoc_authentication_data_authelia_client_id": "hedgedoc", - "var_hedgedoc_authentication_data_authelia_client_secret": "REPLACE_ME", - "var_hedgedoc_authentication_data_authelia_url_base": "https://authelia.example.org", - "var_hedgedoc_guest_allow_create": false, - "var_hedgedoc_guest_allow_change": false, - "var_hedgedoc_free_names_mode": "authed" + "cfg_hedgedoc_defaults": { + "user_name": "hedgedoc", + "directory": "/opt/hedgedoc", + "version": "1.10.3", + "database": { + "kind": "sqlite", + "data": { + "path": "/var/hedgedoc/data.sqlite" + } + }, + "authentication": { + "kind": "internal", + "data": { + } + }, + "guest_allow_create": false, + "guest_allow_change": false, + "free_names_mode": "authed", + "log_level": "error" + } } diff --git a/roles/hedgedoc/tasks/main.json b/roles/hedgedoc/tasks/main.json index 5347cc1..6b03c33 100644 --- a/roles/hedgedoc/tasks/main.json +++ b/roles/hedgedoc/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_hedgedoc" + } + }, { "name": "packages", "become": true, @@ -26,16 +33,41 @@ "name": "user", "become": true, "ansible.builtin.user": { - "name": "{{var_hedgedoc_user_name}}", + "name": "{{cfg_hedgedoc.user_name}}", "create_home": true, - "home": "{{var_hedgedoc_directory}}" + "home": "{{cfg_hedgedoc.directory}}" } }, + { + "name": "database", + "when": "cfg_hedgedoc.database.kind == 'sqlite'", + "block": [ + { + "name": "database | directory", + "become": true, + "ansible.builtin.file": { + "state": "directory", + "path": "{{cfg_hedgedoc.database.data.sqlite.path | dirname}}", + "owner": "{{cfg_hedgedoc.user_name}}" + } + }, + { + "name": "database | file", + "become": true, + "ansible.builtin.file": { + "state": "touch", + "path": "{{cfg_hedgedoc.database.data.sqlite.path}}", + "owner": "{{cfg_hedgedoc.user_name}}" + } + } + ] + + }, { "name": "download", "become": false, "ansible.builtin.get_url": { - "url": "https://github.com/hedgedoc/hedgedoc/releases/download/{{var_hedgedoc_version}}/hedgedoc-{{var_hedgedoc_version}}.tar.gz", + "url": "https://github.com/hedgedoc/hedgedoc/releases/download/{{cfg_hedgedoc.version}}/hedgedoc-{{cfg_hedgedoc.version}}.tar.gz", "dest": "/tmp/hedgedoc.tar.gz" } }, @@ -45,8 +77,8 @@ "ansible.builtin.unarchive": { "remote_src": true, "src": "/tmp/hedgedoc.tar.gz", - "dest": "{{var_hedgedoc_directory | dirname}}", - "owner": "{{var_hedgedoc_user_name}}" + "dest": "{{cfg_hedgedoc.directory | dirname}}", + "owner": "{{cfg_hedgedoc.user_name}}" } }, { @@ -54,7 +86,7 @@ "become": true, "become_user": "hedgedoc", "ansible.builtin.command": { - "chdir": "{{var_hedgedoc_directory}}", + "chdir": "{{cfg_hedgedoc.directory}}", "cmd": "bin/setup" } }, @@ -63,7 +95,7 @@ "become": true, "ansible.builtin.template": { "src": "config.json.j2", - "dest": "{{var_hedgedoc_directory}}/config.json" + "dest": "{{cfg_hedgedoc.directory}}/config.json" } }, { diff --git a/roles/hedgedoc/templates/config.json.j2 b/roles/hedgedoc/templates/config.json.j2 index 509e4b6..2dc3b76 100644 --- a/roles/hedgedoc/templates/config.json.j2 +++ b/roles/hedgedoc/templates/config.json.j2 @@ -1,61 +1,61 @@ { "production": { - "loglevel": "error", -{% if var_hedgedoc_database_kind == 'sqlite' %} + "loglevel": "{{cfg_hedgedoc.log_level}}", +{% if cfg_hedgedoc.database.kind == 'sqlite' %} "db": { "dialect": "sqlite", - "storage": "{{var_hedgedoc_database_data_sqlite_path}}" + "storage": "{{cfg_hedgedoc.database.data.sqlite.path}}" }, {% endif %} -{% if var_hedgedoc_database_kind == 'postgresql' %} +{% if cfg_hedgedoc.database.kind == 'postgresql' %} "db": { "dialect": "postgres", - "host": "{{var_hedgedoc_database_data_postgresql_host}}", - "port": {{var_hedgedoc_database_data_postgresql_port | to_json}}, - "username": "{{var_hedgedoc_database_data_postgresql_username}}", - "password": "{{var_hedgedoc_database_data_postgresql_password}}", - "database": "{{var_hedgedoc_database_data_postgresql_schema}}" + "host": "{{cfg_hedgedoc.database.data.postgresql.host}}", + "port": {{cfg_hedgedoc.database.data.postgresql.port | to_json}}, + "username": "{{cfg_hedgedoc.database.data.postgresql.username}}", + "password": "{{cfg_hedgedoc.database.data.postgresql.password}}", + "database": "{{cfg_hedgedoc.database.data.postgresql.schema}}" }, {% endif %} - "sessionSecret": "{{var_hedgedoc_session_secret}}", + "sessionSecret": "{{cfg_hedgedoc.session_secret}}", "host": "localhost", "allowOrigin": [ "localhost" ], - "domain": "{{var_hedgedoc_domain}}", + "domain": "{{cfg_hedgedoc.domain}}", "urlAddPort": false, "protocolUseSSL": true, -{% if var_hedgedoc_authentication_kind == 'internal' %} +{% if cfg_hedgedoc.authentication.kind == 'internal' %} "email": true, "allowEmailRegister": true, {% endif %} -{% if var_hedgedoc_authentication_kind == 'authelia' %} +{% if cfg_hedgedoc.authentication.kind == 'authelia' %} "oauth2": { - "providerName": "{{var_hedgedoc_authentication_data_authelia_provider_name}}", - "clientID": "{{var_hedgedoc_authentication_data_authelia_client_id}}", - "clientSecret": "{{var_hedgedoc_authentication_data_authelia_client_secret}}", + "providerName": "{{cfg_hedgedoc.authentication.data.authelia.provider_name}}", + "clientID": "{{cfg_hedgedoc.authentication.data.authelia.client_id}}", + "clientSecret": "{{cfg_hedgedoc.authentication.data.authelia.client_secret}}", "scope": "openid email profile", "userProfileUsernameAttr": "sub", "userProfileDisplayNameAttr": "name", "userProfileEmailAttr": "email", - "userProfileURL": "{{var_hedgedoc_authentication_data_authelia_url_base}}/api/oidc/userinfo", - "tokenURL": "{{var_hedgedoc_authentication_data_authelia_url_base}}/api/oidc/token", - "authorizationURL": "{{var_hedgedoc_authentication_data_authelia_url_base}}/api/oidc/authorization" + "userProfileURL": "{{cfg_hedgedoc.authentication.data.authelia.url_base}}/api/oidc/userinfo", + "tokenURL": "{{cfg_hedgedoc.authentication.data.authelia.url_base}}/api/oidc/token", + "authorizationURL": "{{cfg_hedgedoc.authentication.data.authelia.url_base}}/api/oidc/authorization" }, "email": false, "allowEmailRegister": false, {% endif %} - "allowAnonymous": {{var_hedgedoc_guest_allow_create | to_json}}, - "allowAnonymousEdits": {{var_hedgedoc_guest_allow_change | to_json}}, -{% if var_hedgedoc_free_names_mode == 'never' %} + "allowAnonymous": {{cfg_hedgedoc.guest_allow_create | to_json}}, + "allowAnonymousEdits": {{cfg_hedgedoc.guest_allow_change | to_json}}, +{% if cfg_hedgedoc.free_names_mode == 'never' %} "allowFreeURL": false, "requireFreeURLAuthentication": false, {% endif %} -{% if var_hedgedoc_free_names_mode == 'authed' %} +{% if cfg_hedgedoc.free_names_mode == 'authed' %} "allowFreeURL": true, "requireFreeURLAuthentication": true, {% endif %} -{% if var_hedgedoc_free_names_mode == 'always' %} +{% if cfg_hedgedoc.free_names_mode == 'always' %} "allowFreeURL": true, "requireFreeURLAuthentication": false, {% endif %} diff --git a/roles/hedgedoc/templates/systemd-unit.j2 b/roles/hedgedoc/templates/systemd-unit.j2 index 000bd6e..7a1d54f 100644 --- a/roles/hedgedoc/templates/systemd-unit.j2 +++ b/roles/hedgedoc/templates/systemd-unit.j2 @@ -3,8 +3,8 @@ Description=Hedgedoc After=multi-user.target [Service] -WorkingDirectory={{var_hedgedoc_directory}} -User={{var_hedgedoc_user_name}} +WorkingDirectory={{cfg_hedgedoc.directory}} +User={{cfg_hedgedoc.user_name}} Environment="NODE_ENV=production" ExecStart=yarn start SyslogIdentifier=hedgedoc diff --git a/roles/hedgedoc/vardef.json b/roles/hedgedoc/vardef.json deleted file mode 100644 index cb6e8d6..0000000 --- a/roles/hedgedoc/vardef.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "user_name": { - "type": "string", - "mandatory": false - }, - "directory": { - "type": "string", - "mandatory": false - }, - "version": { - "type": "string", - "mandatory": false - }, - "session_secret": { - "type": "string", - "mandatory": true - }, - "database_kind": { - "type": "string", - "mandatory": false, - "options": [ - "sqlite", - "postgresql", - "mariadb" - ] - }, - "database_data_sqlite_path": { - "type": "string", - "mandatory": false - }, - "database_data_postgresql_host": { - "type": "string", - "mandatory": false - }, - "database_data_postgresql_port": { - "type": "integer", - "mandatory": false - }, - "database_data_postgresql_username": { - "type": "string", - "mandatory": false - }, - "database_data_postgresql_password": { - "type": "string", - "mandatory": false - }, - "database_data_postgresql_schema": { - "type": "string", - "mandatory": false - }, - "domain": { - "type": "string", - "mandatory": false - }, - "authentication_kind": { - "type": "string", - "mandatory": false, - "options": [ - "internal", - "authelia" - ] - }, - "authentication_data_authelia_client_id": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_client_secret": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_url_base": { - "type": "string", - "mandatory": false - }, - "guest_allow_create": { - "type": "boolean", - "mandatory": false - }, - "guest_allow_change": { - "type": "boolean", - "mandatory": false - }, - "free_names_mode": { - "type": "string", - "mandatory": false - } -} From 5b283c7804bb482a7d3ef0f238e6ac03cae2adad Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:45:37 +0200 Subject: [PATCH 07/11] [task-406] nginx --- roles/nginx/files/ssl-hardening.conf | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 roles/nginx/files/ssl-hardening.conf diff --git a/roles/nginx/files/ssl-hardening.conf b/roles/nginx/files/ssl-hardening.conf deleted file mode 100644 index 1d5f5f4..0000000 --- a/roles/nginx/files/ssl-hardening.conf +++ /dev/null @@ -1,18 +0,0 @@ -ssl_session_timeout 1d; -ssl_session_cache shared:MozSSL:10m; # about 40000 sessions -ssl_session_tickets off; - -# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam -ssl_dhparam /etc/nginx/dhparam; - -# intermediate configuration -ssl_protocols TLSv1.2 TLSv1.3; -ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; -ssl_prefer_server_ciphers off; - -# HSTS (ngx_http_headers_module is required) (63072000 seconds) -add_header Strict-Transport-Security "max-age=63072000" always; - -# OCSP stapling -ssl_stapling on; -ssl_stapling_verify on; From 88a65ad91927e5195cb8ebf73b49a84b5dfb1eb1 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:47:20 +0200 Subject: [PATCH 08/11] [task-406] hedgedoc --- roles/authelia-for-hedgedoc/cfg.schema.json | 25 +++++++++++++++++++ .../authelia-for-hedgedoc/defaults/main.json | 6 ++--- roles/authelia-for-hedgedoc/tasks/main.json | 9 ++++++- .../templates/authelia-client-conf.json.j2 | 4 +-- roles/hedgedoc-and-nginx/cfg.schema.json | 24 ++++++++++++++++++ roles/hedgedoc-and-nginx/defaults/main.json | 5 ++-- roles/hedgedoc-and-nginx/tasks/main.json | 13 +++++++--- roles/hedgedoc-and-nginx/templates/conf.j2 | 12 ++++----- roles/hedgedoc-and-nginx/vardef.json | 15 ----------- 9 files changed, 81 insertions(+), 32 deletions(-) create mode 100644 roles/authelia-for-hedgedoc/cfg.schema.json create mode 100644 roles/hedgedoc-and-nginx/cfg.schema.json delete mode 100644 roles/hedgedoc-and-nginx/vardef.json diff --git a/roles/authelia-for-hedgedoc/cfg.schema.json b/roles/authelia-for-hedgedoc/cfg.schema.json new file mode 100644 index 0000000..c8bf2cb --- /dev/null +++ b/roles/authelia-for-hedgedoc/cfg.schema.json @@ -0,0 +1,25 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "hedgedoc_url_base": { + "nullable": false, + "type": "string" + }, + "client_id": { + "nullable": false, + "type": "string", + "default": "hedgedoc" + }, + "client_secret": { + "nullable": false, + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "hedgedoc_url_base", + "client_id", + "client_secret" + ] +} diff --git a/roles/authelia-for-hedgedoc/defaults/main.json b/roles/authelia-for-hedgedoc/defaults/main.json index b1e3329..603c7fe 100644 --- a/roles/authelia-for-hedgedoc/defaults/main.json +++ b/roles/authelia-for-hedgedoc/defaults/main.json @@ -1,5 +1,5 @@ { - "var_authelia_for_hedgedoc_hedgedoc_url_base": "https://hedgedoc.example.org", - "var_authelia_for_hedgedoc_client_id": "hedgedoc", - "var_authelia_for_hedgedoc_client_secret": "REPLACE_ME" + "cfg_authelia_for_hedgedoc_defaults": { + "client_id": "hedgedoc" + } } diff --git a/roles/authelia-for-hedgedoc/tasks/main.json b/roles/authelia-for-hedgedoc/tasks/main.json index d229a17..7447ebc 100644 --- a/roles/authelia-for-hedgedoc/tasks/main.json +++ b/roles/authelia-for-hedgedoc/tasks/main.json @@ -1,9 +1,16 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_authelia_for_hedgedoc" + } + }, { "name": "configuration | compute client secret hash", "become": true, "ansible.builtin.shell": { - "cmd": "authelia crypto hash generate bcrypt --password {{var_authelia_for_hedgedoc_client_secret}} | cut --delimiter=' ' --fields='2-'" + "cmd": "authelia crypto hash generate bcrypt --password {{cfg_authelia_for_hedgedoc.client_secret}} | cut --delimiter=' ' --fields='2-'" }, "register": "temp_authelia_for_hedgedoc_client_secret_hashed" }, diff --git a/roles/authelia-for-hedgedoc/templates/authelia-client-conf.json.j2 b/roles/authelia-for-hedgedoc/templates/authelia-client-conf.json.j2 index 49a0c41..4547107 100644 --- a/roles/authelia-for-hedgedoc/templates/authelia-client-conf.json.j2 +++ b/roles/authelia-for-hedgedoc/templates/authelia-client-conf.json.j2 @@ -1,5 +1,5 @@ { - "client_id": "{{var_authelia_for_hedgedoc_client_id}}", + "client_id": "{{cfg_authelia_for_hedgedoc.client_id}}", "client_secret": "{{temp_authelia_for_hedgedoc_client_secret_hashed.stdout}}", "client_name": "Hedgedoc", "public": false, @@ -10,7 +10,7 @@ "profile" ], "redirect_uris": [ - "{{var_authelia_for_hedgedoc_hedgedoc_url_base}}/auth/oauth2/callback" + "{{cfg_authelia_for_hedgedoc.hedgedoc_url_base}}/auth/oauth2/callback" ], "response_types": [ "code" diff --git a/roles/hedgedoc-and-nginx/cfg.schema.json b/roles/hedgedoc-and-nginx/cfg.schema.json new file mode 100644 index 0000000..a56a3c2 --- /dev/null +++ b/roles/hedgedoc-and-nginx/cfg.schema.json @@ -0,0 +1,24 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "domain": { + "nullable": false, + "type": "string" + }, + "tls_mode": { + "nullable": false, + "type": "string", + "options": [ + "disable", + "enable", + "force" + ], + "default": "force" + } + }, + "additionalProperties": false, + "required": [ + "domain" + ] +} diff --git a/roles/hedgedoc-and-nginx/defaults/main.json b/roles/hedgedoc-and-nginx/defaults/main.json index aec6aa3..fec05a1 100644 --- a/roles/hedgedoc-and-nginx/defaults/main.json +++ b/roles/hedgedoc-and-nginx/defaults/main.json @@ -1,4 +1,5 @@ { - "var_hedgedoc_and_nginx_domain": "hedgedoc.example.org", - "var_hedgedoc_and_nginx_tls_mode": "force" + "cfg_hedgedoc_and_nginx_defaults": { + "tls_mode": "force" + } } diff --git a/roles/hedgedoc-and-nginx/tasks/main.json b/roles/hedgedoc-and-nginx/tasks/main.json index 40614bb..560d8a3 100644 --- a/roles/hedgedoc-and-nginx/tasks/main.json +++ b/roles/hedgedoc-and-nginx/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_hedgedoc_and_nginx" + } + }, { "name": "deactivate default site", "become": true, @@ -12,7 +19,7 @@ "become": true, "ansible.builtin.template": { "src": "conf.j2", - "dest": "/etc/nginx/sites-available/{{var_hedgedoc_and_nginx_domain}}" + "dest": "/etc/nginx/sites-available/{{cfg_hedgedoc_and_nginx.domain}}" } }, { @@ -20,8 +27,8 @@ "become": true, "ansible.builtin.file": { "state": "link", - "src": "/etc/nginx/sites-available/{{var_hedgedoc_and_nginx_domain}}", - "dest": "/etc/nginx/sites-enabled/{{var_hedgedoc_and_nginx_domain}}" + "src": "/etc/nginx/sites-available/{{cfg_hedgedoc_and_nginx.domain}}", + "dest": "/etc/nginx/sites-enabled/{{cfg_hedgedoc_and_nginx.domain}}" } }, { diff --git a/roles/hedgedoc-and-nginx/templates/conf.j2 b/roles/hedgedoc-and-nginx/templates/conf.j2 index b9c6601..2212af7 100644 --- a/roles/hedgedoc-and-nginx/templates/conf.j2 +++ b/roles/hedgedoc-and-nginx/templates/conf.j2 @@ -24,27 +24,27 @@ map $http_upgrade $connection_upgrade { {% endmacro %} server { - server_name {{var_hedgedoc_and_nginx_domain}}; + server_name {{cfg_hedgedoc_and_nginx.domain}}; listen 80; listen [::]:80; -{% if (var_element_and_nginx_tls_mode == 'force') %} +{% if (cfg_hedgedoc_and_nginx.tls_mode == 'force') %} return 301 https://$http_host$request_uri; {% else %} {{ hedgedoc_common() }} {% endif %} } -{% if (var_hedgedoc_and_nginx_tls_mode != 'disable') %} +{% if (cfg_hedgedoc_and_nginx.tls_mode != 'disable') %} server { - server_name {{var_hedgedoc_and_nginx_domain}}; + server_name {{cfg_hedgedoc_and_nginx.domain}}; listen [::]:443 ssl http2; listen 443 ssl http2; - ssl_certificate_key /etc/ssl/private/{{var_hedgedoc_and_nginx_domain}}.pem; - ssl_certificate /etc/ssl/fullchains/{{var_hedgedoc_and_nginx_domain}}.pem; + ssl_certificate_key /etc/ssl/private/{{cfg_hedgedoc_and_nginx.domain}}.pem; + ssl_certificate /etc/ssl/fullchains/{{cfg_hedgedoc_and_nginx.domain}}.pem; include /etc/nginx/ssl-hardening.conf; {{ hedgedoc_common() }} diff --git a/roles/hedgedoc-and-nginx/vardef.json b/roles/hedgedoc-and-nginx/vardef.json deleted file mode 100644 index b78ac7a..0000000 --- a/roles/hedgedoc-and-nginx/vardef.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "domain": { - "type": "string", - "mandatory": false - }, - "tls_mode": { - "type": "string", - "options": [ - "disable", - "enable", - "force" - ], - "mandatory": false - } -} From 6294edaa591dbf2c8f637406e23a43130a55993b Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:47:49 +0200 Subject: [PATCH 09/11] [task-406] nginx --- roles/authelia-and-nginx/cfg.schema.json | 24 +++++++++++++++++++++ roles/authelia-and-nginx/defaults/main.json | 5 +++-- roles/authelia-and-nginx/tasks/main.json | 13 ++++++++--- roles/authelia-and-nginx/templates/conf.j2 | 12 +++++------ roles/authelia-and-nginx/vardef.json | 15 ------------- 5 files changed, 43 insertions(+), 26 deletions(-) create mode 100644 roles/authelia-and-nginx/cfg.schema.json delete mode 100644 roles/authelia-and-nginx/vardef.json diff --git a/roles/authelia-and-nginx/cfg.schema.json b/roles/authelia-and-nginx/cfg.schema.json new file mode 100644 index 0000000..59e399d --- /dev/null +++ b/roles/authelia-and-nginx/cfg.schema.json @@ -0,0 +1,24 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "domain": { + "nullable": false, + "type": "string" + }, + "tls_mode": { + "nullable": false, + "type": "string", + "options": [ + "disable", + "enable", + "force" + ], + "enum": "force" + } + }, + "additionalProperties": false, + "required": [ + "domain" + ] +} diff --git a/roles/authelia-and-nginx/defaults/main.json b/roles/authelia-and-nginx/defaults/main.json index 0aaf1b7..28e3be5 100644 --- a/roles/authelia-and-nginx/defaults/main.json +++ b/roles/authelia-and-nginx/defaults/main.json @@ -1,4 +1,5 @@ { - "var_authelia_and_nginx_domain": "authelia.example.org", - "var_authelia_and_nginx_tls_mode": "force" + "cfg_authelia_and_nginx_defaults": { + "tls_mode": "force" + } } diff --git a/roles/authelia-and-nginx/tasks/main.json b/roles/authelia-and-nginx/tasks/main.json index 87dcf2b..c56c915 100644 --- a/roles/authelia-and-nginx/tasks/main.json +++ b/roles/authelia-and-nginx/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_authelia_and_nginx" + } + }, { "name": "deactivate default site", "become": true, @@ -12,7 +19,7 @@ "become": true, "ansible.builtin.template": { "src": "conf.j2", - "dest": "/etc/nginx/sites-available/{{var_authelia_and_nginx_domain}}" + "dest": "/etc/nginx/sites-available/{{cfg_authelia_and_nginx.domain}}" } }, { @@ -20,8 +27,8 @@ "become": true, "ansible.builtin.file": { "state": "link", - "src": "/etc/nginx/sites-available/{{var_authelia_and_nginx_domain}}", - "dest": "/etc/nginx/sites-enabled/{{var_authelia_and_nginx_domain}}" + "src": "/etc/nginx/sites-available/{{cfg_authelia_and_nginx.domain}}", + "dest": "/etc/nginx/sites-enabled/{{cfg_authelia_and_nginx.domain}}" } }, { diff --git a/roles/authelia-and-nginx/templates/conf.j2 b/roles/authelia-and-nginx/templates/conf.j2 index cd3b8d6..2b99bcb 100644 --- a/roles/authelia-and-nginx/templates/conf.j2 +++ b/roles/authelia-and-nginx/templates/conf.j2 @@ -45,27 +45,27 @@ {% endmacro %} server { - server_name {{var_authelia_and_nginx_domain}}; + server_name {{cfg_authelia_and_nginx.domain}}; listen 80; listen [::]:80; -{% if (var_authelia_and_nginx_tls_mode == 'force') %} +{% if (cfg_authelia_and_nginx.tls_mode == 'force') %} return 301 https://$http_host$request_uri; {% else %} {{ authelia_common() }} {% endif %} } -{% if (var_authelia_and_nginx_tls_mode != 'disable') %} +{% if (cfg_authelia_and_nginx.tls_mode != 'disable') %} server { - server_name {{var_authelia_and_nginx_domain}}; + server_name {{cfg_authelia_and_nginx.domain}}; listen [::]:443 ssl http2; listen 443 ssl http2; - ssl_certificate_key /etc/ssl/private/{{var_authelia_and_nginx_domain}}.pem; - ssl_certificate /etc/ssl/fullchains/{{var_authelia_and_nginx_domain}}.pem; + ssl_certificate_key /etc/ssl/private/{{cfg_authelia_and_nginx.domain}}.pem; + ssl_certificate /etc/ssl/fullchains/{{cfg_authelia_and_nginx.domain}}.pem; include /etc/nginx/ssl-hardening.conf; {{ authelia_common() }} diff --git a/roles/authelia-and-nginx/vardef.json b/roles/authelia-and-nginx/vardef.json deleted file mode 100644 index b78ac7a..0000000 --- a/roles/authelia-and-nginx/vardef.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "domain": { - "type": "string", - "mandatory": false - }, - "tls_mode": { - "type": "string", - "options": [ - "disable", - "enable", - "force" - ], - "mandatory": false - } -} From c2e100b1aa8253617f1e48b510d564d906cec350 Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:49:09 +0200 Subject: [PATCH 10/11] [task-406] owncloud --- roles/authelia-for-owncloud/cfg.schema.json | 97 +++++++++++ .../authelia-for-owncloud/defaults/main.json | 25 ++- roles/authelia-for-owncloud/tasks/main.json | 132 ++++++++++----- .../authelia-client-conf-android.json.j2 | 26 ++- .../authelia-client-conf-desktop.json.j2 | 27 +++- .../authelia-client-conf-ios.json.j2 | 27 +++- .../authelia-client-conf-web.json.j2 | 29 +++- roles/authelia-for-owncloud/vardef.json | 34 ---- roles/owncloud-and-nginx/cfg.schema.json | 31 ++++ roles/owncloud-and-nginx/defaults/main.json | 7 +- roles/owncloud-and-nginx/tasks/main.json | 13 +- roles/owncloud-and-nginx/templates/conf.j2 | 14 +- roles/owncloud-and-nginx/vardef.json | 20 --- roles/owncloud/cfg.schema.json | 152 ++++++++++++++++++ roles/owncloud/defaults/main.json | 30 ++-- roles/owncloud/info.md | 15 +- roles/owncloud/tasks/main.json | 65 ++++++-- roles/owncloud/templates/csp.yaml.j2 | 7 + roles/owncloud/templates/env.j2 | 88 ++++++---- roles/owncloud/templates/systemd_unit.j2 | 8 +- roles/owncloud/vardef.json | 75 --------- 21 files changed, 628 insertions(+), 294 deletions(-) create mode 100644 roles/authelia-for-owncloud/cfg.schema.json delete mode 100644 roles/authelia-for-owncloud/vardef.json create mode 100644 roles/owncloud-and-nginx/cfg.schema.json delete mode 100644 roles/owncloud-and-nginx/vardef.json create mode 100644 roles/owncloud/cfg.schema.json create mode 100644 roles/owncloud/templates/csp.yaml.j2 delete mode 100644 roles/owncloud/vardef.json diff --git a/roles/authelia-for-owncloud/cfg.schema.json b/roles/authelia-for-owncloud/cfg.schema.json new file mode 100644 index 0000000..4532214 --- /dev/null +++ b/roles/authelia-for-owncloud/cfg.schema.json @@ -0,0 +1,97 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "owncloud_url_base": { + "nullable": false, + "type": "string" + }, + "web": { + "nullable": true, + "type": "object", + "properties": { + "client_id": { + "nullable": false, + "type": "string", + "default": "owncloud_web" + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }, + "desktop": { + "nullable": true, + "type": "object", + "properties": { + "client_id": { + "nullable": false, + "type": "string", + "default": "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69" + }, + "client_secret": { + "nullable": false, + "type": "string", + "default": "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh" + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }, + "android": { + "nullable": true, + "type": "object", + "properties": { + "client_id": { + "nullable": false, + "type": "string", + "default": "e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD" + }, + "client_secret": { + "nullable": false, + "type": "string", + "default": "dInFYGV33xKzhbRmpqQltYNdfLdJIfJ9L5ISoKhNoT9qZftpdWSP71VrpGR9pmoD" + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + }, + "ios": { + "nullable": true, + "type": "object", + "properties": { + "client_id": { + "nullable": false, + "type": "string", + "default": "mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1" + }, + "client_secret": { + "nullable": false, + "type": "string", + "default": "KFeFWWEZO9TkisIQzR3fo7hfiMXlOpaqP8CFuTbSHzV1TUuGECglPxpiVKJfOXIx" + } + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "owncloud_url_base", + "web", + "desktop", + "android", + "ios" + ] +} diff --git a/roles/authelia-for-owncloud/defaults/main.json b/roles/authelia-for-owncloud/defaults/main.json index 4daa968..ad9f859 100644 --- a/roles/authelia-for-owncloud/defaults/main.json +++ b/roles/authelia-for-owncloud/defaults/main.json @@ -1,10 +1,19 @@ { - "var_authelia_for_owncloud_owncloud_url_base": "https://owncloud.example.org", - "var_authelia_for_owncloud_web_client_id": "owncloud_web", - "var_authelia_for_owncloud_android_client_id": "owncloud_android", - "var_authelia_for_owncloud_android_client_secret": "REPLACE_ME", - "var_authelia_for_owncloud_ios_client_id": "owncloud_ios", - "var_authelia_for_owncloud_ios_client_secret": "REPLACE_ME", - "var_authelia_for_owncloud_desktop_client_id": "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69", - "var_authelia_for_owncloud_desktop_client_secret": "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh" + "cfg_authelia_for_owncloud_defaults": { + "web": { + "client_id": "owncloud_web" + }, + "desktop": { + "client_id": "xdXOt13JKxym1B1QcEncf2XDkLAexMBFwiT9j6EfhhHFJhs2KM9jbjTmf8JBXE69", + "client_secret": "UBntmLjC2yYCeHwsyj73Uwo9TAaecAetRwMw0xYcvNL9yRdLSUi0hUAHfvCHFeFh" + }, + "android": { + "client_id": "e4rAsNUSIUs0lF4nbv9FmCeUkTlV9GdgTLDH1b5uie7syb90SzEVrbN7HIpmWJeD", + "client_secret": "dInFYGV33xKzhbRmpqQltYNdfLdJIfJ9L5ISoKhNoT9qZftpdWSP71VrpGR9pmoD" + }, + "ios": { + "client_id": "mxd5OQDk6es5LzOzRvidJNfXLUZS2oN3oUFeXPP8LpPrhx3UroJFduGEYIBOxkY1", + "client_secret": "KFeFWWEZO9TkisIQzR3fo7hfiMXlOpaqP8CFuTbSHzV1TUuGECglPxpiVKJfOXIx" + } + } } diff --git a/roles/authelia-for-owncloud/tasks/main.json b/roles/authelia-for-owncloud/tasks/main.json index 99c0626..8c956db 100644 --- a/roles/authelia-for-owncloud/tasks/main.json +++ b/roles/authelia-for-owncloud/tasks/main.json @@ -1,50 +1,96 @@ [ { - "name": "configuration | compute client secret hash | web", - "become": true, - "ansible.builtin.shell": { - "cmd": "authelia crypto hash generate bcrypt --password {{var_authelia_for_owncloud_web_client_secret}} | cut --delimiter=' ' --fields='2-'" - }, - "register": "temp_authelia_for_owncloud_web_client_secret_hashed" - }, - { - "name": "configuration | compute client secret hash | android", - "become": true, - "ansible.builtin.shell": { - "cmd": "authelia crypto hash generate bcrypt --password {{var_authelia_for_owncloud_android_client_secret}} | cut --delimiter=' ' --fields='2-'" - }, - "register": "temp_authelia_for_owncloud_android_client_secret_hashed" - }, - { - "name": "configuration | compute client secret hash | ios", - "become": true, - "ansible.builtin.shell": { - "cmd": "authelia crypto hash generate bcrypt --password {{var_authelia_for_owncloud_ios_client_secret}} | cut --delimiter=' ' --fields='2-'" - }, - "register": "temp_authelia_for_owncloud_ios_client_secret_hashed" - }, - { - "name": "configuration | compute client secret hash | desktop", - "become": true, - "ansible.builtin.shell": { - "cmd": "authelia crypto hash generate bcrypt --password {{var_authelia_for_owncloud_desktop_client_secret}} | cut --delimiter=' ' --fields='2-'" - }, - "register": "temp_authelia_for_owncloud_desktop_client_secret_hashed" - }, - { - "name": "configuration | emplace", - "become": true, - "loop": [ - {"src": "authelia-client-conf-web.json.j2", "dest": "/etc/authelia/conf.d/clients/owncloud-web.json"}, - {"src": "authelia-client-conf-desktop.json.j2", "dest": "/etc/authelia/conf.d/clients/owncloud-desktop.json"}, - {"src": "authelia-client-conf-android.json.j2", "dest": "/etc/authelia/conf.d/clients/owncloud-android.json"}, - {"src": "authelia-client-conf-ios.json.j2", "dest": "/etc/authelia/conf.d/clients/owncloud-ios.json"} - ], - "ansible.builtin.template": { - "src": "{{item.src}}", - "dest": "{{item.dest}}" + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_authelia_for_owncloud" } }, + { + "name": "configuration | client", + "block": [ + { + "name": "configuration | client | web", + "when": "cfg_authelia_for_owncloud.web != None", + "block": [ + { + "name": "emplace", + "become": true, + "ansible.builtin.template": { + "src": "authelia-client-conf-web.json.j2", + "dest": "/etc/authelia/conf.d/clients/owncloud-web.json" + } + } + ] + }, + { + "name": "configuration | client | desktop", + "when": "cfg_authelia_for_owncloud.desktop != None", + "block": [ + { + "name": "compute client secret hash", + "become": true, + "ansible.builtin.shell": { + "cmd": "authelia crypto hash generate bcrypt --password {{cfg_authelia_for_owncloud.desktop.client_secret}} | cut --delimiter=' ' --fields='2-'" + }, + "register": "temp_authelia_for_owncloud_desktop_client_secret_hashed" + }, + { + "name": "emplace", + "become": true, + "ansible.builtin.template": { + "src": "authelia-client-conf-desktop.json.j2", + "dest": "/etc/authelia/conf.d/clients/owncloud-desktop.json" + } + } + ] + }, + { + "name": "configuration | client | android", + "when": "cfg_authelia_for_owncloud.android != None", + "block": [ + { + "name": "compute client secret hash", + "become": true, + "ansible.builtin.shell": { + "cmd": "authelia crypto hash generate bcrypt --password {{cfg_authelia_for_owncloud.android.client_secret}} | cut --delimiter=' ' --fields='2-'" + }, + "register": "temp_authelia_for_owncloud_android_client_secret_hashed" + }, + { + "name": "emplace", + "become": true, + "ansible.builtin.template": { + "src": "authelia-client-conf-android.json.j2", + "dest": "/etc/authelia/conf.d/clients/owncloud-android.json" + } + } + ] + }, + { + "name": "configuration | client | ios", + "when": "cfg_authelia_for_owncloud.ios != None", + "block": [ + { + "name": "compute client secret hash", + "become": true, + "ansible.builtin.shell": { + "cmd": "authelia crypto hash generate bcrypt --password {{cfg_authelia_for_owncloud.ios.client_secret}} | cut --delimiter=' ' --fields='2-'" + }, + "register": "temp_authelia_for_owncloud_ios_client_secret_hashed" + }, + { + "name": "emplace", + "become": true, + "ansible.builtin.template": { + "src": "authelia-client-conf-ios.json.j2", + "dest": "/etc/authelia/conf.d/clients/owncloud-ios.json" + } + } + ] + } + ] + }, { "name": "configuration | apply", "become": true, diff --git a/roles/authelia-for-owncloud/templates/authelia-client-conf-android.json.j2 b/roles/authelia-for-owncloud/templates/authelia-client-conf-android.json.j2 index b47cbc0..7c39744 100644 --- a/roles/authelia-for-owncloud/templates/authelia-client-conf-android.json.j2 +++ b/roles/authelia-for-owncloud/templates/authelia-client-conf-android.json.j2 @@ -1,19 +1,33 @@ { - "client_id": "{{var_authelia_for_owncloud_android_client_id}}", + "client_id": "{{cfg_authelia_for_owncloud.android.client_id}}", "client_secret": "{{temp_authelia_for_owncloud_android_client_secret_hashed.stdout}}", "client_name": "ownCloud | Android Client", + + "public": false, "authorization_policy": "one_factor", + "require_pkce": true, + "pkce_challenge_method": "S256", "scopes": [ "openid", + "offline_access", "groups", "profile", - "email", - "offline_access" + "email" + ], + "redirect_uris": [ + "oc://android.owncloud.com" + + + ], "response_types": [ "code" ], - "redirect_uris": [ - "oc://android.owncloud.com" - ] + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "access_token_signed_response_alg": "none", + "userinfo_signed_response_alg": "none", + "token_endpoint_auth_method": "client_secret_basic" } diff --git a/roles/authelia-for-owncloud/templates/authelia-client-conf-desktop.json.j2 b/roles/authelia-for-owncloud/templates/authelia-client-conf-desktop.json.j2 index 4338426..2b33bf2 100644 --- a/roles/authelia-for-owncloud/templates/authelia-client-conf-desktop.json.j2 +++ b/roles/authelia-for-owncloud/templates/authelia-client-conf-desktop.json.j2 @@ -1,20 +1,33 @@ { - "client_id": "{{var_authelia_for_owncloud_desktop_client_id}}", + "client_id": "{{cfg_authelia_for_owncloud.desktop.client_id}}", "client_secret": "{{temp_authelia_for_owncloud_desktop_client_secret_hashed.stdout}}", "client_name": "ownCloud | Desktop Client", + + "public": false, "authorization_policy": "one_factor", + "require_pkce": true, + "pkce_challenge_method": "S256", "scopes": [ "openid", + "offline_access", "groups", "profile", - "email", - "offline_access" - ], - "response_types": [ - "code" + "email" ], "redirect_uris": [ "http://127.0.0.1", "http://localhost" - ] + + + ], + "response_types": [ + "code" + ], + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "access_token_signed_response_alg": "none", + "userinfo_signed_response_alg": "none", + "token_endpoint_auth_method": "client_secret_basic" } diff --git a/roles/authelia-for-owncloud/templates/authelia-client-conf-ios.json.j2 b/roles/authelia-for-owncloud/templates/authelia-client-conf-ios.json.j2 index e529c5d..01eefe2 100644 --- a/roles/authelia-for-owncloud/templates/authelia-client-conf-ios.json.j2 +++ b/roles/authelia-for-owncloud/templates/authelia-client-conf-ios.json.j2 @@ -1,20 +1,33 @@ { - "client_id": "{{var_authelia_for_owncloud_ios_client_id}}", + "client_id": "{{cfg_authelia_for_owncloud.ios.client_id}}", "client_secret": "{{temp_authelia_for_owncloud_ios_client_secret_hashed.stdout}}", "client_name": "ownCloud | iOS Client", + + "public": false, "authorization_policy": "one_factor", + "require_pkce": true, + "pkce_challenge_method": "S256", "scopes": [ "openid", + "offline_access", "groups", "profile", - "email", - "offline_access" - ], - "response_types": [ - "code" + "email" ], "redirect_uris": [ "oc://ios.owncloud.com", "oc.ios://ios.owncloud.com" - ] + + + ], + "response_types": [ + "code" + ], + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "access_token_signed_response_alg": "none", + "userinfo_signed_response_alg": "none", + "token_endpoint_auth_method": "client_secret_basic" } diff --git a/roles/authelia-for-owncloud/templates/authelia-client-conf-web.json.j2 b/roles/authelia-for-owncloud/templates/authelia-client-conf-web.json.j2 index 45b6983..8a30c04 100644 --- a/roles/authelia-for-owncloud/templates/authelia-client-conf-web.json.j2 +++ b/roles/authelia-for-owncloud/templates/authelia-client-conf-web.json.j2 @@ -1,20 +1,33 @@ { - "client_id": "{{var_authelia_for_owncloud_web_client_id}}", + "client_id": "{{cfg_authelia_for_owncloud.web.client_id}}", + "client_name": "ownCloud | Web Client", + "lifespan": "long", "public": true, "authorization_policy": "one_factor", + "require_pkce": true, + "pkce_challenge_method": "S256", "scopes": [ "openid", - "email", + "offline_access", + "groups", "profile", - "groups" + "email" + ], + "redirect_uris": [ + "https://{{cfg_authelia_for_owncloud.owncloud_url_base}}", + "https://{{cfg_authelia_for_owncloud.owncloud_url_base}}/oidc-callback.html", + "https://{{cfg_authelia_for_owncloud.owncloud_url_base}}/oidc-silent-redirect.html", + "https://{{cfg_authelia_for_owncloud.owncloud_url_base}}/apps/openidconnect/redirect" ], "response_types": [ "code" ], - "redirect_uris": [ - "{{var_authelia_for_owncloud_owncloud_url_base}}", - "{{var_authelia_for_owncloud_owncloud_url_base}}/oidc-callback.html", - "{{var_authelia_for_owncloud_owncloud_url_base}}/oidc-silent-redirect.html" - ] + "grant_types": [ + "authorization_code", + "refresh_token" + ], + "access_token_signed_response_alg": "none", + "userinfo_signed_response_alg": "none", + "token_endpoint_auth_method": "none" } diff --git a/roles/authelia-for-owncloud/vardef.json b/roles/authelia-for-owncloud/vardef.json deleted file mode 100644 index 531604d..0000000 --- a/roles/authelia-for-owncloud/vardef.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "owncloud_url_base": { - "type": "string", - "mandatory": false - }, - "web_client_id": { - "type": "string", - "mandatory": false - }, - "android_client_id": { - "type": "string", - "mandatory": false - }, - "android_client_secret": { - "type": "string", - "mandatory": true - }, - "ios_client_id": { - "type": "string", - "mandatory": false - }, - "ios_client_secret": { - "type": "string", - "mandatory": true - }, - "dektop_client_id": { - "type": "string", - "mandatory": false - }, - "desktop_client_secret": { - "type": "string", - "mandatory": false - } -} diff --git a/roles/owncloud-and-nginx/cfg.schema.json b/roles/owncloud-and-nginx/cfg.schema.json new file mode 100644 index 0000000..070ca31 --- /dev/null +++ b/roles/owncloud-and-nginx/cfg.schema.json @@ -0,0 +1,31 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "domain": { + "nullable": false, + "type": "string" + }, + "tls_mode": { + "nullable": false, + "type": "string", + "enum": [ + "disable", + "enable", + "force" + ], + "default": "force" + }, + "maximum_upload_size": { + "nullable": false, + "type": "string", + "default": "1G" + } + }, + "additionalProperties": false, + "required": [ + "domain", + "tls_mode", + "maximum_upload_size" + ] +} diff --git a/roles/owncloud-and-nginx/defaults/main.json b/roles/owncloud-and-nginx/defaults/main.json index 9ad192e..cc7e319 100644 --- a/roles/owncloud-and-nginx/defaults/main.json +++ b/roles/owncloud-and-nginx/defaults/main.json @@ -1,5 +1,6 @@ { - "var_owncloud_and_nginx_domain": "owncloud.example.org", - "var_owncloud_and_nginx_tls_mode": "force", - "var_owncloud_and_nginx_maximum_upload_size": "1G" + "cfg_owncloud_and_nginx_defaults": { + "tls_mode": "force", + "maximum_upload_size": "1G" + } } diff --git a/roles/owncloud-and-nginx/tasks/main.json b/roles/owncloud-and-nginx/tasks/main.json index 004dfa3..19e3f42 100644 --- a/roles/owncloud-and-nginx/tasks/main.json +++ b/roles/owncloud-and-nginx/tasks/main.json @@ -1,4 +1,11 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_owncloud_and_nginx" + } + }, { "name": "deactivate default site", "become": true, @@ -12,7 +19,7 @@ "become": true, "ansible.builtin.template": { "src": "conf.j2", - "dest": "/etc/nginx/sites-available/{{var_owncloud_and_nginx_domain}}" + "dest": "/etc/nginx/sites-available/{{cfg_owncloud_and_nginx.domain}}" } }, { @@ -20,8 +27,8 @@ "become": true, "ansible.builtin.file": { "state": "link", - "src": "/etc/nginx/sites-available/{{var_owncloud_and_nginx_domain}}", - "dest": "/etc/nginx/sites-enabled/{{var_owncloud_and_nginx_domain}}" + "src": "/etc/nginx/sites-available/{{cfg_owncloud_and_nginx.domain}}", + "dest": "/etc/nginx/sites-enabled/{{cfg_owncloud_and_nginx.domain}}" } }, { diff --git a/roles/owncloud-and-nginx/templates/conf.j2 b/roles/owncloud-and-nginx/templates/conf.j2 index 85e67ab..db4e6ac 100644 --- a/roles/owncloud-and-nginx/templates/conf.j2 +++ b/roles/owncloud-and-nginx/templates/conf.j2 @@ -1,7 +1,7 @@ {% macro owncloud_common() %} location / { proxy_pass http://localhost:9200; - client_max_body_size {{var_owncloud_and_nginx_maximum_upload_size}}; + client_max_body_size {{cfg_owncloud_and_nginx.maximum_upload_size}}; } {% endmacro %} @@ -9,24 +9,24 @@ server { listen 80; listen [::]:80; - server_name {{var_owncloud_and_nginx_domain}}; + server_name {{cfg_owncloud_and_nginx.domain}}; -{% if var_owncloud_and_nginx_tls_mode == 'force' %} +{% if cfg_owncloud_and_nginx.tls_mode == 'force' %} return 301 https://$http_host$request_uri; {% else %} {{ owncloud_common() }} {% endif %} } -{% if var_owncloud_and_nginx_tls_mode != 'disable' %} +{% if cfg_owncloud_and_nginx.tls_mode != 'disable' %} server { listen 443 ssl; listen [::]:443 ssl; - server_name {{var_owncloud_and_nginx_domain}}; + server_name {{cfg_owncloud_and_nginx.domain}}; - ssl_certificate_key /etc/ssl/private/{{var_owncloud_and_nginx_domain}}.pem; - ssl_certificate /etc/ssl/fullchains/{{var_owncloud_and_nginx_domain}}.pem; + ssl_certificate_key /etc/ssl/private/{{cfg_owncloud_and_nginx.domain}}.pem; + ssl_certificate /etc/ssl/fullchains/{{cfg_owncloud_and_nginx.domain}}.pem; include /etc/nginx/ssl-hardening.conf; {{ owncloud_common() }} diff --git a/roles/owncloud-and-nginx/vardef.json b/roles/owncloud-and-nginx/vardef.json deleted file mode 100644 index 7872cb8..0000000 --- a/roles/owncloud-and-nginx/vardef.json +++ /dev/null @@ -1,20 +0,0 @@ - -{ - "domain": { - "type": "string", - "mandatory": false - }, - "tls_mode": { - "type": "string", - "options": [ - "disable", - "enable", - "force" - ], - "mandatory": false - }, - "maximum_upload_size": { - "type": "string", - "mandatory": false - } -} diff --git a/roles/owncloud/cfg.schema.json b/roles/owncloud/cfg.schema.json new file mode 100644 index 0000000..6c3c59d --- /dev/null +++ b/roles/owncloud/cfg.schema.json @@ -0,0 +1,152 @@ +{ + "nullable": false, + "type": "object", + "properties": { + "user": { + "nullable": false, + "type": "string", + "default": "owncloud" + }, + "directory": { + "nullable": false, + "type": "string", + "default": "/opt/owncloud" + }, + "version": { + "nullable": false, + "type": "string", + "default": "7.2.0" + }, + "platform": { + "nullable": false, + "type": "string", + "default": "linux-amd64" + }, + "domain": { + "nullable": false, + "type": "string" + }, + "admin_password": { + "nullable": false, + "type": "string" + }, + "authentication": { + "anyOf": [ + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["internal"], + "default": "internal" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + }, + "additionalProperties": false, + "required": [ + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + }, + { + "nullable": false, + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["authelia"], + "default": "authelia" + }, + "data": { + "nullable": false, + "type": "object", + "properties": { + "url_base": { + "nullable": false, + "type": "string" + }, + "web": { + "nullable": true, + "type": "object", + "properties": { + "client_id": { + "type": "string", + "mandatory": false, + "default": "owncloud_web" + } + }, + "additionalProperties": false, + "required": [ + "client_id" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "url_base", + "web" + ] + } + }, + "additionalProperties": false, + "required": [ + "kind", + "data" + ] + } + ] + }, + "public_share": { + "nullable": false, + "type": "object", + "properties": { + "password_necessity": { + "nullable": false, + "type": "string", + "enum": [ + "nothing", + "writable", + "all" + ], + "default": "writable" + }, + "password_policy_active": { + "nullable": false, + "type": "boolean", + "default": true + } + }, + "additionalProperties": false, + "required": [ + "password_necessity", + "password_policy_active" + ], + "default": { + } + } + }, + "additionalProperties": false, + "required": [ + "user", + "directory", + "version", + "platform", + "domain", + "admin_password", + "authentication", + "public_share" + ] +} diff --git a/roles/owncloud/defaults/main.json b/roles/owncloud/defaults/main.json index 1101e12..94f4742 100644 --- a/roles/owncloud/defaults/main.json +++ b/roles/owncloud/defaults/main.json @@ -1,18 +1,16 @@ { - "var_owncloud_user": "owncloud", - "var_owncloud_directory": "/opt/owncloud", - "var_owncloud_version": "5.0.0", - "var_owncloud_platform": "linux-amd64", - "var_owncloud_domain": "owncloud.example.org", - "var_owncloud_admin_password": "REPLACE_ME", - "var_owncloud_authentication_kind": "internal", - "var_owncloud_authentication_data_authelia_url_base": "https://authelia.example.org", - "var_owncloud_authentication_data_authelia_web_client_id": "owncloud_web", - "var_owncloud_authentication_data_authelia_web_client_secret": "REPLACE_ME", - "var_owncloud_authentication_data_authelia_android_client_id": "owncloud_android", - "var_owncloud_authentication_data_authelia_android_client_secret": "REPLACE_ME", - "var_owncloud_authentication_data_authelia_ios_client_id": "owncloud_ios", - "var_owncloud_authentication_data_authelia_ios_client_secret": "REPLACE_ME", - "var_owncloud_public_share_password_necessity": "writable", - "var_owncloud_public_share_password_policy_active": true + "cfg_owncloud_defaults": { + "user": "owncloud", + "directory": "/opt/owncloud", + "version": "7.2.0", + "platform": "linux-amd64", + "domain": "owncloud.example.org", + "authentication": { + "kind": "internal" + }, + "public_share": { + "password_necessity": "writable", + "password_policy_active": true + } + } } diff --git a/roles/owncloud/info.md b/roles/owncloud/info.md index b74ee6d..d8d8e95 100644 --- a/roles/owncloud/info.md +++ b/roles/owncloud/info.md @@ -7,13 +7,26 @@ Cloud-Plattform [ownCloud](https://owncloud.com/) (the rewrite in Go named "Infi - [ownCloud-Dokumentation | How to install ownCloud Infinite Scale Tech Preview in three easy steps](https://owncloud.com/news/howto-install-owncloud-infinite-scale-tech-preview/) - [ownCloud-Dokumentation | oCIS](https://owncloud.dev/ocis/) -- [ownCloud-Dokumentation | Service | Proxy](https://doc.owncloud.com/ocis/next/deployment/services/s-list/proxy.html) +- [ownCloud-Dokumentation | Upgrading](https://doc.owncloud.com/ocis/next/migration/upgrading-ocis.html) +- [ownCloud-Dokumentation | env var types](https://doc.owncloud.com/ocis/next/deployment/services/envvar-types-description.html) - [ownCloud-Dokumentation | Service | Web](https://doc.owncloud.com/ocis/next/deployment/services/s-list/web.html) +- [ownCloud-Dokumentation | Service | Proxy](https://doc.owncloud.com/ocis/next/deployment/services/s-list/proxy.html) - [ownCloud-Dokumentation | Service | Sharing](https://doc.owncloud.com/ocis/next/deployment/services/s-list/sharing.html) - [GitHub | ocis](https://github.com/owncloud/ocis/) - [ownCloud-Foren | OCIS + Authelia](https://central.owncloud.org/t/ocis-authelia/44222) +## Bemerkungen + +- die `.ocis/config/ocis.yaml` wird erzeugt auf Grundlage der `.env` +- `.ocis/config/ocis.yaml` sollte niemals einfach neu erstellt werden, da man sich sonst nicht mehr einloggen kann +- wenn man sich plötzlich nicht mehr über OIDC anmelden kann, kann das daran lieget, dass `.ocis/idm/ldap.crt` abgelaufen ist — siehe dazu [diesen Thread](https://central.owncloud.org/t/certificate-error-after-upgrade-to-5-0-0-from-4-0-6/47824/7); man könnte auch `OCIS_LDAP_INSECURE` auf `true` setzen, aber naja… + + ## ToDo - Download prüfen +- `csp.yaml` einsetzen +- prüfen ob folgende `.env`-Variablen gebraucht werden: + - `PROXY_OIDC_ISSUER` + - `PROXY_OIDC_SKIP_USER_INFO` diff --git a/roles/owncloud/tasks/main.json b/roles/owncloud/tasks/main.json index 0a6e356..af5b1b3 100644 --- a/roles/owncloud/tasks/main.json +++ b/roles/owncloud/tasks/main.json @@ -1,39 +1,70 @@ [ + { + "name": "show vars", + "when": "switch_show_vars", + "ansible.builtin.debug": { + "var": "vars.cfg_owncloud" + } + }, { "name": "user", "become": true, "ansible.builtin.user": { - "name": "{{var_owncloud_user}}", + "name": "{{cfg_owncloud.user}}", "create_home": true, - "home": "{{var_owncloud_directory}}" + "home": "{{cfg_owncloud.directory}}" } }, { "name": "download", "become": true, - "become_user": "{{var_owncloud_user}}", + "become_user": "{{cfg_owncloud.user}}", "ansible.builtin.get_url": { - "url": "https://download.owncloud.com/ocis/ocis/stable/{{var_owncloud_version}}/ocis-{{var_owncloud_version}}-{{var_owncloud_platform}}", - "dest": "{{var_owncloud_directory}}/ocis", + "url": "https://download.owncloud.com/ocis/ocis/stable/{{cfg_owncloud.version}}/ocis-{{cfg_owncloud.version}}-{{cfg_owncloud.platform}}", + "dest": "{{cfg_owncloud.directory}}/ocis", "mode": "u+rx" } }, + { + "name": "directories", + "become": true, + "become_user": "{{cfg_owncloud.user}}", + "loop": [ + "log" + ], + "ansible.builtin.file": { + "state": "directory", + "recurse": true, + "path": "{{cfg_owncloud.directory}}/{{item}}" + } + }, + { + "name": "csp", + "become": true, + "become_user": "{{cfg_owncloud.user}}", + "ansible.builtin.template": { + "src": "csp.yaml.j2", + "mode": "644", + "dest": "{{cfg_owncloud.directory}}/csp.yaml" + } + }, + { + "name": "env", + "become": true, + "become_user": "{{cfg_owncloud.user}}", + "ansible.builtin.template": { + "src": "env.j2", + "mode": "644", + "dest": "{{cfg_owncloud.directory}}/.env" + } + }, { "name": "setup", "become": true, - "become_user": "{{var_owncloud_user}}", + "become_user": "{{cfg_owncloud.user}}", "ansible.builtin.shell": { - "chdir": "{{var_owncloud_directory}}", - "cmd": "rm -f {{var_owncloud_directory}}/.ocis/config/ocis.yaml && ./ocis init --insecure no --admin-password={{var_owncloud_admin_password}}" - } - }, - { - "name": "configuration", - "become": true, - "become_user": "{{var_owncloud_user}}", - "ansible.builtin.template": { - "src": "env.j2", - "dest": "{{var_owncloud_directory}}/.env" + "chdir": "{{cfg_owncloud.directory}}", + "cmd": "./ocis init --insecure no --admin-password={{cfg_owncloud.admin_password}}" } }, { diff --git a/roles/owncloud/templates/csp.yaml.j2 b/roles/owncloud/templates/csp.yaml.j2 new file mode 100644 index 0000000..2373aa5 --- /dev/null +++ b/roles/owncloud/templates/csp.yaml.j2 @@ -0,0 +1,7 @@ +directives: + connect-src: + - '''self''' + - 'https://{{cfg_owncloud.domain}}' +{% if cfg_owncloud.authentication.kind == 'authelia' %} + - '{{cfg_owncloud.authentication.data.url_base}}' +{% endif %} diff --git a/roles/owncloud/templates/env.j2 b/roles/owncloud/templates/env.j2 index 1c53400..e11062a 100644 --- a/roles/owncloud/templates/env.j2 +++ b/roles/owncloud/templates/env.j2 @@ -1,44 +1,62 @@ -OCIS_URL="https://{{var_owncloud_domain}}" -OCIS_INSECURE="false" - -PROXY_TLS="false" - -{% if var_owncloud_authentication_kind == 'internal' %} -PROXY_AUTOPROVISION_ACCOUNTS="false" +## web client +WEB_LOG_LEVEL=info +WEB_LOG_FILE={{cfg_owncloud.directory}}/log/web +WEB_LOG_PRETTY=true +WEB_LOG_COLOR=true +{% if cfg_owncloud.authentication.kind == 'internal' %} +{% endif %} +{% if cfg_owncloud.authentication.kind == 'authelia' %} +WEB_OIDC_AUTHORITY={{cfg_owncloud.authentication.data.url_base}} +WEB_OIDC_CLIENT_ID={{cfg_owncloud.authentication.data.web.client_id}} +WEB_OIDC_RESPONSE_TYPE=code +WEB_OIDC_SCOPE=openid profile email groups +WEB_OPTION_LOGIN_URL={{cfg_owncloud.authentication.data.url_base}} +WEB_OPTION_LOGOUT_URL={{cfg_owncloud.authentication.data.url_base}} +WEB_UI_THEME_SERVER=https://{{cfg_owncloud.domain}} +WEB_UI_CONFIG_SERVER=https://{{cfg_owncloud.domain}} {% endif %} -{% if var_owncloud_authentication_kind == 'authelia' %} -OCIS_OIDC_CLIENT_ID="{{var_owncloud_authentication_data_authelia_web_client_id}}" -OCIS_OIDC_ISSUER="{{var_owncloud_authentication_data_authelia_url_base}}" - -PROXY_AUTOPROVISION_ACCOUNTS="true" -PROXY_OIDC_REWRITE_WELLKNOWN="true" -PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD="none" -PROXY_OIDC_INSECURE="false" -PROXY_USER_OIDC_CLAIM="name" -PROXY_USER_CS3_CLAIM="username" - -WEB_OIDC_AUTHORITY="{{var_owncloud_authentication_data_authelia_url_base}}" -WEB_OIDC_METADATA_URL="{{var_owncloud_authentication_data_authelia_url_base}}/.well-known/openid-configuration" -WEB_OIDC_CLIENT_ID="{{var_owncloud_authentication_data_authelia_web_client_id}}" -WEB_OIDC_SCOPE="openid profile email groups" +## other clients +PROXY_LOG_LEVEL=info +PROXY_LOG_FILE={{cfg_owncloud.directory}}/log/proxy +PROXY_LOG_PRETTY=true +PROXY_LOG_COLOR=true +PROXY_CSP_CONFIG_FILE_LOCATION={{cfg_owncloud.directory}}/csp.yaml +PROXY_TLS=false +{% if cfg_owncloud.authentication.kind == 'internal' %} +PROXY_AUTOPROVISION_ACCOUNTS=false +{% endif %} +{% if cfg_owncloud.authentication.kind == 'authelia' %} +OCIS_URL=https://{{cfg_owncloud.domain}} +PROXY_OIDC_ISSUER={{cfg_owncloud.authentication.data.url_base}} +PROXY_OIDC_REWRITE_WELLKNOWN=true +PROXY_OIDC_ACCESS_TOKEN_VERIFY_METHOD=none +PROXY_OIDC_SKIP_USER_INFO=false +PROXY_AUTOPROVISION_ACCOUNTS=true +PROXY_AUTOPROVISION_CLAIM_USERNAME=preferred_username +PROXY_AUTOPROVISION_CLAIM_EMAIL=email +PROXY_AUTOPROVISION_CLAIM_DISPLAYNAME=name +PROXY_AUTOPROVISION_CLAIM_GROUPS=groups +PROXY_USER_OIDC_CLAIM=preferred_username +PROXY_USER_CS3_CLAIM=username {% endif %} -{% if var_owncloud_public_share_password_necessity == 'nothing' %} -OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD="false" -OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD="false" +## sharing +{% if cfg_owncloud.public_share.password_necessity == 'nothing' %} +OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD=false +OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD=false {% endif %} -{% if var_owncloud_public_share_password_necessity == 'writable' %} -OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD="false" -OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD="true" +{% if cfg_owncloud.public_share.password_necessity == 'writable' %} +OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD=false +OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD=true {% endif %} -{% if var_owncloud_public_share_password_necessity == 'all' %} -OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD="true" -OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD="true" +{% if cfg_owncloud.public_share.password_necessity == 'all' %} +OCIS_SHARING_PUBLIC_SHARE_MUST_HAVE_PASSWORD=true +OCIS_SHARING_PUBLIC_WRITEABLE_SHARE_MUST_HAVE_PASSWORD=true {% endif %} - -{% if var_owncloud_public_share_password_policy_active %} -OCIS_SHARING_PASSWORD_POLICY_DISABLED="false" +{% if cfg_owncloud.public_share.password_policy_active %} +OCIS_SHARING_PASSWORD_POLICY_DISABLED=false {% else %} -OCIS_SHARING_PASSWORD_POLICY_DISABLED="true" +OCIS_SHARING_PASSWORD_POLICY_DISABLED=true {% endif %} + diff --git a/roles/owncloud/templates/systemd_unit.j2 b/roles/owncloud/templates/systemd_unit.j2 index 7e43971..8db49d4 100644 --- a/roles/owncloud/templates/systemd_unit.j2 +++ b/roles/owncloud/templates/systemd_unit.j2 @@ -3,12 +3,12 @@ Description=ownCloud After=network.target [Service] -WorkingDirectory={{var_owncloud_directory}} -EnvironmentFile={{var_owncloud_directory}}/.env -ExecStart={{var_owncloud_directory}}/ocis server +WorkingDirectory={{cfg_owncloud.directory}} +EnvironmentFile={{cfg_owncloud.directory}}/.env +ExecStart={{cfg_owncloud.directory}}/ocis server Type=simple Restart=always -User={{var_owncloud_user}} +User={{cfg_owncloud.user}} [Install] WantedBy=default.target diff --git a/roles/owncloud/vardef.json b/roles/owncloud/vardef.json deleted file mode 100644 index 6641a03..0000000 --- a/roles/owncloud/vardef.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "user": { - "type": "string", - "mandatory": false - }, - "directory": { - "type": "string", - "mandatory": false - }, - "version": { - "type": "string", - "mandatory": false - }, - "platform": { - "type": "string", - "mandatory": false - }, - "domain": { - "type": "string", - "mandatory": false - }, - "admin_password": { - "type": "string", - "mandatory": true - }, - "authentication_kind": { - "type": "string", - "mandatory": false, - "options": [ - "internal", - "authelia" - ] - }, - "authentication_data_authelia_url_base": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_web_client_id": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_web_client_secret": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_android_client_id": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_android_client_secret": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_ios_client_id": { - "type": "string", - "mandatory": false - }, - "authentication_data_authelia_ios_client_secret": { - "type": "string", - "mandatory": false - }, - "public_share_password_necessity": { - "type": "string", - "mandatory": false, - "options": [ - "nothing", - "writable", - "all" - ] - }, - "public_share_password_policy_active": { - "type": "boolean", - "mandatory": false - } -} From 4bb1c0d1be4aee520cba968f7d5329be66d77ddf Mon Sep 17 00:00:00 2001 From: Fenris Wolf Date: Thu, 9 Oct 2025 01:49:33 +0200 Subject: [PATCH 11/11] [del] role:sqlite-for-hedgedoc --- roles/sqlite-for-hedgedoc/defaults/main.json | 4 ---- roles/sqlite-for-hedgedoc/tasks/main.json | 20 -------------------- roles/sqlite-for-hedgedoc/vardef.json | 10 ---------- 3 files changed, 34 deletions(-) delete mode 100644 roles/sqlite-for-hedgedoc/defaults/main.json delete mode 100644 roles/sqlite-for-hedgedoc/tasks/main.json delete mode 100644 roles/sqlite-for-hedgedoc/vardef.json diff --git a/roles/sqlite-for-hedgedoc/defaults/main.json b/roles/sqlite-for-hedgedoc/defaults/main.json deleted file mode 100644 index e574eac..0000000 --- a/roles/sqlite-for-hedgedoc/defaults/main.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "var_sqlite_for_hedgedoc_path": "/var/hedgedoc/data.sqlite", - "var_sqlite_for_hedgedoc_user_name": "hedgedoc" -} diff --git a/roles/sqlite-for-hedgedoc/tasks/main.json b/roles/sqlite-for-hedgedoc/tasks/main.json deleted file mode 100644 index 7495fca..0000000 --- a/roles/sqlite-for-hedgedoc/tasks/main.json +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "directory", - "become": true, - "ansible.builtin.file": { - "state": "directory", - "path": "{{var_sqlite_for_hedgedoc_path | dirname}}", - "owner": "{{var_hedgedoc_user_name}}" - } - }, - { - "name": "file", - "become": true, - "ansible.builtin.file": { - "state": "touch", - "path": "{{var_sqlite_for_hedgedoc_path}}", - "owner": "{{var_sqlite_for_hedgedoc_user_name}}" - } - } -] diff --git a/roles/sqlite-for-hedgedoc/vardef.json b/roles/sqlite-for-hedgedoc/vardef.json deleted file mode 100644 index e62f130..0000000 --- a/roles/sqlite-for-hedgedoc/vardef.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "path": { - "type": "string", - "mandatory": false - }, - "user_name": { - "type": "string", - "mandatory": false - } -}