diff --git a/modules/nixos/ldap/hosts.nix b/modules/nixos/ldap/hosts.nix index c76fcf48..da2ec6ca 100644 --- a/modules/nixos/ldap/hosts.nix +++ b/modules/nixos/ldap/hosts.nix @@ -1,11 +1,70 @@ { config, lib, + inputs, ... }: let - inherit (lib.options) mkOption; + inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapListToAttrs; + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkOptionDefault; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.lists) filter; + cfg = config.users.ldap; + ldap'lib = config.lib.ldap; + sysaccountModule = {config, nixosConfig, name, ldap, ...}: { + options = with lib.types; { + enable = mkEnableOption "sys account" // { + default = true; + }; + uid = mkOption { + type = str; + default = name; + }; + passwordFile = mkOption { + type = nullOr path; + default = null; + }; + object = mkOption { + type = ldap.lib.objectSettingsType; + }; + }; + config = { + object = { + enable = mkAlmostOptionDefault config.enable; + dn = mkOptionDefault (ldap.lib.withBaseDn "uid=${config.uid},${ldap.sysAccountDnSuffix}"); + settings = { + changeType = mkAlmostOptionDefault "add"; + settings = { + uid = mkOptionDefault config.uid; + objectClass' = { + name = "objectClass"; + initial = true; + value = [ "account" "simplesecurityobject" ]; + }; + userPassword = { + initial = true; + value = mkOptionDefault "initial123"; + }; + passwordExpirationTime = { + initial = true; + value = mkOptionDefault "20010101031407Z"; + }; + }; + }; + }; + }; + }; in { options.users.ldap = with lib.types; { + management = { + sysAccounts = mkOption { + type = attrsOf (submoduleWith { + modules = [ sysaccountModule ]; + inherit (config.lib.ldap) specialArgs; + }); + default = { }; + }; + }; domainDnSuffix = mkOption { type = str; default = ""; @@ -14,6 +73,10 @@ in { type = str; default = ""; }; + hostGroupDnSuffix = mkOption { + type = str; + default = ""; + }; serviceDnSuffix = mkOption { type = str; default = ""; @@ -23,4 +86,10 @@ in { default = ""; }; }; + config.users.ldap = { + management.objects = let + sysAccountObjects = mapAttrsToList (_: acc: acc.object) cfg.management.sysAccounts; + enabledObjects = filter (object: object.enable) sysAccountObjects; + in mapListToAttrs ldap'lib.mapObjectSettingsToPair enabledObjects; + }; } diff --git a/modules/nixos/ldap/ldap-common.sh b/modules/nixos/ldap/ldap-common.sh index 94515ce9..57cb997d 100644 --- a/modules/nixos/ldap/ldap-common.sh +++ b/modules/nixos/ldap/ldap-common.sh @@ -29,6 +29,12 @@ ldapwhoami() { command ldapwhoami "${LDAP_ARGS[@]}" } +ldappasswd() { + local LDAP_ARGS=("$@") + ldap_args_op + command ldappasswd "${LDAP_ARGS[@]}" +} + ldapsearch() { local LDAP_ARGS=("$@") ldap_args_op diff --git a/modules/nixos/ldap/ldap-sync.sh b/modules/nixos/ldap/ldap-sync.sh index 99c4e111..5ae06f4a 100644 --- a/modules/nixos/ldap/ldap-sync.sh +++ b/modules/nixos/ldap/ldap-sync.sh @@ -23,6 +23,80 @@ ldap_parse() { fi } +sysaccount_password() { + local LDAP_SYSACCOUNT_UID=$1 + local LDAP_SYSACCOUNT_PASSWORD_PATH=$2 + shift 2 + + echo "updating uid=$LDAP_SYSACCOUNT_UID,$LDAP_DNSUFFIX_SYSACCOUNT ..." >&2 + if ! ldappasswd -T "$LDAP_SYSACCOUNT_PASSWORD_PATH" "uid=$LDAP_SYSACCOUNT_UID,$LDAP_DNSUFFIX_SYSACCOUNT$LDAPBASE"; then + echo "failed to use ldappasswd, falling back to modify..." >&2 + ldapmodify <&2 + for LDAP_PRIVILEGE_PERMISSION_CN in "$@"; do + ipa privilege-add-permission "$LDAP_PRIVILEGE_CN" --permissions="$LDAP_PRIVILEGE_PERMISSION_CN" || true + done +} + +role_privileges() { + local LDAP_ROLE_CN=$1 LDAP_ROLE_PRIVILEGE_CN + shift 1 + + echo "updating cn=$LDAP_ROLE_CN,$LDAP_DNSUFFIX_ROLE ..." >&2 + for LDAP_ROLE_PRIVILEGE_CN in "$@"; do + ipa role-add-privilege "$LDAP_ROLE_CN" --privileges="$LDAP_ROLE_PRIVILEGE_CN" || true + done +} + +role_members() { + local LDAP_ROLE_CN=$1 LDAP_ROLE_MEMBER_DN LDAP_ROLE_MEMBER_CN LDAP_ROLE_MEMBER_TYPE + shift 1 + + echo "updating cn=$LDAP_ROLE_CN,$LDAP_DNSUFFIX_ROLE ..." >&2 + for LDAP_ROLE_MEMBER_DN in "$@"; do + case $LDAP_ROLE_MEMBER_DN in + uid=*",$LDAP_DNSUFFIX_USER"*) + LDAP_ROLE_MEMBER_TYPE=users + ;; + cn=*",$LDAP_DNSUFFIX_GROUP"*) + LDAP_ROLE_MEMBER_TYPE=groups + ;; + fqdn=*",$LDAP_DNSUFFIX_HOST"*) + LDAP_ROLE_MEMBER_TYPE=hosts + ;; + cn=*",$LDAP_DNSUFFIX_HOSTGROUP"*) + LDAP_ROLE_MEMBER_TYPE=hostgroups + ;; + krbprincipalname=*",$LDAP_DNSUFFIX_SERVICE"*) + LDAP_ROLE_MEMBER_TYPE=services + ;; + *) + echo "WARN: unknown role member type for $LDAP_ROLE_MEMBER_DN" >&2 + ipa role-modify "$LDAP_ROLE_CN" --addattr=member="$LDAP_ROLE_MEMBER_DN" || true + continue + ;; + esac + LDAP_ROLE_MEMBER_CN=${LDAP_ROLE_MEMBER_DN%%,*} + LDAP_ROLE_MEMBER_CN=${LDAP_ROLE_MEMBER_CN#*=} + ipa role-add-member "$LDAP_ROLE_CN" --${LDAP_ROLE_MEMBER_TYPE}="$LDAP_ROLE_MEMBER_CN" || true + done +} + smbsync_group() { local LDAP_GROUP_CN=$1 SMB_GROUP_DATA SMB_GROUP_SID shift 1 diff --git a/modules/nixos/ldap/management.nix b/modules/nixos/ldap/management.nix index fbc8ac5b..d502a844 100644 --- a/modules/nixos/ldap/management.nix +++ b/modules/nixos/ldap/management.nix @@ -10,10 +10,18 @@ inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.attrsets) attrValues; inherit (lib.lists) filter; - inherit (lib.strings) concatStringsSep concatMapStringsSep escapeShellArgs; + inherit (lib.strings) concatStringsSep concatMapStringsSep; inherit (config.users) ldap; cfg = config.users.ldap.management; + ldap'lib = config.lib.ldap; enabledObjects = filter (object: object.enable) (attrValues cfg.objects); + sysAccounts = filter (acc: acc.enable) (attrValues cfg.sysAccounts); + sysAccountPasswordFiles = concatMapStringsSep "," (acc: "${acc.uid}=${toString acc.passwordFile}") sysAccounts; + privileges = filter (priv: priv.enable) (attrValues cfg.privileges); + privilegePermissions = concatMapStringsSep "," (priv: "${priv.cn}=${concatStringsSep "." priv.permissions}") privileges; + roles = filter (role: role.enable) (attrValues cfg.roles); + rolePrivileges = concatMapStringsSep "," (role: "${role.cn}=${concatStringsSep "." role.privileges}") roles; + roleMembers = concatMapStringsSep "+" (role: "${role.cn}=${concatMapStringsSep "%" ldap'lib.withBaseDn role.members}") roles; smbSyncUsers = filter (user: user.samba.sync.enable) (attrValues cfg.users); smbSyncGroups = filter (group: group.samba.sync.enable) (attrValues cfg.groups); modifyObjects = filter (object: object.changeType == "modify") enabledObjects; @@ -42,6 +50,56 @@ ldapmodify -f "$MAN_LDAP_DELETE" ''; + sysaccountScript = pkgs.writeShellScript "ldap-management-sysaccounts.sh" '' + set -eu + + source ${./ldap-common.sh} + source ${./ldap-sync.sh} + + IFS=',' declare -a 'SYSACCOUNT_PASSWORD_FILES=($SYSACCOUNT_PASSWORD_FILES)' + for SYSACCOUNT_PASSWORD_FILE in "''${SYSACCOUNT_PASSWORD_FILES[@]}"; do + SYSACCOUNT_UID=''${SYSACCOUNT_PASSWORD_FILE%%=*} + SYSACCOUNT_PASSWORD_PATH=''${SYSACCOUNT_PASSWORD_FILE#*=} + if [[ -n $SYSACCOUNT_PASSWORD_PATH ]]; then + sysaccount_password "$SYSACCOUNT_UID" "$SYSACCOUNT_PASSWORD_PATH" + fi + done + ''; + privilegeScript = pkgs.writeShellScript "ldap-management-privileges.sh" '' + set -eu + + source ${./ldap-common.sh} + source ${./ldap-sync.sh} + + IFS=',' declare -a 'PRIVILEGE_PERMISSIONS=($PRIVILEGE_PERMISSIONS)' + for PRIVILEGE_PERMISSION in "''${PRIVILEGE_PERMISSIONS[@]}"; do + PRIVILEGE_CN=''${PRIVILEGE_PERMISSION%%=*} + PRIVILEGE_PERMS=''${PRIVILEGE_PERMISSION#*=} + IFS='.' declare -a 'PRIVILEGE_PERMS=($PRIVILEGE_PERMS)' + privilege_permissions "$PRIVILEGE_CN" "''${PRIVILEGE_PERMS[@]}" + done + ''; + roleScript = pkgs.writeShellScript "ldap-management-rols.sh" '' + set -eu + + source ${./ldap-common.sh} + source ${./ldap-sync.sh} + + IFS=',' declare -a 'ROLE_PRIVILEGES=($ROLE_PRIVILEGES)' + for ROLE_PRIVILEGE in "''${ROLE_PRIVILEGES[@]}"; do + ROLE_CN=''${ROLE_PRIVILEGE%%=*} + ROLE_PRIVS=''${ROLE_PRIVILEGE#*=} + IFS='.' declare -a 'ROLE_PRIVS=($ROLE_PRIVS)' + role_privileges "$ROLE_CN" "''${ROLE_PRIVS[@]}" + done + IFS='+' declare -a 'ROLE_MEMBERS=($ROLE_MEMBERS)' + for ROLE_MEMBER in "''${ROLE_MEMBERS[@]}"; do + ROLE_CN=''${ROLE_MEMBER%%=*} + ROLE_MEMS=''${ROLE_MEMBER#*=} + IFS='%' declare -a 'ROLE_MEMS=($ROLE_MEMS)' + role_members "$ROLE_CN" "''${ROLE_MEMS[@]}" + done + ''; syncScript = pkgs.writeShellScript "ldap-management-sync.sh" '' set -eu @@ -106,7 +164,9 @@ in { ]; serviceConfig = { Type = mkOptionDefault "oneshot"; - ExecStart = [ "${managementScript}" ]; + ExecStart = [ + "${managementScript}" + ]; RemainAfterExit = mkOptionDefault true; }; }; @@ -117,10 +177,15 @@ in { path = mkMerge [ path [ pkgs.xxd ] + (mkIf config.security.ipa.enable [ pkgs.freeipa ]) ]; restartTriggers = [ smbSyncGroupNames smbSyncUserNames + sysAccountPasswordFiles + privilegePermissions + rolePrivileges + roleMembers ]; environment = mkMerge [ ldapEnv @@ -128,13 +193,29 @@ in { (mapOptionDefaults { LDAP_DNSUFFIX_USER = ldap.userDnSuffix; LDAP_DNSUFFIX_GROUP = ldap.groupDnSuffix; + LDAP_DNSUFFIX_SYSACCOUNT = ldap.sysAccountDnSuffix; + LDAP_DNSUFFIX_PERMISSION = ldap.permissionDnSuffix; + LDAP_DNSUFFIX_PRIVILEGE = ldap.privilegeDnSuffix; + LDAP_DNSUFFIX_ROLE = ldap.roleDnSuffix; + LDAP_DNSUFFIX_HOST = ldap.hostDnSuffix; + LDAP_DNSUFFIX_HOSTGROUP = ldap.hostGroupDnSuffix; + LDAP_DNSUFFIX_SERVICE = ldap.serviceDnSuffix; SMB_SYNC_GROUPS = concatStringsSep "," smbSyncGroupNames; SMB_SYNC_USERS = concatStringsSep "," smbSyncUserNames; + SYSACCOUNT_PASSWORD_FILES = sysAccountPasswordFiles; + PRIVILEGE_PERMISSIONS = privilegePermissions; + ROLE_PRIVILEGES = rolePrivileges; + ROLE_MEMBERS = roleMembers; }) ]; serviceConfig = { Type = mkOptionDefault "oneshot"; - ExecStart = [ "${syncScript}" ]; + ExecStart = mkMerge [ + (mkIf (privileges != [ ]) [ "${privilegeScript}" ]) + (mkIf (roles != [ ]) [ "${roleScript}" ]) + [ "${syncScript}" ] + (mkIf (sysAccounts != [ ]) [ "${sysaccountScript}" ]) + ]; }; }; timers.ldap-management-sync = { diff --git a/modules/nixos/ldap/object.nix b/modules/nixos/ldap/object.nix index 0d4323f0..83b9952c 100644 --- a/modules/nixos/ldap/object.nix +++ b/modules/nixos/ldap/object.nix @@ -62,7 +62,7 @@ ''; in { modify = object: let - enabledSettings' = filterAttrs (_: setting: setting.enable) object.settings; + enabledSettings' = filterAttrs (_: setting: setting.enable && !setting.initial) object.settings; enabledSettings = ldap'lib.mkLdapModifyObjectSettings enabledSettings'; replaceSettings' = filterAttrs (_: setting: setting.modifyType == "replace") enabledSettings'; replaceSettings = ldap'lib.mkLdapModifyObjectSettings replaceSettings'; @@ -114,6 +114,10 @@ value = mkOption { type = ldapValueType; }; + initial = mkOption { + type = bool; + default = false; + }; modifyType = mkOption { type = enum [ "replace" "add" "delete" ]; default = "replace"; diff --git a/modules/nixos/ldap/permissions.nix b/modules/nixos/ldap/permissions.nix index 1a3759c3..3f31ea48 100644 --- a/modules/nixos/ldap/permissions.nix +++ b/modules/nixos/ldap/permissions.nix @@ -5,7 +5,7 @@ ... }: let inherit (inputs.self.lib.lib) mkAlmostOptionDefault mapOptionDefaults mapListToAttrs; - inherit (lib.options) mkOption; + inherit (lib.options) mkOption mkEnableOption; inherit (lib.modules) mkIf mkMerge mkOptionDefault; inherit (lib.attrsets) attrNames mapAttrs mapAttrsToList; inherit (lib.lists) filter; @@ -55,8 +55,7 @@ }; sysaccount = { location = ldap.sysAccountDnSuffix; - # TODO: targetFilter - target = "uid=*"; + targetFilter = "(objectclass=account)"; }; }; in { @@ -95,13 +94,13 @@ }; members = mkOption { type = listOf str; + default = [ ]; }; object = mkOption { type = ldap.lib.objectSettingsType; }; }; config = let - conf.members = mkIf (config.bindType != "permission") (mkOptionDefault [ ]); conf.targetFilter = mkIf (config.target != null) (mkOptionDefault null); conf.object = { dn = mkOptionDefault (ldap.lib.withBaseDn "cn=${config.cn},${ldap.permissionDnSuffix}"); @@ -129,6 +128,73 @@ }; in mkMerge [ conf target ]; }; + privilegeModule = {config, name, ldap, ...}: { + options = with lib.types; { + enable = mkEnableOption "privilege" // { + default = true; + }; + cn = mkOption { + type = str; + default = name; + }; + permissions = mkOption { + type = listOf str; + default = [ ]; + }; + object = mkOption { + type = ldap.lib.objectSettingsType; + }; + }; + config = { + object = { + enable = mkAlmostOptionDefault config.enable; + dn = mkOptionDefault (ldap.lib.withBaseDn "cn=${config.cn},${ldap.privilegeDnSuffix}"); + settings = { + changeType = mkAlmostOptionDefault "add"; + settings = mapOptionDefaults { + cn = config.cn; + objectClass = [ "top" "nestedgroup" "groupofnames" ]; + }; + }; + }; + }; + }; + roleModule = {config, name, ldap, ...}: { + options = with lib.types; { + enable = mkEnableOption "role" // { + default = true; + }; + cn = mkOption { + type = str; + default = name; + }; + privileges = mkOption { + type = listOf str; + default = [ ]; + }; + members = mkOption { + type = listOf str; + default = [ ]; + }; + object = mkOption { + type = ldap.lib.objectSettingsType; + }; + }; + config = { + object = { + enable = mkAlmostOptionDefault config.enable; + dn = mkOptionDefault (ldap.lib.withBaseDn "cn=${config.cn},${ldap.roleDnSuffix}"); + settings = { + changeType = mkAlmostOptionDefault "add"; + settings = mapOptionDefaults { + cn = config.cn; + objectClass = [ "top" "nestedgroup" "groupofnames" ]; + member = mkIf (config.members != [ ]) (mkOptionDefault (map ldap.lib.withBaseDn config.members)); + }; + }; + }; + }; + }; in { options.users.ldap = with lib.types; { management = { @@ -139,6 +205,20 @@ in { }); default = { }; }; + privileges = mkOption { + type = attrsOf (submoduleWith { + modules = [ privilegeModule ]; + inherit (config.lib.ldap) specialArgs; + }); + default = { }; + }; + roles = mkOption { + type = attrsOf (submoduleWith { + modules = [ roleModule ]; + inherit (config.lib.ldap) specialArgs; + }); + default = { }; + }; }; permissionDnSuffix = mkOption { type = str; @@ -152,8 +232,9 @@ in { }; config.users.ldap = { management.objects = let - permissionObjects = mapAttrsToList (_: user: user.object) cfg.management.permissions; - enabledObjects = filter (object: object.enable) (permissionObjects); + permissionObjects = mapAttrsToList (_: perm: perm.object) cfg.management.permissions; + privilegeObjects = mapAttrsToList (_: priv: priv.object) cfg.management.privileges; + enabledObjects = filter (object: object.enable) (permissionObjects ++ privilegeObjects); in mapListToAttrs ldap'lib.mapObjectSettingsToPair enabledObjects; }; } diff --git a/nixos/ipa.nix b/nixos/ipa.nix index fa939324..4c1d9e74 100644 --- a/nixos/ipa.nix +++ b/nixos/ipa.nix @@ -31,6 +31,7 @@ in { roleDnSuffix = mkDefault "cn=roles,cn=accounts,"; serviceDnSuffix = mkDefault "cn=services,cn=accounts,"; hostDnSuffix = mkDefault "cn=computers,cn=accounts,"; + hostGroupDnSuffix = mkDefault "cn=hostgroups,cn=accounts,"; sysAccountDnSuffix = mkDefault "cn=sysaccounts,cn=etc,"; domainDnSuffix = mkDefault "cn=ad,cn=etc,"; }; diff --git a/nixos/ldap/permissions.nix b/nixos/ldap/permissions.nix index 7f24d516..5c80715c 100644 --- a/nixos/ldap/permissions.nix +++ b/nixos/ldap/permissions.nix @@ -2,7 +2,6 @@ inherit (lib.modules) mkDefault; inherit (config.users) ldap; inherit (ldap.management) permissions; - adminPriv = "cn=Custom Management Admin,${ldap.privilegeDnSuffix}"; in { config.users.ldap.management = { enable = mkDefault true; @@ -16,7 +15,6 @@ in { location = ldap.permissionDnSuffix; target = "cn=*"; rights = "all"; - members = [ adminPriv ]; attrs = [ "member" "cn" "o" "ou" "owner" "description" "objectclass" "seealso" "businesscategory" "ipapermtarget" "ipapermright" "ipapermincludedattr" "ipapermbindruletype" "ipapermexcludedattr" "ipapermtargetto" "ipapermissiontype" "ipapermlocation" "ipapermdefaultattr" "ipapermtargetfrom" "ipapermtargetfilter" @@ -26,7 +24,6 @@ in { location = ldap.privilegeDnSuffix; target = "cn=*"; rights = "all"; - members = [ adminPriv ]; attrs = [ "member" "memberof" "cn" "o" "ou" "owner" "description" "objectclass" "seealso" "businesscategory" ]; @@ -35,52 +32,82 @@ in { location = ldap.roleDnSuffix; target = "cn=*"; rights = "all"; - members = [ adminPriv ]; attrs = [ "member" "memberof" "cn" "o" "ou" "owner" "description" "objectclass" "seealso" "businesscategory" ]; }; "Custom Role Modify" = { targetType = "role"; - rights = [ "write" ]; - members = [ adminPriv ]; + rights = [ "write" "add" ]; attrs = permissions."Custom Role Admin".attrs; }; "Custom Host Permission" = { targetType = "host"; rights = [ "write" ]; - members = [ adminPriv ]; attrs = [ "memberof" ]; }; "Custom SysAccount Permission" = { targetType = "sysaccount"; - rights = [ "write" ]; - members = [ adminPriv ]; + rights = "all"; attrs = [ - "memberof" + "member" "memberof" "uid" "o" "ou" "description" "objectclass" "seealso" "businesscategory" + "passwordExpirationTime" "nsIdleTimeout" + ]; + }; + "Custom SysAccount Admin" = { + location = ldap.sysAccountDnSuffix; + target = "uid=*"; + rights = [ "add" "write" "delete" ]; + attrs = permissions."Custom SysAccount Permission".attrs ++ [ + "userPassword" ]; }; "Custom Service Permission" = { targetType = "service"; rights = [ "write" ]; - members = [ adminPriv ]; attrs = [ "memberof" ]; }; }; - objects = { - ${adminPriv} = { - changeType = "add"; - settings = { - objectClass = [ "top" "nestedgroup" "groupofnames" ]; - member = map config.lib.ldap.withBaseDn [ - "cn=Security Architect,${ldap.roleDnSuffix}" - ]; - }; + privileges = { + "Custom Management Admin" = { + permissions = [ + "Custom Permission Admin" + "Custom Privilege Admin" + "Custom Role Admin" + "Custom Role Modify" + "Custom Host Permission" + "Custom SysAccount Permission" + "Custom SysAccount Admin" + "Custom Service Permission" + ]; }; + }; + roles = { + "Security Architect" = { + privileges = [ + "Custom Management Admin" + # you can't manage roles if you can't see them .-. + "RBAC Readers" + ]; + # allow reimu to actually make these changes... + members = [ + "fqdn=reimu.${config.networking.domain},${ldap.hostDnSuffix}" + ]; + }; + }; + sysAccounts = { + peep = { + passwordFile = config.sops.secrets.ldap-peep-password.path; + }; + keycloak = { + passwordFile = config.sops.secrets.ldap-keycloak-password.path; + }; + }; + objects = { # change default public access "cn=System: Read User Compat Tree,${ldap.permissionDnSuffix}" = { settings.ipaPermBindRuleType = "all"; @@ -91,10 +118,16 @@ in { "cn=System: Read User Standard Attributes,${ldap.permissionDnSuffix}" = { settings.ipaPermBindRuleType = "all"; }; - # allow reimu to actually make these changes... - "cn=Security Architect,${ldap.roleDnSuffix}" = { - settings.member = [ "fqdn=reimu.${config.networking.domain},${ldap.hostDnSuffix}${ldap.base}" ]; - }; + }; + }; + config.sops.secrets = let + sopsFile = mkDefault ../secrets/ldap.yaml; + in { + ldap-peep-password = { + inherit sopsFile; + }; + ldap-keycloak-password = { + inherit sopsFile; }; }; } diff --git a/nixos/ldap/samba.nix b/nixos/ldap/samba.nix index 1c24a47f..5bbd4312 100644 --- a/nixos/ldap/samba.nix +++ b/nixos/ldap/samba.nix @@ -1,10 +1,6 @@ {config, lib, ...}: let inherit (lib.modules) mkDefault; inherit (config.users) ldap; - inherit (ldap.management) permissions; - adminPriv = "cn=Custom Management Admin,${ldap.privilegeDnSuffix}"; - smbPriv = "cn=Samba smbd,${ldap.privilegeDnSuffix}"; - smbRole = "cn=Samba smbd,${ldap.roleDnSuffix}"; smbAccountAttrs = [ "sambasid" "sambapwdlastset" "sambaacctflags" "sambapasswordhistory" "sambantpassword" ]; smbGroupAttrs = [ "sambasid" "sambagrouptype" ]; smbDomainAttrs = [ "sambasid" "sambaRefuseMachinePwdChange" "sambaMinPwdLength" "sambaAlgorithmicRidBase" "sambaPwdHistoryLength" "sambaDomainName" "sambaMinPwdAge" "sambaMaxPwdAge" "sambaLockoutThreshold" "sambaForceLogoff" "sambaLogonToChgPwd" "sambaLockoutObservationWindow" "sambaNextUserRid" "sambaLockoutDuration" ]; @@ -15,70 +11,58 @@ in { "Custom Samba User Read" = { targetType = "user"; attrs = [ "ipanthash" "ipanthomedirectory" "ipanthomedirectorydrive" "ipantlogonscript" "ipantprofilepath" "ipantsecurityidentifier" ] ++ smbAccountAttrs; - members = [ smbPriv ]; }; "Custom Samba User Modify" = { targetType = "user"; rights = [ "write" ]; attrs = smbAccountAttrs; - members = permissions."Custom Samba User Admin".members; }; "Custom Samba User Admin" = { targetType = "user"; - rights = [ "write" "add" ]; - attrs = [ "objectclass" ]; - members = [ adminPriv ]; + rights = [ "write" ]; + attrs = smbAccountAttrs ++ [ "objectclass" ]; }; "Custom Samba Group Read" = { targetType = "user-group"; attrs = [ "ipantsecurityidentifier" "gidnumber" ] ++ smbGroupAttrs; - members = [ smbPriv ]; }; "Custom Samba Group Modify" = { targetType = "user-group"; rights = [ "write" ]; attrs = smbGroupAttrs; - members = permissions."Custom Samba Group Admin".members; }; "Custom Samba Group Admin" = { targetType = "user-group"; - rights = [ "write" "add" ]; - attrs = [ "objectclass" ]; - members = [ adminPriv ]; + rights = [ "write" ]; + attrs = smbGroupAttrs ++ [ "objectclass" ]; }; "Custom Samba Domain Read" = { targetType = "samba-domain"; attrs = [ "objectClass" ] ++ smbDomainAttrs; - members = [ smbPriv ]; }; "Custom Samba Domain Modify" = { targetType = "samba-domain"; - rights = [ "write" ]; + rights = [ "write" "add" ]; attrs = smbDomainAttrs; - members = permissions."Custom Samba Domain Admin".members; }; "Custom Samba Domain Admin" = { targetType = "domain"; - rights = [ "write" "add" ]; - attrs = [ "objectclass" ]; - members = [ adminPriv ]; + rights = [ "write" ]; + attrs = smbDomainAttrs ++ [ "objectclass" ]; }; "Custom Samba Realm Read" = { targetType = "domain"; attrs = [ "objectClass" "ipaNTSecurityIdentifier" "ipaNTFlatName" "ipaNTDomainGUID" "ipaNTFallbackPrimaryGroup" ] ++ smbDomainAttrs; - members = [ smbPriv ]; }; "Custom Samba Realm Modify" = { targetType = "domain"; rights = [ "write" ]; attrs = smbDomainAttrs; - members = permissions."Custom Samba Realm Admin".members; }; "Custom Samba Realm Admin" = { - targetType = "user-group"; - rights = [ "write" "add" ]; - attrs = [ "objectclass" ]; - members = [ adminPriv ]; + targetType = "domain"; + rights = [ "write" ]; + attrs = smbDomainAttrs ++ [ "objectclass" ]; }; }; users = { @@ -149,27 +133,45 @@ in { }; }; }; + sysAccounts = { + samba = { + passwordFile = config.sops.secrets.ldap-samba-password.path; + }; + }; + privileges = { + "Samba smbd" = { + permissions = [ + "Custom Samba User Read" + "Custom Samba Group Read" + "Custom Samba Domain Read" + "Custom Samba Realm Read" + ]; + }; + "Custom Management Admin" = { + permissions = [ + "Custom Samba User Admin" + "Custom Samba Group Admin" + "Custom Samba Domain Admin" + "Custom Samba Realm Admin" + "Custom Samba User Modify" + "Custom Samba Group Modify" + "Custom Samba Domain Modify" + "Custom Samba Realm Modify" + ]; + }; + }; + roles = { + "Samba smbd" = { + privileges = [ + "Samba smbd" + ]; + members = [ + "krbprincipalname=cifs/hakurei.${config.networking.domain}@${config.security.ipa.realm},${ldap.serviceDnSuffix}" + ldap.management.sysAccounts.samba.object.dn + ]; + }; + }; objects = { - ${smbPriv} = { - changeType = "add"; - settings = { - objectClass = [ "top" "nestedgroup" "groupofnames" ]; - member = map config.lib.ldap.withBaseDn [ - "cn=Security Architect,${ldap.roleDnSuffix}" - "uid=samba,${ldap.sysAccountDnSuffix}" - smbRole - ]; - }; - }; - ${smbRole} = { - changeType = "add"; - settings = { - objectClass = [ "top" "nestedgroup" "groupofnames" ]; - member = map config.lib.ldap.withBaseDn [ - "krbprincipalname=cifs/hakurei.${config.networking.domain}@${config.security.ipa.realm},${ldap.serviceDnSuffix}" - ]; - }; - }; "cn=${config.networking.domain},${ldap.domainDnSuffix}" = { objectClasses = [ "sambaDomain" ]; settings = { @@ -179,4 +181,11 @@ in { }; }; }; + config.sops.secrets = let + sopsFile = mkDefault ../secrets/ldap.yaml; + in { + ldap-samba-password = { + inherit sopsFile; + }; + }; } diff --git a/nixos/secrets/ldap.yaml b/nixos/secrets/ldap.yaml new file mode 100644 index 00000000..08ecd694 --- /dev/null +++ b/nixos/secrets/ldap.yaml @@ -0,0 +1,122 @@ +ldap-samba-password: ENC[AES256_GCM,data:2EnURacB0d6VXikBM39XzHG0evJRaWEmPC6pFRwTuLQ=,iv:YuFq8+vgN5UKJNgYgZleYT8GbM5LVgUeyvWXWXNLq/M=,tag:pUiD6975QkBn8ceQbFuDuA==,type:str] +ldap-peep-password: ENC[AES256_GCM,data:RtEE7EbmS70jqRt8HeUSoYJoUfcWGvLNoNeSBGb6mwk=,iv:/4zlBSlhsPuE9isT3K1qchAL/cEKVgTVXSHzrOYF6Ag=,tag:NoP6XouQVwvL/FNuAbzCKA==,type:str] +ldap-keycloak-password: ENC[AES256_GCM,data:pt//mcGuc90gG6PSx81nBHpZ1b+0zOPMb8ffIVWF4ng=,iv:8jYaVf/R1Me5DApeaSDFzG21PGVLM4CJboEg8ZSb+mo=,tag:UDMBTSziG088eGvXQ0jUxg==,type:str] +sops: + shamir_threshold: 1 + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age12ze362pu5mza6ef9akrptr7hfe4auaqul4rkta7kyy2tnrstqensgmujeq + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZjZBbStJdU5VeGNXUG92 + OE5udnNJVUh0cjJEUFBuRllLaCt0MnZpcm1RCkduQTc5QU5EVE5GdUFlNU5zdFJs + N3J6MTJweUQrbFZJdE9xbTh4REJvM00KLS0tIEhCWXBjQWJvYmFnb0trUTlhQk1o + bUhUOFRoanZacXBKOTJaempzelVwbzQK6tsNplwqkrjwiUwxxaMguD1q7SeKKKsa + yB7S3XMBNFdX5eJ2+aGw6+omivu2426QZIW98gc0KgbVptY272mX6w== + -----END AGE ENCRYPTED FILE----- + - recipient: age176uyyyk7veqnzmm8xzwfhf0u23m6hm02cldlfkldunqe6std0gcq6lg057 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyNC9rL0dHQUE5RU1tUFFX + dWphQzJSRS9zdWZLKzdlRFJEVXI4OGJzNWxFCkRRTzMyY1NWYm5vNUthUG53bzg3 + U2loZzdYZWZ1TEVxR0xiNldUeXU5ZW8KLS0tIGFYWXlkaFhtdVpvajBhbjIvOE4x + UjBFcDEyeTIvekU5VG9VNnlXQXVzcWsKt00QmEPogo7/wWKhMEHfgkXnwfcb1V9+ + YafYEH30j3Kk0gVBZDJiNypDZub+aeL7zosass/lURsmZwFdDOvKFQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age15hmlkd9p5rladsjzpmvrh6u34xvggu9mzdsdxdj3ms43tltxeuhq4g7g9k + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5N1B4c0srYVVNNFlPWkYz + QUNXdFBNUllJTTBvcjRJNGMyUGRuWWIzRzBrCndOS1pPMzA5Qk1rc29LS25QL2ZP + dkV0U0tJU0xOSzFBcjRvQUxmSVZJZjAKLS0tIE8wSGlPcHd3SHJCUHFKQkhpQ1Bv + WXNZNTcwK2toNDJiUWsyNDlPb1FhNUEKlbd6VF324AYaW6tFDo4WYgwRq3p3qex7 + Hqa9QPSqgrbJFLKeONwBx/BlDqhKxuNKDTUQpCX1YyxEFhrbnLZ4zQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age10t6kc5069cyky929vvxk8aznqyxpkx3k5h5rmlyz83xtjmr22ahqe8mzes + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuQTZCOUl3cmVYYk1ueHA5 + RlhpRlF2OFppc0c0NXgzY2k1NGMwWFRkSGpnCjEzQnR5TndVWVJFRW9ETzFJbFhK + R1hzTGlycWlzbEplc1ZVb2xiV1pMTGcKLS0tIGhyNlVKUHFqYm1QbDZ6TzJKekE2 + TmtxM1dubG1mVFBzTHdHdGZiaGRFVWcKiUM/aB7G4dp/j/GGxkRVRUwE5FTo9Z0r + ukFy8RpFm3Ctvl1MIZ30M0NNMTppu/CTOmoSo0OSxKE9Vltw/WtFLA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1a2quf2ekkj94ygu7wgvhrvh44fwn32c0l2cwvgvjh23wst90s54szdsvgr + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjRit6SlJVVWR1TGZxZ3Ni + MGlINjZCVkZqVTdSNWhpZFNLNXFqVEZBd1JFCmtyR2lJQmJNNGM1djRZZk9aYnRC + a3hFMzcvV3Z2TnZ6clNRdU10MEJnam8KLS0tIGFobXUvNHFPN1pNNm9QMXZhR3ZK + M3ZvQXptWksrdVhHMjE0SXZNWW9hRW8KbMZ2iWMsV+rLfSgJHwyd7OW9Dvf6EFWf + ldeW837x2uZCCR7Es7HShjC8Q7rXOsPsbnyuybTvj4zvh0qPAl/Fpw== + -----END AGE ENCRYPTED FILE----- + - recipient: age16klpkaut5759dut8mdm3jn0rnp8w6kxyvs9n6ntqrdsayjtd7upqlvw489 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLaWhrdHhYaEhPN3MySWM2 + MWhpUE5FZnEzRW54bEF2eWk1S3pYL2ppeWdVCnRUSWdMQys2aElQTDA3eFpueVVP + SG4vZlQzWE5XVWdRVUlhNWhNQTZUVXMKLS0tIFVnaXRsbTArM0pJZ1N6cndYbXJY + YTRNd2N2ajVGU3FJWTk1cVdvbmM1VWsKING/3HcLu3Yp3n4LtEPB677jdPMPC63r + MwnHsBJx5CBZEou1D91WUXOFy6tVGyoouUb7XDOKrKx9FEx8/qbTPQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age13qgddr326g5je0fpq2r3k940vsr3fh9nlvl9xtcxk3xg2x0k3vsq7pvzaj + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqWkVXMlNlc3BqSXh0eklK + TzZIQXN5am9scXFzc05GaTNQR1YwMXBBUWxjCm9XbHlvckhvbmxaKzBnVENwZHR4 + a2wyVEFOZHB5TXhZQ1JvZ0crL21ZbTQKLS0tIHZlSVVycUFidVBWREhsVFVHUklH + Q3c1NWJTcnZJc3dvVldRdDRiblAydUEKZ1Mtn+PQxyCg8OZ2lAB+rEfVAPk14pH1 + eub12LarVz5nqgW+XhMb6ztJ5ks9xle9reIeHhILFtpvW8wahXTYVQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1ktmx2szedfnpe5xumnzs8vkk0ffqgga6ved3drtksg9pye6ndsnsnqq488 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4bVVvSnoxUitRd3NGR0N0 + Zlhvc00yNzNDMURDZlFwdm9mOWpGa1hCeVFvClZhYVdoM2lNUGRwK3hGTk83Rjhn + YkRsTTM1ODBrWXpSTWx6Y1RpdnBTNlUKLS0tIGlOVVpIaUlQbzk0azFqT2JOL2pE + WFdaN0lEWDRxVGErWFIyRFFTcDBqRHcKfnvyeArVg/pTTBRoX5buAMK0egwZfY5M + LAQmTRAddbycMiHYAk2S2PRPW+mE/Bwg3Khi3G+LqTAX/1XrrXENWg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-04-03T19:02:13Z" + mac: ENC[AES256_GCM,data:Cak6rkD3J3tU6ADwlnFiNVN9qAuAnywE0mzZMAiT5sXCgV7QPzD21D57kxwNMKon8dUaYVtIrQ/01xzruiYNGrk2mzMqZ6W7Mf0U9yjp3AkJ88K1RlZyGUby/4TdjgSg9bNDSg17rai8EpnMwe6mqpPcQbnLmUwg1iaN0gLhEj4=,iv:Fx3u7GvTaVp1cyBRkei2RL6IqPttTTZKNQOAM0CRaNM=,tag:LfewOWvxfdPC4ArN9ufLAw==,type:str] + pgp: + - created_at: "2024-04-02T17:59:55Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQIMA82M54yws73UARAAuEh+cW6lgZ0jigOUDH1kkoVLNlUEch4GKMFafvFlk40h + feVlHi/wOFsaKsUynMDN6IkoFEdjevv1TJ7Eh5xY7S0Ua9OppyFetszxDVkaXxiv + XZNow/fFSiBnjMAMnPEz/jqs3OSoKkrH8C6CbIt0K2pWMxFz7EW64nH1ZkboTrde + JP9w1Kpl0GAGlOJrNI6cGiOyP4LxhoVJq494kBLkLNgP9KFWrd4kA2Qof9fNAo24 + b5Wmnvfa1mNhQH5xzSQEHBH6gVTGtcq0Pt0UYROZuo/DwJTOh3oXmOWkLb9YIE0i + ctDoKNtBW3+jpJI7nKSxp3Ys0BcZmowcpaByp9nW3/EaveqeWDgWnn0NNwrcHloi + z5xURx59rT/rRm4vztYp9WUyyeXIA7SmoDJ1/JhqeMNhd0VcCrqsG8dmO6+kwx8w + MXHVcNnisM5Jx0Wg/6becT6p3Ej1dHAEKSNoUNrWcVo/hThT1HvvBY9HvnMDsBp4 + at6bYIl+F3JT3bBIbVFNpNynPQGzKxdOp+GmCtTsauECgBNivqpGabo5CTR7Shih + KqgpUuBJsM2rPUQiOro/eZOLlTtSRwHFZ0l/q1Mwm4ZhKbiqC/urMcsfZZUZyNh0 + 8wgFUncvJDiAbOrlrSB3Zij92DDlZqYlFiO07tF3YxPL5s386S/qpTUOAscLlnPS + XAGW1p93RF0qwdScAA01nQnA2RMyYW8tMeBV96y0OW8QrJua8b2rozqCP6Uesyze + Xz0XVMNcw2S7hQAedQIF6BAPG4rnzgyDVjOMVGDNzcwuSzJnEaL2DiPK6JoE + =+wSd + -----END PGP MESSAGE----- + fp: CD8CE78CB0B3BDD4 + - created_at: "2024-04-02T17:59:55Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hQEMA2W9MER3HLb7AQf/e0yDYqiD6lYq5lRUKGX7ILpCIix1qrHzml3hLSoXvlsj + CbYyP/M18chVJ40LkJrD5fLKkTH/qOuBU5mKR2DY7mhmMYVTGp91KR8kJYExbszr + gveKzmHczrTbCzpuoVUCzoKu68HQ+s8Cvj/puxrwy8AiiRk0g4Visr9q9yhrDy50 + KQtb8vZysLA90mquMu4QOodoTn5zQMuVCqChPj3xJnGfBg5B4DM7kd3A6lAWXxC4 + vFsMDPvT/lSJbDIu8DIigRgYNYXygG2vW93NS0zgRvm0YdjmbJeWrjbpBy9kDqRm + /zLZHybVPKRhuu3rIAMXZjsfpfS8Ap/tBRPDvP29o9JcAQXecjL0ZSMdeNWZImj3 + pIBAlVzUcgMX2U0NvSm8GZgd9cR+AAQSpF80jFdZEFGG3l/0c0UOOeBO7+WmMBtr + qezAj3MfzsOfFuydY4BM8IogcqQ4n46u+rf43ms= + =ld0s + -----END PGP MESSAGE----- + fp: 65BD3044771CB6FB + unencrypted_suffix: _unencrypted + version: 3.8.1