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."
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:
```bash

View File

@@ -36,7 +36,7 @@
if [[ -n "''${prompt_value-}" ]]; then
echo "$prompt_value" | tr -d "\n" > "$out"/password
else
xkcdpass --numwords 3 --delimiter - --count 1 | tr -d "\n" > "$out"/password
xkcdpass --numwords 4 --delimiter - --count 1 | tr -d "\n" > "$out"/password
fi
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."
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.

View File

@@ -1,5 +1,4 @@
{
_class,
pkgs,
config,
lib,
@@ -34,13 +33,8 @@ in
};
clan.core.vars.generators.user-password = {
files.user-password-hash =
{
neededFor = "users";
}
// (lib.optionalAttrs (_class == "nixos") {
restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
});
files.user-password-hash.neededFor = "users";
files.user-password-hash.restartUnits = lib.optional (config.services.userborn.enable) "userborn.service";
prompts.user-password.type = "hidden";
prompts.user-password.persist = true;
@@ -58,7 +52,7 @@ in
if [[ -n "''${prompt_value-}" ]]; then
echo "$prompt_value" | tr -d "\n" > "$out"/user-password
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
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/mycelium.md
- reference/clanServices/sshd.md
- reference/clanServices/users.md
- reference/clanServices/hello-world.md
- reference/clanServices/wifi.md
- reference/clanServices/zerotier.md