Compare commits
225 Commits
vars-docs
...
zerotier_r
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b3f087079 | ||
|
|
59aec481b2 | ||
|
|
fe04eb827f | ||
|
|
6b059ca71d | ||
|
|
9ea5156f32 | ||
|
|
519ff4c0f3 | ||
|
|
bc045ee972 | ||
|
|
5de0d37f0e | ||
|
|
3574b37a29 | ||
|
|
2921ae7b84 | ||
|
|
8f5cae5671 | ||
|
|
bc241cdd5f | ||
|
|
d1b65d5a06 | ||
|
|
8402463296 | ||
|
|
461e7ee968 | ||
|
|
b273cc9c6a | ||
|
|
51f3ffec42 | ||
|
|
48ddf22879 | ||
|
|
7a9f3dfc03 | ||
|
|
2588813578 | ||
|
|
c95ab34807 | ||
|
|
54fc2aec03 | ||
|
|
9a03644a80 | ||
|
|
381c190ba2 | ||
|
|
bd50e1ee40 | ||
|
|
00d38180d3 | ||
|
|
7e1b7b056d | ||
|
|
4ec3043a4e | ||
|
|
78634d0165 | ||
|
|
4d4a689519 | ||
|
|
bd4285a638 | ||
|
|
c418d688dc | ||
|
|
69ea1a211f | ||
|
|
02117d8698 | ||
|
|
91643bafbe | ||
|
|
8223120521 | ||
|
|
8e279a1e71 | ||
|
|
d6c891750d | ||
|
|
c73d954b55 | ||
|
|
4ec6ec0090 | ||
|
|
ec98cdf097 | ||
|
|
4ad348d881 | ||
|
|
728d651ad1 | ||
|
|
fb4c151969 | ||
|
|
3cf979f0ed | ||
|
|
3bc31b3e3f | ||
|
|
99f167a89f | ||
|
|
ed432cc4cf | ||
|
|
4ec5be9476 | ||
|
|
00a864663b | ||
|
|
9f1d8d22e8 | ||
|
|
6f791ac086 | ||
|
|
133f4aee53 | ||
|
|
91985504d0 | ||
|
|
ba5968ce93 | ||
|
|
3370212cea | ||
|
|
3043a92815 | ||
|
|
77921f2857 | ||
|
|
f22c8f166e | ||
|
|
d6ae9cde3f | ||
|
|
51b6717202 | ||
|
|
d27576c130 | ||
|
|
0a972b387c | ||
|
|
e8bbe91685 | ||
|
|
455268f6ce | ||
|
|
ce2e80bcf1 | ||
|
|
8e9105735c | ||
|
|
db75af2445 | ||
|
|
24014564e8 | ||
|
|
4939723477 | ||
|
|
8be04e790b | ||
|
|
eaf94f90fe | ||
|
|
ac07265ea4 | ||
|
|
92ca540a42 | ||
|
|
8b18418e7c | ||
|
|
9b1573db63 | ||
|
|
47be7d6865 | ||
|
|
1e18d7b897 | ||
|
|
f099e92394 | ||
|
|
668fc39dba | ||
|
|
589d353285 | ||
|
|
62eedacd33 | ||
|
|
4ce8f03ea6 | ||
|
|
75367f4d6f | ||
|
|
1a344f759a | ||
|
|
3cc1ea6d83 | ||
|
|
09af3f38ee | ||
|
|
0f71ffd3c7 | ||
|
|
0fef161391 | ||
|
|
854481fd49 | ||
|
|
74f853bd7c | ||
|
|
5613cbe7cb | ||
|
|
4b549365f7 | ||
|
|
e03fcc25e7 | ||
|
|
a798fcb359 | ||
|
|
d163f0da14 | ||
|
|
92e2c841e3 | ||
|
|
01856cf4cb | ||
|
|
0d04b24473 | ||
|
|
bc521a1b9b | ||
|
|
eb321df10d | ||
|
|
cdceb2a211 | ||
|
|
6546f8a952 | ||
|
|
b7798f5466 | ||
|
|
132728d757 | ||
|
|
2a52548120 | ||
|
|
71533f118f | ||
|
|
c9ab0a42ac | ||
|
|
e7fe50fd6e | ||
|
|
757f2412a6 | ||
|
|
f8d153b318 | ||
|
|
782a9375bf | ||
|
|
e332ae9059 | ||
|
|
9a9d6bf22d | ||
|
|
593c2d3d5b | ||
|
|
59c463f326 | ||
|
|
f1416bdcba | ||
|
|
7a38e976a4 | ||
|
|
ae28196039 | ||
|
|
a1b7c4f8f7 | ||
|
|
66b6290d32 | ||
|
|
4aff2a9d40 | ||
|
|
9b39ca42e0 | ||
|
|
104058b79c | ||
|
|
5dd30a8edd | ||
|
|
5127a74515 | ||
|
|
fd1c0dfabc | ||
|
|
3d8fab062d | ||
|
|
559c13f41b | ||
|
|
3afe48f9cf | ||
|
|
555c2e1bc9 | ||
|
|
80bc3daf96 | ||
|
|
fc1a68b99c | ||
|
|
cbdf8745eb | ||
|
|
b08f9743f0 | ||
|
|
50239028b6 | ||
|
|
0f0cfbc7e0 | ||
|
|
d4e601586d | ||
|
|
ada80be417 | ||
|
|
e4b316c14a | ||
|
|
a0fda9b819 | ||
|
|
125a882938 | ||
|
|
fc223939ec | ||
|
|
2152646df6 | ||
|
|
1f9b44a4ad | ||
|
|
8a1f924f72 | ||
|
|
e43779f8d6 | ||
|
|
69b0c36381 | ||
|
|
479d7d536e | ||
|
|
19a209c75a | ||
|
|
c249994e18 | ||
|
|
6910620629 | ||
|
|
3f17a6c121 | ||
|
|
864b131010 | ||
|
|
50c8df7e40 | ||
|
|
a80df32c59 | ||
|
|
b1e3e3616e | ||
|
|
3d680bcc5f | ||
|
|
3f5bf8e171 | ||
|
|
31ff7b903c | ||
|
|
62eb42ae5b | ||
|
|
d25818580d | ||
|
|
13eba4d7c5 | ||
|
|
86c4555bc0 | ||
|
|
39eb13eebb | ||
|
|
daea2da358 | ||
|
|
d995c0b118 | ||
|
|
5e22830048 | ||
|
|
15d117d06b | ||
|
|
c936830bc6 | ||
|
|
8e50ddc84b | ||
|
|
f2134754c5 | ||
|
|
f49df8d574 | ||
|
|
d873e667ba | ||
|
|
6c2fa3e4ed | ||
|
|
0bce953c2f | ||
|
|
dd1f045022 | ||
|
|
f7cd8c8863 | ||
|
|
ee0f111fc9 | ||
|
|
ea32fdbd93 | ||
|
|
1f3aa0075e | ||
|
|
5d38824d8e | ||
|
|
5ee6156b29 | ||
|
|
a90197cfd4 | ||
|
|
cd1351cd6f | ||
|
|
1b193123b2 | ||
|
|
81126da053 | ||
|
|
67795730a2 | ||
|
|
e6797c6f20 | ||
|
|
8c42cc377c | ||
|
|
5750ab8d3a | ||
|
|
d3397af442 | ||
|
|
ea3818bb50 | ||
|
|
93280a9f98 | ||
|
|
d89ddfabec | ||
|
|
e2946615f0 | ||
|
|
bce9f9a747 | ||
|
|
b494bdee21 | ||
|
|
13632ff659 | ||
|
|
90ad8054d0 | ||
|
|
716d4a17f5 | ||
|
|
dcd1273f3f | ||
|
|
899c9eed0e | ||
|
|
af85041e5e | ||
|
|
6a96ce8679 | ||
|
|
60195f9614 | ||
|
|
447b0bf8ac | ||
|
|
fd162f6fc8 | ||
|
|
e4bf6523ad | ||
|
|
5312799784 | ||
|
|
7d265a6156 | ||
|
|
f8428947ca | ||
|
|
196d7c95c0 | ||
|
|
6be40f6f79 | ||
|
|
3aefabd818 | ||
|
|
230e7e6769 | ||
|
|
46bae67645 | ||
|
|
890e8c7003 | ||
|
|
0d3a62321a | ||
|
|
ef82e07293 | ||
|
|
7c8c3811f4 | ||
|
|
9b2c97a855 | ||
|
|
785f789628 | ||
|
|
a034fefb51 | ||
|
|
bcd846fe5e |
@@ -8,6 +8,6 @@ jobs:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: nix run .#deploy-docs
|
||||
- run: nix run --print-build-logs .#deploy-docs
|
||||
env:
|
||||
SSH_HOMEPAGE_KEY: ${{ secrets.SSH_HOMEPAGE_KEY }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -52,3 +52,5 @@ pkgs/clan-app/ui/.fonts
|
||||
*.gif
|
||||
*.mp4
|
||||
*.mkv
|
||||
|
||||
.jj
|
||||
|
||||
@@ -30,7 +30,7 @@ In the Clan ecosystem, security is paramount. Learn how to handle secrets effect
|
||||
|
||||
The Clan project thrives on community contributions. We welcome everyone to contribute and collaborate:
|
||||
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in [contributing](https://docs.clan.lol/contributing/contributing/)<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in [contributing](https://docs.clan.lol/guides/contributing/CONTRIBUTING/)<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
|
||||
## Join the revolution
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ let
|
||||
elem
|
||||
filter
|
||||
filterAttrs
|
||||
flip
|
||||
genAttrs
|
||||
hasPrefix
|
||||
pathExists
|
||||
@@ -45,7 +44,7 @@ in
|
||||
flake.check = genAttrs [ "x86_64-linux" "aarch64-darwin" ] (
|
||||
system:
|
||||
let
|
||||
checks = flip filterAttrs self.checks.${system} (
|
||||
checks = filterAttrs (
|
||||
name: _check:
|
||||
!(hasPrefix "nixos-test-" name)
|
||||
&& !(hasPrefix "nixos-" name)
|
||||
@@ -57,7 +56,7 @@ in
|
||||
"clan-core-for-checks"
|
||||
"clan-deps"
|
||||
])
|
||||
);
|
||||
) self.checks.${system};
|
||||
in
|
||||
inputs.nixpkgs.legacyPackages.${system}.runCommand "fast-flake-checks-${system}"
|
||||
{ passthru.checks = checks; }
|
||||
|
||||
@@ -29,9 +29,20 @@
|
||||
imports = [ self.nixosModules.test-install-machine-without-system ];
|
||||
|
||||
clan.core.vars.generators.test = lib.mkForce { };
|
||||
|
||||
disko.devices.disk.main.preCreateHook = lib.mkForce "";
|
||||
|
||||
# Every option here should match the options set through `clan flash write`
|
||||
# if you get a mass rebuild on the disko derivation, this means you need to
|
||||
# adjust something here. Also make sure that the injected json in clan flash write
|
||||
# is up to date.
|
||||
i18n.defaultLocale = "de_DE.UTF-8";
|
||||
console.keyMap = "de";
|
||||
services.xserver.xkb.layout = "de";
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRWUusawhlIorx7VFeQJHmMkhl9X3QpnvOdhnV/bQNG root@target\n"
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
perSystem =
|
||||
@@ -44,6 +55,8 @@
|
||||
dependencies = [
|
||||
pkgs.disko
|
||||
pkgs.buildPackages.xorg.lndir
|
||||
pkgs.glibcLocales
|
||||
pkgs.kbd.out
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".pkgs.perlPackages.ConfigIniFiles
|
||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".pkgs.perlPackages.FileSlurp
|
||||
|
||||
@@ -83,10 +96,10 @@
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.succeed("echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIRWUusawhlIorx7VFeQJHmMkhl9X3QpnvOdhnV/bQNG root@target' > ./test_id_ed25519.pub")
|
||||
# Some distros like to automount disks with spaces
|
||||
machine.succeed('mkdir -p "/mnt/with spaces" && mkfs.ext4 /dev/vdc && mount /dev/vdc "/mnt/with spaces"')
|
||||
machine.succeed("clan flash write --debug --flake ${self.checks.x86_64-linux.clan-core-for-checks} --yes --disk main /dev/vdc test-flash-machine-${pkgs.hostPlatform.system}")
|
||||
machine.succeed("clan flash write --ssh-pubkey ./test_id_ed25519.pub --keymap de --language de_DE.UTF-8 --debug --flake ${self.checks.x86_64-linux.clan-core-for-checks} --yes --disk main /dev/vdc test-flash-machine-${pkgs.hostPlatform.system}")
|
||||
'';
|
||||
} { inherit pkgs self; };
|
||||
};
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/admin";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.certificates = module;
|
||||
|
||||
@@ -8,7 +8,7 @@ The service consists of two roles:
|
||||
- A `server` role: This is the DNS-server that will be queried when trying to
|
||||
resolve clan-internal services. It defines the top-level domain.
|
||||
- A `default` role: This does two things. First, it sets up the nameservers so
|
||||
thatclan-internal queries are resolved via the `server` machine, while
|
||||
that clan-internal queries are resolved via the `server` machine, while
|
||||
external queries are resolved as normal via DHCP. Second, it allows exposing
|
||||
services (see example below).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
clan.modules = {
|
||||
emergency-access = lib.modules.importApply ./default.nix { };
|
||||
emergency-access = ./default.nix;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
# The test for this module in ./tests/vm/default.nix shows an example of how
|
||||
# the service is used.
|
||||
|
||||
{ packages }:
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
@@ -34,20 +33,17 @@
|
||||
settings,
|
||||
|
||||
# The name of this instance of the service
|
||||
instanceName,
|
||||
|
||||
# The current machine
|
||||
machine,
|
||||
|
||||
# All roles of this service, with their assigned machines
|
||||
roles,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Analog to 'perSystem' of flake-parts.
|
||||
# For every instance of this service we will add a nixosModule to a morning-machine
|
||||
nixosModule =
|
||||
{ config, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
# Interaction examples what you could do here:
|
||||
# - Get some settings of this machine
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
clan.modules = {
|
||||
importer = lib.modules.importApply ./default.nix { };
|
||||
importer = ./default.nix;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
{
|
||||
roles,
|
||||
lib,
|
||||
settings,
|
||||
...
|
||||
}:
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.localbackup = module;
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
};
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: user:
|
||||
_name: user:
|
||||
lib.nameValuePair "matrix-password-${user.name}" {
|
||||
files."matrix-password-${user.name}" = { };
|
||||
migrateFact = "matrix-password-${user.name}";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.matrix-synapse = module;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{ packages }:
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
@@ -11,15 +10,15 @@
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.allowAllInterfaces = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
description = "If true, Telegraf will listen on all interfaces. Otherwise, it will only listen on the interfaces specified in `interfaces`";
|
||||
type = lib.types.nullOr lib.types.bool;
|
||||
default = null;
|
||||
description = "Deprecated. Has no effect.";
|
||||
};
|
||||
|
||||
options.interfaces = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ "zt+" ];
|
||||
description = "List of interfaces to expose the metrics to";
|
||||
type = lib.types.nullOr (lib.types.listOf lib.types.str);
|
||||
default = null;
|
||||
description = "Deprecated. Has no effect.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.monitoring = module;
|
||||
|
||||
perSystem =
|
||||
{ ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
clan.nixosTests.monitoring = {
|
||||
imports = [ ./tests/vm/default.nix ];
|
||||
|
||||
imports = [
|
||||
(lib.modules.importApply ./tests/vm/default.nix {
|
||||
inherit (self) packages;
|
||||
inherit pkgs;
|
||||
})
|
||||
];
|
||||
clan.modules.monitoring = module;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -11,34 +11,54 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
jsonpath = "/tmp/telegraf.json";
|
||||
auth_user = "prometheus";
|
||||
in
|
||||
{
|
||||
warnings =
|
||||
lib.optionals (settings.allowAllInterfaces != null) [
|
||||
"monitoring.settings.allowAllInterfaces is deprecated and and has no effect. Please remove it from your inventory."
|
||||
"The monitoring service will now always listen on all interfaces over https."
|
||||
]
|
||||
++ (lib.optionals (settings.interfaces != null) [
|
||||
"monitoring.settings.interfaces is deprecated and and has no effect. Please remove it from your inventory."
|
||||
"The monitoring service will now always listen on all interfaces over https."
|
||||
]);
|
||||
|
||||
networking.firewall.interfaces = lib.mkIf (settings.allowAllInterfaces == false) (
|
||||
builtins.listToAttrs (
|
||||
map (name: {
|
||||
inherit name;
|
||||
value.allowedTCPPorts = [
|
||||
9273
|
||||
9990
|
||||
];
|
||||
}) settings.interfaces
|
||||
)
|
||||
);
|
||||
|
||||
networking.firewall.allowedTCPPorts = lib.mkIf (settings.allowAllInterfaces == true) [
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
9273
|
||||
9990
|
||||
];
|
||||
|
||||
clan.core.vars.generators."telegraf" = {
|
||||
clan.core.vars.generators."telegraf-certs" = {
|
||||
files.crt = {
|
||||
restartUnits = [ "telegraf.service" ];
|
||||
deploy = true;
|
||||
secret = false;
|
||||
};
|
||||
files.key = {
|
||||
mode = "0600";
|
||||
restartUnits = [ "telegraf.service" ];
|
||||
};
|
||||
|
||||
runtimeInputs = [
|
||||
pkgs.openssl
|
||||
];
|
||||
|
||||
script = ''
|
||||
openssl req -x509 -nodes -newkey rsa:4096 \
|
||||
-keyout "$out"/key \
|
||||
-out "$out"/crt \
|
||||
-subj "/C=US/ST=CA/L=San Francisco/O=Example Corp/OU=IT/CN=example.com"
|
||||
'';
|
||||
};
|
||||
|
||||
clan.core.vars.generators."telegraf" = {
|
||||
files.password.restartUnits = [ "telegraf.service" ];
|
||||
files.password-env.restartUnits = [ "telegraf.service" ];
|
||||
files.miniserve-auth.restartUnits = [ "telegraf.service" ];
|
||||
|
||||
dependencies = [ "telegraf-certs" ];
|
||||
|
||||
runtimeInputs = [
|
||||
pkgs.coreutils
|
||||
pkgs.xkcdpass
|
||||
@@ -57,11 +77,37 @@
|
||||
enable = true;
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "telegraf.service" ];
|
||||
wants = [ "telegraf.service" ];
|
||||
requires = [ "telegraf.service" ];
|
||||
serviceConfig = {
|
||||
LoadCredential = [
|
||||
"auth_file_path:${config.clan.core.vars.generators.telegraf.files.miniserve-auth.path}"
|
||||
"telegraf_crt_path:${config.clan.core.vars.generators.telegraf-certs.files.crt.path}"
|
||||
"telegraf_key_path:${config.clan.core.vars.generators.telegraf-certs.files.key.path}"
|
||||
];
|
||||
Environment = [
|
||||
"AUTH_FILE_PATH=%d/auth_file_path"
|
||||
"CRT_PATH=%d/telegraf_crt_path"
|
||||
"KEY_PATH=%d/telegraf_key_path"
|
||||
];
|
||||
Restart = "on-failure";
|
||||
User = "telegraf";
|
||||
Group = "telegraf";
|
||||
RuntimeDirectory = "telegraf-www";
|
||||
};
|
||||
script = "${pkgs.miniserve}/bin/miniserve -p 9990 /run/telegraf-www --auth-file \"$AUTH_FILE_PATH\" --tls-cert \"$CRT_PATH\" --tls-key \"$KEY_PATH\"";
|
||||
};
|
||||
|
||||
systemd.services.telegraf = {
|
||||
serviceConfig = {
|
||||
LoadCredential = [
|
||||
"telegraf_crt_path:${config.clan.core.vars.generators.telegraf-certs.files.crt.path}"
|
||||
"telegraf_key_path:${config.clan.core.vars.generators.telegraf-certs.files.key.path}"
|
||||
];
|
||||
Environment = [
|
||||
"CRT_PATH=%d/telegraf_crt_path"
|
||||
"KEY_PATH=%d/telegraf_key_path"
|
||||
];
|
||||
};
|
||||
script = "${pkgs.miniserve}/bin/miniserve -p 9990 ${jsonpath} --auth-file ${config.clan.core.vars.generators.telegraf.files.miniserve-auth.path}";
|
||||
};
|
||||
|
||||
services.telegraf = {
|
||||
@@ -69,6 +115,7 @@
|
||||
environmentFiles = [
|
||||
(builtins.toString config.clan.core.vars.generators.telegraf.files.password-env.path)
|
||||
];
|
||||
|
||||
extraConfig = {
|
||||
agent.interval = "60s";
|
||||
inputs = {
|
||||
@@ -104,10 +151,12 @@
|
||||
metric_version = 2;
|
||||
basic_username = "${auth_user}";
|
||||
basic_password = "$${BASIC_AUTH_PWD}";
|
||||
tls_cert = "$${CRT_PATH}";
|
||||
tls_key = "$${KEY_PATH}";
|
||||
};
|
||||
|
||||
outputs.file = {
|
||||
files = [ jsonpath ];
|
||||
files = [ "/run/telegraf-www/telegraf.json" ];
|
||||
data_format = "json";
|
||||
json_timestamp_units = "1s";
|
||||
};
|
||||
|
||||
@@ -1,24 +1,95 @@
|
||||
{ ... }:
|
||||
{
|
||||
name = "monitoring";
|
||||
|
||||
clan = {
|
||||
directory = ./.;
|
||||
inventory = {
|
||||
machines.peer1 = { };
|
||||
machines.peer1 = {
|
||||
deploy.targetHost = "[2001:db8:1::1]";
|
||||
};
|
||||
|
||||
instances."test" = {
|
||||
module.name = "monitoring";
|
||||
module.input = "self";
|
||||
|
||||
roles.telegraf.machines.peer1 = { };
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nodes = {
|
||||
peer1 =
|
||||
{ lib, ... }:
|
||||
{
|
||||
services.telegraf.extraConfig = {
|
||||
agent.interval = lib.mkForce "1s";
|
||||
outputs.prometheus_client = {
|
||||
# BUG: We have to disable basic auth here because the prometheus_client
|
||||
# output plugin will otherwise deadlock Telegraf on startup.
|
||||
basic_password = lib.mkForce "";
|
||||
basic_username = lib.mkForce "";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# !!! ANY CHANGES HERE MUST BE REFLECTED IN:
|
||||
# clan_lib/metrics/telegraf.py::get_metrics
|
||||
testScript =
|
||||
{ ... }:
|
||||
{ nodes, ... }:
|
||||
''
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import ssl
|
||||
import json
|
||||
import shlex
|
||||
import urllib.request
|
||||
from base64 import b64encode
|
||||
start_all()
|
||||
|
||||
peer1.wait_for_unit("network-online.target")
|
||||
peer1.wait_for_unit("telegraf.service")
|
||||
peer1.wait_for_unit("telegraf-json.service")
|
||||
|
||||
# Fetch the basic auth password from the secret file
|
||||
password = peer1.succeed("cat ${nodes.peer1.clan.core.vars.generators.telegraf.files.password.path}").strip()
|
||||
credentials = f"prometheus:{password}"
|
||||
|
||||
print("Using credentials:", credentials)
|
||||
peer1.succeed(f"curl -k -u {credentials} https://localhost:9990/telegraf.json")
|
||||
peer1.succeed(f"curl -k -u {credentials} https://localhost:9273/metrics")
|
||||
|
||||
cert_path = "${nodes.peer1.clan.core.vars.generators.telegraf-certs.files.crt.path}"
|
||||
url = "https://192.168.1.1:9990/telegraf.json" # HTTPS required
|
||||
|
||||
print("Waiting for /var/run/telegraf-www/telegraf.json to be bigger then 200 bytes")
|
||||
peer1.wait_until_succeeds(f"test \"$(stat -c%s /var/run/telegraf-www/telegraf.json)\" -ge 200", timeout=30)
|
||||
|
||||
encoded_credentials = b64encode(credentials.encode("utf-8")).decode("utf-8")
|
||||
headers = {"Authorization": f"Basic {encoded_credentials}"}
|
||||
req = urllib.request.Request(url, headers=headers) # noqa: S310
|
||||
|
||||
# Trust the provided CA/server certificate
|
||||
context = ssl.create_default_context(cafile=cert_path)
|
||||
context.check_hostname = False
|
||||
context.verify_mode = ssl.CERT_REQUIRED
|
||||
|
||||
found_system = False
|
||||
with urllib.request.urlopen(req, context=context, timeout=5) as response:
|
||||
for raw_line in response:
|
||||
line_str = raw_line.decode("utf-8").strip()
|
||||
if not line_str:
|
||||
continue
|
||||
obj = json.loads(line_str)
|
||||
if obj.get("name") == "nixos_systems":
|
||||
found_system = True
|
||||
print("Found nixos_systems metric in json output")
|
||||
break
|
||||
|
||||
assert found_system, "nixos_systems metric not found in json output"
|
||||
|
||||
'';
|
||||
}
|
||||
|
||||
6
clanServices/monitoring/tests/vm/sops/machines/peer1/key.json
Executable file
6
clanServices/monitoring/tests/vm/sops/machines/peer1/key.json
Executable file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:ACFpRJRDIgVPurZwHYW0J1MnvyuiRGnXMeQj1nb9rDAIqHbZzZk8+E0Nu1+EdXwk78ziP6tHR1GQP2ILTtpLME4lXXRVjouW5Eo=,iv:ctR1HENO3XGIq1/gzYi47nateYzsSK317EKn92ptqDI=,tag:q1yuk/ZMx3nuORkiT/XXqg==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvMUtabnp3V0dzNFFYRzk0\nd0ZJbUtDMXRPRGxpRjhYR1MyQzdJYWdJTUFrCjBNV0pPTTlIOHBBbzlEQkFzVy92\ndENxcDdIZlNDSm1oZTNveUtIeVc3MXcKLS0tIGtocENjMFNYT0s1LzhYNy92QU5G\nREVEdjErb0xPSE1yb0g5bGlackh6bEUKwxBoDteD7+JfnlFF71CHx4oEdV/TFYcF\n3JPYUbTWAIyMtUu/CLbX+Pn9Mv+McrEIqhwT7TWL/YbELKVadX/k5Q==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-18T14:33:37Z",
|
||||
"mac": "ENC[AES256_GCM,data:4631iJmioJ2vZ2PTFbdEJu7UqtyQbp43XBlgEbFAviGZdugb3weVI24rJ8m1Rdnxq8uciEeiX6YHBhURdWQY4JNm2wTGnjz7e2PwQ8FCwOmxCcIQPpdKKsziq/M4HArgD66eUxIWfTt1yJfHgBcUuuANbrbH8MirllT+hJTBhqE=,iv:rM8a/MpKbK7DlqjuR4BG77XDHLK11Q+E2rzZLDJalhk=,tag:bbGMn4anXrLHg4eLA0/CXA==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../users/admin
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"type": "age"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
25.11
|
||||
@@ -0,0 +1,33 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
k1PNWTkgLsXO8DNkCudxcvPElXfmaw6zwaLrZys=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer1
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data: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,iv:q3j8EAokyyxiszf+wyRqxEr2igaD1bX7YnFx/NbsGg8=,tag:HKKYWRJEUwW2/TxL+5dSng==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaeXRjU214aWk5ajl1aW9E\naGJlb1ViaVRmMTBHdkFDQUNDZS94WFZiNUNvCllmWTJBck9hR3U3V09VWDZwQ2xI\nd3ZEQnBIUG5ZSTVIdS8rQ2FMYVhyNk0KLS0tIEE1UG8rSzFyU01sVXhGVHpoaE9i\nSis4Qi9tMGFqbTNMTDZUVk1ZdXkrM28Km4VkfaOsZ69ckjvrg+os43H/O1IoWHzC\nt4LqZRz1Tk7/d1aLWavSPPjVYrCOMZeNBqGbQpGfjjuXrafClRNQdQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3R1RHTGViTnRLVVkyM3J0\nbm96cGVPTlo4NXBNL0g1eEVSNG9DUkgwVFRBCmRKVTlMRmV3Tmg2RTZIclBlWlcr\ndzI5MUxhcllzbE1IMDNxa08zVkpITmsKLS0tIG01Y2dyQkY3UmRudFk2d0p6bThn\nemlaWnZoS3p4VHhMTFFwTm9VN0ttYzQKVbLFgtK6NIRIiryWHeeOPD45iwUds4QD\n7b8xYYoxlo+DETggxK6Vz3IdT/BSK5bFtgAxl864b5gW+Aw4c6AO5w==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-18T14:33:37Z",
|
||||
"mac": "ENC[AES256_GCM,data:XKCnd0QrAlOCECSeSvbLYHMLbmUh4fMRnLaTb5ARoP4Zc9joWGsCaRZxokc2/sG4BXA/6pkbQXHyIOudKbcBpVjjvs9E+6Mnzt53nfRoH/iOkYPbN2EO49okVZJXW0M1rlBxrxvGuiDlz2p2p6L7neKLy4EB482pYea5+dUr2Yw=,iv:oj/MkZCfkvCmAb79uzEvKwEAm1bKtWhS4rPRAWSgRgw=,tag:h5TPPILXkhJplnDT2Gqtfw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer1
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:Q0Vn7J0nERccBYT8HZxHF0Zi5qxmMu40n0H1c+L2SCRF6vRLdURxXKDwvh8xtTU=,iv:ucExjoYDFYy19GsBbNNldJRPBSpT+L+x4PrwTG+m2K8=,tag:/Quupyy/nnUNZsDudEMmNA==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQWWo5OEJ5N1RTR0xMaDhL\nQnlUV2RrRXIzM01OemhQWjVkd3FNZjRhR2dzCi9IeE56b3VZTkNkdW9DMzVia3Zx\nbklxWmFpenRjdEIrc0ZDTGdmSTAxRTQKLS0tIHZJdjdYUzhhY0YzQjRqS0psZmpI\nVHJpUjNZNHRpc2ZWSml1TVNNejhiT28K8TTP/J+XspXZ7TVYj9YaBhEodPIXjojB\nRLqAIgJXRaK4NCLukC6l0IMii6w5J/512RnO2ZBTGhKfbdLfyLOFqg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrZVc5b0FhbzNXcG1zUDlD\neEVWcWpSRkRCMkxBTHdBM3dCbjVpR3FBa0VjCitlTmx4eUJOMHlaU0dFZEhpK3ZD\nZzlMQXVuZWpnaUNmQW9kOGtOaGVDMU0KLS0tIFNlUi9LSzF0UEJCSVBiRlRSNFQz\nNHhMbmNlRXd4ZEJQWVcvTWdCRWEzMUkKls7RbmNOdPDx8z15F+7qay9qIWx6jNsN\nTahT+GgbG29t1aGQCb0yEzKuUyAp39maxxSWToPsfCgJSYJ8RYiUng==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-18T14:33:39Z",
|
||||
"mac": "ENC[AES256_GCM,data:g+9/fRiqom2+W28ZpiF+oBj9V6ieq5Xz3sRz3GyzvHoLr6yw51JvpG2QuYNYANW0WCiUjFDkU0qPj/9gLHcuX52nc+gNaTzznb1QGPg7WCGSQI7xaMzyYsPxHpg/BOdj5CL8GyLiOWstD1ch0kc3bJmyu68sJUs04uGtHAADzsE=,iv:oASrYaZarEPDu0R3hd/jMazLgwG5r//hIdMyU/tN15o=,tag:o1fgf5oy+rlWXg88FN5Nfw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer1
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:4NIUEK05kEQAKjR8F9mU3M/XvtZXw+X6CejVI0usMcb4WzagNz7XTVDhLWXZ9St5Ev0Y,iv:bD2+rDLMoWSqUAIZRJof0wRrJVya1xwZUTIJBdCs98I=,tag:g2s4byFHTzwU3ikcBGMElA==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQeVh2M2tqSGlOVkpzNlhU\nd0pMd1R0c0tQWnZzdXViWmtxcjl1Wk1Ka0FNCnBUUWJVbjlyR1hSNGpXNWlPRHJB\nNnMzN3BMQ2NDamFBMlhHbVdJUEZ6cjQKLS0tIEJjWmI0ZDl1NXgrSW9uc0R0LzAr\neEwwOC9DdDg2RTJHQ0M3QTFlcVBaSE0K2Du4NguefdEyY1gS6OuVdO3gHga4omcR\n8B+K1wUfIQbArxZLawPxrj7WNDoW5d4mF9fA3MeV1DFyc4KwtYZmUw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvWkdBakVrMVR4RU8xdDlF\nRDkvL0Mrb3ltazhIMjRLZDVlSTVlaFY2ODBBCnlQM2s0SGEvZjFDN3dGWDhIN0dK\nenhQbjZ1ZS9QZzg5SE5XazZXS3dFSkkKLS0tIHJhKzhadGpjTXd4L3hOQkhpR0Fy\nYzhTN2dxVSt3OE5uZFpuWmVlYW4vd1kKwHOxP0C5mLcm4oIT/sGQtUsdsmu3LSN0\nSola5+N+IrAZ+HKnuZlDLZ5JmJSc5j/YhGNn7KR1xhkhfGSS1e3UZw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-18T14:33:39Z",
|
||||
"mac": "ENC[AES256_GCM,data:ehbrYqTJcsBKGHUB25JHFnKXrJ6z3LkcElZ89xVr4XxLet+odbhsjIoP2FCcxex7PlXcegMduhHBpXwNGUbX+IUNAXTxlWA9CLDmYhWuS2WLiEVXrS11NE03/zUyHdVx/C38dbIPrWD9iaYSrAiuOyfqDTh9k/Bn7vehLTtadoE=,iv:Nk2WVuJydi5tfsb1Mib4A6NocBCDp9QoIbSadq3bIDI=,tag:IaoyfCv3SkmtemXMR9XnkA==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer1
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:0BmP+NwG/NGe6R5yU55/MdPEQ8E5u+VXWtvstHc4GpDtmBY=,iv:vo8XBcN7KcYjiyKvvp+XDOdP9yR9B7wJi0XlaiCdVbk=,tag:brK9ntAPSuOvw/C+oDo51g==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1ntpf7lqqw4zrk8swjvwtyfak7f2wg04uf7ggu6vk2yyt9qt74qkswn25ck",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4Tk1INGtybUVlejlNNlZE\nVms3TkdRVVF1T0E4TmV3NmxvYWVEL2U3WVhNCjJIaHhBcWVlMEYxRjg5bzJpTWdJ\neUhaRTNRTmtlTW0zUXQxTVZEMkQ2MFEKLS0tIFNGWDI4b2FXTE8xQ2xqb0cyK3FI\ncktHWnE5c1ZSVFpmQU1HZmU2VVB1QmcK/s1fVmwpMMg4BYkkAJzSY7hVQWae1F7g\nmfH8EGlr74mifWUNEbd49/K13nl8atQx6bcau83JIEQR+yyihuY4Jw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsL2FXVytUUVZnVU90bG5L\nYURiYjgwN3RuTldWMGl4clpUWmxkeUsrVzM0CkhKZFgwWHl4dWhNSWRQRXVPNDR6\na3hHNmp2RG9YNDhNM2MyV2FuOGY2UlUKLS0tIFpNU2tNOHdhRDRTdHhYWVh2NGZa\nU3J3S0hpclZzWGIwTlFyczdNZkZSZTAKXCZrLaIOVq90ejoKMaRiK0xNw8WOPcnm\nz2uxProEYvQhY8k29mhCFX5HCN0tGn1XTtHeDL7uHuKuFsnSG/fgYQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-18T14:33:39Z",
|
||||
"mac": "ENC[AES256_GCM,data:QkGJKj/H+MI9Mr9Up5NDUToSddY5eTz47egc2+IatfxR8RebKJ2/mYaeLV26vPdmY60bIac4N/nZkoa6IVBhkHHMvsEHsx3nD6Lro9Wf/pWP8Zddzr90LF5p2+wusq25JutKQiPKOb2gmrcagmSsH/7V/UqI/my3PMeKmw6irhw=,iv:hOtHF/cDFdNfvqCKRhJsOwAHEiQmCPjENzsg23sKG+Q=,tag:K7qG9b4fQD0VbAV8OYp3vw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
pkgs.syncthing
|
||||
];
|
||||
script = ''
|
||||
syncthing generate --config "$out"
|
||||
export TMPDIR=/tmp
|
||||
TEMPORARY=$(mktemp -d)
|
||||
syncthing generate --config "$out" --data "$TEMPORARY"
|
||||
mv "$out"/key.pem "$out"/key
|
||||
mv "$out"/cert.pem "$out"/cert
|
||||
cat "$out"/config.xml | grep -oP '(?<=<device id=")[^"]+' | uniq > "$out"/id
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
priority = lib.mkDefault 10;
|
||||
# TODO add user space network support to clan-cli
|
||||
module = "clan_lib.network.tor";
|
||||
peers = lib.mapAttrs (name: machine: {
|
||||
peers = lib.mapAttrs (name: _machine: {
|
||||
host.var = {
|
||||
machine = name;
|
||||
generator = "tor_${instanceName}";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.trusted-nix-caches = module;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.users = module;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
{ packages }:
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib)
|
||||
@@ -29,6 +28,15 @@ in
|
||||
default = true;
|
||||
description = "Automatically try to join this wifi network";
|
||||
};
|
||||
keyMgmt = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "wpa-psk";
|
||||
description = ''
|
||||
Key management used for the connection.
|
||||
One of "none" (WEP or no password protection), "ieee8021x" (Dynamic WEP), "owe" (Opportunistic Wireless Encryption), "wpa-psk" (WPA2 + WPA3 personal),
|
||||
"sae" (WPA3 personal only), "wpa-eap" (WPA2 + WPA3 enterprise) or "wpa-eap-suite-b-192" (WPA3 enterprise only).
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
@@ -50,7 +58,7 @@ in
|
||||
ssid_path =
|
||||
network_name: config.clan.core.vars.generators."wifi.${network_name}".files.network-name.path;
|
||||
|
||||
secret_generator = name: value: {
|
||||
secret_generator = name: _value: {
|
||||
name = "wifi.${name}";
|
||||
value = {
|
||||
prompts.network-name.type = "line";
|
||||
@@ -80,7 +88,7 @@ in
|
||||
wifi.mode = "infrastructure";
|
||||
wifi.ssid = "$ssid_${name}";
|
||||
wifi-security.psk = "$pw_${name}";
|
||||
wifi-security.key-mgmt = "wpa-psk";
|
||||
wifi-security.key-mgmt = networkCfg.keyMgmt;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.wifi = module;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{ lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.wireguard = module;
|
||||
|
||||
33
clanServices/yggdrasil/README.md
Normal file
33
clanServices/yggdrasil/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
This module sets up [yggdrasil](https://yggdrasil-network.github.io/) across
|
||||
your clan.
|
||||
|
||||
Yggdrasil is designed to be a future-proof and decentralised alternative to
|
||||
the structured routing protocols commonly used today on the internet. Inside
|
||||
your clan, it will allow you to reach all of your machines.
|
||||
|
||||
## Example Usage
|
||||
|
||||
While you can specify statically configured peers for each host, yggdrasil does
|
||||
auto-discovery of local peers.
|
||||
|
||||
```nix
|
||||
inventory = {
|
||||
|
||||
machines = {
|
||||
peer1 = { };
|
||||
peer2 = { };
|
||||
};
|
||||
|
||||
instances = {
|
||||
yggdrasil = {
|
||||
|
||||
# Deploy on all machines
|
||||
roles.default.tags.all = { };
|
||||
|
||||
# Or individual hosts
|
||||
roles.default.machines.peer1 = { };
|
||||
roles.default.machines.peer2 = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
125
clanServices/yggdrasil/default.nix
Normal file
125
clanServices/yggdrasil/default.nix
Normal file
@@ -0,0 +1,125 @@
|
||||
{ ... }:
|
||||
{
|
||||
_class = "clan.service";
|
||||
manifest.name = "clan-core/yggdrasil";
|
||||
manifest.description = "Yggdrasil encrypted IPv6 routing overlay network";
|
||||
|
||||
roles.default = {
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.extraMulticastInterfaces = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.attrs;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Additional interfaces to use for Multicast. See
|
||||
https://yggdrasil-network.github.io/configurationref.html#multicastinterfaces
|
||||
for reference.
|
||||
'';
|
||||
example = [
|
||||
{
|
||||
Regex = "(wg).*";
|
||||
Beacon = true;
|
||||
Listen = true;
|
||||
Port = 5400;
|
||||
Priority = 1020;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
options.peers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Static peers to configure for this host.
|
||||
If not set, local peers will be auto-discovered
|
||||
'';
|
||||
example = [
|
||||
"tcp://192.168.1.1:6443"
|
||||
"quic://192.168.1.1:6443"
|
||||
"tls://192.168.1.1:6443"
|
||||
"ws://192.168.1.1:6443"
|
||||
];
|
||||
};
|
||||
};
|
||||
perInstance =
|
||||
{ settings, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
|
||||
clan.core.vars.generators.yggdrasil = {
|
||||
|
||||
files.privateKey = { };
|
||||
files.publicKey.secret = false;
|
||||
files.address.secret = false;
|
||||
|
||||
runtimeInputs = with pkgs; [
|
||||
yggdrasil
|
||||
jq
|
||||
openssl
|
||||
];
|
||||
|
||||
script = ''
|
||||
# Generate private key
|
||||
openssl genpkey -algorithm Ed25519 -out $out/privateKey
|
||||
|
||||
# Generate corresponding public key
|
||||
openssl pkey -in $out/privateKey -pubout -out $out/publicKey
|
||||
|
||||
# Derive IPv6 address from key
|
||||
echo "{\"PrivateKeyPath\": \"$out/privateKey\"}" | yggdrasil -useconf -address | tr -d '\n' > $out/address
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.yggdrasil.serviceConfig.BindReadOnlyPaths = [
|
||||
"%d/key:/key"
|
||||
];
|
||||
|
||||
systemd.services.yggdrasil.serviceConfig.LoadCredential =
|
||||
"key:${config.clan.core.vars.generators.yggdrasil.files.privateKey.path}";
|
||||
|
||||
services.yggdrasil = {
|
||||
enable = true;
|
||||
openMulticastPort = true;
|
||||
# We don't need this option, because we persist our keys with
|
||||
# vars by ourselfs. This option creates an unnessesary additional
|
||||
# systemd service to save/load the keys and should be removed
|
||||
# from the NixOS module entirely, as it can be replaced by the
|
||||
# (at the time of writing undocumented) PrivateKeyPath= setting.
|
||||
# See https://github.com/NixOS/nixpkgs/pull/440910#issuecomment-3301835895 for details.
|
||||
persistentKeys = false;
|
||||
settings = {
|
||||
PrivateKeyPath = "/key";
|
||||
IfName = "ygg";
|
||||
Peers = settings.peers;
|
||||
MulticastInterfaces = [
|
||||
# Ethernet is preferred over WIFI
|
||||
{
|
||||
Regex = "(eth|en).*";
|
||||
Beacon = true;
|
||||
Listen = true;
|
||||
Port = 5400;
|
||||
Priority = 1024;
|
||||
}
|
||||
{
|
||||
Regex = "(wl).*";
|
||||
Beacon = true;
|
||||
Listen = true;
|
||||
Port = 5400;
|
||||
Priority = 1025;
|
||||
}
|
||||
]
|
||||
++ settings.extraMulticastInterfaces;
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 5400 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
24
clanServices/yggdrasil/flake-module.nix
Normal file
24
clanServices/yggdrasil/flake-module.nix
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix {
|
||||
inherit (self) packages;
|
||||
};
|
||||
in
|
||||
{
|
||||
clan.modules = {
|
||||
yggdrasil = module;
|
||||
};
|
||||
perSystem =
|
||||
{ ... }:
|
||||
{
|
||||
clan.nixosTests.yggdrasil = {
|
||||
imports = [ ./tests/vm/default.nix ];
|
||||
|
||||
clan.modules.yggdrasil = module;
|
||||
};
|
||||
};
|
||||
}
|
||||
67
clanServices/yggdrasil/tests/vm/default.nix
Normal file
67
clanServices/yggdrasil/tests/vm/default.nix
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
name = "yggdrasil";
|
||||
|
||||
clan = {
|
||||
test.useContainers = false;
|
||||
directory = ./.;
|
||||
inventory = {
|
||||
|
||||
machines.peer1 = { };
|
||||
machines.peer2 = { };
|
||||
|
||||
instances."yggdrasil" = {
|
||||
module.name = "yggdrasil";
|
||||
module.input = "self";
|
||||
|
||||
# Assign the roles to the two machines
|
||||
roles.default.machines.peer1 = { };
|
||||
roles.default.machines.peer2 = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
# Wait for both machines to be ready
|
||||
peer1.wait_for_unit("multi-user.target")
|
||||
peer2.wait_for_unit("multi-user.target")
|
||||
|
||||
# Check that yggdrasil service is running on both machines
|
||||
peer1.wait_for_unit("yggdrasil")
|
||||
peer2.wait_for_unit("yggdrasil")
|
||||
peer1.succeed("systemctl is-active yggdrasil")
|
||||
peer2.succeed("systemctl is-active yggdrasil")
|
||||
|
||||
# Check that both machines have yggdrasil network interfaces
|
||||
peer1.wait_until_succeeds("ip link show | grep -E 'ygg'", 30)
|
||||
peer2.wait_until_succeeds("ip link show | grep -E 'ygg'", 30)
|
||||
|
||||
# Get yggdrasil IPv6 addresses from both machines
|
||||
peer1_ygg_ip = peer1.succeed("yggdrasilctl -json getself | jq -r '.address'").strip()
|
||||
peer2_ygg_ip = peer2.succeed("yggdrasilctl -json getself | jq -r '.address'").strip()
|
||||
|
||||
# Compare runtime addresses with saved addresses from vars
|
||||
expected_peer1_ip = "${builtins.readFile ./vars/per-machine/peer1/yggdrasil/address/value}"
|
||||
expected_peer2_ip = "${builtins.readFile ./vars/per-machine/peer2/yggdrasil/address/value}"
|
||||
|
||||
print(f"peer1 yggdrasil IP: {peer1_ygg_ip}")
|
||||
print(f"peer2 yggdrasil IP: {peer2_ygg_ip}")
|
||||
print(f"peer1 expected IP: {expected_peer1_ip}")
|
||||
print(f"peer2 expected IP: {expected_peer2_ip}")
|
||||
|
||||
# Verify that runtime addresses match expected addresses
|
||||
assert peer1_ygg_ip == expected_peer1_ip, f"peer1 runtime IP {peer1_ygg_ip} != expected IP {expected_peer1_ip}"
|
||||
assert peer2_ygg_ip == expected_peer2_ip, f"peer2 runtime IP {peer2_ygg_ip} != expected IP {expected_peer2_ip}"
|
||||
|
||||
# Wait a bit for the yggdrasil network to establish connectivity
|
||||
import time
|
||||
time.sleep(10)
|
||||
|
||||
# Test connectivity: peer1 should be able to ping peer2 via yggdrasil
|
||||
peer1.succeed(f"ping -6 -c 3 {peer2_ygg_ip}")
|
||||
|
||||
# Test connectivity: peer2 should be able to ping peer1 via yggdrasil
|
||||
peer2.succeed(f"ping -6 -c 3 {peer1_ygg_ip}")
|
||||
'';
|
||||
}
|
||||
6
clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json
Executable file
6
clanServices/yggdrasil/tests/vm/sops/machines/peer1/key.json
Executable file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age1p8trv2dmpanl3gnzj294c4t5uysu7d6rfjncp5lmn6redyda8fns6p7kca",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
6
clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json
Executable file
6
clanServices/yggdrasil/tests/vm/sops/machines/peer2/key.json
Executable file
@@ -0,0 +1,6 @@
|
||||
[
|
||||
{
|
||||
"publickey": "age107mprppm3r9u7f26e6t5mhtdny0h5ugfmfjy8kac2tw9nrh9a3ksex0xca",
|
||||
"type": "age"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:jDEog7FFXl28Le3rh5VTiY0DFmLhIy2ZccFjuYWx+OQrKNEqTLI1fzaeMWIcgu6ln6wfGUk640d3IhmrF45MVZiJGkpkOU8UFx0=,iv:4oGaoxhFQwr9OQfdLL7y1N/gJo/uGkTPG/xicVprIAQ=,tag:Smu0/P2bQB66w+0J2Bjlxw==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpQ2hib2Mrb0plWUVwNWU5\nWmpxNlduaUVJckhuQlhQbUJpanloWGFLelJ3CjJJMlBGbGRTWEhGUHh2VVkzUzNa\nL3FGVkF3R3JJT051UTg4UlkwOHRNanMKLS0tIDVWcHU4NmFMUWp3STFTYmg5YmNp\nVzd1Uzg2Wkp5QnJ3V1Qyb2lwSXdBRDgK/V5lgw2TePhUC9ngW53ZapIMkcwPvJus\ns0jUYkStHXjsvEiN7BG8cG7/vRbLD8CnKXnmieM20mT6o7GHGfhHMg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-17T07:12:51Z",
|
||||
"mac": "ENC[AES256_GCM,data:gy/1NFmpFz/tdhgU/Vr+xg46DUjy9ZbrAtCBnIxclwZLJ/fneBpblv8TFgdysY4Ay6jp1S/TOc8eyr+KLHMqcBlje09wd1ac/Y3ee6GccXitB+/c5ayuXX/ShVCdicsr/9COw7vfndAQPU8XIz6tdy0dbL7jgVTyViZW/P5CXEU=,iv:BQ/INwTTCshl5BVnJbVzHW8rwafERS6bKh2JAJsMv9s=,tag:QhsbjeEBivbl8fQLHjiKtQ==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../users/admin
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:1rVgSwg2qPHuXUOQCgOunaNYiBbsh99dZ2y0BV4TxzACwdb3lb6/XnLeDenLELOpKruZQoNJax/NziRr+VHzmh/TlQhNgTkS71A=,iv:Wi5/cFOETb1rhAYeyzkpppzSSm+S+8cCQYc7zkp74FY=,tag:JQHFZJwYMQH4jUqSw6Ld8Q==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGV3ZLZmNrejlvTFF6NDZW\nYmljS0VXQUtCR3IzMG9tMksvSllVVkIxVTEwCi9Fd1dBbmFlYmF2cE1raVJoS3RR\nWmxQY3RwanRZUE5aN1Q2SzhJOFU1elEKLS0tIG9RMElDMEo3TFJjU0RvU3FMQk12\nT1pNc1VjeUliejk3YmJ6d29zUU15aDQKuZ62Q/ywLrpyu1jB34OCPKQEDd150qH6\nHzyw+MasUlzKNs0ZrALwfhnCKiNb/Pq0Lu660Dx5/sFxI/TAqC7NGg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-17T07:13:24Z",
|
||||
"mac": "ENC[AES256_GCM,data:N7mmiEZxinOgWdd7QcZBAumnWaApjlQVww4EzAQ1/JH5i8r8CIfPh/7lGMQntlJj5ob+UgrS96nl6XKdvs3Bt7z34zPq7KV3c0mSmclEctRfcZiG4F+rZ0QIMIRJjq7xJL/M9WupSn8Lgms7qHJMdJyHdDkw47bmXz3MIw9c9zo=,iv:ZYPoo5jTIGnZ1HcAWlr26gloVhSjfhwbO/xH5YCbgF0=,tag:UKMVMGEfqyfo04cIkuKD0A==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../users/admin
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"type": "age"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
25.11
|
||||
@@ -0,0 +1 @@
|
||||
200:fa3b:ad0e:6821:9a51:3ad5:62a4:9ab1
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer1
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:oLWxmCqCLyKCdN90eScYC4eMsY5mcpXexk03P+KfQX9hCUg7iOSv+BTujvAFuJA0z2Pgg7B/L0noYSImE3208gDC2exdZme+szpNwxD6oh1bBx5XuYGc/TDzEl7IdPrf1piuqCkWgD6wNb9aFVA9NB/CrNaszY8=,iv:pU8OGFwtqkxy0+iyhWaOnWdSVvaxYBUgnQwv89CTfKc=,tag:V/GVEvjEpeaf3Tl3XCVL7w==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age1p8trv2dmpanl3gnzj294c4t5uysu7d6rfjncp5lmn6redyda8fns6p7kca",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBidXZxMVg2bkFCekFza3FV\naGVJTjRSSnQrVkgyTVU4Vk9YZFR2Nk1Xcnl3ClNTZnJsR2xZc3hGRFA0NGp2L2Uy\nU2w0N1ZON0xQRXRKL0NId1J3dWNSeXcKLS0tIFlKNk5walJrM2FGM0ozYTBUNVN1\nNHd0N3g2VWFjTUZtbHExdmsvSjJQUGMKDHgRMyTf4CuoIRdsfl6TmPLgcjxHdR4N\nzNmnSmT6QXJr4gBQ7e/3zpMdq4sKzyAOjJPkQra8nJ/KvhpFwXkdtg==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1L3hBYnNTdEhTK1M0TEUx\nM1BFb3IwWDZPc2tkN0JUNXRPWkhEWHpXaFFNCkFlZ3Ixb1hhVWMvUmpKdCtjbW5h\nTVpLSkdxUXI4SVE3MW5LZkFVSmM3dDgKLS0tICtKWGYzbFQ1VGQydktHSDVadVQy\nM3JTSGc0NWVHWGl4akV2VUNNVjVvT00KKmbkGJ2KclTBb7NI0MamWZnlWMaXscws\nYO261RHc/j4s3KdbWATklh2KTicKpgta0mh294Y+hKYLGgBpnXjtOw==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-17T07:12:51Z",
|
||||
"mac": "ENC[AES256_GCM,data:YG4k+PvsF0NVfjqKY/MBhCOwn9Kcn5orq8aD41X3NEPBT+wU5RlN0XqXhH2nkZ52ZHdCN84Ulbd4guwBcJcUtGvxqOpfE4SJ9RFE+SjYw+2+S9wlArQx5R5Zd+Sr+Rgtaip3moENbxETxHZazbEK3u5o0aXKrZvoXH2xgPRYUOg=,iv:lDnNELLpqykrsmoORMW7p6gF43C2QvPwf0PZep2pEo8=,tag:CZNOBx3Aeoq5WeDbANqFVw==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1,3 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAguIpeMvvMtdilU6tsqdBClci2YUgBKEUPQ5ID55zOVY=
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -0,0 +1 @@
|
||||
25.11
|
||||
@@ -0,0 +1 @@
|
||||
200:3975:b69f:fd15:f39a:bf24:f644:432b
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/machines/peer2
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": "ENC[AES256_GCM,data:Ik+mzD41SwfGZrqGi5oy0u8ZS8qCKgV34aohIt7J/11S3ayhKKN8451cYPltGg+2i/+2DWRSkqYZsctgIahvthnvb30r91XHRUCtE3oT8iPOKwEuW2xnZBL2dK0qHrKFGn8B/o3Bl/+4cWuR5Jt9QHlN4oF3o50=,iv:a9mSIr7TT9im19P5XKiDGL71hMLfQE8IB6NV8WABZ+s=,tag:dVQ0HZdpbkcmFA37Il+VIw==,type:str]",
|
||||
"sops": {
|
||||
"age": [
|
||||
{
|
||||
"recipient": "age107mprppm3r9u7f26e6t5mhtdny0h5ugfmfjy8kac2tw9nrh9a3ksex0xca",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3WEtncHIrd2YrbHduUm4y\nYkh1U0NERDR0MzRNQXZ0elNMZzl0ZmJPMlVVCnJ1UC9uNnk0dC9JVzdReUxLZmdR\nMGIwSjBKUW8yQmQ1R3dqU29ZM2czMEUKLS0tIFpMM3l6YnVFRUtLOFRvSTBXRXU0\nQUJWNk5obzBINS90dWwybXlXdEZFZjgKrZtViJwgPpKT+Bhx6ymEhf6QmnMmZ6Jf\n3kIxzDWxGbxrDTrrdXm33gYs9bRvtXsTACRT3TRAKIwSjIV/ycCUBA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
},
|
||||
{
|
||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArY1A4blFZNjdTU3lGUFA3\nb1hscVhLVmtuQnJMS3VHZVVEOXBDRktXNVhjCkdLZEFFZXhubFJrZTU3RjRDN1lh\nVzgyd3E3a0NGTGh1N2lPQWZBVG9BaW8KLS0tIFN1eEhpMk5mUkNaL29MS2NlWDdP\nVXFtb3c0Y25MT3NLK0N2RStkY1R0MGsKLv8yOSl2iQx39JRJA/e0dOtIz7ZND0+o\nzmqxapD6pxbj8RGswj0szLrxaveWT6Vkmmy/a4fz35uw3xuF7uiJJA==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||
}
|
||||
],
|
||||
"lastmodified": "2025-09-17T07:13:24Z",
|
||||
"mac": "ENC[AES256_GCM,data:KCBHfavyg1U/Z1e3rr0jdHivUa5/rl42N/K6c0BR47srdYqcpAS+SWW6tH7kPI3EO+P7TgXVoGlmcXaKgrlRpe37eNzdAT6PJYm7rhe6rm2UgZ1yw/NFqA11p/i3dDbTzYHaHMNGGGg9t/BdT1tD0zCICfptGQnSSBx/BEmT3ak=,iv:GOk8/z1mLIVKxFX4ayt9HvA90gv0Af1KqcDbdJRUYu4=,tag:hJpOBFRESQXmE7iMqDqO6g==,type:str]",
|
||||
"unencrypted_suffix": "_unencrypted",
|
||||
"version": "3.10.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../../sops/users/admin
|
||||
@@ -0,0 +1,3 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEA40UksAF1BjKgbYTd3motmeXa/belhNOoRfaaPQTXy8E=
|
||||
-----END PUBLIC KEY-----
|
||||
@@ -6,77 +6,74 @@
|
||||
manifest.categories = [ "Utility" ];
|
||||
manifest.readme = builtins.readFile ./README.md;
|
||||
|
||||
roles.peer = {
|
||||
perInstance =
|
||||
{ instanceName, roles, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
roles.moon = {
|
||||
roles.default = {
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.stableEndpoints = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
options.networkId = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Make this machine a moon.
|
||||
Other machines can join this moon by adding this moon in their config.
|
||||
It will be reachable under the given stable endpoints.
|
||||
'';
|
||||
example = ''
|
||||
[ 1.2.3.4" "10.0.0.3/9993" "2001:abcd:abcd::3/9993" ]
|
||||
The zerotier network id to use. If not set, a network will be generated for you.
|
||||
If you administrate your zerotier network via my.zerotier.com, you should set this.
|
||||
'';
|
||||
example = "8056c2e21c000001";
|
||||
};
|
||||
|
||||
};
|
||||
perInstance =
|
||||
{
|
||||
instanceName,
|
||||
settings,
|
||||
roles,
|
||||
...
|
||||
}:
|
||||
{ instanceName, settings, ... }:
|
||||
{
|
||||
nixosModule =
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
config.clan.core.networking.zerotier.moon.stableEndpoints = settings.stableEndpoints;
|
||||
config = lib.mkMerge [
|
||||
# code to start/configure zerotier
|
||||
({ config, ... }: {
|
||||
services.zerotierone = {
|
||||
enable = true;
|
||||
joinNetworks = [ config.clan."zerotier_${instanceName}".networkId ];
|
||||
};
|
||||
systemd.network.networks."09-zerotier" = {
|
||||
matchConfig.Name = "zt*";
|
||||
networkConfig = {
|
||||
LLDP = true;
|
||||
MulticastDNS = true;
|
||||
KeepConfiguration = "static";
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPre = [
|
||||
"+${pkgs.writeShellScript "init-zerotier" ''
|
||||
# compare hashes of the current identity secret and the one in the config
|
||||
hash1=$(sha256sum /var/lib/zerotier-one/identity.secret | cut -d ' ' -f 1)
|
||||
hash2=$(sha256sum ${config.clan.core.vars.generators.zerotier.files.zerotier-identity-secret.path} | cut -d ' ' -f 1)
|
||||
if [[ "$hash1" != "$hash2" ]]; then
|
||||
echo "Identity secret has changed, backing up old identity to /var/lib/zerotier-one/identity.secret.bac"
|
||||
cp /var/lib/zerotier-one/identity.secret /var/lib/zerotier-one/identity.secret.bac
|
||||
cp /var/lib/zerotier-one/identity.public /var/lib/zerotier-one/identity.public.bac
|
||||
cp ${config.clan.core.vars.generators.zerotier.files.zerotier-identity-secret.path} /var/lib/zerotier-one/identity.secret
|
||||
zerotier-idtool getpublic /var/lib/zerotier-one/identity.secret > /var/lib/zerotier-one/identity.public
|
||||
fi
|
||||
|
||||
# cleanup old networks
|
||||
if [[ -d /var/lib/zerotier-one/networks.d ]]; then
|
||||
find /var/lib/zerotier-one/networks.d \
|
||||
-type f \
|
||||
-name "*.conf" \
|
||||
-not \( ${
|
||||
lib.concatMapStringsSep " -o " (
|
||||
netId: ''-name "${netId}.conf"''
|
||||
) config.services.zerotierone.joinNetworks
|
||||
} \) \
|
||||
-delete
|
||||
fi
|
||||
''}"
|
||||
];
|
||||
})
|
||||
];
|
||||
};
|
||||
@@ -87,16 +84,22 @@
|
||||
interface =
|
||||
{ lib, ... }:
|
||||
{
|
||||
options.allowedIps = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Extra machines by their zerotier ip that the zerotier controller
|
||||
should accept. These could be external machines.
|
||||
'';
|
||||
example = ''
|
||||
[ "fd5d:bbe3:cbc5:fe6b:f699:935d:bbe3:cbc5" ]
|
||||
'';
|
||||
options = {
|
||||
allowedIps = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = ''
|
||||
Extra machines by their zerotier ip that the zerotier controller
|
||||
should accept. These could be external machines.
|
||||
'';
|
||||
example = ''
|
||||
[ "fd5d:bbe3:cbc5:fe6b:f699:935d:bbe3:cbc5" ]
|
||||
'';
|
||||
};
|
||||
settings = lib.mkOption {
|
||||
description = "override the network config in /var/lib/zerotier/bla/$network.json";
|
||||
type = lib.types.json;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -119,54 +122,135 @@
|
||||
uniqueStrings = list: builtins.attrNames (builtins.groupBy lib.id list);
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(import ./shared.nix {
|
||||
inherit
|
||||
instanceName
|
||||
roles
|
||||
config
|
||||
lib
|
||||
pkgs
|
||||
;
|
||||
})
|
||||
];
|
||||
config = {
|
||||
systemd.services.zerotier-inventory-autoaccept =
|
||||
let
|
||||
machines = uniqueStrings (
|
||||
(lib.optionals (roles ? moon) (lib.attrNames roles.moon.machines))
|
||||
++ (lib.optionals (roles ? controller) (lib.attrNames roles.controller.machines))
|
||||
++ (lib.optionals (roles ? peer) (lib.attrNames roles.peer.machines))
|
||||
);
|
||||
networkIps = builtins.foldl' (
|
||||
ips: name:
|
||||
if
|
||||
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
|
||||
then
|
||||
ips
|
||||
++ [
|
||||
(builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value")
|
||||
]
|
||||
else
|
||||
ips
|
||||
) [ ] machines;
|
||||
allHostIPs = settings.allowedIps ++ networkIps;
|
||||
in
|
||||
{
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "zerotierone.service" ];
|
||||
path = [ config.clan.core.clanPkgs.zerotierone ];
|
||||
serviceConfig.ExecStart = pkgs.writeShellScript "zerotier-inventory-autoaccept" ''
|
||||
${lib.concatMapStringsSep "\n" (host: ''
|
||||
${config.clan.core.clanPkgs.zerotier-members}/bin/zerotier-members allow --member-ip ${host}
|
||||
'') allHostIPs}
|
||||
'';
|
||||
};
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPre = [
|
||||
"+${pkgs.writeShellScript "init-zerotier-${instanceName}" ''
|
||||
mkdir -p /var/lib/zerotier-one/controller.d/${instanceName}
|
||||
ln -sfT ${pkgs.writeText "net.json" (builtins.toJSON settings.settings)} /var/lib/zerotier-one/controller.d/network/${config.clan."zerotier_${instanceName}".networkId}.json
|
||||
|
||||
clan.core.networking.zerotier.controller.enable = lib.mkDefault true;
|
||||
};
|
||||
''}"
|
||||
];
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPost = [
|
||||
"+${pkgs.writeShellScript "whitelist-controller" ''
|
||||
${config.clan.core.clanPkgs.zerotier-members}/bin/zerotier-members allow ${
|
||||
builtins.substring 0 10 config.clan."zerotier_${instanceName}".networkId
|
||||
}
|
||||
''}"
|
||||
];
|
||||
systemd.services.zerotier-inventory-autoaccept =
|
||||
let
|
||||
machines = uniqueStrings (
|
||||
(lib.optionals (roles ? moon) (lib.attrNames roles.moon.machines))
|
||||
++ (lib.optionals (roles ? controller) (lib.attrNames roles.controller.machines))
|
||||
++ (lib.optionals (roles ? peer) (lib.attrNames roles.peer.machines))
|
||||
);
|
||||
networkIps = builtins.foldl' (
|
||||
ips: name:
|
||||
if
|
||||
builtins.pathExists "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value"
|
||||
then
|
||||
ips
|
||||
++ [
|
||||
(builtins.readFile "${config.clan.core.settings.directory}/vars/per-machine/${name}/zerotier/zerotier-ip/value")
|
||||
]
|
||||
else
|
||||
ips
|
||||
) [ ] machines;
|
||||
allHostIPs = settings.allowedIps ++ networkIps;
|
||||
in
|
||||
{
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "zerotierone.service" ];
|
||||
path = [ config.clan.core.clanPkgs.zerotierone ];
|
||||
serviceConfig.ExecStart = pkgs.writeShellScript "zerotier-inventory-autoaccept" ''
|
||||
${lib.concatMapStringsSep "\n" (host: ''
|
||||
${config.clan.core.clanPkgs.zerotier-members}/bin/zerotier-members allow --member-ip ${host}
|
||||
'') allHostIPs}
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# there a bunch of different scenarios that can happen which we need to take care of
|
||||
## controller is not a peer (the controller doesn't have an ipv4 and is not part of the network)
|
||||
## controller has multiple networks (currently the code only creates a single network per controller, so we need to figure out the API call to get another network created)
|
||||
## controller has multiple networks but is peer in only some
|
||||
## I guess we need to make an attrset of controllers to networks and then create the networks with the controller key
|
||||
# every controller key will be shared, so all network specific ids can be shared
|
||||
perMachine = { instances, machine, lib, ... }: let
|
||||
# an attrset of { controller1 = { instance1 = {}; instance2 = {}; }; controller2 = { instance3 = {}; }; }
|
||||
controllerNetworks = lib.foldlAttrs (acc: instanceName: instance: lib.recursiveUpdate acc { ${lib.head (lib.attrNames instance.roles.controller.machines)} = { ${instanceName} = {}; }; }) {} instances;
|
||||
getInstanceController = instance: lib.head (lib.attrNames instance.roles.controller.machines);
|
||||
in {
|
||||
nixosModule = { pkgs, config, ... }: {
|
||||
config = lib.mkMerge [
|
||||
{ # every controller gets a shared network key, from which we can derive multiple network ids
|
||||
# we have this var shared, so we can create it when evaluating any machine
|
||||
clan.core.vars.generators = lib.mapAttrs' (controllerName: _: lib.nameValuePair "zerotier_controller_${controllerName}" {
|
||||
shared = true;
|
||||
files.zerotier-identity-secret.deploy = false;
|
||||
runtimeInputs = [
|
||||
config.services.zerotierone.package
|
||||
pkgs.python3
|
||||
];
|
||||
script = ''
|
||||
python3 ${./generate.py} --mode network \
|
||||
--ip "$out/zerotier-ip" \
|
||||
--identity-secret "$out/zerotier-identity-secret"
|
||||
'';
|
||||
}) controllerNetworks;
|
||||
}
|
||||
{ # every instance in a controller gets a network id, which is derived from the controller's shared network key
|
||||
clan.core.vars.generators = lib.mapAttrs' (instanceName: instance: lib.nameValuePair "zerotier_network_${instanceName}" {
|
||||
shared = true;
|
||||
files.zerotier-network-id.secret = false;
|
||||
dependencies = [
|
||||
config.clan.core.vars.generators."zerotier_controller_${getInstanceController instance}"
|
||||
];
|
||||
runtimeInputs = [
|
||||
config.services.zerotierone.package
|
||||
pkgs.python3
|
||||
];
|
||||
script = ''
|
||||
python3 ${./generate.py} --mode network-id \
|
||||
--network-id "$out/zerotier-network-id"
|
||||
# TODO we need to pass in the controller key
|
||||
'';
|
||||
}) instances;
|
||||
}
|
||||
{ # define nixos options, which we need to propagate certain information to other roles (like controller)
|
||||
options.clan = lib.mapAttrs' (instanceName: _: lib.nameValuePair "zerotier_${instanceName}" {
|
||||
networkId = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The zerotier network id assigned to this machine";
|
||||
default = if instances.${instanceName}.settings.networkId != null then instances.${instanceName}.settings.networkId else "generated-per-machine";
|
||||
};
|
||||
});
|
||||
}
|
||||
# if we have set null as networkId, we assume that we have a controller and generate a shared key for it
|
||||
# (lib.mkIf (settings.networkId == null) {
|
||||
# clan.core.vars.generators."zerotier_${instanceName}" = {
|
||||
# files.zerotier-network-id.secret = false;
|
||||
# files.zerotier-identity-secret.deploy = false;
|
||||
# shared = true;
|
||||
# runtimeInputs = [
|
||||
# config.services.zerotierone.package
|
||||
# pkgs.python3
|
||||
# ];
|
||||
# script = ''
|
||||
# source ${(pkgs.callPackage ../../../pkgs/minifakeroot { })}/share/minifakeroot/rc
|
||||
# python3 ${./generate.py} --mode network \
|
||||
# --ip "$out/zerotier-ip" \
|
||||
# --identity-secret "$out/zerotier-identity-secret" \
|
||||
# --network-id "$out/zerotier-network-id"
|
||||
# '';
|
||||
# };
|
||||
# clan."zerotier_${instanceName}".networkId =
|
||||
# config.clan.core.vars.generators."zerotier_${instanceName}".files.zerotier-network-id.value;
|
||||
# })
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
module = lib.modules.importApply ./default.nix { };
|
||||
module = ./default.nix;
|
||||
in
|
||||
{
|
||||
clan.modules.zerotier = module;
|
||||
|
||||
@@ -28,38 +28,5 @@ in
|
||||
config = {
|
||||
clan.core.networking.zerotier.networkId = networkId;
|
||||
clan.core.networking.zerotier.name = instanceName;
|
||||
|
||||
systemd.services.zerotierone.serviceConfig.ExecStartPost = lib.mkIf (moonIps != [ ]) (
|
||||
lib.mkAfter [
|
||||
"+${pkgs.writeScript "orbit-moons-by-ip" ''
|
||||
#!${pkgs.python3.interpreter}
|
||||
import json
|
||||
import ipaddress
|
||||
import subprocess
|
||||
|
||||
def compute_member_id(ipv6_addr: str) -> str:
|
||||
addr = ipaddress.IPv6Address(ipv6_addr)
|
||||
addr_bytes = bytearray(addr.packed)
|
||||
|
||||
# Extract the bytes corresponding to the member_id (node_id)
|
||||
node_id_bytes = addr_bytes[10:16]
|
||||
node_id = int.from_bytes(node_id_bytes, byteorder="big")
|
||||
|
||||
member_id = format(node_id, "x").zfill(10)[-10:]
|
||||
|
||||
return member_id
|
||||
def main() -> None:
|
||||
ips = json.loads(${builtins.toJSON (builtins.toJSON moonIps)})
|
||||
for ip in ips:
|
||||
member_id = compute_member_id(ip)
|
||||
res = subprocess.run(["zerotier-cli", "orbit", member_id, member_id])
|
||||
if res.returncode != 0:
|
||||
print(f"Failed to add {member_id} to orbit")
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
''}"
|
||||
]
|
||||
);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
18
devFlake/flake.lock
generated
18
devFlake/flake.lock
generated
@@ -84,11 +84,11 @@
|
||||
},
|
||||
"nixpkgs-dev": {
|
||||
"locked": {
|
||||
"lastModified": 1757449886,
|
||||
"narHash": "sha256-XNhjHidr4i581CVyufJtrleYYgn/55cQONYG3uvIYEY=",
|
||||
"lastModified": 1758573205,
|
||||
"narHash": "sha256-0ybDco+HjG5h46wx7ww4JIyg3y/mBDgkMCVX/Ua0e/Q=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1779f9e0d8b45d88d7525665dd4d2a5b65041248",
|
||||
"rev": "803b1683f562edc00665874bf98c1aad0b111482",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -107,11 +107,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756738487,
|
||||
"narHash": "sha256-8QX7Ab5CcICp7zktL47VQVS+QeaU4YDNAjzty7l7TQE=",
|
||||
"lastModified": 1758272005,
|
||||
"narHash": "sha256-1u3xTH+3kaHhztPmWtLAD8LF5pTYLR2CpsPFWTFnVtQ=",
|
||||
"owner": "NuschtOS",
|
||||
"repo": "search",
|
||||
"rev": "5feeaeefb571e6ca2700888b944f436f7c05149b",
|
||||
"rev": "aa975a3757f28ce862812466c5848787b868e116",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -165,11 +165,11 @@
|
||||
"nixpkgs": []
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1756662192,
|
||||
"narHash": "sha256-F1oFfV51AE259I85av+MAia221XwMHCOtZCMcZLK2Jk=",
|
||||
"lastModified": 1758206697,
|
||||
"narHash": "sha256-/DbPkh6PZOgfueCbs3uzlk4ASU2nPPsiVWhpMCNkAd0=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "1aabc6c05ccbcbf4a635fb7a90400e44282f61c4",
|
||||
"rev": "128222dc911b8e2e18939537bed1762b7f3a04aa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
183
docs/mkdocs.yml
183
docs/mkdocs.yml
@@ -1,4 +1,4 @@
|
||||
site_name: Clan Documentation
|
||||
site_name: Documentation
|
||||
site_url: https://docs.clan.lol
|
||||
repo_url: https://git.clan.lol/clan/clan-core/
|
||||
repo_name: "_>"
|
||||
@@ -45,82 +45,80 @@ exclude_docs: |
|
||||
/drafts/
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Getting Started:
|
||||
- Overview: index.md
|
||||
- Creating Your First Clan: guides/getting-started/index.md
|
||||
- Add Machines: guides/getting-started/add-machines.md
|
||||
- Add User: guides/getting-started/add-user.md
|
||||
- Add Services: guides/getting-started/add-services.md
|
||||
- Deploy to Physical Machine:
|
||||
- Create USB Installer: guides/getting-started/create-installer.md
|
||||
- Deploy Physical Machine: guides/getting-started/hardware-report-physical.md
|
||||
- Deploy to Virtual Machine: guides/getting-started/hardware-report-virtual.md
|
||||
- Configure Disk Config: guides/getting-started/choose-disk.md
|
||||
- Update Machine: guides/getting-started/update.md
|
||||
- Continuous Integration: guides/getting-started/flake-check.md
|
||||
- Convert Existing NixOS Config: guides/getting-started/convert-flake.md
|
||||
- Guides:
|
||||
- Getting Started:
|
||||
- Creating Your First Clan: guides/getting-started/index.md
|
||||
- Add Machines: guides/getting-started/add-machines.md
|
||||
- Add User: guides/getting-started/add-user.md
|
||||
- Add Services: guides/getting-started/add-services.md
|
||||
- Deploy to Physical Machine:
|
||||
- Create USB Installer: guides/getting-started/create-installer.md
|
||||
- Deploy Physical Machine: guides/getting-started/hardware-report-physical.md
|
||||
- Deploy to Virtual Machine: guides/getting-started/hardware-report-virtual.md
|
||||
- Configure Disk Config: guides/getting-started/choose-disk.md
|
||||
- Update Machine: guides/getting-started/update.md
|
||||
- Continuous Integration: guides/getting-started/flake-check.md
|
||||
- Convert Existing NixOS Config: guides/getting-started/convert-flake.md
|
||||
- ClanServices: guides/clanServices.md
|
||||
- Backup & Restore: guides/backups.md
|
||||
- Disk Encryption: guides/disk-encryption.md
|
||||
- Inventory:
|
||||
- Introduction to Inventory: guides/inventory/inventory.md
|
||||
- File Autoincludes: guides/inventory/autoincludes.md
|
||||
|
||||
- Clan Services:
|
||||
- Inventory Guide: guides/inventory/clanServices.md
|
||||
- Author Your Own Service: guides/services/community.md
|
||||
- Vars:
|
||||
- Overview: guides/vars-overview.md
|
||||
- Getting Started: guides/vars-backend.md
|
||||
- Concepts: guides/vars-concepts.md
|
||||
- Advanced Examples: guides/vars-advanced-examples.md
|
||||
- Troubleshooting: guides/vars-troubleshooting.md
|
||||
- Age Plugins: guides/age-plugins.md
|
||||
- Secrets management: guides/secrets.md
|
||||
- Networking: guides/networking.md
|
||||
- Zerotier VPN: guides/mesh-vpn.md
|
||||
- How to disable Secure Boot: guides/secure-boot.md
|
||||
- Introduction to Vars: guides/vars/vars-overview.md
|
||||
- Minimal Example: guides/vars/vars-backend.md
|
||||
- Diving deeper: guides/vars/vars-concepts.md
|
||||
- Advanced Examples: guides/vars/vars-advanced-examples.md
|
||||
- Troubleshooting: guides/vars/vars-troubleshooting.md
|
||||
- Sops Backend:
|
||||
- Yubikeys & Age Plugins: guides/vars/sops/age-plugins.md
|
||||
- Managing Users (OLD): guides/secrets.md
|
||||
- Networking:
|
||||
- Introduction to Networking: guides/networking/networking.md
|
||||
- Zerotier VPN: guides/networking/mesh-vpn.md
|
||||
- Disko Templates:
|
||||
- Community Disko Templates: guides/disko-templates/community.md
|
||||
- Backups:
|
||||
- Introduction to Backups: guides/backups.md
|
||||
- Flake-parts: guides/flake-parts.md
|
||||
- macOS: guides/macos.md
|
||||
- NixOS Rebuild: guides/nixos-rebuild.md
|
||||
- macOS:
|
||||
- Managing macOS Machines: guides/macos.md
|
||||
# Should be part of the respective sections above
|
||||
# machines, disko, clan
|
||||
- Templates: concepts/templates.md
|
||||
- Migrations:
|
||||
- clan modules --> clan services: guides/migrations/migrate-inventory-services.md
|
||||
- Facts --> Vars: guides/migrations/migration-facts-vars.md
|
||||
- Disk id: guides/migrations/disk-id.md
|
||||
- Disk Encryption: guides/disk-encryption.md
|
||||
- Disable Secure Boot: guides/secure-boot.md
|
||||
- Contributing:
|
||||
- Contributing: guides/contributing/CONTRIBUTING.md
|
||||
- Debugging: guides/contributing/debugging.md
|
||||
- Hacking: guides/contributing/CONTRIBUTING.md
|
||||
- Advanced Debugging: guides/contributing/debugging.md
|
||||
- Testing: guides/contributing/testing.md
|
||||
|
||||
- Writing a Service Module: guides/services/community.md
|
||||
- Writing a Disko Template: guides/disko-templates/community.md
|
||||
- Migrations:
|
||||
- Migrate from clan modules to services: guides/migrations/migrate-inventory-services.md
|
||||
- Facts Vars Migration: guides/migrations/migration-facts-vars.md
|
||||
- Disk id: guides/migrations/disk-id.md
|
||||
- Concepts:
|
||||
- Inventory: concepts/inventory.md
|
||||
- Generators: concepts/generators.md
|
||||
- Autoincludes: concepts/autoincludes.md
|
||||
- Templates: concepts/templates.md
|
||||
- Reference:
|
||||
- Overview: reference/index.md
|
||||
- Browse Options: "/options"
|
||||
- Services:
|
||||
- Overview:
|
||||
- reference/clanServices/index.md
|
||||
- reference/clanServices/admin.md
|
||||
- reference/clanServices/borgbackup.md
|
||||
- reference/clanServices/certificates.md
|
||||
- reference/clanServices/coredns.md
|
||||
- reference/clanServices/data-mesher.md
|
||||
- reference/clanServices/dyndns.md
|
||||
- reference/clanServices/emergency-access.md
|
||||
- reference/clanServices/garage.md
|
||||
- reference/clanServices/hello-world.md
|
||||
- reference/clanServices/importer.md
|
||||
- reference/clanServices/localbackup.md
|
||||
- reference/clanServices/matrix-synapse.md
|
||||
- reference/clanServices/mycelium.md
|
||||
- reference/clanServices/monitoring.md
|
||||
- reference/clanServices/packages.md
|
||||
- reference/clanServices/sshd.md
|
||||
- reference/clanServices/syncthing.md
|
||||
- reference/clanServices/trusted-nix-caches.md
|
||||
- reference/clanServices/users.md
|
||||
- reference/clanServices/wifi.md
|
||||
- reference/clanServices/wireguard.md
|
||||
- reference/clanServices/zerotier.md
|
||||
- API: reference/clanServices/clan-service-author-interface.md
|
||||
- Clan Options: reference/options/clan.md
|
||||
- Clan Inventory Options: reference/options/clan_inventory.md
|
||||
|
||||
- Clan Service API: reference/clanServices/clan-service-author-interface.md
|
||||
|
||||
- clan.core (Machine Options):
|
||||
- Overview: reference/clan.core/index.md
|
||||
- reference/clan.core/backups.md
|
||||
- reference/clan.core/deployment.md
|
||||
- reference/clan.core/facts.md
|
||||
- reference/clan.core/networking.md
|
||||
- reference/clan.core/postgresql.md
|
||||
- reference/clan.core/settings.md
|
||||
- reference/clan.core/sops.md
|
||||
- reference/clan.core/state.md
|
||||
- reference/clan.core/vars.md
|
||||
|
||||
- CLI:
|
||||
- Overview: reference/cli/index.md
|
||||
@@ -139,19 +137,7 @@ nav:
|
||||
- reference/cli/vars.md
|
||||
- reference/cli/vms.md
|
||||
|
||||
- clan.core (NixOS Options):
|
||||
- Overview: reference/clan.core/index.md
|
||||
- reference/clan.core/backups.md
|
||||
- reference/clan.core/deployment.md
|
||||
- reference/clan.core/facts.md
|
||||
- reference/clan.core/networking.md
|
||||
- reference/clan.core/postgresql.md
|
||||
- reference/clan.core/settings.md
|
||||
- reference/clan.core/sops.md
|
||||
- reference/clan.core/state.md
|
||||
- reference/clan.core/vars.md
|
||||
|
||||
- Developer-api: api.md
|
||||
- HTTP API: api.md
|
||||
|
||||
- Decisions:
|
||||
- Architecture Decisions: decisions/README.md
|
||||
@@ -162,7 +148,35 @@ nav:
|
||||
- 05-deployment-parameters: decisions/05-deployment-parameters.md
|
||||
- Template: decisions/_template.md
|
||||
- Glossary: reference/glossary.md
|
||||
- Browse Options: "/options"
|
||||
- Services:
|
||||
- Introduction to ClanServices: reference/clanServices/index.md
|
||||
- Official:
|
||||
- reference/clanServices/admin.md
|
||||
- reference/clanServices/borgbackup.md
|
||||
- reference/clanServices/certificates.md
|
||||
- reference/clanServices/coredns.md
|
||||
- reference/clanServices/data-mesher.md
|
||||
- reference/clanServices/dyndns.md
|
||||
- reference/clanServices/emergency-access.md
|
||||
- reference/clanServices/garage.md
|
||||
- reference/clanServices/hello-world.md
|
||||
- reference/clanServices/importer.md
|
||||
- reference/clanServices/localbackup.md
|
||||
- reference/clanServices/matrix-synapse.md
|
||||
- reference/clanServices/mycelium.md
|
||||
- reference/clanServices/monitoring.md
|
||||
- reference/clanServices/packages.md
|
||||
- reference/clanServices/sshd.md
|
||||
- reference/clanServices/syncthing.md
|
||||
- reference/clanServices/trusted-nix-caches.md
|
||||
- reference/clanServices/users.md
|
||||
- reference/clanServices/wifi.md
|
||||
- reference/clanServices/wireguard.md
|
||||
- reference/clanServices/yggdrasil.md
|
||||
- reference/clanServices/zerotier.md
|
||||
- Community: community/services/index.md
|
||||
|
||||
- Search Clan Options: "/options"
|
||||
|
||||
docs_dir: site
|
||||
site_dir: out
|
||||
@@ -220,8 +234,7 @@ extra:
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- macros
|
||||
- redoc-tag
|
||||
- redirects:
|
||||
redirect_maps:
|
||||
guides/getting-started/secrets.md: concepts/generators.md
|
||||
guides/getting-started/secrets.md: guides/vars/vars-overview.md
|
||||
|
||||
@@ -37,7 +37,6 @@ pkgs.stdenv.mkDerivation {
|
||||
++ (with pkgs.python3Packages; [
|
||||
mkdocs
|
||||
mkdocs-material
|
||||
mkdocs-macros
|
||||
mkdocs-redoc-tag
|
||||
mkdocs-redirects
|
||||
]);
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
buildClanOptions = self'.legacyPackages.clan-internals-docs;
|
||||
# Simply evaluated options (JSON)
|
||||
# { clanCore = «derivation JSON»; clanModules = { ${name} = «derivation JSON» }; }
|
||||
jsonDocs = pkgs.callPackage ./get-module-docs.nix {
|
||||
@@ -73,8 +72,7 @@
|
||||
# A file that contains the links to all clanModule docs
|
||||
export CLAN_MODULES_VIA_SERVICE=${clanModulesViaService}
|
||||
export CLAN_SERVICE_INTERFACE=${self'.legacyPackages.clan-service-module-interface}/share/doc/nixos/options.json
|
||||
|
||||
export BUILD_CLAN_PATH=${buildClanOptions}/share/doc/nixos/options.json
|
||||
export CLAN_OPTIONS_PATH=${self'.legacyPackages.clan-options}/share/doc/nixos/options.json
|
||||
|
||||
mkdir $out
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
let
|
||||
inherit (lib)
|
||||
mapAttrsToList
|
||||
flip
|
||||
mapAttrs
|
||||
mkOption
|
||||
types
|
||||
@@ -41,10 +40,7 @@
|
||||
prefix = [ ];
|
||||
}).config.manifest;
|
||||
|
||||
loadFile = file: if builtins.pathExists file then builtins.readFile file else "";
|
||||
|
||||
settingsModules =
|
||||
module: flip mapAttrs (getRoles module) (_roleName: roleConfig: roleConfig.interface);
|
||||
settingsModules = module: mapAttrs (_roleName: roleConfig: roleConfig.interface) (getRoles module);
|
||||
|
||||
# Map each letter to its capitalized version
|
||||
capitalizeChar =
|
||||
@@ -99,7 +95,7 @@
|
||||
|
||||
**${manifest.description}**
|
||||
|
||||
${loadFile (module._file + "/../README.md")}
|
||||
${lib.optionalString (manifest ? readme) manifest.readme}
|
||||
|
||||
${
|
||||
if manifest.categories != [ ] then
|
||||
@@ -115,7 +111,7 @@
|
||||
instances.${name} = lib.mkOption {
|
||||
inherit description;
|
||||
type = types.submodule {
|
||||
options.roles = flip mapAttrs (settingsModules module) (
|
||||
options.roles = mapAttrs (
|
||||
roleName: roleSettingsModule:
|
||||
mkOption {
|
||||
type = types.submodule {
|
||||
@@ -138,7 +134,7 @@
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
) (settingsModules module);
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -205,25 +201,31 @@
|
||||
# };
|
||||
|
||||
packages = {
|
||||
docs-options = privateInputs.nuschtos.packages.${pkgs.stdenv.hostPlatform.system}.mkMultiSearch {
|
||||
inherit baseHref;
|
||||
title = "Clan Options";
|
||||
# scopes = mapAttrsToList mkScope serviceModules;
|
||||
scopes = [
|
||||
{
|
||||
docs-options =
|
||||
if privateInputs ? nuschtos then
|
||||
privateInputs.nuschtos.packages.${pkgs.stdenv.hostPlatform.system}.mkMultiSearch {
|
||||
inherit baseHref;
|
||||
name = "Flake Options (clan.nix file)";
|
||||
modules = docModules;
|
||||
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
|
||||
title = "Clan Options";
|
||||
# scopes = mapAttrsToList mkScope serviceModules;
|
||||
scopes = [
|
||||
{
|
||||
inherit baseHref;
|
||||
name = "Flake Options (clan.nix file)";
|
||||
modules = docModules;
|
||||
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
|
||||
}
|
||||
{
|
||||
name = "Machine Options (clan.core NixOS options)";
|
||||
optionsJSON = "${coreOptions}/share/doc/nixos/options.json";
|
||||
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "Machine Options (clan.core NixOS options)";
|
||||
optionsJSON = "${coreOptions}/share/doc/nixos/options.json";
|
||||
urlPrefix = "https://git.clan.lol/clan/clan-core/src/branch/main/";
|
||||
|
||||
}
|
||||
];
|
||||
};
|
||||
else
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "empty";
|
||||
buildCommand = "echo 'This is an empty derivation' > $out";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -40,7 +41,7 @@ from clan_lib.services.modules import (
|
||||
# Get environment variables
|
||||
CLAN_CORE_PATH = Path(os.environ["CLAN_CORE_PATH"])
|
||||
CLAN_CORE_DOCS = Path(os.environ["CLAN_CORE_DOCS"])
|
||||
BUILD_CLAN_PATH = os.environ.get("BUILD_CLAN_PATH")
|
||||
CLAN_OPTIONS_PATH = Path(os.environ["CLAN_OPTIONS_PATH"])
|
||||
|
||||
# Options how to author clan.modules
|
||||
# perInstance, perMachine, ...
|
||||
@@ -326,7 +327,7 @@ Each `clanService`:
|
||||
|
||||
See [Migration Guide](../../guides/migrations/migrate-inventory-services.md) for help on migrating.
|
||||
|
||||
Learn how to use `clanServices` in practice in the [Using clanServices guide](../../guides/clanServices.md).
|
||||
Learn how to use `clanServices` in practice in the [Using clanServices guide](../../guides/inventory/clanServices.md).
|
||||
"""
|
||||
|
||||
with indexfile.open("w") as of:
|
||||
@@ -442,6 +443,84 @@ Typically needed by module authors to define roles, behavior and metadata for di
|
||||
of.write(output)
|
||||
|
||||
|
||||
def produce_inventory_docs() -> None:
|
||||
if not CLAN_OPTIONS_PATH:
|
||||
msg = f"Environment variables are not set correctly: CLAN_OPTIONS_PATH={CLAN_OPTIONS_PATH}. Expected a path to the optionsJSON"
|
||||
raise ClanError(msg)
|
||||
|
||||
if not OUT:
|
||||
msg = f"Environment variables are not set correctly: $out={OUT}"
|
||||
raise ClanError(msg)
|
||||
|
||||
output = """# Inventory
|
||||
This provides an overview of the available options of the `inventory` model.
|
||||
|
||||
It can be set via the `inventory` attribute of the [`clan`](./clan.md#inventory) function, or via the [`clan.inventory`](./clan.md#inventory) attribute of flake-parts.
|
||||
|
||||
"""
|
||||
# Inventory options are already included under the clan attribute
|
||||
# We just omitted them in the clan docs, because we want a separate output for the inventory model
|
||||
with Path(CLAN_OPTIONS_PATH).open() as f:
|
||||
options: dict[str, dict[str, Any]] = json.load(f)
|
||||
|
||||
clan_root_option = options_to_tree(options)
|
||||
# Find the inventory options
|
||||
inventory_opt: None | Option = None
|
||||
for opt in clan_root_option.suboptions:
|
||||
if opt.name == "inventory":
|
||||
inventory_opt = opt
|
||||
break
|
||||
|
||||
if not inventory_opt:
|
||||
print("No inventory options found.")
|
||||
sys.exit(1)
|
||||
# Render the inventory options
|
||||
# This for loop excludes the root node
|
||||
for option in inventory_opt.suboptions:
|
||||
output += options_docs_from_tree(option, init_level=2)
|
||||
|
||||
outfile = Path(OUT) / "options/clan_inventory.md"
|
||||
outfile.parent.mkdir(parents=True, exist_ok=True)
|
||||
with Path.open(outfile, "w") as of:
|
||||
of.write(output)
|
||||
|
||||
|
||||
def produce_clan_options_docs() -> None:
|
||||
if not CLAN_OPTIONS_PATH:
|
||||
msg = f"Environment variables are not set correctly: CLAN_OPTIONS_PATH={CLAN_OPTIONS_PATH}. Expected a path to the optionsJSON"
|
||||
raise ClanError(msg)
|
||||
|
||||
if not OUT:
|
||||
msg = f"Environment variables are not set correctly: $out={OUT}"
|
||||
raise ClanError(msg)
|
||||
|
||||
output = """# Clan Options
|
||||
This provides an overview of the available options
|
||||
|
||||
Those can be set via [`clan-core.lib.clan`](./clan.md#inventory) function,
|
||||
or via the [`clan`](./clan.md) attribute of flake-parts.
|
||||
|
||||
"""
|
||||
# Inventory options are already included under the clan attribute
|
||||
# We just omitted them in the clan docs, because we want a separate output for the inventory model
|
||||
with Path(CLAN_OPTIONS_PATH).open() as f:
|
||||
options: dict[str, dict[str, Any]] = json.load(f)
|
||||
|
||||
clan_root_option = options_to_tree(options)
|
||||
# Render the inventory options
|
||||
# This for loop excludes the root node
|
||||
# Exclude inventory options
|
||||
for option in clan_root_option.suboptions:
|
||||
if "inventory" in option.name:
|
||||
continue
|
||||
output += options_docs_from_tree(option, init_level=2)
|
||||
|
||||
outfile = Path(OUT) / "options/clan.md"
|
||||
outfile.parent.mkdir(parents=True, exist_ok=True)
|
||||
with Path.open(outfile, "w") as of:
|
||||
of.write(output)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Option:
|
||||
name: str
|
||||
@@ -556,6 +635,7 @@ def options_docs_from_tree(
|
||||
|
||||
if __name__ == "__main__":
|
||||
produce_clan_core_docs()
|
||||
|
||||
produce_inventory_docs()
|
||||
produce_clan_options_docs()
|
||||
produce_clan_service_author_docs()
|
||||
produce_clan_service_docs()
|
||||
|
||||
27
docs/site/community/services/index.md
Normal file
27
docs/site/community/services/index.md
Normal file
@@ -0,0 +1,27 @@
|
||||
Services provided by the community
|
||||
|
||||
!!! tip "Add your own!"
|
||||
|
||||
Have you built a service or a tool for? Open a PR adding a link to this page!
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- [Your Service Foo](https://example.com) :octicons-link-external-16:
|
||||
|
||||
---
|
||||
|
||||
Does this and that
|
||||
|
||||
- [Your Service Foo](https://example.com) :octicons-link-external-16:
|
||||
|
||||
---
|
||||
|
||||
Does this and that
|
||||
|
||||
- [Your Service Foo](https://example.com) :octicons-link-external-16:
|
||||
|
||||
---
|
||||
|
||||
Does this and that
|
||||
|
||||
</div>
|
||||
@@ -1,45 +0,0 @@
|
||||
# Generators
|
||||
|
||||
Generators are the core mechanism of the clan vars system for automating the creation and management of generated files, especially secrets, in your NixOS configurations.
|
||||
|
||||
## What are Generators?
|
||||
|
||||
Generators solve a common problem: instead of manually running commands like `mkpasswd` to create password hashes and copying them into your configuration, generators automate this process declaratively.
|
||||
|
||||
A generator defines:
|
||||
|
||||
- **Input prompts**: Values to request from users (passwords, names, etc.)
|
||||
- **Generation script**: Logic to transform inputs into outputs
|
||||
- **Output files**: Generated files that can be secrets or public data
|
||||
- **Dependencies**: Other generators this one depends on
|
||||
- **Runtime inputs**: Tools and packages needed by the script
|
||||
|
||||
## Key Benefits
|
||||
|
||||
- **Reproducible**: Same inputs produce same outputs across machines
|
||||
- **Declarative**: Defined in your NixOS configuration alongside usage
|
||||
- **Secure**: Automatic handling of secrets storage and deployment
|
||||
- **Collaborative**: Shared generators work across team environments
|
||||
- **Automated**: No manual copy-paste of generated values
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
- **Password hashing**: Generate secure password hashes for user accounts
|
||||
- **SSH keys**: Create and manage SSH host and user keys
|
||||
- **Certificates**: Generate TLS certificates and certificate authorities
|
||||
- **API tokens**: Create secure random tokens for services
|
||||
- **Configuration files**: Generate config files that depend on secrets
|
||||
|
||||
## Learning Path
|
||||
|
||||
1. **Start here**: [Vars Getting Started Guide](../guides/vars-backend.md) - Hands-on tutorial with practical examples
|
||||
2. **Understand the architecture**: [Vars Concepts Guide](../guides/vars-concepts.md) - Deep dive into design principles and patterns
|
||||
3. **Explore complex scenarios**: [Advanced Examples](../guides/vars-advanced-examples.md) - Real-world patterns and best practices
|
||||
4. **Troubleshoot issues**: [Troubleshooting Guide](../guides/vars-troubleshooting.md) - Common problems and solutions
|
||||
|
||||
## API Reference
|
||||
|
||||
For complete configuration options and technical details, see:
|
||||
|
||||
- [Vars NixOS Module Reference](../reference/clan.core/vars.md) - All configuration options
|
||||
- [Vars CLI Reference](../reference/cli/vars.md) - Command-line interface
|
||||
@@ -1,59 +0,0 @@
|
||||
## Using Age Plugins
|
||||
|
||||
If you wish to use a key generated using an [age plugin] as your admin key, extra care is needed.
|
||||
|
||||
You must **precede your secret key with a comment that contains its corresponding recipient**.
|
||||
|
||||
This is usually output as part of the generation process
|
||||
and is only required because there is no unified mechanism for recovering a recipient from a plugin secret key.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```title="~/.config/sops/age/keys.txt"
|
||||
# public key: age1zdy49ek6z60q9r34vf5mmzkx6u43pr9haqdh5lqdg7fh5tpwlfwqea356l
|
||||
AGE-PLUGIN-FIDO2-HMAC-1QQPQZRFR7ZZ2WCV...
|
||||
```
|
||||
|
||||
!!! note
|
||||
The comment that precedes the plugin secret key need only contain the recipient.
|
||||
Any other text is ignored.
|
||||
|
||||
In the example above, you can specify `# recipient: age1zdy...`, `# public: age1zdy....` or even
|
||||
just `# age1zdy....`
|
||||
|
||||
You will need to add an entry into your `flake.nix` to ensure that the necessary `age` plugins
|
||||
are loaded when using Clan:
|
||||
|
||||
```nix title="flake.nix"
|
||||
{
|
||||
inputs.clan-core.url = "https://git.clan.lol/clan/clan-core/archive/main.tar.gz";
|
||||
inputs.nixpkgs.follows = "clan-core/nixpkgs";
|
||||
|
||||
outputs =
|
||||
{ self, clan-core, ... }:
|
||||
let
|
||||
# Sometimes this attribute set is defined in clan.nix
|
||||
clan = clan-core.lib.clan {
|
||||
inherit self;
|
||||
|
||||
meta.name = "myclan";
|
||||
|
||||
# Add Yubikey and FIDO2 HMAC plugins
|
||||
# Note: the plugins listed here must be available in nixpkgs.
|
||||
secrets.age.plugins = [
|
||||
"age-plugin-yubikey"
|
||||
"age-plugin-fido2-hmac"
|
||||
];
|
||||
|
||||
machines = {
|
||||
# elided for brevity
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit (clan) nixosConfigurations nixosModules clanInternals;
|
||||
|
||||
# elided for brevity
|
||||
};
|
||||
}
|
||||
```
|
||||
@@ -5,7 +5,7 @@ This guide provides an example setup for a single-disk ZFS system with native en
|
||||
This configuration only applies to `systemd-boot` enabled systems and **requires** UEFI booting.
|
||||
|
||||
!!! Info "Secure Boot"
|
||||
This guide is compatible with systems that have [secure boot disabled](../guides/secure-boot.md). If you encounter boot issues, check if secure boot needs to be disabled in your UEFI settings.
|
||||
This guide is compatible with systems that have [secure boot disabled](./secure-boot.md). If you encounter boot issues, check if secure boot needs to be disabled in your UEFI settings.
|
||||
|
||||
Replace the highlighted lines with your own disk-id.
|
||||
You can find our your disk-id by executing:
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
Machines can be added using the following methods
|
||||
|
||||
- Create a file `machines/{machine_name}/configuration.nix` (See: [File Autoincludes](../../concepts/autoincludes.md))
|
||||
- Create a file `machines/{machine_name}/configuration.nix` (See: [File Autoincludes](../inventory/autoincludes.md))
|
||||
- Imperative via cli command: `clan machines create`
|
||||
- Editing nix expressions in flake.nix See [`clan-core.lib.clan`](/options/?scope=Flake Options (clan.nix file))
|
||||
|
||||
See the complete [list](../../concepts/autoincludes.md) of auto-loaded files.
|
||||
See the complete [list](../inventory/autoincludes.md) of auto-loaded files.
|
||||
|
||||
## Create a machine
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ In Clan Services are multi-Host & role-based:
|
||||
|
||||
- You can use tags instead of explicit machine names.
|
||||
|
||||
To learn more: [Guide about clanService](../clanServices.md)
|
||||
To learn more: [Guide about clanService](../inventory/clanServices.md)
|
||||
|
||||
!!! Important
|
||||
It is recommended to add at least one networking service such as `zerotier` that allows to reach all your clan machines from your setup computer across the globe.
|
||||
@@ -41,7 +41,7 @@ To learn more: [Guide about clanService](../clanServices.md)
|
||||
```
|
||||
|
||||
1. See [reference/clanServices](../../reference/clanServices/index.md) for all available services and how to configure them.
|
||||
Or read [authoring/clanServices](../../guides/services/community.md) if you want to bring your own
|
||||
Or read [authoring/clanServices](../services/community.md) if you want to bring your own
|
||||
|
||||
2. Replace `__YOUR_CONTROLLER_` with the *name* of your machine.
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ Clan needs to know where it can reach your hosts. For testing purpose set
|
||||
}
|
||||
```
|
||||
|
||||
See our guide on for properly [configuring machines networking](../networking.md)
|
||||
See our guide on for properly [configuring machines networking](../networking/networking.md)
|
||||
|
||||
## Next Steps
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ sudo umount /dev/sdb1
|
||||
|
||||
## Boot From USB Stick
|
||||
|
||||
- To use, boot from the Clan USB drive with **secure boot turned off**. For step by step instructions go to [Disabling Secure Boot](../../guides/secure-boot.md)
|
||||
- To use, boot from the Clan USB drive with **secure boot turned off**. For step by step instructions go to [Disabling Secure Boot](../secure-boot.md)
|
||||
|
||||
## (Optional) Connect to Wifi Manually
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Now that you have created a machine, added some services, and set up secrets, this guide will walk you through how to deploy it.
|
||||
|
||||
|
||||
### Step 0. Prerequisites
|
||||
### Prerequisites
|
||||
- [x] RAM > 2GB
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [adding and configuring machine guide](./add-machines.md)
|
||||
@@ -45,7 +45,7 @@ This is an example of the booted installer.
|
||||
│ │Onion address: 6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion │ │
|
||||
│ │Multicast DNS: nixos-installer.local │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Press 'Ctrl-C' for console access │
|
||||
│ Press 'Ctrl-C' for console access │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
@@ -75,12 +75,12 @@ This is an example of the booted installer.
|
||||
|
||||
There are two ways to deploy your machine:
|
||||
|
||||
### Generating a Hardware Report
|
||||
|
||||
The following command will generate a hardware report with [nixos-facter](https://github.com/nix-community/nixos-facter) and writes it back into your machine folder. The `--phases kexec` flag makes sure we are not yet formatting anything, instead if the target system is not a NixOS machine it will use [kexec](https://wiki.archlinux.org/title/Kexec) to switch to a NixOS kernel.
|
||||
|
||||
=== "Password"
|
||||
### Generating a Hardware Report
|
||||
|
||||
The following command will generate a hardware report with [nixos-facter](https://github.com/nix-community/nixos-facter) and writes it back into your machine folder. The `--phases kexec` flag makes sure we are not yet formatting anything, instead if the target system is not a NixOS machine it will use [kexec](https://wiki.archlinux.org/title/Kexec) to switch to a NixOS kernel.
|
||||
|
||||
**Password**
|
||||
|
||||
```terminal
|
||||
clan machines install [MACHINE] \
|
||||
@@ -90,11 +90,10 @@ There are two ways to deploy your machine:
|
||||
```
|
||||
|
||||
=== "QR Code"
|
||||
### Generating a Hardware Report
|
||||
**QR Code**
|
||||
|
||||
The following command will generate a hardware report with [nixos-facter](https://github.com/nix-community/nixos-facter) and writes it back into your machine folder. The `--phases kexec` flag makes sure we are not yet formatting anything, instead if the target system is not a NixOS machine it will use [kexec](https://wiki.archlinux.org/title/Kexec) to switch to a NixOS kernel.
|
||||
**Using a JSON String or File Path**:
|
||||
|
||||
#### Using a JSON String or File Path
|
||||
Copy the JSON string contained in the QR Code and provide its path or paste it directly:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --json [JSON] \
|
||||
@@ -102,7 +101,8 @@ There are two ways to deploy your machine:
|
||||
--phases kexec
|
||||
```
|
||||
|
||||
#### Using an Image Containing the QR Code
|
||||
**Using an Image Containing the QR Code**:
|
||||
|
||||
Provide the path to an image file containing the QR code displayed by the installer:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --png [PATH] \
|
||||
@@ -112,3 +112,5 @@ There are two ways to deploy your machine:
|
||||
|
||||
|
||||
If you are using our template `[MACHINE]` would be `jon`
|
||||
|
||||
[Next Step (Choose Disk Format)](./choose-disk.md){ .md-button .md-button--primary }
|
||||
@@ -2,7 +2,7 @@
|
||||
# Update Machines
|
||||
|
||||
The Clan command line interface enables you to update machines remotely over SSH.
|
||||
In this guide we will teach you how to set a `targetHost` in Nix,
|
||||
In this guide we will teach you how to set a `targetHost` in Nix,
|
||||
and how to define a remote builder for your machine closures.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Ensure that the root login is secured and only used when necessary.
|
||||
|
||||
## Multiple Target Hosts
|
||||
|
||||
You can now experiment with a new interface that allows you to define multiple `targetHost` addresses for different VPNs. Learn more and try it out in our [networking guide](../networking.md).
|
||||
You can now experiment with a new interface that allows you to define multiple `targetHost` addresses for different VPNs. Learn more and try it out in our [networking guide](../networking/networking.md).
|
||||
|
||||
## Updating Machine Configurations
|
||||
|
||||
@@ -65,7 +65,7 @@ During an update, clan will ssh into the `buildHost` and run `nixos-rebuild` fro
|
||||
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
clan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
@@ -101,7 +101,7 @@ To exclude machines from being updated when running `clan machines update` witho
|
||||
one can set the `clan.deployment.requireExplicitUpdate` option to true:
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
clan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user