mirror of
https://github.com/gensokyo-zone/infrastructure.git
synced 2026-02-09 04:19:19 -08:00
chore(idp): sys accounts
This commit is contained in:
parent
db2f7d27b3
commit
34d1b400e1
10 changed files with 561 additions and 81 deletions
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 <<EOF
|
||||
dn: uid=$LDAP_SYSACCOUNT_UID,$LDAP_DNSUFFIX_SYSACCOUNT$LDAPBASE
|
||||
changetype: modify
|
||||
replace: userPassword
|
||||
userPassword:< file://$LDAP_SYSACCOUNT_PASSWORD_PATH
|
||||
-
|
||||
delete: passwordExpirationTime
|
||||
-
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
privilege_permissions() {
|
||||
local LDAP_PRIVILEGE_CN=$1 LDAP_PRIVILEGE_PERMISSION_CN
|
||||
shift 1
|
||||
|
||||
echo "updating cn=$LDAP_PRIVILEGE_CN,$LDAP_DNSUFFIX_PRIVILEGE ..." >&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
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
|||
};
|
||||
};
|
||||
};
|
||||
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
|
||||
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"
|
||||
];
|
||||
};
|
||||
};
|
||||
${smbRole} = {
|
||||
changeType = "add";
|
||||
settings = {
|
||||
objectClass = [ "top" "nestedgroup" "groupofnames" ];
|
||||
member = map config.lib.ldap.withBaseDn [
|
||||
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 = {
|
||||
"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;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
122
nixos/secrets/ldap.yaml
Normal file
122
nixos/secrets/ldap.yaml
Normal file
|
|
@ -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
|
||||
Loading…
Add table
Add a link
Reference in a new issue