Codex bootstrapped this as an uncommitted, parallel identity/control plane under domain2 (lukasrosier.com) alongside the router migration; committing it now that it's been exercised together this session: - LLDAP admin login verified against a freshly rotated, pinix-only admin secret (pinixLldapAdmin.age, distinct from the lldapAdmin secret shared with blunix -- rotating one no longer risks the other). - Dex OIDC discovery and the LDAP connector work end-to-end through Traefik (dex.lukasrosier.com, head.lukasrosier.com). - Headscale's OIDC `allowed_groups` gate is intentionally not set yet: any account in this still-empty LLDAP directory may register a node for now. Re-add the "intern" gate once real accounts exist and the bootstrap is done. - tnix successfully joined headscale-pinix via a pre-auth key as a second, parallel tailscale identity (not yet made declarative). Not committed: tailnet-dns.nix (a separate, more speculative netns'd resolver experiment for this tailnet, untouched today) and its default.nix import. This remains a parallel control plane during bootstrap -- see docs/pinix-identity-stack.md. tailscale.nix on tnix/pinix, the existing blunix-controlled tailnet, and 0ff.space DNS are unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C5FvfdKcQjEFQ4aLrepcS1
103 lines
3.3 KiB
Nix
103 lines
3.3 KiB
Nix
{ config, pkgs, ... }:
|
|
|
|
{
|
|
# Keep the LDAP bind password out of Dex's generated configuration. The
|
|
# Dex LDAP connector expands $LDAP_BIND_PW after parsing the YAML, so this
|
|
# covers the connector without putting the secret in the store.
|
|
systemd.services.dex-ldap-env = {
|
|
description = "Render the pinix Dex LDAP bind password into a runtime env file";
|
|
before = [ "dex.service" ];
|
|
requiredBy = [ "dex.service" ];
|
|
after = [ "lldap.service" ];
|
|
wants = [ "lldap.service" ];
|
|
restartTriggers = [ config.age.secrets.pinixLldapAdmin.file ];
|
|
path = [ pkgs.coreutils pkgs.gnused ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
RuntimeDirectory = "dex-ldap-env";
|
|
RuntimeDirectoryMode = "0700";
|
|
ExecStart = "${pkgs.writeShellScript "pinix-dex-ldap-env" (builtins.readFile ../../../scripts/dex-ldap-env.sh)} ${config.age.secrets.pinixLldapAdmin.path} /run/dex-ldap-env/bindpw.env";
|
|
};
|
|
};
|
|
|
|
services.dex = {
|
|
enable = true;
|
|
environmentFile = "/run/dex-ldap-env/bindpw.env";
|
|
settings = {
|
|
logger.level = "info";
|
|
issuer = "https://dex.${config.domain2}/dex";
|
|
|
|
# Unlike the old blunix module, keep Dex's signing keys and sessions
|
|
# across a restart. StateDirectory is created for the DynamicUser by
|
|
# systemd and remains outside the Nix store.
|
|
storage = {
|
|
type = "sqlite3";
|
|
config.file = "/var/lib/dex/dex.db";
|
|
};
|
|
|
|
web.http = "127.0.0.1:5556";
|
|
|
|
# This is a separate control plane during bootstrap. Existing clients
|
|
# continue using blunix until the new LLDAP account/group and a new
|
|
# Headscale pre-auth key have been created manually.
|
|
staticClients = [
|
|
{
|
|
id = "headscale";
|
|
name = "headscale";
|
|
redirectURIs = [ "https://head.${config.domain2}/oidc/callback" ];
|
|
secretFile = config.age.secrets.oidcHeadscale.path;
|
|
}
|
|
];
|
|
|
|
connectors = [
|
|
{
|
|
type = "ldap";
|
|
id = "ldap";
|
|
name = "LDAP";
|
|
config = {
|
|
host = "127.0.0.1:3890";
|
|
insecureNoSSL = true;
|
|
startTLS = false;
|
|
bindDN = "uid=admin,ou=people,${config.ldapBaseDN2}";
|
|
bindPW = "$LDAP_BIND_PW";
|
|
userSearch = {
|
|
baseDN = "ou=people,${config.ldapBaseDN2}";
|
|
username = "uid";
|
|
idAttr = "uid";
|
|
emailAttr = "mail";
|
|
nameAttr = "displayName";
|
|
preferredUsernameAttr = "uid";
|
|
};
|
|
groupSearch = {
|
|
baseDN = "ou=groups,${config.ldapBaseDN2}";
|
|
filter = "(objectClass=groupOfUniqueNames)";
|
|
userMatchers = [
|
|
{
|
|
userAttr = "DN";
|
|
groupAttr = "member";
|
|
}
|
|
];
|
|
nameAttr = "cn";
|
|
};
|
|
};
|
|
}
|
|
];
|
|
};
|
|
};
|
|
|
|
systemd.services.dex = {
|
|
after = [ "lldap.service" ];
|
|
wants = [ "lldap.service" ];
|
|
serviceConfig = {
|
|
StateDirectory = "dex";
|
|
StateDirectoryMode = "0700";
|
|
Restart = "on-failure";
|
|
RestartSec = "5s";
|
|
};
|
|
restartTriggers = [
|
|
config.age.secrets.pinixLldapAdmin.file
|
|
config.age.secrets.oidcHeadscale.file
|
|
];
|
|
};
|
|
}
|