Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c9eb36d57 |
@@ -52,33 +52,6 @@ The home config is also exposed for use beyond these hosts:
|
|||||||
(`inputs.<this>.homeModules.default`). Consumers must supply the module args
|
(`inputs.<this>.homeModules.default`). Consumers must supply the module args
|
||||||
these expect: `inputs` always, `identity` for git/desktop, `portable` for sway.
|
these expect: `inputs` always, `identity` for git/desktop, `portable` for sway.
|
||||||
|
|
||||||
## Directory authentication (SSSD → Authentik LDAP)
|
|
||||||
|
|
||||||
Every NixOS host authenticates users against the Authentik LDAP outpost via
|
|
||||||
SSSD, implemented in [`modules/sssd.nix`](./modules/sssd.nix) and enabled by
|
|
||||||
default through the `services.authentikLdap.enable` option (added to
|
|
||||||
`baseModules`). The **EDaaS** WSL box opts out
|
|
||||||
(`services.authentikLdap.enable = false`) as a work-managed environment; the
|
|
||||||
macOS host is unaffected (SSSD is Linux-only).
|
|
||||||
|
|
||||||
- Connects over LDAPS to `ldap.lyrapup.pet:636`, search base
|
|
||||||
`dc=ldap,dc=goauthentik,dc=io`, binding as
|
|
||||||
`cn=sssd-bind,ou=users,dc=ldap,dc=goauthentik,dc=io`.
|
|
||||||
- The schema mappings match Authentik's non-standard object classes
|
|
||||||
(`goauthentik.io/ldap/user`, `goauthentik.io/ldap/group`) over the POSIX
|
|
||||||
attributes (`uid`, `uidNumber`, `gidNumber`, `homeDirectory`).
|
|
||||||
- Home directories are created on first login (`pam_mkhomedir`).
|
|
||||||
|
|
||||||
### Secrets (agenix)
|
|
||||||
|
|
||||||
The LDAP bind credential is an [agenix](https://github.com/ryantm/agenix)
|
|
||||||
secret, decrypted at activation with each host's SSH host key. The decrypted
|
|
||||||
plaintext is a full `sssd.conf` drop-in delivered to
|
|
||||||
`/etc/sssd/conf.d/01-ldap-authtok.conf`, so the password never enters the Nix
|
|
||||||
store. Owner setup (host recipient keys, encrypting the bind password, DNS for
|
|
||||||
`ldap.lyrapup.pet`, rebuild) is documented in
|
|
||||||
[`secrets/README.md`](./secrets/README.md).
|
|
||||||
|
|
||||||
## Applying
|
## Applying
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
Generated
+30
-52
@@ -25,11 +25,11 @@
|
|||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "pkgs/firefox-addons",
|
"dir": "pkgs/firefox-addons",
|
||||||
"lastModified": 1782014564,
|
"lastModified": 1782964936,
|
||||||
"narHash": "sha256-F/royQHyJAyKWKrV8AaG4Yf1yjzxa+PFk5xvTdvBrzk=",
|
"narHash": "sha256-wXEBDr7/dFQYhVpDwCKc9fkrYQQE4x0bdirX1bsLBGA=",
|
||||||
"owner": "rycee",
|
"owner": "rycee",
|
||||||
"repo": "nur-expressions",
|
"repo": "nur-expressions",
|
||||||
"rev": "d6668e34bbce788459883a1097bf0ee170f49c61",
|
"rev": "64feee871e0373dd6121e412c3fb12e372d1bfb5",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -93,11 +93,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1778716662,
|
"lastModified": 1782949081,
|
||||||
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
|
"narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=",
|
||||||
"owner": "hercules-ci",
|
"owner": "hercules-ci",
|
||||||
"repo": "flake-parts",
|
"repo": "flake-parts",
|
||||||
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
|
"rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -130,17 +130,16 @@
|
|||||||
"git-hooks": {
|
"git-hooks": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"gitignore": "gitignore",
|
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781733627,
|
"lastModified": 1782908218,
|
||||||
"narHash": "sha256-U3yTuGBnmXvXoQI3qkpfEDsn9RovQPAjN7ndRco+3u0=",
|
"narHash": "sha256-wLMOrPgVyeF3XmP+qfYcLqnVdTxikdcSvbIY7rA9jTA=",
|
||||||
"owner": "cachix",
|
"owner": "cachix",
|
||||||
"repo": "git-hooks.nix",
|
"repo": "git-hooks.nix",
|
||||||
"rev": "3bbec39bc90eadfa031e6f3b77272f3f60803e39",
|
"rev": "9f7e99119ece7705299595299f3b031f39356de1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -149,27 +148,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gitignore": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"git-hooks",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709087332,
|
|
||||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "hercules-ci",
|
|
||||||
"repo": "gitignore.nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
@@ -177,11 +155,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781981105,
|
"lastModified": 1782704057,
|
||||||
"narHash": "sha256-/1nNBbA7PrSQpTc9Qazkhl4kIPg+TNl0CjxS3UQJKlw=",
|
"narHash": "sha256-G1I1gd32F7mp9LAe1DaZ4ZL7NX5gyiKwdCMwro1Vrck=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "7bfff44b465909f69a442701293bc0badcf476dc",
|
"rev": "868d0a692de703c2de98fab61968e4e310b7c28e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -253,11 +231,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1782030356,
|
"lastModified": 1782636943,
|
||||||
"narHash": "sha256-h4WpMr455AfRub0FXBaon6Vcpe0waUyJ4GivIW6oyd4=",
|
"narHash": "sha256-ripjZa7BBLwL1uS5VJF3s/VpZpWt5ZIQEvkJ/FJNpQw=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nix-index-database",
|
"repo": "nix-index-database",
|
||||||
"rev": "3017088b49efd404f78e3b104f553b97e4af786b",
|
"rev": "058b1f9381fa79fcda49982370a750ff92dbba43",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -274,11 +252,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781520503,
|
"lastModified": 1782930066,
|
||||||
"narHash": "sha256-XuqQQG1qRyc3o8ld937sDLQNx+QrGV852KJ0dNglJDg=",
|
"narHash": "sha256-DIidHEvUpyFYxS2/Fl6PCMCPumLaV1epqT51BbOdEAQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixos-apple-silicon",
|
"repo": "nixos-apple-silicon",
|
||||||
"rev": "43043ad207529650f9fa68e1705f7cf9c08bfdeb",
|
"rev": "94cf7943ad3e6ec166858070d426ca9a71250f75",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -294,11 +272,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781622756,
|
"lastModified": 1782562157,
|
||||||
"narHash": "sha256-JrPh4M6S7aPsEE9tOENuZrxC6o2szSLlK+t4+nLke9s=",
|
"narHash": "sha256-a7+T6QSeowynwZ1ZJJbP8T8ntAytvrui8kFGJmIZt2c=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "08018c72174a4df5657f8d94178ac69fb9c243e5",
|
"rev": "a9cf7546a938c737b079e738de73934a13de9784",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -330,11 +308,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781216227,
|
"lastModified": 1782847225,
|
||||||
"narHash": "sha256-9mUW6gNwoN2SWc/l0fW4svPNOulXLl8ijqKyeSOGgJE=",
|
"narHash": "sha256-JC9PjqKYG9ve5U8aDOLQipp3+KLANBHUvGdLZlxzdKI=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "a0374025a863d007d98e3297f6aa46cc3141c2f0",
|
"rev": "95ca1e203c0750115fd4a6f17d5a245dfe6b1edd",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -346,11 +324,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs-unstable": {
|
"nixpkgs-unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781577229,
|
"lastModified": 1782723713,
|
||||||
"narHash": "sha256-lrp67w8AulE9Ks53n27I45ADSzbOCn4H+CNW1Ck8B+8=",
|
"narHash": "sha256-oPXCU/SSUokcGaJREHibG1CBX3+s/W7orDWQOZDsEeQ=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "567a49d1913ce81ac6e9582e3553dd90a955875f",
|
"rev": "b5aa0fbd538984f6e3d201be0005b4463d8b09f8",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -369,11 +347,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1781971008,
|
"lastModified": 1782919967,
|
||||||
"narHash": "sha256-T2u2RQZWKvD1J+TgcxjiJr8IymBr/PrUNeAGhMZFZU4=",
|
"narHash": "sha256-pRwjfB5HQJ3m8J8bOR43pPHtHI7VUJSqwLA3P06cOY0=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixvim",
|
"repo": "nixvim",
|
||||||
"rev": "7afca458f064f166d3a9c98db3b41a984fe46492",
|
"rev": "667c8471f4a0fb24d702d1a61af8609f1a5f1ba6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -46,15 +46,6 @@
|
|||||||
url = "github:cachix/git-hooks.nix";
|
url = "github:cachix/git-hooks.nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
# agenix: age-encrypted secrets, decrypted at activation with each host's
|
|
||||||
# SSH host key. Provides the SSSD LDAP bind credential (secrets/, see
|
|
||||||
# modules/sssd.nix). The darwin module is intentionally unused (SSSD is
|
|
||||||
# Linux-only).
|
|
||||||
agenix = {
|
|
||||||
url = "github:ryantm/agenix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
inputs.home-manager.follows = "home-manager";
|
|
||||||
};
|
|
||||||
# Declarative Neovim (the editor; see home/editor.nix). Release
|
# Declarative Neovim (the editor; see home/editor.nix). Release
|
||||||
# branch matched to the pinned nixpkgs (26.05); follows our nixpkgs to keep a
|
# branch matched to the pinned nixpkgs (26.05); follows our nixpkgs to keep a
|
||||||
# single nixpkgs in the closure. editor.nix sets programs.nixvim.nixpkgs.source
|
# single nixpkgs in the closure. editor.nix sets programs.nixvim.nixpkgs.source
|
||||||
@@ -132,9 +123,7 @@
|
|||||||
./modules/users.nix
|
./modules/users.nix
|
||||||
./modules/common-nixos.nix
|
./modules/common-nixos.nix
|
||||||
./modules/features.nix
|
./modules/features.nix
|
||||||
./modules/sssd.nix
|
|
||||||
commonModule
|
commonModule
|
||||||
inputs.agenix.nixosModules.default
|
|
||||||
home-manager.nixosModules.home-manager
|
home-manager.nixosModules.home-manager
|
||||||
{
|
{
|
||||||
home-manager.useGlobalPkgs = true;
|
home-manager.useGlobalPkgs = true;
|
||||||
|
|||||||
@@ -62,11 +62,6 @@
|
|||||||
|
|
||||||
features.swayDesktop.enable = false;
|
features.swayDesktop.enable = false;
|
||||||
|
|
||||||
# Opt out of fleet-wide SSSD/Authentik LDAP auth: this is a work-managed WSL
|
|
||||||
# box, not part of the personal directory. Every other NixOS host inherits the
|
|
||||||
# default-true from modules/sssd.nix.
|
|
||||||
services.authentikLdap.enable = false;
|
|
||||||
|
|
||||||
# NOTE: this user's systemd --user lingering -- so the home-manager renovate
|
# NOTE: this user's systemd --user lingering -- so the home-manager renovate
|
||||||
# timer fires without an open login session -- is enabled from the host table
|
# timer fires without an open login session -- is enabled from the host table
|
||||||
# in flake.nix (users.emmathorpe.linger = true) and applied by
|
# in flake.nix (users.emmathorpe.linger = true) and applied by
|
||||||
|
|||||||
@@ -1,130 +0,0 @@
|
|||||||
# Authentik LDAP authentication for NixOS hosts.
|
|
||||||
#
|
|
||||||
# Wires SSSD (System Security Services Daemon) to the Authentik LDAP outpost so
|
|
||||||
# every Linux host authenticates users against the same directory that backs the
|
|
||||||
# SSO stack. Enabled by default on every NixOS host via baseModules; the EDaaS
|
|
||||||
# WSL box opts out (services.authentikLdap.enable = false) because it is a
|
|
||||||
# work-managed Windows-hosted environment.
|
|
||||||
#
|
|
||||||
# The Authentik LDAP provider exposes NON-standard object classes/attributes
|
|
||||||
# (goauthentik.io/ldap/user, goauthentik.io/ldap/group) alongside the POSIX
|
|
||||||
# attributes (uid, uidNumber, gidNumber, homeDirectory), so the schema mappings
|
|
||||||
# below are explicit rather than relying on an RFC2307 default.
|
|
||||||
#
|
|
||||||
# The bind password is NOT inlined: services.sssd.config renders to the world-
|
|
||||||
# readable Nix store, so the credential is delivered out-of-band by agenix as an
|
|
||||||
# sssd.conf drop-in under /etc/sssd/conf.d/ (SSSD merges conf.d/*.conf after the
|
|
||||||
# main file). See secrets/README.md.
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
cfg = config.services.authentikLdap;
|
|
||||||
|
|
||||||
# Directory coordinates for the Authentik LDAP provider.
|
|
||||||
ldapUri = "ldaps://ldap.lyrapup.pet:636";
|
|
||||||
searchBase = "dc=ldap,dc=goauthentik,dc=io";
|
|
||||||
bindDn = "cn=sssd-bind,ou=users,dc=ldap,dc=goauthentik,dc=io";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.authentikLdap.enable =
|
|
||||||
lib.mkEnableOption "SSSD authentication against the Authentik LDAP outpost"
|
|
||||||
// {
|
|
||||||
default = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
|
||||||
services.sssd = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
# Non-secret sssd.conf. The bind password is injected separately via the
|
|
||||||
# agenix conf.d drop-in (ldap_default_authtok lives there, not here) to
|
|
||||||
# keep it out of the Nix store.
|
|
||||||
config = ''
|
|
||||||
[sssd]
|
|
||||||
config_file_version = 2
|
|
||||||
services = nss, pam
|
|
||||||
domains = default
|
|
||||||
|
|
||||||
[nss]
|
|
||||||
# Do not walk the whole directory for `getent passwd` etc.
|
|
||||||
filter_users = root
|
|
||||||
filter_groups = root
|
|
||||||
|
|
||||||
[pam]
|
|
||||||
|
|
||||||
[domain/default]
|
|
||||||
# --- Providers --------------------------------------------------------
|
|
||||||
id_provider = ldap
|
|
||||||
auth_provider = ldap
|
|
||||||
chpass_provider = none
|
|
||||||
access_provider = permit
|
|
||||||
|
|
||||||
# --- Connection -------------------------------------------------------
|
|
||||||
ldap_uri = ${ldapUri}
|
|
||||||
ldap_search_base = ${searchBase}
|
|
||||||
ldap_default_bind_dn = ${bindDn}
|
|
||||||
ldap_default_authtok_type = password
|
|
||||||
# ldap_default_authtok is supplied by the agenix drop-in in conf.d.
|
|
||||||
|
|
||||||
# --- TLS (LDAPS on 636; no StartTLS) ---------------------------------
|
|
||||||
ldap_id_use_start_tls = false
|
|
||||||
ldap_tls_reqcert = demand
|
|
||||||
|
|
||||||
# --- Schema: Authentik LDAP provider ---------------------------------
|
|
||||||
# Authentik returns DN-valued group membership (member/memberOf), so
|
|
||||||
# rfc2307bis (not rfc2307) is the correct base schema.
|
|
||||||
ldap_schema = rfc2307bis
|
|
||||||
|
|
||||||
# Users: goauthentik.io/ldap/user, keyed by uid; POSIX attrs are
|
|
||||||
# standard names (uidNumber/gidNumber/homeDirectory).
|
|
||||||
ldap_user_object_class = goauthentik.io/ldap/user
|
|
||||||
ldap_user_name = uid
|
|
||||||
ldap_user_uid_number = uidNumber
|
|
||||||
ldap_user_gid_number = gidNumber
|
|
||||||
ldap_user_home_directory = homeDirectory
|
|
||||||
ldap_user_gecos = displayName
|
|
||||||
ldap_user_shell = loginShell
|
|
||||||
|
|
||||||
# Groups: goauthentik.io/ldap/group, keyed by cn.
|
|
||||||
ldap_group_object_class = goauthentik.io/ldap/group
|
|
||||||
ldap_group_name = cn
|
|
||||||
ldap_group_gid_number = gidNumber
|
|
||||||
ldap_group_member = member
|
|
||||||
|
|
||||||
# --- Behaviour --------------------------------------------------------
|
|
||||||
cache_credentials = true
|
|
||||||
enumerate = false
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# agenix delivers the bind password as an sssd.conf drop-in. The decrypted
|
|
||||||
# plaintext IS a valid conf.d snippet:
|
|
||||||
#
|
|
||||||
# [domain/default]
|
|
||||||
# ldap_default_authtok = <the bind password>
|
|
||||||
#
|
|
||||||
# SSSD requires conf.d files to be root-owned and 0600 or it ignores them.
|
|
||||||
age.secrets.ldap-bind = {
|
|
||||||
file = ../secrets/ldap-bind.age;
|
|
||||||
path = "/etc/sssd/conf.d/01-ldap-authtok.conf";
|
|
||||||
owner = "root";
|
|
||||||
group = "root";
|
|
||||||
mode = "0600";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Restart SSSD when the credential drop-in changes. agenix writes secrets in
|
|
||||||
# a system activation script that runs before systemd (re)starts services on
|
|
||||||
# a `switch`, so the file is present by the time sssd starts; the trigger
|
|
||||||
# picks up rotations of the bind password.
|
|
||||||
systemd.services.sssd.restartTriggers = [ config.age.secrets.ldap-bind.path ];
|
|
||||||
|
|
||||||
# Create home directories on first login for LDAP users (they have no
|
|
||||||
# locally-provisioned home). NixOS wires nss + the SSSD PAM stack when
|
|
||||||
# services.sssd.enable is true; mkHomeDir adds pam_mkhomedir to it.
|
|
||||||
security.pam.services.login.makeHomeDir = true;
|
|
||||||
security.pam.services.sshd.makeHomeDir = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
# Secrets (agenix)
|
|
||||||
|
|
||||||
Encrypted secrets for the fleet, managed with [agenix](https://github.com/ryantm/agenix).
|
|
||||||
|
|
||||||
Each secret is an age-encrypted file (`*.age`) encrypted to a set of recipient
|
|
||||||
public keys declared in [`secrets.nix`](./secrets.nix). A host decrypts its
|
|
||||||
secrets at activation using its SSH **host** key
|
|
||||||
(`/etc/ssh/ssh_host_ed25519_key`), so every host that must read a secret has to
|
|
||||||
be listed as a recipient for it.
|
|
||||||
|
|
||||||
`secrets.nix` is read only by the `agenix` CLI. It is never imported into the
|
|
||||||
NixOS evaluation.
|
|
||||||
|
|
||||||
## Secrets in this repo
|
|
||||||
|
|
||||||
| File | Purpose | Recipients |
|
|
||||||
| --------------- | ----------------------------------------------------------------------- | ----------------------------------- |
|
|
||||||
| `ldap-bind.age` | SSSD → Authentik LDAP bind credential, as an `sssd.conf` drop-in snippet | all SSSD-enabled hosts (not EDaaS) |
|
|
||||||
|
|
||||||
Consumed by [`modules/sssd.nix`](../modules/sssd.nix) via
|
|
||||||
`age.secrets.ldap-bind.path`, which places the decrypted snippet at
|
|
||||||
`/etc/sssd/conf.d/01-ldap-authtok.conf`.
|
|
||||||
|
|
||||||
> **`ldap-bind.age` is not committed yet.** Only `ldap-bind.age.PLACEHOLDER`
|
|
||||||
> ships in this change (real host recipient keys and the real password were not
|
|
||||||
> available when it was written). Follow the steps below to create the real
|
|
||||||
> secret, then delete the `.PLACEHOLDER`.
|
|
||||||
|
|
||||||
## Owner setup checklist
|
|
||||||
|
|
||||||
Run these once (per new host or when the bind password rotates):
|
|
||||||
|
|
||||||
### 1. Collect host recipient keys
|
|
||||||
|
|
||||||
On each SSSD-enabled host (all Linux hosts **except** EDaaS):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cat /etc/ssh/ssh_host_ed25519_key.pub
|
|
||||||
```
|
|
||||||
|
|
||||||
Paste each value into the matching placeholder in `secrets.nix`, replacing the
|
|
||||||
`AAAA_PLACEHOLDER_REPLACE_ME_*` strings. (Optionally uncomment and set `admin`
|
|
||||||
to an operator user key so the secret can be edited off-host.)
|
|
||||||
|
|
||||||
### 2. Encrypt the bind password
|
|
||||||
|
|
||||||
The plaintext must be a **full sssd.conf drop-in snippet**, because SSSD cannot
|
|
||||||
read `ldap_default_authtok` from a separate file — it only merges `conf.d/*.conf`.
|
|
||||||
The content is exactly:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[domain/default]
|
|
||||||
ldap_default_authtok = <the sssd-bind service-account password>
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the password of the `sssd-bind` (Terraform: `sssd-bind`) Authentik LDAP
|
|
||||||
service account. Then, from the repo root:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Requires the agenix CLI: `nix run github:ryantm/agenix -- -e secrets/ldap-bind.age`
|
|
||||||
cd secrets
|
|
||||||
agenix -e ldap-bind.age
|
|
||||||
```
|
|
||||||
|
|
||||||
An `$EDITOR` opens; paste the two-line snippet above, save, quit. agenix writes
|
|
||||||
the encrypted `ldap-bind.age`. Commit it and delete `ldap-bind.age.PLACEHOLDER`.
|
|
||||||
|
|
||||||
### 3. Rekey after changing recipients
|
|
||||||
|
|
||||||
If you add/remove hosts in `secrets.nix`, re-encrypt every secret to the new
|
|
||||||
recipient set:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
cd secrets
|
|
||||||
agenix -r
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. DNS
|
|
||||||
|
|
||||||
`ldap.lyrapup.pet` must resolve to the Authentik LDAP outpost and serve LDAPS on
|
|
||||||
port 636 with a certificate the hosts trust (`ldap_tls_reqcert = demand`). If the
|
|
||||||
cert is not from a system-trusted CA, add it to the hosts' trust store
|
|
||||||
(`security.pki.certificateFiles`) or relax `ldap_tls_reqcert` in
|
|
||||||
`modules/sssd.nix`.
|
|
||||||
|
|
||||||
### 5. Rebuild
|
|
||||||
|
|
||||||
```sh
|
|
||||||
sudo nixos-rebuild switch --flake .#<host>
|
|
||||||
```
|
|
||||||
|
|
||||||
Verify with `getent passwd <ldap-user>` and `id <ldap-user>`.
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
THIS IS A PLACEHOLDER, NOT A REAL AGE SECRET.
|
|
||||||
|
|
||||||
The real secrets/ldap-bind.age is produced by the repo owner with `agenix -e`
|
|
||||||
(see secrets/README.md) and is a binary age-encrypted blob. It is intentionally
|
|
||||||
NOT committed here because:
|
|
||||||
* the real host age recipients are not available to the author of this change
|
|
||||||
(they are each host's /etc/ssh/ssh_host_ed25519_key.pub), and
|
|
||||||
* fabricating an encrypted blob or fake host keys would be misleading.
|
|
||||||
|
|
||||||
Committing this file as `ldap-bind.age` would let modules/sssd.nix reference
|
|
||||||
`../secrets/ldap-bind.age` and evaluate, but SSSD would fail to decrypt it at
|
|
||||||
runtime. Do ONE of the following before deploying:
|
|
||||||
|
|
||||||
1. Preferred: generate the real secret (secrets/README.md), commit it as
|
|
||||||
secrets/ldap-bind.age, and delete this .PLACEHOLDER file.
|
|
||||||
|
|
||||||
The decrypted plaintext must be a valid sssd.conf drop-in (NOT the bare
|
|
||||||
password):
|
|
||||||
|
|
||||||
[domain/default]
|
|
||||||
ldap_default_authtok = <the sssd-bind service-account password>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
let
|
|
||||||
lyrathorpe-mbp = "ssh-ed25519 AAAA_PLACEHOLDER_REPLACE_ME_mbp";
|
|
||||||
lyrathorpe-t400 = "ssh-ed25519 AAAA_PLACEHOLDER_REPLACE_ME_t400";
|
|
||||||
lyrathorpe-macpro31 = "ssh-ed25519 AAAA_PLACEHOLDER_REPLACE_ME_macpro31";
|
|
||||||
lyrathorpe-rpi5 = "ssh-ed25519 AAAA_PLACEHOLDER_REPLACE_ME_rpi5";
|
|
||||||
sssdHosts = [
|
|
||||||
lyrathorpe-mbp
|
|
||||||
lyrathorpe-t400
|
|
||||||
lyrathorpe-macpro31
|
|
||||||
lyrathorpe-rpi5
|
|
||||||
];
|
|
||||||
in
|
|
||||||
{
|
|
||||||
"ldap-bind.age".publicKeys = sssdHosts;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user