Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
1c2ec9c
eel draft
jaysa68 May 6, 2026
dc768aa
ldap and krb modules
jaysa68 May 7, 2026
2eebbd3
nix fmt
jaysa68 May 7, 2026
a68f0db
move kerberos-kdc into auth module dir
jaysa68 May 7, 2026
9ebc0e5
use cpw instead of change-password in heimdal acl
jaysa68 May 7, 2026
ba0900a
publicKeyType should just be publicKey
jaysa68 May 7, 2026
52cd212
specify 312
jaysa68 May 7, 2026
2c97b1f
add buildPerlPackage
jaysa68 May 7, 2026
3853184
ok, custom installPhase
jaysa68 May 7, 2026
bcf8783
only need nativeBuildInputs makeWrapper
jaysa68 May 7, 2026
0352865
writeShellScriptBin
jaysa68 May 7, 2026
9655a2e
mkIf localDeployment
jaysa68 May 8, 2026
19c6b9f
fix format
jaysa68 May 8, 2026
d51cb62
still fixing deployment
jaysa68 May 8, 2026
e6f69e8
autoreconfHook
jaysa68 May 8, 2026
c011087
add eel host key and ldap deploy secret
jaysa68 May 8, 2026
20b3ffb
temp acme certs, fix ldap secret path
jaysa68 May 8, 2026
cc6cb22
extremely sad fucked up eels octet
jaysa68 May 8, 2026
93a6c6f
make ldap-keytab secret optional for now
jaysa68 May 8, 2026
771b9f4
rekey eel secrets
jaysa68 May 8, 2026
c4c61f8
at last, the keytab secret. after kdc dump
jaysa68 May 8, 2026
153e62f
nix fmt
jaysa68 May 8, 2026
8389c23
i have no mouth and i must rekey
jaysa68 May 8, 2026
b9e28cf
kerb backup script, firewall rules
jaysa68 May 8, 2026
2ab8319
TLS cipher string in OpenSSL compatible format
jaysa68 May 8, 2026
b74efb7
upload eels real key
May 8, 2026
e36852b
i forgot to rekey dude
May 8, 2026
00dd7dc
ldap-git-backup: add missing Error.pm perl dependency
May 8, 2026
52ee4f5
ldap-server: pass -F to slapcat for NixOS config dir
May 8, 2026
9916dfb
ldap-git-backup: patch /usr/bin/perl shebang for NixOS
May 8, 2026
d7516ec
ldap-server: add openssh to ldap-git-backup service PATH
May 8, 2026
a47d913
ldap-server: use openssh_gssapi in ldap-git-backup service PATH
May 8, 2026
48d7103
ldap-server: set git user config in ldap-git-backup script
jaysa68 May 8, 2026
0f074ef
ldap-server: treat git gc exit code 7 as success
jaysa68 May 8, 2026
c3d92d9
ldap-server: handle git gc exit 7 so git push always runs
jaysa68 May 8, 2026
28ea16f
add ldapai for admin access
jaysa68 May 8, 2026
7cf9918
temp patch to drop OpenLDAPaci
jaysa68 May 8, 2026
c9ab2dd
post-install fix pls
jaysa68 May 8, 2026
2ef45b7
nix fmt
jaysa68 May 9, 2026
adc9e86
add comment referring to puppet, motd, acme certs that are real
jaysa68 May 9, 2026
e657c91
correct kdc name
jaysa68 May 9, 2026
add6ed6
add openssl in base.nix
jaysa68 May 10, 2026
90e8ab0
fullchain cert
jaysa68 May 10, 2026
59b721b
dont mess with motd module
jaysa68 May 10, 2026
5ad2e2e
point clients at ldap0 and kdc (eel) as primary servers
jaysa68 May 10, 2026
e1b0feb
add acme cert lol
jaysa68 May 10, 2026
0b25818
enable fast false
jaysa68 May 10, 2026
689d47c
rekey ldap-eel keytab
jaysa68 May 10, 2026
cacf0c6
rekey secrets
May 10, 2026
6862d74
move kdc services start after ldap
jaysa68 May 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@
{
imports = commonModules ++ modules;
deployment.tags = [ group ];
deployment.allowLocalDeployment = true; # for debugging and deploying when github actions deployment breaks
deployment.targetHost = "${host}.ocf.berkeley.edu";
# TODO: Think of a less ugly way of doing this
deployment.targetUser =
Expand Down Expand Up @@ -284,6 +285,7 @@
ocf-cosmic-applets = ocf-cosmic-applets.packages.${final.stdenv.hostPlatform.system}.default;
ocf-cosmic-greeter = final.callPackage ./pkgs/ocf-cosmic-greeter.nix { };
ocf-hplip = final.callPackage ./pkgs/ocf-hplip.nix { };
ldap-git-backup = final.callPackage ./pkgs/ldap-git-backup.nix { };
};

agenix-rekey = agenix-rekey.configure {
Expand Down Expand Up @@ -320,7 +322,7 @@
system = overrideSystem.${host} or defaultSystem;
pkgs = pkgsFor system;
modules = colmenaConfig.imports;
specialArgs = { inherit inputs; };
specialArgs = { inherit self inputs; };
}
) colmenaHosts;
};
Expand Down
31 changes: 31 additions & 0 deletions hosts/servers/eel.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
pkgs,
lib,
config,
...
}:

{
imports = [ ../../hardware/virtualized.nix ];

networking.hostName = "eel";

ocf.motd.description = ''
LDAP and Kerberos server; crucial to the rest of our infrastucture working.
'';

ocf.network = {
enable = true;
lastOctet = 98;
};

ocf.kerberosKdc.enable = true;
ocf.ldapServer.enable = true;

ocf.acme.extraCerts = [
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the extraCerts urls should be passed into a url module options in the respective modules. this would enforce correct behavior as the modules would be able to require that certs are added for ldaps://* to work properly. make sure that the module throws an error when it is enabled without adding a tls cert

"ldap0.ocf.berkeley.edu"
"kdc.ocf.berkeley.edu"
];

system.stateVersion = "25.11";
}
15 changes: 9 additions & 6 deletions modules/auth.nix → modules/auth/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

let
cfg = config.ocf.auth;
keytabSecretPath = ../secrets/master-keyed/keytabs + "/${config.networking.hostName}.age";
keytabSecretPath = ../../secrets/master-keyed/keytabs + "/${config.networking.hostName}.age";
hasKeytab = builtins.pathExists keytabSecretPath;
in
{
Expand All @@ -16,7 +16,7 @@ in
};

config = lib.mkIf cfg.enable {
age.secrets.root-password-hash.rekeyFile = ../secrets/master-keyed/root-password-hash.age;
age.secrets.root-password-hash.rekeyFile = ../../secrets/master-keyed/root-password-hash.age;

# Per-host keytab for GSSAPI SSH authentication
# Only configured if the host has a keytab in secrets/master-keyed/keytabs/<hostname>.age
Expand All @@ -34,7 +34,7 @@ in

ldap = {
enable = true;
server = "ldaps://ldap.ocf.berkeley.edu";
server = "ldaps://ldap0.ocf.berkeley.edu ldaps://ldap.ocf.berkeley.edu";
base = "dc=OCF,dc=Berkeley,dc=EDU";
daemon.enable = true;
extraConfig = ''
Expand All @@ -59,7 +59,7 @@ in
};

environment.etc."ldap/ldap.conf".text = ''
URI ldaps://ldap.ocf.berkeley.edu
URI ldaps://ldap0.ocf.berkeley.edu ldaps://ldap.ocf.berkeley.edu
BASE dc=ocf,dc=berkeley,dc=edu
TLS_REQCERT hard
TLS_CACERT /etc/ssl/certs/ca-certificates.crt
Expand Down Expand Up @@ -126,8 +126,11 @@ in

settings = {
realms."OCF.BERKELEY.EDU" = {
admin_server = "kerberos.ocf.berkeley.edu";
kdc = [ "kerberos.ocf.berkeley.edu" ];
admin_server = "kdc.ocf.berkeley.edu";
kdc = [
"kdc.ocf.berkeley.edu"
"kerberos.ocf.berkeley.edu"
];
};
domain_realm = {
"ocf.berkeley.edu" = "OCF.BERKELEY.EDU";
Expand Down
44 changes: 44 additions & 0 deletions modules/auth/kerberos-kdc/check-pass-strength.py
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be done natively with kerberos, and all clients can enforce passwords by writing to kerberos and handling the error + maybe parsing the policy to get the password requirements.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does not need to be fixed now and is not a regression. will create an issue

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Enforce OCF account password complexity.

Designed to be used as an external password check program by Heimdal. Uses
ocflib to validate password strength with the same requirements as all other
password changing tools.

Details on interface Heimdal uses:
http://www.h5l.org/manual/HEAD/info/heimdal/Password-changing.html

Example usage:
$ echo -e "principal: ckuehl@OCF.BERKELEY.EDU\nnew-password: hello" | ./check-pass-strength

(ported directly from our old puppet module: https://github.com/ocf/puppet/blob/master/modules/ocf_kerberos/files/check-pass-strength)
"""
import sys

import ocflib.account.utils as utils
import ocflib.account.validators as validators


if __name__ == '__main__':
data = {}
while True:
line = sys.stdin.readline().rstrip('\n')
if line == 'end' or not line:
break
else:
line = line.split(':')
assert len(line) == 2, 'Could not parse input: ' + str(line)
data[line[0]] = line[1][1:]
try:
username = utils.extract_username_from_principal(data['principal'])
password = data['new-password']
except (KeyError, ValueError):
print('Did not receive principal or password from input', file=sys.stderr)
sys.exit(1)
else:
try:
validators.validate_password(username, password)
except ValueError as e:
print(e, file=sys.stderr)
else:
print('APPROVED')
128 changes: 128 additions & 0 deletions modules/auth/kerberos-kdc/default.nix
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are missing options specified in ocf/puppet. some might be default, but we should double check or specify anyway.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you moved kerberos-kdc/ under auth/, but did not add a requirement for security.krb5.package to be pkgs.heimdal. honestly i think its ok to just put it in modules/kerberos-kdc and add an assertion for security.krb5.package == pkgs.heimdal

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
{
lib,
config,
pkgs,
...
}:

let
cfg = config.ocf.kerberosKdc;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kdc should be KDC but whatever lol


# check-pass-strength wrapped with a Python environment that has ocflib.
checkPassStrength = pkgs.writeShellScript "check-pass-strength" ''
exec ${pkgs.python312.withPackages (ps: [ ps.ocflib ])}/bin/python3 \
${./check-pass-strength.py} "$@"
'';
in
{
options.ocf.kerberosKdc = {
enable = lib.mkEnableOption "OCF Kerberos KDC server (Heimdal)";
};

# The KDC database lives in /var/lib/heimdal/ and must be initialized manually:
# kadmin -l init OCF.BERKELEY.EDU
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was going to say do this automatically, but i am leaning on letting it fail so that the person deploying knows that they have to either init an empty kdc or migrate. so i think this is ok 👍

# For migration between hosts, dump with: kadmin -l dump <file>
# and restore with: kadmin -l load <file>

config = lib.mkIf cfg.enable {
services.kerberos_server = {
enable = true;
settings = {
kdc.extra-addresses = "127.0.0.2";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this necessary

kdc.enable-fast = false;

realms."OCF.BERKELEY.EDU" = {
acl = [
# Staff /admin principals have full KDC access
{
principal = "*/admin";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we check if a wildcard like this is ok? ocf/puppet explicitly specifies each user's admin and root principal

access = [ "all" ];
}
# Staff /root principals can change any principal's password
{
principal = "*/root";
access = [ "cpw" ];
target = "*@OCF.BERKELEY.EDU";
}
# create/admin is used by account creation tooling (ocflib)
{
principal = "create/admin";
access = [
"add"
"get"
"cpw"
];
target = "*@OCF.BERKELEY.EDU";
}
];
};

# a wrapper for ocflib's `validate_password`. more complex than doing
# it natively, but good to standardize password requirements across
# ocf/utils and ocf/ocfweb. heimdal's external password checking like
# this might not be easily possible in MIT...? consider if migrating
# off of heimdal kerb.

password_quality = {
policies = "external-check";
external_program = "${checkPassStrength}";
};
};
};

# KDC must start after slapd so SASL/GSSAPI is available for KDC → LDAP lookups
systemd.services.kdc.after = [ "openldap.service" ];

environment.systemPackages = [ pkgs.heimdal ];

networking.firewall = {
allowedTCPPorts = [
88 # kerberos
749 # kadmin
];
allowedUDPPorts = [
88 # kerberos
464 # kpasswd
];
};

systemd.tmpfiles.rules = [
"d /var/backups/kerberos 0700 root root -"
];

# unlike LDAP, not uploaded to github (for now?)
systemd.services.kerberos-git-backup = {
description = "Kerberos KDC git backup";
after = [ "kdc.service" ];
requires = [ "kdc.service" ];
path = [
pkgs.heimdal
pkgs.git
];
serviceConfig = {
Type = "oneshot";
User = "root";
UMask = "0077";
};
script = ''
dir=/var/backups/kerberos
[ -d "$dir/.git" ] || git -C "$dir" init -q
kadmin -l dump --decrypt "$dir/kerberos.dump"
git -C "$dir" add kerberos.dump
git -C "$dir" commit -q -m 'kerberos-git-backup' --allow-empty kerberos.dump
git -C "$dir" gc --auto --quiet
'';
};

systemd.timers.kerberos-git-backup = {
description = "Run Kerberos KDC git backup daily";
wantedBy = [ "timers.target" ];
timerConfig = {
# Run before rsnapshot so the backup server gets a fresh daily snapshot
OnCalendar = "*-*-* 01:00:00";
Persistent = true;
};
};

};
}
Loading
Loading