diff --git a/hosts/picard/default.nix b/hosts/picard/default.nix index 984a4bb3..32c4caa0 100644 --- a/hosts/picard/default.nix +++ b/hosts/picard/default.nix @@ -66,6 +66,17 @@ enableACME = true; forceSSL = true; locations."/".return = "307 https://xyno.space$request_uri"; + } // (lib.findOutTlsConfig "xyno.systems" config); + + security.acme.certs."xyno.systems" = { + dnsProvider = "ionos"; + dnsResolver = "1.1.1.1:53"; + group = "nginx"; + extraDomainNames = [ + "*.xyno.systems" + ]; + credentialsFile = "${config.age.secrets.cloudflareAcme.path}"; + }; services.nginx.appendHttpConfig = '' diff --git a/lib/options.nix b/lib/options.nix index 13610bad..f4852ff8 100644 --- a/lib/options.nix +++ b/lib/options.nix @@ -15,4 +15,20 @@ rec { type = types.bool; example = true; }; + findOutTlsConfig = domain: config: + let + spl = builtins.splitString "." domain; + outerDomain = builtins.concatStringsSep "." (builtins.take (builtins.length spl - 1) spl); + in + lib.mkMerge [ + ((lib.hasAttr outerDomain config.acme.certs) && { + forceSSL = true; + useACMEHost = "${domain}"; + }) + (!(lib.hasAttr outerDomain config.acme.certs) && { + forceSSL = true; + enableACME = true; + }) + ]; + } diff --git a/nixos-modules/services/authelia.nix b/nixos-modules/services/authelia.nix new file mode 100644 index 00000000..eb57ae6c --- /dev/null +++ b/nixos-modules/services/authelia.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.ragon.services.authelia; + stateDir = "/var/lib/authelia"; + instanceName = "main"; +in +{ + options.ragon.services.authelia.enable = lib.mkEnableOption "Enables the authelia SSO Server"; + options.ragon.services.authelia.domain = + lib.mkOption { + type = lib.types.str; + default = "sso.xyno.systems"; + }; + config = lib.mkIf cfg.enable { + + ragon.secrets.autheliaStorageEncryption = { }; + ragon.secrets.autheliaSessionSecret = { }; + ragon.secrets.autheliaOidcIssuerPrivateKey = { }; + ragon.secrets.autheliaOidcHmacSecret = { }; + ragon.secrets.autheliaJwtSecret = { }; + ragon.secrets.autheliaEmail = { user = "authelia"; }; + services.authelia.instances.${instanceName} = { + enable = true; + secrets = { + storageEncryptionKeyFile = config.age.secrets.autheliaStorageEncryption.path; + sessionSecretFile = config.age.secrets.autheliaSessionSecret.path; + oidcIssuerPrivateKeyFile = config.age.secrets.autheliaOidcIssuerPrivateKey.path; + oidcHmacSecretFile = config.age.secrets.autheliaOidcHmacSecret.path; + jwtSecretFile = config.age.secrets.autheliaJwtSecret.path; + }; + settingstFiles = [ + config.age.secrets.autheliaEmail.path + ]; + settings = { + theme = "auto"; + default_2fa_method = "webauthn"; + authentication_backend = { + file = { + path = "${stateDir}/users.yml"; + }; + }; + storage = { + postgres = { + host = "/run/postgresql"; + }; + }; + notifier = { + smtp = { + address = "smtp://smtp.ionos.de:465"; + sender = "xyno.systems SSO "; + username = "machdas@xyno.space"; + subject = "[xyno.systems SSO] {title}"; + startup_check_address = "autodelete@phochkamp.de"; + }; + }; + + }; + }; + systemd.tmpfiles.rules = [ + "d ${stateDir} 0755 authelia authelia -" + ]; + ragon.agenix.secrets.autheliaSecret.owner = "authelia"; + services.nginx.virtualHosts."${cfg.domain}" = { + locations."/".proxyWebsockets = true; + locations."/".proxyPass = "http://127.0.0.1:${toString config.services.authelia.instances.${instanceName}.settings.server.port}"; + } // (lib.my.findOutTlsConfig cfg.domain config); + services.postgresql = { + enable = true; + + # Ensure the database, user, and permissions always exist + ensureDatabases = [ "authelia" ]; + ensureUsers = [ + { + name = "authelia"; + ensurePermissions."DATABASE authelia" = "ALL PRIVILEGES"; + } + ]; + }; + ragon.persist.extraDirectories = [ + "${stateDir}" + ]; + }; +} diff --git a/nixos-modules/services/hedgedoc.nix b/nixos-modules/services/hedgedoc.nix index dc77ec23..b796eef1 100644 --- a/nixos-modules/services/hedgedoc.nix +++ b/nixos-modules/services/hedgedoc.nix @@ -5,38 +5,54 @@ let in { options.ragon.services.hedgedoc.enable = lib.mkEnableOption "Enables the hedgedoc BitWarden Server"; - options.ragon.services.hedgedoc.domainPrefix = + options.ragon.services.hedgedoc.domain = lib.mkOption { type = lib.types.str; - default = "md"; + default = "md.xyno.systems"; }; config = lib.mkIf cfg.enable { + ragon.secrets.autheliaHedgedoc = { user = "authelia"; }; + services.authelia.instances.main.settingsFiles = [ + config.age.secrets.autheliaHedgedoc.path + ]; services.hedgedoc = { enable = true; environmentFile = "${config.age.secrets.hedgedocSecret.path}"; configuration = { protocolUseSSL = true; sessionSecret = "$SESSION_SECRET"; - allowEmailRegister = false; - domain = "${cfg.domainPrefix}.${domain}"; + allowAnonymous = false; + allowAnonymousEdits = false; + allowFreeURL = true; + email = false; + oauth2 = { + clientID = "$OAUTH2_CLIENT_ID"; + clientSecret = "$OAUTH2_CLIENT_SECRET"; + providerName = "xyno.systems SSO"; + authorizationURL = "https://sso.xyno.systems/oauth2/authorize"; + tokenURL = "https://sso.xyno.systems/oauth2/token"; + userProfileURL = "https://sso.xyno.systems/oauth2/userinfo"; + scope = "openid profile email"; + userProfileUsernameAttr = "sub"; + userProfileEmailAttr = "email"; + userProfileDisplayNameAttr = "name"; + }; + domain = "${cfg.domain}"; db = { dialect = "postgres"; host = "/run/postgresql"; database = "hedgedoc"; }; - allowAnonymousEdits = false; - allowFreeURL = true; }; }; ragon.agenix.secrets.hedgedocSecret.owner = "hedgedoc"; services.nginx.virtualHosts."${cfg.domainPrefix}.${domain}" = { - forceSSL = true; - useACMEHost = "${domain}"; locations."/".proxyWebsockets = true; locations."/".proxyPass = "http://127.0.0.1:${toString config.services.hedgedoc.configuration.port}"; - }; + } // (lib.my.findOutTlsConfig cfg.domain config); services.postgresql = { + enable = true; # Ensure the database, user, and permissions always exist diff --git a/secrets/autheliaEmail.age b/secrets/autheliaEmail.age new file mode 100644 index 00000000..5f9a03ea Binary files /dev/null and b/secrets/autheliaEmail.age differ diff --git a/secrets/autheliaHedgedoc.age b/secrets/autheliaHedgedoc.age new file mode 100644 index 00000000..97b1f7c5 Binary files /dev/null and b/secrets/autheliaHedgedoc.age differ diff --git a/secrets/autheliaJwtSecret.age b/secrets/autheliaJwtSecret.age new file mode 100644 index 00000000..5d9ba158 Binary files /dev/null and b/secrets/autheliaJwtSecret.age differ diff --git a/secrets/autheliaOidcHmacSecret.age b/secrets/autheliaOidcHmacSecret.age new file mode 100644 index 00000000..e583745d --- /dev/null +++ b/secrets/autheliaOidcHmacSecret.age @@ -0,0 +1,18 @@ +age-encryption.org/v1 +-> ssh-ed25519 WceKOQ GZX8heSkmIlR0J+glN7UIQEqaLlYiDAnAtCYCZink0s +4WCVq/9p/hy0PsLD7+Xicsqy4n/CCjF46AlxqUr950o +-> ssh-ed25519 ugHWWw 2/N4tJuirok6G0/i5Y3sHwzzWeVBXr55eWjT5q4C8QE +fso+V6NHhnE/4iW74YBllmgo8VDpA3QsDC5Rq1N5sLY +-> ssh-ed25519 UU9RSA 74yR0bY8fTudfvg9ZmunA1/8pc/vqfX0Kg1vufsjMX0 +ODe/eWGr70mV3isA1qb4l3ZwIczq7qEKEYXobZoPH3Q +-> ssh-ed25519 RJI3BA QBti5H5B20NtfcJ2IRLlV5PtbyzdqoluODTIynoDWnM +dBCr4Pz5hI0sZJzwD0yGFaqfNDOFSdUjuGFLoYL+waQ +-> ssh-ed25519 XnvJKw cErhiyosJiu1ieQrbTBvnB0A+5p5Hbda2TUVpSOAJVk +tF60UWD0gfrCZ6NJ16IcpWor68ODW8pEfPsLDqaJVzc +-> ssh-ed25519 7NL5Ng dl85dHSW8wlQX8jgSiS9T5n+MyCTGaNMucd4plvylG8 +rwWOHQvMbeC6AxktqLUEtFIs164lqv9AKR+3go7HD2Q +-> Mq'A-grease g '`\|R +UFazsV5qBZJpqg +--- JlKOgp5LUisHVWidRe4gM8gW7i4LIZp6QpX/39visbU +`q @*_§I*òU֍1_gUZGoiQR0<Ed[M f*Pr",|YH=2W|]2ǖ*Ğ`Bw* +QKU)q-ZenL~ \ No newline at end of file diff --git a/secrets/autheliaOidcIssuerPrivateKey.age b/secrets/autheliaOidcIssuerPrivateKey.age new file mode 100644 index 00000000..74db3fd1 Binary files /dev/null and b/secrets/autheliaOidcIssuerPrivateKey.age differ diff --git a/secrets/autheliaSessionSecret.age b/secrets/autheliaSessionSecret.age new file mode 100644 index 00000000..5d7336b5 Binary files /dev/null and b/secrets/autheliaSessionSecret.age differ diff --git a/secrets/autheliaStorageEncryption.age b/secrets/autheliaStorageEncryption.age new file mode 100644 index 00000000..6c03770c --- /dev/null +++ b/secrets/autheliaStorageEncryption.age @@ -0,0 +1,18 @@ +age-encryption.org/v1 +-> ssh-ed25519 WceKOQ kK8Inu+x8bNb40lDV/syTa5gihjFWLkjECtmVmBgWlg +yBiROhh6uRPoMsy8WU5c251QDagUthHBmBkiUUGy9Q0 +-> ssh-ed25519 ugHWWw 7iV+BBHTbvCtIApzmDKHDtp3DoPtVX8qrAF3VMV95nI +2jbqLmcnjVEgcIg+XaPjg4DhUFTBfVX0tDjJHLR4TGg +-> ssh-ed25519 UU9RSA pipBNg64f60hGCTU2DjcTVVI6OpV9OyFAy2r9hp9Ggc +R+FsNnj+TLIa8OS0jnZGb/aS+0BBtY1N5ELZSieHPFM +-> ssh-ed25519 RJI3BA HwU4W2QgXjVO127XV4pwHXLTZRC46R58m53bxV647jY +z0PgUObWS0rYjxMPZkXAwI4Ft5mgdkM+JCZxzHrfmlo +-> ssh-ed25519 XnvJKw CLN1vmYCs1yLmttKMhUifsp5k4rTXLLKk6PgBSXJ2C0 +EwDObMlQXc+Kio0MAQS0rgRmnBw9+N9SWeI4xmGrL9E +-> ssh-ed25519 7NL5Ng PIKvmA6BPcAunBDRdPpvWKztPXZu6h0LlE7RLtJIMzw +BVsAeAJFweKWhO6V9P3VoUxMtasI44OJPMhAlv5Hpco +-> 83-grease 9@=d4zg AUuq< Q}7Z +fRY6D7W54hHKl4J1JgHEQWxHJvXIkreypqabYStbcKboraN28Mv1pw44euOX4Tkk +A6rB1Zc/VgfB5XZr7Tf1Bn8Gwsrxt4eZs1QTVz5zSJqSBCNeOlb2y1guLRij +--- o7qrmcQdzLf5evB6xmNxv9oob81KzOiBHMGAFWRvgzg +PCqrIqԚoQŎl]0q/DBItn Dqv ßgf|DÚ)5|EtF3QN{sG^d ~2F3)|j{yx: \ No newline at end of file diff --git a/secrets/hedgedocSecret.age b/secrets/hedgedocSecret.age index bb0de103..accaeb0c 100644 Binary files a/secrets/hedgedocSecret.age and b/secrets/hedgedocSecret.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index c06187c5..6ae1aff8 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -38,4 +38,11 @@ in "picardSlidingSyncSecret.age".publicKeys = pubkeys.ragon.host "picard"; "picardResticPassword.age".publicKeys = pubkeys.ragon.host "picard"; "picardResticHealthCheckUrl.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaStorageEncryption.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaSessionSecret.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaOidcIssuerPrivateKey.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaOidcHmacSecret.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaJwtSecret.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaEmail.age".publicKeys = pubkeys.ragon.host "picard"; + "autheliaHedgedoc.age".publicKeys = pubkeys.ragon.host "picard"; }