migrate clanmodules/{user,root}-password to clanServices/users

Move the functionality of both modules into a new clanService.
root-password was previously just a special case of user-password. This
migrates it into a deduplicated clan service and adds checks
This commit is contained in:
pinpox
2025-06-10 09:27:59 +02:00
parent 774c3ff5dc
commit 39a8374dee
22 changed files with 277 additions and 12 deletions

View File

@@ -1,9 +1,11 @@
--- ---
description = "Automatically generates and configures a password for the root user." description = "Automatically generates and configures a password for the root user."
categories = ["System"] categories = ["System"]
features = [ "inventory" ] features = ["inventory", "deprecated"]
--- ---
This module is deprecated and will be removed in a future release. It's functionality has been replaced by the user-password service.
After the system was installed/deployed the following command can be used to display the root-password: After the system was installed/deployed the following command can be used to display the root-password:
```bash ```bash

View File

@@ -36,7 +36,7 @@
if [[ -n "''${prompt_value-}" ]]; then if [[ -n "''${prompt_value-}" ]]; then
echo "$prompt_value" | tr -d "\n" > "$out"/password echo "$prompt_value" | tr -d "\n" > "$out"/password
else else
xkcdpass --numwords 3 --delimiter - --count 1 | tr -d "\n" > "$out"/password xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/password
fi fi
mkpasswd -s -m sha-512 < "$out"/password | tr -d "\n" > "$out"/password-hash mkpasswd -s -m sha-512 < "$out"/password | tr -d "\n" > "$out"/password-hash
''; '';

View File

@@ -1,7 +1,7 @@
--- ---
description = "Automatically generates and configures a password for the specified user account." description = "Automatically generates and configures a password for the specified user account."
categories = ["System"] categories = ["System"]
features = ["inventory"] features = ["inventory", "deprecated"]
--- ---
If setting the option prompt to true, the user will be prompted to type in their desired password. If setting the option prompt to true, the user will be prompted to type in their desired password.

View File

@@ -1,5 +1,4 @@
{ {
_class,
pkgs, pkgs,
config, config,
lib, lib,
@@ -34,13 +33,8 @@ in
}; };
clan.core.vars.generators.user-password = { clan.core.vars.generators.user-password = {
files.user-password-hash = files.user-password-hash.neededFor = "users";
{ files.user-password-hash.restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
neededFor = "users";
}
// (lib.optionalAttrs (_class == "nixos") {
restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
});
prompts.user-password.type = "hidden"; prompts.user-password.type = "hidden";
prompts.user-password.persist = true; prompts.user-password.persist = true;
@@ -58,7 +52,7 @@ in
if [[ -n "''${prompt_value-}" ]]; then if [[ -n "''${prompt_value-}" ]]; then
echo "$prompt_value" | tr -d "\n" > "$out"/user-password echo "$prompt_value" | tr -d "\n" > "$out"/user-password
else else
xkcdpass --numwords 3 --delimiter - --count 1 | tr -d "\n" > "$out"/user-password xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/user-password
fi fi
mkpasswd -s -m sha-512 < "$out"/user-password | tr -d "\n" > "$out"/user-password-hash mkpasswd -s -m sha-512 < "$out"/user-password | tr -d "\n" > "$out"/user-password-hash
''; '';

View File

@@ -0,0 +1,83 @@
{ ... }:
{
_class = "clan.service";
manifest.name = "clan-core/users";
manifest.description = "Automatically generates and configures a password for the specified user account.";
manifest.categories = [ "System" ];
roles.default = {
interface =
{ lib, ... }:
{
options = {
user = lib.mkOption {
type = lib.types.str;
example = "alice";
description = "The user the password should be generated for.";
};
prompt = lib.mkOption {
type = lib.types.bool;
default = true;
example = false;
description = "Whether the user should be prompted.";
};
};
};
perInstance =
{ settings, ... }:
{
nixosModule =
{
config,
pkgs,
lib,
...
}:
{
users.mutableUsers = false;
users.users.${settings.user}.hashedPasswordFile =
config.clan.core.vars.generators."user-password-${settings.user}".files.user-password-hash.path;
clan.core.vars.generators."user-password-${settings.user}" = {
# files.user-password-hash.neededFor = "users";
files.user-password-hash.restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
files.user-password.deploy = false;
prompts.user-password = lib.mkIf settings.prompt {
type = "hidden";
persist = true;
description = "You can autogenerate a password, if you leave this prompt blank.";
};
runtimeInputs = [
pkgs.coreutils
pkgs.xkcdpass
pkgs.mkpasswd
];
script =
(
if settings.prompt then
''
prompt_value=$(cat "$prompts"/user-password)
if [[ -n "''${prompt_value-}" ]]; then
echo "$prompt_value" | tr -d "\n" > "$out"/user-password
else
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/user-password
fi
''
else
''
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/user-password
''
)
+ ''
mkpasswd -s -m sha-512 < "$out"/user-password | tr -d "\n" > "$out"/user-password-hash
'';
};
};
};
};
}

View File

@@ -0,0 +1,18 @@
{ lib, self, ... }:
{
clan.modules = {
users = lib.modules.importApply ./default.nix { };
};
perSystem =
{ pkgs, ... }:
{
checks = lib.optionalAttrs (pkgs.stdenv.isLinux) {
users = import ./tests/vm/default.nix {
inherit pkgs;
clan-core = self;
nixosLib = import (self.inputs.nixpkgs + "/nixos/lib") { };
};
};
};
}

View File

@@ -0,0 +1,67 @@
{
pkgs,
nixosLib,
clan-core,
...
}:
nixosLib.runTest (
{ ... }:
{
imports = [
clan-core.modules.nixosVmTest.clanTest
];
hostPkgs = pkgs;
name = "users";
clan = {
directory = ./.;
modules."@clan/users" = ../../default.nix;
inventory = {
machines.server = { };
instances = {
root-password-test = {
module.name = "@clan/users";
roles.default.machines."server".settings = {
user = "root";
prompt = false;
};
};
user-password-test = {
module.name = "@clan/users";
roles.default.machines."server".settings = {
user = "testuser";
prompt = false;
};
};
};
};
};
nodes = {
server = {
users.users.testuser.group = "testuser";
users.groups.testuser = { };
users.users.testuser.isNormalUser = true;
};
};
testScript = ''
start_all()
server.wait_for_unit("multi-user.target")
# Check that the testuser account exists
server.succeed("id testuser")
# Try to log in as the user using the generated password
# TODO: fix
# password = server.succeed("cat /run/clan/vars/user-password/user-password").strip()
# server.succeed(f"echo '{password}' | su - testuser -c 'echo Login successful'")
'';
}
)

View File

@@ -0,0 +1,6 @@
[
{
"publickey": "age1qkxvpqjp4tevcm2wpq3hea3563s2nhcsfe8vdy6pztegzjmnfa4qljmrjm",
"type": "age"
}
]

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:01pW9z9mKMQsUTK2rT8ccwu7gO2Yvi8Jhyi/qRzrfL86Z1MiTk1j6fDp6wGxRC69J7m9PDxo7Hu9ce7lV3+6YFMtfojXv+kCjvY=,iv:A79Xk0n41qdCpnu0YRD5rdyBfG0iDn+X/9tcbcZzRws=,tag:WA8hmNYU78StBokCJZQClA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHeUg0a2pRcDNLbVN1dzZ0\neTM3bEJHVXpLd2p2cVBTUDZoWURlVGNFTmxnCmhPTDRGY1NtRDMxdmd3YlQvQTFa\nd0pVc0Y4T1ZtR1RmK05oVnFGRHFQd1UKLS0tIEVDYjBnemN4UlU2Y3lKbWpDYnFp\nb1NnMWY1RzRUMStiYnpuYUxsaWx1Z2sKqdARj14dDQPBejEwTZil+ZamvGCLc9X9\neXVWDOevDZEhh5RR3cNIMu/9wm+HyndY0Rbvfb+HrB3WmuL64Tx4/g==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-11T15:51:37Z",
"mac": "ENC[AES256_GCM,data:8AfKCzuW1c9xrn+k64XiX6mperaHZTI989WqQyInSB6xENNWIiOVpLCb9UtLOqvAie3dEQ9J8batiLygdJRK8GqBQj+Zch2Ep0DARLGwL6I6SlqpcWEYnorYMlmNoHnMj/5kr6QIhPJkbXdgTrhyYO4QWtn4d+z3tOgF8E1BW2M=,iv:ghBgDOpbn/k6sfGyiWPKWjhb19RTy1ohi15sw2JLhvM=,tag:z9Nq/hOCPbEdzLLw5kQVnQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../users/admin

View File

@@ -0,0 +1,4 @@
{
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"type": "age"
}

View File

@@ -0,0 +1 @@
../../../../../../sops/machines/server

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:WCfszumboEpj8psAL4/630uxTuStQ7trUoj7FQ2CcceVfL4SKTt0nVT8LmWLMZnZpX6OB5DUKxPHjNqpPLEa6YhXKS97T79Dr7hEB/iOChduVWVzgU2cSXXrjbcrp5cmDc/5jtk0E6KSmw==,iv:5DX62dwMGypwkl6uPs8QOOZ4SKhAe9E0iFPDkyAqCFg=,tag:nepp8PU/D2uJBlOE18C+2A==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qkxvpqjp4tevcm2wpq3hea3563s2nhcsfe8vdy6pztegzjmnfa4qljmrjm",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2eTl2VGVwZU5SczdRSk9S\nMTNzNGJ3WUE5TnhmdjNXclU5NnJVdEhBWWtFCnZTRlduVThOODdVeFgwLzBxQkJa\nSS9pczlhYm9vendoZ2xJbHJwaGQ1TUEKLS0tIHlYbkN5ZGJIbHAzM1NTQmNiZjJK\nMXRMY05yZTZ4cXI4Sk1xZHo5anBaNmcKnm+/1QW23Uyqvo1iTAZfRzHNJCfKFPSL\njmUiNkVMaUXpp1dtYrOwo/LDIQXhIVoRv7blcPRCe4wUAhJRp4DUVQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBUzU4bld6TjN4RzdjV0Mr\nMkw0Q3dxUER0NElXOU1wT21LbW5NQUY5Q3pJCjBCa0JLZDNQVFdRd1gyTHJ5cHlB\nVzdsNnNpU0xJTHpEM2NYemkyRFh6L2sKLS0tIE5SSHY2dFAzeGVndVRtZmNqYzJ6\nSDNTQkRoZE52b3k0OW1ZU0RocGRobWMK3VEaZCWECR6cQDvCo/UxZlRrM4ugpeA8\n2Req5+01wValB0Xlwady/hbQRL3Ag9t3IfemHfn7ZUc4TUVEtOoEcQ==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-11T15:51:40Z",
"mac": "ENC[AES256_GCM,data:KMVBXRd6kLfq4Ur751dpdIiaWOhxo0RvKznQ+8q5m+rC+3z0CLOuuR3hnx/dsdSdfZYU7FRXSJvIO4CXBZNanamLmcD58tECihRmq2c8iSuHvKnYJvcZOBVoqmSpE8wr84xYZOMEXr8BeD1d+PK5+j18vzx9JaySlqD9m/ixGig=,iv:LUHc0fa5WLlMkOqZJ9tLa1xXOrhiZTf55lpvpaSbeQA=,tag:k4Wm5JiYc0r45GdgMSYYlg==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/admin

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:FjZKJ5DoOqVleFckTUXVf9wFVCi9,iv:190oDlNNmlUinxyLu3z0KjWGzi7b0+3KFsAiVZxt9vY=,tag:pS4wWccJnCGGC1yqWKfnyw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKYmowcHlsVkVHOU9DQzB3\nbEQ3cytHcmVkVmJBOS9sLzFwa0tzcUZ0WGtvCk10MjU5dDJOKzRPQXVPTkpNNUs0\nSHpKT05CZnB1d285VGlLcUthY3U3ck0KLS0tIEJtdXFzTmE1NExoUExieG5JZE05\nUW5JK2dWbjBuMWxjU2lWbE1tOE5TelUKPMG/xE4uB7pLya4mB/3cwwO7nuUPDDJ2\nRE9stD6wUjvTeJ5EORfyfD8HfjonWjr8El/plmjfGWuhSNm4+aBrTg==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-11T15:51:40Z",
"mac": "ENC[AES256_GCM,data:YfadVhFo+DohhBc1a1lKY+SJowybCcVGtI28KAgh2pkslUTGjH1a3tHIXEQD8Obsy1v9V83m1XWhqFkxbFQ+aW/niGFq7Qk+Vx6GTbiBEGq6zd/VqzIZwTXVgdXlqSEvutIXOqEBjXa+raJuLGZs7hc/ORDjO4IqWdwvGBxjmgQ=,iv:CSIdSnjAg1iXp3M3DZ/gAAqyFzgj9CziHe4VwaD4Mu4=,tag:X/BWo7vNKN4h1/kxUCffJA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/admin

View File

@@ -0,0 +1 @@
../../../../../../sops/machines/server

View File

@@ -0,0 +1,19 @@
{
"data": "ENC[AES256_GCM,data:7faAUnNk4mFwRx29l3xdeAvEMmbaqghe7yx7sMByxaOsoKxf4oQDlY7cNR/4z9/Ga9onZ2QS2fwU3JkDLFJvJPr4hGzcu1eNhl8QOzNBRKM6j7rk902gwvHi30M4Dh1fGIoqfLte2HfdjA==,iv:qFvSXoMoVqbJUHW8REM+dzqwpQkCkQoiuxJzhKT78cU=,tag:FdWs17KTkGEIVQrgbNWIDQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qkxvpqjp4tevcm2wpq3hea3563s2nhcsfe8vdy6pztegzjmnfa4qljmrjm",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZeGd4b1NucWJkSHN0WVRY\nWmRIeWJ1V1N1RVNiQzdKRFN0NHZjNUdTRFhNCmhTV3p2TXkxeUNVdm5ucHB2a3lp\nMHpVcDNKTzlKcnQ1MlNUME5pQ2FEdnMKLS0tIFZkT014YmQ4aVV4Z2FhUkMwRWgv\nY3JuSTdWV1pvTFZpbDhoSWE5Wld3L1kKEehLVyPqQw0nW/z8boU1dOKLRZADmrXy\n9ilBtqwTxCTw5yx1CubnITQyratqLkki6JTJ9s91dLb0B8t6pvaRQQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlQ3NsMW05L0VmUEQvdCtZ\nT3c4bk9wV25QN0VZbVZtZkxvaUVlWDFUZGdjCk5GVXpQbDRrWkwzS1NzREFQVUxq\nSXNESGY4NUZ1Wjd6U3FFSnM0eDNzZG8KLS0tIEdUMEJLdWV5NjREVkNTM2hReHdx\nMHF3bUxIQWF4STM4UVBhSWxMQ0NFVEEKuakIYSudIr/UzYlgpulfaR9DRUo+bZsg\nrkbT4xyFEdL5P7zAeOlW2kZDOtKTT+PJxrU5OPGakpbHaE1RdRbv1Q==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-11T15:51:43Z",
"mac": "ENC[AES256_GCM,data:d2b3B0mVdt6xrEw6ipNotIKCaDs6mpB82Xsr0pCRyMI/l4lde+IWc+BuirpVuC8LiXT3UBmJ8oWP1MXgpzunVY81QITxdx9RbydeJSx95slDOqXiwjZ8YPgEVmxXZJRHU5SuXYGB+/aDJRcW12fsmjpmIyXrGPE0at5zcurpsoI=,iv:ywTkbrsN2df/C59O1TU9WjBqjLMorZNHqHLR7hU2ono=,tag:XZjrxAfk25vAXDxp7oDWUQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/admin

View File

@@ -0,0 +1,15 @@
{
"data": "ENC[AES256_GCM,data:VjgSlcBS7KVkVSIo7aU3MHMu95vB0A==,iv:vooZAcgif2CMsbYx8QnE20R1pgiTa/jPp23+Exwyt/8=,tag:WsU2L6Ipbu51HpTJE6dvTg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBySUFNeVBlWGtmdUpQUWNL\ndURGZWcwRWNIV0NTRVVMR013R2dHUVRlbjA4Ck10WWticVZHbmQwUm50TEp1RzA4\nL3RGbDU3SXBJUlhkWEQxb1U2cXUzTkEKLS0tIHB1L0p4T1ZHd0RxSTN0Mjl2SjBl\nU1plT2NteVdUUU1LeUkrVWt4Q0tHZW8KZMQJ/7eAevNUsQAxgs0CdJ/3KXikinaw\nFrfiV3Nk/XeezyU7Gyh2dRkdX/KCpdSMniFL/pyeiZEqW+ALSeI3xA==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2025-06-11T15:51:43Z",
"mac": "ENC[AES256_GCM,data:wEi6vOpe5X/wO8QaAsbdYfQCQwcZmUhj9jgKuObBC2PTLVWWCYf8CZ6wSgt3/Ho/5TxoCKe1hoIqt+RE52ZKHFRwA0W3zfvkCpREHf2SOfq3NHxEn4/IDvQXRAwAvfgwc58u5nHhjpU7OpSNWLyKsuY+HR/kFRUO6nQVyAEHLUY=,iv:IXeMbEDc6033t1a/q1afwSblrmw1vK0iS8XL6mSOZZM=,tag:sB25pUTGBYm/vOtBp2eAWA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.10.2"
}
}

View File

@@ -0,0 +1 @@
../../../../../../sops/users/admin

View File

@@ -93,6 +93,7 @@ nav:
- reference/clanServices/localsend.md - reference/clanServices/localsend.md
- reference/clanServices/mycelium.md - reference/clanServices/mycelium.md
- reference/clanServices/sshd.md - reference/clanServices/sshd.md
- reference/clanServices/users.md
- reference/clanServices/hello-world.md - reference/clanServices/hello-world.md
- reference/clanServices/wifi.md - reference/clanServices/wifi.md
- reference/clanServices/zerotier.md - reference/clanServices/zerotier.md