This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / configs / zitadel.nix
7.4 kB 223 lines
1let 2 domain = "id.lassul.us"; 3 port = 1411; 4in 5{ 6 config, 7 lib, 8 pkgs, 9 ... 10}: 11let 12 cfg = config.services.zitadel; 13 vars = config.clan.core.vars.generators.zitadel.files; 14 yaml = pkgs.formats.yaml { }; 15 configFile = yaml.generate "config.yaml" cfg.settings; 16 args = lib.cli.toCommandLineShellGNU { } { 17 config = [ configFile ]; 18 steps = [ 19 (yaml.generate "steps.yaml" cfg.steps) 20 vars."steps.yaml".path 21 ]; 22 masterkeyFile = cfg.masterKeyFile; 23 inherit (cfg) tlsMode; 24 }; 25 idpCredentials = name: url: { 26 prompts.client_id = { 27 description = '' 28 ${name} login on ${domain}: client id of an OAuth app (${url}) 29 with the callback URL 30 https://${domain}/ui/login/login/externalidp/callback 31 Leave empty to not offer ${name} logins. 32 ''; 33 persist = true; 34 }; 35 prompts.client_secret = { 36 description = "${name} login on ${domain}: client secret of that OAuth app"; 37 type = "hidden"; 38 persist = true; 39 }; 40 }; 41in 42{ 43 # Zitadel: identity provider for lassul.us services (OIDC). Anyone can 44 # register; users sign in with a passkey or an external login (GitHub, 45 # Google, their own OpenID provider via byoidc) linked to their account. The 46 # login policy, these logins and the services' projects and OIDC apps come from 47 # lass.zitadel (modules/zitadel); the zitadel-reconcile service applies 48 # them. Further IdPs and the grants of "managed" projects are done in the 49 # console at https://id.lassul.us/ui/console. 50 # 51 # Example projects for services on other hosts, once they speak OIDC (the 52 # client secret ends up in /var/lib/zitadel-apps/<project>-<app>.env here): 53 # lass.zitadel.projects.assist = { 54 # access = "declarative"; 55 # users = [ "lass@lassul.us" ]; 56 # apps.web.redirectUris = [ "https://assist.lassul.us/<callback>" ]; 57 # }; 58 # lass.zitadel.projects.flix = { 59 # access = "managed"; 60 # # jellyfin-plugin-sso with a provider named id.lassul.us 61 # apps.jellyfin.redirectUris = [ "https://flix.lassul.us/sso/OID/redirect/id.lassul.us" ]; 62 # }; 63 64 clan.core.vars.generators.zitadel = { 65 files."masterkey".owner = "zitadel"; 66 # initial password of the admin user lass, changed at first login 67 files."admin-password".deploy = false; 68 files."steps.yaml".owner = "zitadel"; 69 runtimeInputs = [ 70 pkgs.jq 71 pkgs.openssl 72 pkgs.pwgen 73 ]; 74 script = '' 75 openssl rand -hex 16 | tr -d '\n' > "$out/masterkey" 76 pwgen -s -c -n -y 32 1 | tr -d '\n' > "$out/admin-password" 77 jq -n --rawfile pw "$out/admin-password" \ 78 '{FirstInstance: {Org: {Human: {Password: $pw}}}}' > "$out/steps.yaml" 79 ''; 80 }; 81 82 services.zitadel = { 83 enable = true; 84 masterKeyFile = vars."masterkey".path; 85 settings = { 86 Port = port; 87 ExternalDomain = domain; 88 ExternalPort = 443; 89 ExternalSecure = true; 90 Machine.Identification = { 91 PrivateIp.Enabled = false; 92 Hostname.Enabled = true; 93 Webhook.Enabled = false; 94 }; 95 Database.postgres = { 96 Host = "/run/postgresql"; 97 Port = 5432; 98 Database = "zitadel"; 99 User.Username = "zitadel"; 100 Admin.Username = "zitadel"; 101 Admin.ExistingDatabase = "zitadel"; 102 }; 103 }; 104 steps.FirstInstance = { 105 InstanceName = "lassul.us"; 106 Org = { 107 Name = "lassul.us"; 108 Human = { 109 UserName = "lass"; 110 FirstName = "lass"; 111 LastName = "lassulus"; 112 Email = { 113 Address = "lass@lassul.us"; 114 Verified = true; 115 }; 116 PasswordChangeRequired = true; 117 }; 118 }; 119 }; 120 }; 121 122 lass.zitadel.loginPolicy = { 123 allowRegister = true; 124 allowExternalIdp = true; 125 allowUsernamePassword = true; 126 passwordlessType = "PASSWORDLESS_TYPE_ALLOWED"; 127 }; 128 # Verification codes and password resets. Zitadel asks every user whose 129 # address is unverified (registration, byoidc) to verify it before the 130 # login finishes. Sent as the send-only account id@lassul.us of the 131 # mailserver here (configs/mailserver.nix), which DKIM-signs it. 132 lass.zitadel.smtp = { 133 senderAddress = "id@lassul.us"; 134 senderName = "lassul.us ID"; 135 host = "mail.lassul.us:465"; 136 tls = true; 137 user = "id@lassul.us"; 138 passwordFile = config.clan.core.vars.generators.mailserver-id.files."password".path; 139 }; 140 lass.zitadel.idps = { 141 GitHub = { 142 type = "github"; 143 clientIdFile = config.clan.core.vars.generators.zitadel-github.files.client_id.path; 144 clientSecretFile = config.clan.core.vars.generators.zitadel-github.files.client_secret.path; 145 scopes = [ 146 "read:user" 147 "user:email" 148 ]; 149 }; 150 Google = { 151 type = "google"; 152 clientIdFile = config.clan.core.vars.generators.zitadel-google.files.client_id.path; 153 clientSecretFile = config.clan.core.vars.generators.zitadel-google.files.client_secret.path; 154 scopes = [ 155 "openid" 156 "profile" 157 "email" 158 ]; 159 }; 160 # byoidc (configs/byoidc.nix): sign in with any OpenID provider. Anyone 161 # can run one that claims any email address, so these accounts are never 162 # linked to existing ones. 163 byoidc = { 164 type = "oidc"; 165 name = "Your own provider"; 166 issuer = "https://byoidc.lassul.us"; 167 clientId = "zitadel"; 168 clientSecretFile = config.clan.core.vars.generators.byoidc.files."client-secret".path; 169 providerOptions = { 170 isLinkingAllowed = false; 171 isCreationAllowed = true; 172 isAutoCreation = true; 173 isAutoUpdate = true; 174 }; 175 }; 176 }; 177 clan.core.vars.generators.zitadel-github = 178 idpCredentials "GitHub" "https://github.com/settings/applications/new"; 179 clan.core.vars.generators.zitadel-google = 180 idpCredentials "Google" "https://console.cloud.google.com/apis/credentials"; 181 182 # The database and its owner come from ensureDatabases/ensureUsers, so the 183 # zitadel role needs no CREATEROLE/CREATEDB. `zitadel init zitadel` creates 184 # only the schemas inside it; start-from-setup then skips the role and 185 # database creation that start-from-init would attempt. 186 systemd.services.zitadel = { 187 after = [ "postgresql.target" ]; 188 requires = [ "postgresql.target" ]; 189 serviceConfig = { 190 ExecStartPre = "${lib.getExe' cfg.package "zitadel"} init zitadel --config ${configFile}"; 191 ExecStart = lib.mkForce "${lib.getExe' cfg.package "zitadel"} start-from-setup ${args}"; 192 }; 193 }; 194 195 services.postgresql = { 196 enable = true; 197 ensureDatabases = [ "zitadel" ]; 198 ensureUsers = [ 199 { 200 name = "zitadel"; 201 ensureDBOwnership = true; 202 } 203 ]; 204 }; 205 206 # users, passkeys, IdP links, OIDC apps; its secrets are encrypted with the 207 # masterkey from clan vars 208 lass.backup.state.zitadel.preBackup = '' 209 mkdir -p /var/backup/postgresql 210 ${pkgs.sudo}/bin/sudo -u postgres ${config.services.postgresql.package}/bin/pg_dump \ 211 zitadel | ${pkgs.gzip}/bin/gzip > /var/backup/postgresql/zitadel.sql.gz 212 ''; 213 214 # Zitadel serves the console, OIDC and its gRPC APIs on one port over h2c. 215 services.nginx.virtualHosts.${domain} = { 216 enableACME = true; 217 forceSSL = true; 218 locations."/".extraConfig = '' 219 grpc_pass grpc://127.0.0.1:${toString port}; 220 grpc_set_header Host $host; 221 ''; 222 }; 223}