This repository has no description
0

Configure Feed

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

superconfig / configs / zitadel.nix
5.9 kB 187 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, other OIDC) linked to their account. The login policy, the GitHub 46 # and Google 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 lass.zitadel.idps = { 129 GitHub = { 130 type = "github"; 131 clientIdFile = config.clan.core.vars.generators.zitadel-github.files.client_id.path; 132 clientSecretFile = config.clan.core.vars.generators.zitadel-github.files.client_secret.path; 133 scopes = [ 134 "read:user" 135 "user:email" 136 ]; 137 }; 138 Google = { 139 type = "google"; 140 clientIdFile = config.clan.core.vars.generators.zitadel-google.files.client_id.path; 141 clientSecretFile = config.clan.core.vars.generators.zitadel-google.files.client_secret.path; 142 scopes = [ 143 "openid" 144 "profile" 145 "email" 146 ]; 147 }; 148 }; 149 clan.core.vars.generators.zitadel-github = 150 idpCredentials "GitHub" "https://github.com/settings/applications/new"; 151 clan.core.vars.generators.zitadel-google = 152 idpCredentials "Google" "https://console.cloud.google.com/apis/credentials"; 153 154 # The database and its owner come from ensureDatabases/ensureUsers, so the 155 # zitadel role needs no CREATEROLE/CREATEDB. `zitadel init zitadel` creates 156 # only the schemas inside it; start-from-setup then skips the role and 157 # database creation that start-from-init would attempt. 158 systemd.services.zitadel = { 159 after = [ "postgresql.target" ]; 160 requires = [ "postgresql.target" ]; 161 serviceConfig = { 162 ExecStartPre = "${lib.getExe' cfg.package "zitadel"} init zitadel --config ${configFile}"; 163 ExecStart = lib.mkForce "${lib.getExe' cfg.package "zitadel"} start-from-setup ${args}"; 164 }; 165 }; 166 167 services.postgresql = { 168 enable = true; 169 ensureDatabases = [ "zitadel" ]; 170 ensureUsers = [ 171 { 172 name = "zitadel"; 173 ensureDBOwnership = true; 174 } 175 ]; 176 }; 177 178 # Zitadel serves the console, OIDC and its gRPC APIs on one port over h2c. 179 services.nginx.virtualHosts.${domain} = { 180 enableACME = true; 181 forceSSL = true; 182 locations."/".extraConfig = '' 183 grpc_pass grpc://127.0.0.1:${toString port}; 184 grpc_set_header Host $host; 185 ''; 186 }; 187}