Compare commits
179 Commits
feat/clan-
...
init/edito
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e1a0a0c5a | ||
|
|
fdacfb8ecf | ||
|
|
508a26d68d | ||
|
|
8055c21984 | ||
|
|
9bb6ed313f | ||
|
|
8c36df77cc | ||
|
|
2284b060be | ||
|
|
491b5d28f2 | ||
|
|
bf212ce9c4 | ||
|
|
35be09feaa | ||
|
|
4ee90b4b9f | ||
|
|
cab69935ef | ||
|
|
54fcfda43e | ||
|
|
d137342243 | ||
|
|
3eba6e85cc | ||
|
|
d395e2abf3 | ||
|
|
b971156df1 | ||
|
|
c885a3fec8 | ||
|
|
ae7794dddd | ||
|
|
acaa69e2bf | ||
|
|
e37f7e2760 | ||
|
|
245b615209 | ||
|
|
a78f5b2bec | ||
|
|
396caeff39 | ||
|
|
d5a639104d | ||
|
|
fb1b428c12 | ||
|
|
bfe37c2457 | ||
|
|
39b34d9ff3 | ||
|
|
fd29ed4693 | ||
|
|
9db4e5cf2f | ||
|
|
e28a02ec73 | ||
|
|
c1e7e25641 | ||
|
|
21104a0465 | ||
|
|
0f53475499 | ||
|
|
7aa85d8aaf | ||
|
|
e9b0ce6a78 | ||
|
|
d174fbd445 | ||
|
|
8687801cee | ||
|
|
6ebfd29c87 | ||
|
|
c8456f7d68 | ||
|
|
6b03645f7a | ||
|
|
2cb7adb377 | ||
|
|
78ab7ebc7f | ||
|
|
82a4ecf82b | ||
|
|
43b56e21b2 | ||
|
|
a47c2f3e69 | ||
|
|
a34fa4f69b | ||
|
|
e13217b1c9 | ||
|
|
1e4a3a3eee | ||
|
|
e39d8cb909 | ||
|
|
7c48730bbb | ||
|
|
da5f363bee | ||
|
|
24ec74ae37 | ||
|
|
64a98281f0 | ||
|
|
5863ddca0e | ||
|
|
5de3ab88e9 | ||
|
|
4cfc335e2c | ||
|
|
e25bd69c68 | ||
|
|
fe17f9e1a1 | ||
|
|
7980f13bed | ||
|
|
fef16a84a9 | ||
|
|
97a1d8b52a | ||
|
|
f9b32cbd09 | ||
|
|
4d66f2a14c | ||
|
|
473c236214 | ||
|
|
eeaf1c84a9 | ||
|
|
f6efd11eae | ||
|
|
8762ee4420 | ||
|
|
0568608be6 | ||
|
|
a0194f34d2 | ||
|
|
b3297532ad | ||
|
|
cd915e171f | ||
|
|
1e94bf02da | ||
|
|
1c2781267b | ||
|
|
ac8162a08d | ||
|
|
1476619515 | ||
|
|
8288048682 | ||
|
|
fd41badbc6 | ||
|
|
d574faf253 | ||
|
|
81522c96e5 | ||
|
|
e668a7f536 | ||
|
|
3293ac0c14 | ||
|
|
be841cdec2 | ||
|
|
49e39ec505 | ||
|
|
c25f7934ba | ||
|
|
4f6d25160f | ||
|
|
0bf9a566eb | ||
|
|
148a0c90cc | ||
|
|
789bf3d0c8 | ||
|
|
59c558ffc6 | ||
|
|
c5e62074a6 | ||
|
|
9999379f81 | ||
|
|
dd1cfe3834 | ||
|
|
cd0b360b49 | ||
|
|
8c0fb90c1a | ||
|
|
86ae7cbbfb | ||
|
|
fdf63fd605 | ||
|
|
82fa89b57e | ||
|
|
cad492e830 | ||
|
|
2abd5bbe37 | ||
|
|
aad130166f | ||
|
|
3e9a1ea68f | ||
|
|
2acd06c9fa | ||
|
|
f45d3385c2 | ||
|
|
23c9291912 | ||
|
|
1893ebef19 | ||
|
|
fd00a941dc | ||
|
|
9ab5a9507d | ||
|
|
1a4c20e49e | ||
|
|
f138e59da8 | ||
|
|
ddd9318ea1 | ||
|
|
aee2fdcffa | ||
|
|
d1b810dfad | ||
|
|
4dede0ee5c | ||
|
|
3506d6ba0d | ||
|
|
f2a3415e2c | ||
|
|
2e821c4525 | ||
|
|
bbba7e9087 | ||
|
|
15dd4ea25f | ||
|
|
5a6eeda125 | ||
|
|
f8e08a610e | ||
|
|
fc7f544199 | ||
|
|
8aaa95737a | ||
|
|
7dedae9920 | ||
|
|
01e5b02633 | ||
|
|
f4de3ac83d | ||
|
|
9e65cf2b5b | ||
|
|
8134583641 | ||
|
|
5d8ee29ed4 | ||
|
|
d9ce211d1a | ||
|
|
9ec8b71765 | ||
|
|
4fef9c3652 | ||
|
|
393ed517e2 | ||
|
|
159198b81a | ||
|
|
83ea2312a1 | ||
|
|
022a55639f | ||
|
|
6f2430b191 | ||
|
|
6236defde6 | ||
|
|
9a8a5f4c00 | ||
|
|
6908527ebd | ||
|
|
d013ef20da | ||
|
|
570f04ecdc | ||
|
|
3a9a7eedf9 | ||
|
|
ee552d3020 | ||
|
|
b95d95554a | ||
|
|
a09e680fa0 | ||
|
|
853d8221c0 | ||
|
|
43c799c3d0 | ||
|
|
f231f1e0c7 | ||
|
|
a48df5b993 | ||
|
|
e08342a6f3 | ||
|
|
e0f56c3c6b | ||
|
|
64c5a81f74 | ||
|
|
56fad0fd4a | ||
|
|
3dce5d2f95 | ||
|
|
bfe4f2c8f4 | ||
|
|
1051367ca4 | ||
|
|
480bb396ed | ||
|
|
b5653c169b | ||
|
|
5606101ce8 | ||
|
|
3da4117702 | ||
|
|
f383c6f82d | ||
|
|
af86980192 | ||
|
|
c681cc0998 | ||
|
|
0804e5e415 | ||
|
|
95f93d8800 | ||
|
|
4602c06835 | ||
|
|
a3f6996d69 | ||
|
|
7f424c862b | ||
|
|
94449a02d5 | ||
|
|
ed14f3e827 | ||
|
|
152a908dc9 | ||
|
|
ac0cb620cf | ||
|
|
6a484fef66 | ||
|
|
fc1bf17b9c | ||
|
|
39d6edc673 | ||
|
|
4a66cdffaf | ||
|
|
216c560830 | ||
|
|
cf67de2f69 |
@@ -5,11 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
checks:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: nix run --refresh github:Mic92/nix-fast-build -- --no-nom --eval-workers 10
|
||||
checks-impure:
|
||||
runs-on: nix
|
||||
steps:
|
||||
|
||||
13
.gitea/workflows/deploy.yaml
Normal file
13
.gitea/workflows/deploy.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy-docs:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: nix run .#deploy-docs
|
||||
env:
|
||||
SSH_HOMEPAGE_KEY: ${{ secrets.SSH_HOMEPAGE_KEY }}
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -13,6 +13,9 @@ nixos.qcow2
|
||||
**/*.glade~
|
||||
/docs/out
|
||||
|
||||
# dream2nix
|
||||
.dream2nix
|
||||
|
||||
# python
|
||||
__pycache__
|
||||
.coverage
|
||||
@@ -28,3 +31,8 @@ build
|
||||
build-dir
|
||||
repo
|
||||
.env
|
||||
|
||||
# node
|
||||
node_modules
|
||||
dist
|
||||
.webui
|
||||
16
README.md
16
README.md
@@ -1,6 +1,6 @@
|
||||
# cLAN Core Repository
|
||||
# Clan Core Repository
|
||||
|
||||
Welcome to the cLAN Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the cLAN project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
|
||||
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the cLAN project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
|
||||
|
||||
## Why Clan?
|
||||
|
||||
@@ -14,11 +14,11 @@ Our mission is simple: to democratize computing by providing tools that empower
|
||||
- **Robust Backup Management:** Long-term, self-hosted data preservation.
|
||||
- **Intuitive Secret Management:** Simplified encryption and password management processes.
|
||||
|
||||
## Getting Started with cLAN
|
||||
## Getting Started with Clan
|
||||
|
||||
If you're new to cLAN and eager to dive in, start with our quickstart guide and explore the core functionalities that Clan offers:
|
||||
If you're new to Clan and eager to dive in, start with our quickstart guide and explore the core functionalities that Clan offers:
|
||||
|
||||
- **Quickstart Guide**: Check out [getting started](https://docs.clan.lol/#starting-with-a-new-clan-project)<!-- [docs/site/index.md](docs/site/index.md) --> to get up and running with cLAN in no time.
|
||||
- **Quickstart Guide**: Check out [getting started](https://docs.clan.lol/#starting-with-a-new-clan-project)<!-- [docs/site/index.md](docs/site/index.md) --> to get up and running with Clan in no time.
|
||||
|
||||
### Managing Secrets
|
||||
|
||||
@@ -26,7 +26,7 @@ In the Clan ecosystem, security is paramount. Learn how to handle secrets effect
|
||||
|
||||
- **Secrets Management**: Securely manage secrets by consulting [secrets](https://docs.clan.lol/getting-started/secrets/)<!-- [secrets.md](docs/site/getting-started/secrets.md) -->.
|
||||
|
||||
### Contributing to cLAN
|
||||
### Contributing to Clan
|
||||
|
||||
The Clan project thrives on community contributions. We welcome everyone to contribute and collaborate:
|
||||
|
||||
@@ -34,12 +34,12 @@ The Clan project thrives on community contributions. We welcome everyone to cont
|
||||
|
||||
## Join the Revolution
|
||||
|
||||
Clan is more than a tool; it's a movement towards a better digital future. By contributing to the cLAN project, you're part of changing technology for the better, together.
|
||||
Clan is more than a tool; it's a movement towards a better digital future. By contributing to the Clan project, you're part of changing technology for the better, together.
|
||||
|
||||
### Community and Support
|
||||
|
||||
Connect with us and the Clan community for support and discussion:
|
||||
|
||||
- [Matrix channel](https://matrix.to/#/!djzOHBBBHnwQkgNgdV:matrix.org?via=blog.clan.lol) for live discussions.
|
||||
- [Matrix channel](https://matrix.to/#/#clan:lassul.us) for live discussions.
|
||||
- IRC bridges (coming soon) for real-time chat support.
|
||||
|
||||
|
||||
@@ -46,7 +46,6 @@
|
||||
syncthing = import ./syncthing nixosTestArgs;
|
||||
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
|
||||
};
|
||||
schemaTests = pkgs.callPackages ./schemas.nix { inherit self; };
|
||||
|
||||
flakeOutputs =
|
||||
lib.mapAttrs' (
|
||||
@@ -58,7 +57,7 @@
|
||||
self'.legacyPackages.homeConfigurations or { }
|
||||
);
|
||||
in
|
||||
{ inherit renderClanOptions; } // nixosTests // schemaTests // flakeOutputs;
|
||||
{ inherit renderClanOptions; } // nixosTests // flakeOutputs;
|
||||
legacyPackages = {
|
||||
nixosTests =
|
||||
let
|
||||
|
||||
@@ -1,49 +1,33 @@
|
||||
{ self, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
perSystem =
|
||||
{ ... }:
|
||||
{
|
||||
nodes,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
dependencies = [
|
||||
self
|
||||
pkgs.stdenv.drvPath
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.toplevel
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.diskoScript
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.clan.deployment.file
|
||||
self.inputs.nixpkgs.legacyPackages.${pkgs.hostPlatform.system}.disko
|
||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||
in
|
||||
{
|
||||
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||
flash = (import ../lib/test-base.nix) {
|
||||
name = "flash";
|
||||
nodes.target = {
|
||||
virtualisation.emptyDiskImages = [ 4096 ];
|
||||
virtualisation.memorySize = 3000;
|
||||
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
|
||||
environment.etc."install-closure".source = "${closureInfo}/store-paths";
|
||||
# checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||
# flash = (import ../lib/test-base.nix) {
|
||||
# name = "flash";
|
||||
# nodes.target = {
|
||||
# virtualisation.emptyDiskImages = [ 4096 ];
|
||||
# virtualisation.memorySize = 3000;
|
||||
# environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
|
||||
# environment.etc."install-closure".source = "${closureInfo}/store-paths";
|
||||
|
||||
nix.settings = {
|
||||
substituters = lib.mkForce [ ];
|
||||
hashed-mirrors = null;
|
||||
connect-timeout = lib.mkForce 3;
|
||||
flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
|
||||
experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
};
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.succeed("clan --flake ${../..} flash --debug --yes --disk main /dev/vdb test_install_machine")
|
||||
'';
|
||||
} { inherit pkgs self; };
|
||||
};
|
||||
# nix.settings = {
|
||||
# substituters = lib.mkForce [ ];
|
||||
# hashed-mirrors = null;
|
||||
# connect-timeout = lib.mkForce 3;
|
||||
# flake-registry = pkgs.writeText "flake-registry" ''{"flakes":[],"version":2}'';
|
||||
# experimental-features = [
|
||||
# "nix-command"
|
||||
# "flakes"
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
# testScript = ''
|
||||
# start_all()
|
||||
# machine.succeed("clan --debug --flake ${../..} flash --yes --disk main /dev/vdb test_install_machine")
|
||||
# '';
|
||||
# } { inherit pkgs self; };
|
||||
# };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
unset CLAN_DIR
|
||||
|
||||
export PATH="${
|
||||
lib.makeBinPath [
|
||||
pkgs.gitMinimal
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
{ lib, modulesPath, ... }:
|
||||
{
|
||||
imports = [
|
||||
self.clanModules.diskLayouts
|
||||
self.clanModules.disk-layouts
|
||||
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
clan.diskLayouts.singleDiskExt4.device = "/dev/vdb";
|
||||
clan.disk-layouts.singleDiskExt4.device = "/dev/vdb";
|
||||
|
||||
environment.etc."install-successful".text = "ok";
|
||||
|
||||
@@ -63,7 +63,9 @@
|
||||
};
|
||||
};
|
||||
nodes.client = {
|
||||
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
|
||||
environment.systemPackages = [
|
||||
self.packages.${pkgs.system}.clan-cli
|
||||
] ++ self.packages.${pkgs.system}.clan-cli.runtimeDependencies;
|
||||
environment.etc."install-closure".source = "${closureInfo}/store-paths";
|
||||
virtualisation.memorySize = 2048;
|
||||
nix.settings = {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
{
|
||||
self,
|
||||
runCommand,
|
||||
check-jsonschema,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clanModules.clanCore = self.nixosModules.clanCore;
|
||||
|
||||
baseModule = {
|
||||
imports = (import (pkgs.path + "/nixos/modules/module-list.nix")) ++ [
|
||||
{
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
clanCore.clanName = "dummy";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
optionsFromModule =
|
||||
module:
|
||||
let
|
||||
evaled = lib.evalModules {
|
||||
modules = [
|
||||
module
|
||||
baseModule
|
||||
];
|
||||
};
|
||||
in
|
||||
evaled.options.clan;
|
||||
|
||||
clanModuleSchemas = lib.mapAttrs (
|
||||
_: module: self.lib.jsonschema.parseOptions (optionsFromModule module)
|
||||
) clanModules;
|
||||
|
||||
mkTest =
|
||||
name: schema:
|
||||
runCommand "schema-${name}" { } ''
|
||||
${check-jsonschema}/bin/check-jsonschema \
|
||||
--check-metaschema ${builtins.toFile "schema-${name}" (builtins.toJSON schema)}
|
||||
touch $out
|
||||
'';
|
||||
in
|
||||
lib.mapAttrs' (name: schema: {
|
||||
name = "schema-${name}";
|
||||
value = mkTest name schema;
|
||||
}) clanModuleSchemas
|
||||
@@ -4,10 +4,11 @@
|
||||
nodes.machine =
|
||||
{ self, config, ... }:
|
||||
{
|
||||
environment.etc."privkey.age".source = ./key.age;
|
||||
imports = [ (self.nixosModules.clanCore) ];
|
||||
environment.etc."secret".source = config.sops.secrets.secret.path;
|
||||
environment.etc."group-secret".source = config.sops.secrets.group-secret.path;
|
||||
sops.age.keyFile = ./key.age;
|
||||
sops.age.keyFile = "/etc/privkey.age";
|
||||
|
||||
clanCore.clanDir = "${./.}";
|
||||
clanCore.machineName = "machine";
|
||||
|
||||
2
clanModules/borgbackup/README.md
Normal file
2
clanModules/borgbackup/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Efficient, deduplicating backup program with optional compression and secure encryption.
|
||||
---
|
||||
@@ -1,4 +1,5 @@
|
||||
Email-based instant messaging for Desktop.
|
||||
---
|
||||
|
||||
!!! warning "Under construction"
|
||||
|
||||
|
||||
2
clanModules/disk-layouts/README.md
Normal file
2
clanModules/disk-layouts/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Automatically format a disk drive on clan installation
|
||||
---
|
||||
@@ -1,6 +1,6 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
options.clan.diskLayouts.singleDiskExt4 = {
|
||||
options.clan.disk-layouts.singleDiskExt4 = {
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "/dev/disk/by-id/ata-Samsung_SSD_850_EVO_250GB_S21PNXAGB12345";
|
||||
@@ -13,13 +13,14 @@
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = config.clan.diskLayouts.singleDiskExt4.device;
|
||||
device = config.clan.disk-layouts.singleDiskExt4.device;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
priority = 1;
|
||||
};
|
||||
ESP = {
|
||||
size = "512M";
|
||||
2
clanModules/ergochat/README.md
Normal file
2
clanModules/ergochat/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
A modern IRC server
|
||||
---
|
||||
@@ -1,29 +1,26 @@
|
||||
{ inputs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
flake.clanModules = {
|
||||
diskLayouts = {
|
||||
imports = [
|
||||
./diskLayouts.nix
|
||||
inputs.disko.nixosModules.default
|
||||
];
|
||||
disk-layouts = {
|
||||
imports = [ ./disk-layouts ];
|
||||
};
|
||||
borgbackup = ./borgbackup.nix;
|
||||
ergochat = ./ergochat.nix;
|
||||
borgbackup = ./borgbackup;
|
||||
deltachat = ./deltachat;
|
||||
graphical = ./graphical.nix;
|
||||
localbackup = ./localbackup.nix;
|
||||
localsend = ./localsend.nix;
|
||||
matrix-synapse = ./matrix-synapse.nix;
|
||||
moonlight = ./moonlight.nix;
|
||||
sshd = ./sshd.nix;
|
||||
sunshine = ./sunshine.nix;
|
||||
syncthing = ./syncthing;
|
||||
ergochat = ./ergochat;
|
||||
localbackup = ./localbackup;
|
||||
localsend = ./localsend;
|
||||
matrix-synapse = ./matrix-synapse;
|
||||
moonlight = ./moonlight;
|
||||
root-password = ./root-password;
|
||||
thelounge = ./thelounge.nix;
|
||||
vm-user = ./vm-user.nix;
|
||||
waypipe = ./waypipe.nix;
|
||||
xfce = ./xfce.nix;
|
||||
xfce-vm = ./xfce-vm.nix;
|
||||
zt-tcp-relay = ./zt-tcp-relay.nix;
|
||||
sshd = ./sshd;
|
||||
sunshine = ./sunshine;
|
||||
static-hosts = ./static-hosts;
|
||||
syncthing = ./syncthing;
|
||||
thelounge = ./thelounge;
|
||||
trusted-nix-caches = ./trusted-nix-caches;
|
||||
user-password = ./user-password;
|
||||
xfce = ./xfce;
|
||||
zerotier-static-peers = ./zerotier-static-peers;
|
||||
zt-tcp-relay = ./zt-tcp-relay;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
_: { fonts.enableDefaultPackages = true; }
|
||||
2
clanModules/localbackup/README.md
Normal file
2
clanModules/localbackup/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Automatically backups current machine to local directory.
|
||||
---
|
||||
2
clanModules/localsend/README.md
Normal file
2
clanModules/localsend/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Securely sharing files and messages over a local network without internet connectivity.
|
||||
---
|
||||
2
clanModules/matrix-synapse/README.md
Normal file
2
clanModules/matrix-synapse/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
A federated messaging server with end-to-end encryption.
|
||||
---
|
||||
2
clanModules/moonlight/README.md
Normal file
2
clanModules/moonlight/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
A desktop streaming client optimized for remote gaming and synchronized movie viewing.
|
||||
---
|
||||
@@ -1,6 +1,5 @@
|
||||
Creates a root-password
|
||||
|
||||
!!! tip "This module sets the password for the root user (automatically)."
|
||||
Automatically generates and configures a password for the root user.
|
||||
---
|
||||
|
||||
After the system was installed/deployed the following command can be used to display the root-password:
|
||||
|
||||
@@ -8,6 +7,5 @@ After the system was installed/deployed the following command can be used to dis
|
||||
clan secrets get {machine_name}-password
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
See also: [Facts / Secrets](../../getting-started/secrets.md)
|
||||
|
||||
2
clanModules/sshd/README.md
Normal file
2
clanModules/sshd/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Enables secure remote access to the machine over ssh
|
||||
---
|
||||
@@ -1,6 +1,7 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.PasswordAuthentication = false;
|
||||
|
||||
services.openssh.hostKeys = [
|
||||
{
|
||||
2
clanModules/static-hosts/README.md
Normal file
2
clanModules/static-hosts/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Statically configure the host names of machines based on their respective zerotier-ip.
|
||||
---
|
||||
30
clanModules/static-hosts/default.nix
Normal file
30
clanModules/static-hosts/default.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
options.clan.static-hosts = {
|
||||
excludeHosts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ config.clanCore.machineName ];
|
||||
description = "Hosts that should be excluded";
|
||||
};
|
||||
};
|
||||
|
||||
config.networking.hosts =
|
||||
let
|
||||
clanDir = config.clanCore.clanDir;
|
||||
machineDir = clanDir + "/machines/";
|
||||
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
|
||||
machines = builtins.readDir machineDir;
|
||||
filteredMachines = lib.filterAttrs (
|
||||
name: _: !(lib.elem name config.clan.static-hosts.excludeHosts)
|
||||
) machines;
|
||||
in
|
||||
lib.filterAttrs (_: value: value != null) (
|
||||
lib.mapAttrs' (
|
||||
machine: _:
|
||||
let
|
||||
path = zerotierIpMachinePath machine;
|
||||
in
|
||||
if builtins.pathExists path then lib.nameValuePair (builtins.readFile path) [ machine ] else null
|
||||
) filteredMachines
|
||||
);
|
||||
}
|
||||
2
clanModules/sunshine/README.md
Normal file
2
clanModules/sunshine/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
A desktop streaming server optimized for remote gaming and synchronized movie viewing.
|
||||
---
|
||||
@@ -1,7 +1,5 @@
|
||||
Syncthing is a free, open-source file synchronization application designed to allow users to synchronize files between multiple devices over the internet or local networks securely and privately.
|
||||
|
||||
It is an alternative to cloud-based file sharing services.
|
||||
|
||||
A secure, file synchronization app for devices over networks, offering a private alternative to cloud services.
|
||||
---
|
||||
## Usage
|
||||
|
||||
We recommend configuring this module as an sync-service through the provided options. Although it provides a Web GUI through which more usage scenarios are supported.
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
'';
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"folder1"
|
||||
"folder2"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
2
clanModules/thelounge/README.md
Normal file
2
clanModules/thelounge/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Modern web IRC client
|
||||
---
|
||||
2
clanModules/trusted-nix-caches/README.md
Normal file
2
clanModules/trusted-nix-caches/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
This module sets the `clan.lol` and `nix-community` cache up as a trusted cache.
|
||||
----
|
||||
10
clanModules/trusted-nix-caches/default.nix
Normal file
10
clanModules/trusted-nix-caches/default.nix
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
nix.settings.trusted-substituters = [
|
||||
"https://cache.clan.lol"
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
nix.settings.trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="
|
||||
];
|
||||
}
|
||||
18
clanModules/user-password/README.md
Normal file
18
clanModules/user-password/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
Automatically generates and configures a password for the specified user account.
|
||||
---
|
||||
|
||||
If setting the option prompt to true, the user will be prompted to type in their desired password.
|
||||
|
||||
!!! Note
|
||||
This module will set `mutableUsers` to `false`, meaning you can not manage user passwords through `passwd` anymore.
|
||||
|
||||
|
||||
After the system was installed/deployed the following command can be used to display the user-password:
|
||||
|
||||
```bash
|
||||
clan secrets get {machine_name}-user-password
|
||||
```
|
||||
|
||||
See also: [Facts / Secrets](../../getting-started/secrets.md)
|
||||
|
||||
To regenerate the password, delete the password files in the clan directory and redeploy the machine.
|
||||
49
clanModules/user-password/default.nix
Normal file
49
clanModules/user-password/default.nix
Normal file
@@ -0,0 +1,49 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options.clan.user-password = {
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "alice";
|
||||
description = "The user the password should be generated for.";
|
||||
};
|
||||
prompt = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = "Whether the user should be prompted.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
users.mutableUsers = false;
|
||||
users.users.${config.clan.user-password.user}.hashedPasswordFile =
|
||||
config.clanCore.facts.services.user-password.secret.user-password-hash.path;
|
||||
sops.secrets."${config.clanCore.machineName}-user-password-hash".neededForUsers = true;
|
||||
clanCore.facts.services.user-password = {
|
||||
secret.user-password = { };
|
||||
secret.user-password-hash = { };
|
||||
generator.prompt = (
|
||||
lib.mkIf config.clan.user-password.prompt "Set the password for your $user: ${config.clan.user-password.user}.
|
||||
You can autogenerate a password, if you leave this prompt blank."
|
||||
);
|
||||
generator.path = with pkgs; [
|
||||
coreutils
|
||||
xkcdpass
|
||||
mkpasswd
|
||||
];
|
||||
generator.script = ''
|
||||
if [[ -n $prompt_value ]]; then
|
||||
echo $prompt_value > $secrets/user-password
|
||||
else
|
||||
xkcdpass --numwords 3 --delimiter - --count 1 > $secrets/user-password
|
||||
fi
|
||||
cat $secrets/user-password | mkpasswd -s -m sha-512 > $secrets/user-password-hash
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
security = {
|
||||
sudo.wheelNeedsPassword = false;
|
||||
polkit.enable = true;
|
||||
rtkit.enable = true;
|
||||
};
|
||||
|
||||
users.users.user = {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
uid = 1000;
|
||||
initialHashedPassword = "";
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"video"
|
||||
"render"
|
||||
];
|
||||
shell = "/run/current-system/sw/bin/bash";
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./vm-user.nix
|
||||
./graphical.nix
|
||||
];
|
||||
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
displayManager.autoLogin.enable = true;
|
||||
displayManager.autoLogin.user = "user";
|
||||
desktopManager.xfce.enable = true;
|
||||
desktopManager.xfce.enableScreensaver = false;
|
||||
xkb.layout = "us";
|
||||
};
|
||||
}
|
||||
2
clanModules/xfce/README.md
Normal file
2
clanModules/xfce/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
A lightweight desktop manager
|
||||
---
|
||||
5
clanModules/zerotier-static-peers/README.md
Normal file
5
clanModules/zerotier-static-peers/README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
Statically configure the `zerotier` peers of a clan network.
|
||||
---
|
||||
Statically configure the `zerotier` peers of a clan network.
|
||||
|
||||
Requires a machine, that is the zerotier controller configured in the network.
|
||||
71
clanModules/zerotier-static-peers/default.nix
Normal file
71
clanModules/zerotier-static-peers/default.nix
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clanDir = config.clanCore.clanDir;
|
||||
machineDir = clanDir + "/machines/";
|
||||
machinesFileSet = builtins.readDir machineDir;
|
||||
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
|
||||
|
||||
zerotierNetworkIdPath = machines: machineDir + machines + "/facts/zerotier-network-id";
|
||||
networkIdsUnchecked = builtins.map (
|
||||
machine:
|
||||
let
|
||||
fullPath = zerotierNetworkIdPath machine;
|
||||
in
|
||||
if builtins.pathExists fullPath then builtins.readFile fullPath else null
|
||||
) machines;
|
||||
networkIds = lib.filter (machine: machine != null) networkIdsUnchecked;
|
||||
networkId = builtins.elemAt networkIds 0;
|
||||
in
|
||||
#TODO:trace on multiple found network-ids
|
||||
#TODO:trace on no single found networkId
|
||||
{
|
||||
options.clan.zerotier-static-peers = {
|
||||
excludeHosts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ config.clanCore.machineName ];
|
||||
description = "Hosts that should be excluded";
|
||||
};
|
||||
};
|
||||
|
||||
config.systemd.services.zerotier-static-peers-autoaccept =
|
||||
let
|
||||
machines = builtins.readDir machineDir;
|
||||
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
|
||||
filteredMachines = lib.filterAttrs (
|
||||
name: _: !(lib.elem name config.clan.static-hosts.excludeHosts)
|
||||
) machines;
|
||||
hosts = lib.mapAttrsToList (host: _: host) (
|
||||
lib.mapAttrs' (
|
||||
machine: _:
|
||||
let
|
||||
fullPath = zerotierIpMachinePath machine;
|
||||
in
|
||||
if builtins.pathExists fullPath then
|
||||
lib.nameValuePair (builtins.readFile fullPath) [ machine ]
|
||||
else
|
||||
null
|
||||
) filteredMachines
|
||||
);
|
||||
in
|
||||
lib.mkIf (config.clan.networking.zerotier.controller.enable) {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "zerotierone.service" ];
|
||||
path = [ pkgs.zerotierone ];
|
||||
serviceConfig.ExecStart = pkgs.writeScript "static-zerotier-peers-autoaccept" ''
|
||||
#!/bin/sh
|
||||
${lib.concatMapStringsSep "\n" (host: ''
|
||||
${
|
||||
inputs.clan-core.packages.${pkgs.system}.zerotier-members
|
||||
}/bin/zerotier-members allow --member-ip ${host}
|
||||
'') hosts}
|
||||
'';
|
||||
};
|
||||
|
||||
config.clan.networking.zerotier.networkId = lib.mkDefault networkId;
|
||||
}
|
||||
2
clanModules/zt-tcp-relay/README.md
Normal file
2
clanModules/zt-tcp-relay/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Enable ZeroTier VPN over TCP for networks where UDP is blocked.
|
||||
---
|
||||
@@ -20,7 +20,7 @@
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${
|
||||
pkgs.callPackage ../pkgs/zt-tcp-relay { }
|
||||
pkgs.callPackage ../../pkgs/zt-tcp-relay { }
|
||||
}/bin/zt-tcp-relay --listen [::]:${builtins.toString config.clan.zt-tcp-relay.port}";
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
||||
@@ -1,6 +1,6 @@
|
||||
source_up
|
||||
|
||||
watch_file $(find ./nix -name "*.nix" -printf '"%p" ')
|
||||
watch_file $(find ./nix -name "*.nix" -printf '%p ')
|
||||
|
||||
# Because we depend on nixpkgs sources, uploading to builders takes a long time
|
||||
use flake .#docs --builders ''
|
||||
|
||||
30
docs/main.py
Normal file
30
docs/main.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
def define_env(env: Any) -> None:
|
||||
static_dir = "/static/"
|
||||
video_dir = "https://clan.lol/" + "videos/"
|
||||
asciinema_dir = static_dir + "asciinema-player/"
|
||||
|
||||
@env.macro
|
||||
def video(name: str) -> str:
|
||||
return f"""<video loop muted autoplay id="{name}">
|
||||
<source src={video_dir + name} type="video/webm">
|
||||
Your browser does not support the video tag.
|
||||
</video>"""
|
||||
|
||||
@env.macro
|
||||
def asciinema(name: str) -> str:
|
||||
return f"""<div id="{name}">
|
||||
<script src="{asciinema_dir}/asciinema-player.min.js"></script>
|
||||
<script>
|
||||
AsciinemaPlayer.create('{video_dir + name}',
|
||||
document.getElementById("{name}"), {{
|
||||
loop: true,
|
||||
autoPlay: true,
|
||||
controls: false,
|
||||
speed: 1.5,
|
||||
theme: "solarized-light"
|
||||
}});
|
||||
</script>
|
||||
</div>"""
|
||||
@@ -1,4 +1,4 @@
|
||||
site_name: cLAN documentation
|
||||
site_name: Clan Docs
|
||||
site_url: https://docs.clan.lol
|
||||
repo_url: https://git.clan.lol/clan/clan-core/
|
||||
repo_name: clan-core
|
||||
@@ -10,22 +10,24 @@ validation:
|
||||
unrecognized_links: warn
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- attr_list
|
||||
- footnotes
|
||||
- md_in_html
|
||||
- meta
|
||||
- plantuml_markdown
|
||||
- pymdownx.emoji:
|
||||
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- footnotes
|
||||
- meta
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.highlight:
|
||||
use_pygments: true
|
||||
anchor_linenums: true
|
||||
- toc:
|
||||
title: On this page
|
||||
|
||||
@@ -35,29 +37,23 @@ exclude_docs: |
|
||||
/drafts/
|
||||
|
||||
nav:
|
||||
- Blog:
|
||||
- blog/index.md
|
||||
- Getting started:
|
||||
- index.md
|
||||
- Configure: getting-started/configure.md
|
||||
- Deploy Machine: getting-started/machines.md
|
||||
- Installer: getting-started/installer.md
|
||||
- Setup Networking: getting-started/networking.md
|
||||
- Provision Secrets & Passwords: getting-started/secrets.md
|
||||
- Configure: getting-started/configure.md
|
||||
- Secrets & Facts: getting-started/secrets.md
|
||||
- Deploy Machine: getting-started/deploy.md
|
||||
- Mesh VPN: getting-started/mesh-vpn.md
|
||||
- Backup & Restore: getting-started/backups.md
|
||||
- Flake-parts: getting-started/flake-parts.md
|
||||
- Templates: templates/index.md
|
||||
- Reference:
|
||||
- clan-core:
|
||||
- reference/clan-core/index.md
|
||||
- reference/clan-core/backups.md
|
||||
- reference/clan-core/facts.md
|
||||
- reference/clan-core/sops.md
|
||||
- reference/clan-core/state.md
|
||||
- clanModules:
|
||||
- Modules:
|
||||
- Clan Modules:
|
||||
- reference/clanModules/borgbackup.md
|
||||
- reference/clanModules/deltachat.md
|
||||
- reference/clanModules/diskLayouts.md
|
||||
- reference/clanModules/disk-layouts.md
|
||||
- reference/clanModules/ergochat.md
|
||||
- reference/clanModules/graphical.md
|
||||
- reference/clanModules/localbackup.md
|
||||
- reference/clanModules/localsend.md
|
||||
- reference/clanModules/matrix-synapse.md
|
||||
@@ -66,19 +62,39 @@ nav:
|
||||
- reference/clanModules/sshd.md
|
||||
- reference/clanModules/sunshine.md
|
||||
- reference/clanModules/syncthing.md
|
||||
- reference/clanModules/static-hosts.md
|
||||
- reference/clanModules/thelounge.md
|
||||
- reference/clanModules/vm-user.md
|
||||
- reference/clanModules/waypipe.md
|
||||
- reference/clanModules/xfce-vm.md
|
||||
- reference/clanModules/trusted-nix-caches.md
|
||||
- reference/clanModules/user-password.md
|
||||
- reference/clanModules/xfce.md
|
||||
- reference/clanModules/zerotier-static-peers.md
|
||||
- reference/clanModules/zt-tcp-relay.md
|
||||
- CLI:
|
||||
- reference/cli/index.md
|
||||
- reference/cli/backups.md
|
||||
- reference/cli/config.md
|
||||
- reference/cli/facts.md
|
||||
- reference/cli/flakes.md
|
||||
- reference/cli/flash.md
|
||||
- reference/cli/history.md
|
||||
- reference/cli/machines.md
|
||||
- reference/cli/secrets.md
|
||||
- reference/cli/ssh.md
|
||||
- reference/cli/vms.md
|
||||
- Clan Core:
|
||||
- reference/clan-core/index.md
|
||||
- reference/clan-core/backups.md
|
||||
- reference/clan-core/facts.md
|
||||
- reference/clan-core/sops.md
|
||||
- reference/clan-core/state.md
|
||||
- Contributing: contributing/contributing.md
|
||||
|
||||
docs_dir: site
|
||||
site_dir: out
|
||||
|
||||
theme:
|
||||
logo: static/logo.png
|
||||
logo: static/clan-white.png
|
||||
favicon: static/clan-dark.png
|
||||
name: material
|
||||
features:
|
||||
- navigation.instant
|
||||
@@ -88,6 +104,8 @@ theme:
|
||||
- content.tabs.link
|
||||
icon:
|
||||
repo: fontawesome/brands/git
|
||||
font:
|
||||
code: Roboto Mono
|
||||
|
||||
palette:
|
||||
# Palette toggle for light mode
|
||||
@@ -108,5 +126,35 @@ theme:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to light mode
|
||||
|
||||
extra_css:
|
||||
- static/asciinema-player/custom-theme.css
|
||||
- static/asciinema-player/asciinema-player.css
|
||||
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/regular/comment
|
||||
link: https://matrix.to/#/#clan:lassul.us
|
||||
- icon: fontawesome/brands/gitlab
|
||||
link: https://git.clan.lol/clan/clan-core
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/clan-lol/clan-core
|
||||
- icon: fontawesome/solid/rss
|
||||
link: /feed_rss_created.xml
|
||||
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- blog
|
||||
- macros
|
||||
- rss:
|
||||
match_path: blog/posts/.*
|
||||
use_git: false
|
||||
date_from_meta:
|
||||
as_creation: "date"
|
||||
as_update: "date"
|
||||
datetime_format: "%Y-%m-%d %H:%M"
|
||||
default_timezone: Europe/Paris
|
||||
default_time: "17:18"
|
||||
categories:
|
||||
- categories
|
||||
- tags
|
||||
|
||||
@@ -1,19 +1,32 @@
|
||||
{ pkgs, module-docs, ... }:
|
||||
{
|
||||
pkgs,
|
||||
module-docs,
|
||||
clan-cli-docs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
uml-c4 = pkgs.python3Packages.plantuml-markdown.override { plantuml = pkgs.plantuml-c4; };
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "clan-documentation";
|
||||
|
||||
src = ../.;
|
||||
|
||||
nativeBuildInputs =
|
||||
[ pkgs.python3 ]
|
||||
[
|
||||
pkgs.python3
|
||||
uml-c4
|
||||
]
|
||||
++ (with pkgs.python3Packages; [
|
||||
mkdocs
|
||||
mkdocs-material
|
||||
mkdocs-rss-plugin
|
||||
mkdocs-macros
|
||||
]);
|
||||
configurePhase = ''
|
||||
mkdir -p ./site/reference
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}:
|
||||
|
||||
writeShellScriptBin "deploy-docs" ''
|
||||
set -eux -o pipefail
|
||||
set -eu -o pipefail
|
||||
export PATH="${
|
||||
lib.makeBinPath [
|
||||
coreutils
|
||||
@@ -17,6 +17,12 @@ writeShellScriptBin "deploy-docs" ''
|
||||
]
|
||||
}"
|
||||
|
||||
#########################################
|
||||
# #
|
||||
# DO NOT PRINT THE SSH KEY TO THE LOGS #
|
||||
# #
|
||||
#########################################
|
||||
set +x
|
||||
if [ -n "''${SSH_HOMEPAGE_KEY:-}" ]; then
|
||||
echo "$SSH_HOMEPAGE_KEY" > ./ssh_key
|
||||
chmod 600 ./ssh_key
|
||||
@@ -24,6 +30,13 @@ writeShellScriptBin "deploy-docs" ''
|
||||
else
|
||||
sshExtraArgs=
|
||||
fi
|
||||
set -x
|
||||
###########################
|
||||
# #
|
||||
# END OF DANGER ZONE #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
rsync \
|
||||
-e "ssh -o StrictHostKeyChecking=no $sshExtraArgs" \
|
||||
|
||||
@@ -54,19 +54,17 @@
|
||||
in
|
||||
{
|
||||
devShells.docs = pkgs.callPackage ./shell.nix {
|
||||
inherit (self'.packages) docs;
|
||||
inherit (self'.packages) docs clan-cli-docs;
|
||||
inherit module-docs;
|
||||
};
|
||||
packages = {
|
||||
docs = pkgs.python3.pkgs.callPackage ./default.nix {
|
||||
inherit (self'.packages) clan-cli-docs;
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit module-docs;
|
||||
};
|
||||
deploy-docs = pkgs.callPackage ./deploy-docs.nix { inherit (config.packages) docs; };
|
||||
inherit module-docs;
|
||||
};
|
||||
legacyPackages = {
|
||||
foo = jsonDocs;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,20 +38,7 @@ let
|
||||
) clanModules;
|
||||
|
||||
clanModulesReadmes = builtins.mapAttrs (
|
||||
module_name: _module:
|
||||
let
|
||||
readme = "${self}/clanModules/${module_name}/README.md";
|
||||
readmeContents =
|
||||
if
|
||||
builtins.trace "Trying to get Module README.md for ${module_name} from ${readme}"
|
||||
# TODO: Edge cases
|
||||
(builtins.pathExists readme)
|
||||
then
|
||||
(builtins.readFile readme)
|
||||
else
|
||||
null;
|
||||
in
|
||||
readmeContents
|
||||
module_name: _module: self.lib.modules.getReadme module_name
|
||||
) clanModules;
|
||||
|
||||
# clanCore docs
|
||||
|
||||
@@ -74,7 +74,7 @@ def render_option(name: str, option: dict[str, Any], level: int = 3) -> str:
|
||||
read_only = option.get("readOnly")
|
||||
|
||||
res = f"""
|
||||
{"#" * level} {sanitize(name)} {{#{sanitize(name)}}}
|
||||
{"#" * level} {sanitize(name)}
|
||||
{"Readonly" if read_only else ""}
|
||||
{option.get("description", "No description available.")}
|
||||
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
docs,
|
||||
pkgs,
|
||||
module-docs,
|
||||
clan-cli-docs,
|
||||
...
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
inputsFrom = [ docs ];
|
||||
shellHook = ''
|
||||
mkdir -p ./site/reference
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
chmod +w ./site/reference/*
|
||||
|
||||
echo "Generated API documentation in './site/reference/' "
|
||||
|
||||
21
docs/site/blog/.authors.yml
Normal file
21
docs/site/blog/.authors.yml
Normal file
@@ -0,0 +1,21 @@
|
||||
authors:
|
||||
Lassulus:
|
||||
name: "Lassulus"
|
||||
description: "Contributor to Clan"
|
||||
avatar: "https://avatars.githubusercontent.com/u/621759?v=4"
|
||||
url: "https://http://lassul.us/"
|
||||
Mic92:
|
||||
name: "Mic92"
|
||||
description: "Contributor to Clan"
|
||||
avatar: "https://avatars.githubusercontent.com/u/96200?v=4"
|
||||
url: "https://thalheim.io"
|
||||
W:
|
||||
name: "W"
|
||||
description: "Founder of Clan"
|
||||
avatar: "/static/w_profile.webp"
|
||||
url: ""
|
||||
Qubasa:
|
||||
name: "Qubasa"
|
||||
description: "Contributor to Clan"
|
||||
avatar: "https://avatars.githubusercontent.com/u/22085373?v=4"
|
||||
url: "https://github.com/Qubasa"
|
||||
2
docs/site/blog/index.md
Normal file
2
docs/site/blog/index.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Blog
|
||||
|
||||
72
docs/site/blog/posts/hello-world.md
Normal file
72
docs/site/blog/posts/hello-world.md
Normal file
@@ -0,0 +1,72 @@
|
||||
---
|
||||
title: "Introducing Clan: Full-Stack Computing Redefined"
|
||||
description: "Introducing Clan, a new model for a decentralized network, designed to provide families, smaller groups, and small businesses a platform that’s private, secure, and user-friendly."
|
||||
authors:
|
||||
- W
|
||||
- Qubasa
|
||||
date: 2024-03-19
|
||||
---
|
||||
|
||||
|
||||
In a digital age where users are guided increasingly toward submission and dependence, Clan reclaims computing and networking from the ground up.
|
||||
|
||||
Clan enables users to build any system from a git repository, automate secret handling, and join devices in a secure darknet. This control extends beyond applications to communication protocols and the operating system itself, putting you fully in charge of your own digital environment.
|
||||
|
||||
## Why We're Building Clan
|
||||
|
||||
Our mission is simple: to restore fun, freedom, and functionality to computing as an open source project. We believe in building tools that empower users, foster innovation, and challenge the limitations imposed by outdated paradigms. Clan, in its essence, is an open source endeavor; it's our contribution to a future where technology serves humanity, not the other way around.
|
||||
|
||||
## How Clan Changes the Game
|
||||
Clan embodies a new philosophy in system, application, and network design. It enables seamless, secure communication across devices, simplifies software distribution and updates, and offers both public and private network configurations. Here are some of the ways it accomplishes this:
|
||||
|
||||
- **Nix as a Foundation:** Imagine a safety net for your computer's operating system, one that lets you make changes or updates without the fear of causing a crash or losing data. Nix simplifies the complexities of system design, ensuring that updates are safe and systems are more reliable.
|
||||
|
||||
- **Simplified System Deployment:** Building and managing a computer system, from the operating system to the software you use, often feels like putting together a complex puzzle. With Clan, the puzzle pieces are replaced by a set of building blocks. Leveraging the power of Nix and Clan's innovative toolkit, anyone from tech-savvy administrators to everyday users can create and maintain what we call "full-stack systems" (everything your computer needs to run smoothly).
|
||||
|
||||
- **A Leap in Connectivity:** Imagine if you could create private, secure pathways between your devices, bypassing the noisy and often insecure internet. Clan makes this possible through something called "overlay networks." These networks are like private tunnels, allowing your devices to talk to each other securely and directly. With Clan's built-in overlay networks and automatically configured services, connecting your devices becomes seamless, secure, and hassle-free.
|
||||
|
||||
- **Security Through Separation:** Clan employs sandboxing and virtual machines, a technology that runs code in isolated environments - so even if you explore new Clans, your system remains protected from potential threats.
|
||||
|
||||
- **Reliable:** With Clan, your data and services are preserved for the long haul. We focus on self-hosted backups and integration with the [Fediverse](https://de.wikipedia.org/wiki/Fediverse), a network of interconnected, independent online communities, so your digital life remains uninterrupted and under your control.
|
||||
|
||||
|
||||
## A Glimpse at Clan's Features
|
||||
|
||||
- **Social Scaling:** Choose between creating a private sanctuary for your closest contacts, a dynamic space for a self-contained community, or embracing the open web with public Clans anyone can join.
|
||||
|
||||
{{ video(name="show_join.webm")}}
|
||||
|
||||
- **Seamless VM Integration:** Applications running in virtual machines can appear and behave as if they're part of your main operating system — a blend of power and simplicity.
|
||||
|
||||
{{ video(name="show_run.webm")}}
|
||||
|
||||
- **Robust Backup Management:** Keep your data safe _forever_ - never worry about cloud services disappearing in 10 years.
|
||||
|
||||
{{ asciinema(name="backups.cast") }}
|
||||
|
||||
- **Intuitive Secret Management:** Clan simplifies digital security by automating the creation and management of encryption keys and passwords for your services.
|
||||
|
||||
{{ asciinema(name="secrets.cast") }}
|
||||
|
||||
- **Remote Install:** Set up and manage Clan systems anywhere in the world with just a QR scan or SSH access, making remote installations as easy as snapping a photo or sharing a link.
|
||||
|
||||
{{ asciinema(name="nixos-install.cast") }}
|
||||
|
||||
|
||||
## Who Stands to Benefit?
|
||||
|
||||
Clan is for anyone and everyone who believes in the power of open source technology to connect, empower, and protect. From system administrators to less tech-savvy individuals, small business owners to privacy-conscious users, Clan offers something for everyone — a way to reclaim control and redefine how we interact with technology.
|
||||
|
||||
## Join the Revolution
|
||||
|
||||
Ready to control your digital world? Clan is more than a tool—it's a movement. Secure your data, manage your systems easily, or connect with others how you like. Start with Clan for a better digital future.
|
||||
|
||||
Connect with us on our [Matrix channel at clan.lol](https://matrix.to/#/#clan:lassul.us) or through our IRC bridges (coming soon).
|
||||
|
||||
Want to see the code? Check it out [on our Gitea](https://git.clan.lol/clan/clan-core) or [on GitHub](https://github.com/clan-lol/clan-core).
|
||||
|
||||
Or follow our [RSS feed](https://docs.clan.lol/feed_rss_created.xml)!
|
||||
|
||||
Join us and be part of changing technology for the better, together.
|
||||
|
||||
|
||||
13
docs/site/blog/posts/new-docs.md
Normal file
13
docs/site/blog/posts/new-docs.md
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "New documentation site and weekly new meetup"
|
||||
authors:
|
||||
- Lassulus
|
||||
- Mic92
|
||||
date: 2024-04-16
|
||||
---
|
||||
|
||||
Last week, we added a new documentation hub for clan at [docs.clan.lol](https://docs.clan.lol).
|
||||
We are still working on improving the installation procedures, so stay tuned.
|
||||
We now have weekly office hours where people are invited to hangout and ask questions.
|
||||
They are every Wednesday 15:30 UTC (17:30 CEST) in our [jitsi](https://jitsi.lassul.us/clan.lol).
|
||||
Otherwise drop by in our [matrix channel](https://matrix.to/#/#clan:lassul.us).
|
||||
324
docs/site/drafts/secret-cli.md
Normal file
324
docs/site/drafts/secret-cli.md
Normal file
@@ -0,0 +1,324 @@
|
||||
## Secrets (CLI Reference)
|
||||
|
||||
#### Adding Secrets (set)
|
||||
|
||||
```bash
|
||||
clan secrets set mysecret
|
||||
> Paste your secret:
|
||||
```
|
||||
|
||||
!!! note
|
||||
As you type your secret won't be displayed. Press Enter to save the secret.
|
||||
|
||||
#### List all Secrets (list)
|
||||
|
||||
```bash
|
||||
clan secrets list
|
||||
```
|
||||
|
||||
#### Assigning Access (set)
|
||||
|
||||
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
|
||||
|
||||
```bash
|
||||
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
|
||||
#### Displaying Secrets (get)
|
||||
|
||||
```bash
|
||||
clan secrets get mysecret
|
||||
```
|
||||
|
||||
#### Rename
|
||||
|
||||
TODO
|
||||
|
||||
#### Remove
|
||||
|
||||
TODO
|
||||
|
||||
#### import-sops
|
||||
|
||||
TODO
|
||||
|
||||
### Users (Reference)
|
||||
|
||||
Learn how to manage users and allowing access to existing secrets.
|
||||
|
||||
#### list user
|
||||
|
||||
Lists all added users
|
||||
|
||||
```bash
|
||||
clan secrets user list
|
||||
```
|
||||
|
||||
``` {.console, title="Example output", .no-copy}
|
||||
jon
|
||||
sara
|
||||
```
|
||||
|
||||
!!! Question "Who can execute this command?"
|
||||
Everyone - completely public.
|
||||
|
||||
#### add user
|
||||
|
||||
add a user
|
||||
|
||||
```bash
|
||||
clan secrets users add {username} {public-key}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Changes can be trusted by maintainer review in version control.
|
||||
|
||||
#### get user
|
||||
|
||||
get a user public key
|
||||
|
||||
```bash
|
||||
clan secrets users get {username}
|
||||
```
|
||||
|
||||
``` {.console, title="Example output", .no-copy}
|
||||
age1zk8uzrte55wkg9lkqxu5x6twsj2ja4lehegks0cw4mkg6jv37d9qsjpt44
|
||||
```
|
||||
|
||||
#### remove user
|
||||
|
||||
remove a user
|
||||
|
||||
```bash
|
||||
clan secrets users remove {username}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Changes can be trusted by maintainer review in version control.
|
||||
|
||||
#### add-secret user
|
||||
|
||||
Grants the user (`username`) access to the secret (`secret_name`)
|
||||
|
||||
```bash
|
||||
clan secrets users add-secret {username} {secret_name}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Requires the executor of the command to have access to the secret (`secret_name`).
|
||||
|
||||
#### remove-secret user
|
||||
|
||||
remove the user (`username`) from accessing the secret (`secret_name`)
|
||||
|
||||
!!! Danger "Make sure at least one person has access."
|
||||
It might still be possible for the machine to access the secret. (See [machines](#machines))
|
||||
|
||||
We highly recommend to use version control such as `git` which allows you to rollback secrets in case anything gets messed up.
|
||||
|
||||
```bash
|
||||
clan secrets users remove-secret {username} {secret_name}
|
||||
```
|
||||
|
||||
!!! Question "Who can execute this command?"
|
||||
Requires the executor of the command to have access to the secret (`secret_name`).
|
||||
|
||||
### Machines (Reference)
|
||||
|
||||
- [list](): list machines
|
||||
- [add](): add a machine
|
||||
- [get](): get a machine public key
|
||||
- [remove](): remove a machine
|
||||
- [add-secret](): allow a machine to access a secret
|
||||
- [remove-secret](): remove a machine's access to a secret
|
||||
|
||||
#### List machine
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
|
||||
```bash
|
||||
clan secrets machines list
|
||||
```
|
||||
|
||||
#### Add machine
|
||||
|
||||
For clan machines the machine key is generated automatically on demand if none exists.
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
If you already have a device key and want to add it manually, see: [How to obtain a remote key](#obtain-remote-keys-manually)
|
||||
|
||||
#### get machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove machine
|
||||
|
||||
TODO
|
||||
|
||||
#### add-secret machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove-secret machine
|
||||
|
||||
TODO
|
||||
|
||||
### Groups (Reference)
|
||||
|
||||
The Clan-CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
- [list](): list groups
|
||||
- [add-user](): add a user to group
|
||||
- [remove-user](): remove a user from group
|
||||
- [add-machine](): add a machine to group
|
||||
- [remove-machine](): remove a machine from group
|
||||
- [add-secret](): allow a user to access a secret
|
||||
- [remove-secret](): remove a group's access to a secret
|
||||
|
||||
#### List Groups
|
||||
|
||||
```bash
|
||||
clan secrets groups list
|
||||
```
|
||||
|
||||
#### add-user
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
clan secrets groups add-user admins <username>
|
||||
```
|
||||
|
||||
!!! info
|
||||
The group is created if no such group existed before.
|
||||
|
||||
The user must exist in beforehand (See: [users](#users-reference))
|
||||
|
||||
```{.console, .no-copy}
|
||||
.
|
||||
├── flake.nix
|
||||
. ...
|
||||
└── sops
|
||||
├── groups
|
||||
│ └── admins
|
||||
│ └── users
|
||||
│ └── <username> -> ../../../users/<username>
|
||||
```
|
||||
|
||||
#### remove-user
|
||||
|
||||
TODO
|
||||
|
||||
#### add-machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove-machine
|
||||
|
||||
TODO
|
||||
|
||||
#### add-secret
|
||||
|
||||
```bash
|
||||
clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
#### remove-secret
|
||||
|
||||
TODO
|
||||
|
||||
### Key (Reference)
|
||||
|
||||
- [generate]() generate age key
|
||||
- [show]() show age public key
|
||||
- [update]() re-encrypt all secrets with current keys (useful when changing keys)
|
||||
|
||||
#### generate
|
||||
|
||||
TODO
|
||||
|
||||
#### show
|
||||
|
||||
TODO
|
||||
|
||||
#### update
|
||||
|
||||
TODO
|
||||
|
||||
## Further
|
||||
|
||||
Secrets in the repository follow this structure:
|
||||
|
||||
```{.console, .no-copy}
|
||||
sops/
|
||||
├── secrets/
|
||||
│ └── <secret_name>/
|
||||
│ ├── secret
|
||||
│ └── users/
|
||||
│ └── <your_username>/
|
||||
```
|
||||
|
||||
The content of the secret is stored encrypted inside the `secret` file under `mysecret`.
|
||||
|
||||
By default, secrets are encrypted with your key to ensure readability.
|
||||
|
||||
### Obtain remote keys manually
|
||||
|
||||
To fetch a **SSH host key** from a preinstalled system:
|
||||
|
||||
```bash
|
||||
ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
!!! Success
|
||||
This command converts the SSH key into an age key on the fly. Since this is the format used by the clan secrets backend.
|
||||
|
||||
Once added the **SSH host key** enables seamless integration of existing machines with clan.
|
||||
|
||||
Then add the key by executing:
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
See also: [Machine reference](#machines-reference)
|
||||
|
||||
### NixOS integration
|
||||
|
||||
A NixOS machine will automatically import all secrets that are encrypted for the
|
||||
current machine. At runtime it will use the host key to decrypt all secrets into
|
||||
an in-memory, non-persistent filesystem using [sops-nix](https://github.com/Mic92/sops-nix).
|
||||
In your nixos configuration you can get a path to secrets like this `config.sops.secrets.<name>.path`. For example:
|
||||
|
||||
```nix
|
||||
{ config, ...}: {
|
||||
sops.secrets.my-password.neededForUsers = true;
|
||||
|
||||
users.users.mic92 = {
|
||||
isNormalUser = true;
|
||||
passwordFile = config.sops.secrets.my-password.path;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
|
||||
### Migration: Importing existing sops-based keys / sops-nix
|
||||
|
||||
`clan secrets` stores each secret in a single file, whereas [sops](https://github.com/Mic92/sops-nix) commonly allows to put all secrets in a yaml or json document.
|
||||
|
||||
If you already happened to use sops-nix, you can migrate by using the `clan secrets import-sops` command by importing these files:
|
||||
|
||||
```bash
|
||||
% clan secrets import-sops --prefix matchbox- --group admins --machine matchbox nixos/matchbox/secrets/secrets.yaml
|
||||
```
|
||||
|
||||
This will create secrets for each secret found in `nixos/matchbox/secrets/secrets.yaml` in a `./sops` folder of your repository.
|
||||
Each member of the group `admins` in this case will be able to decrypt the secrets with their respective key.
|
||||
|
||||
Since our clan secret module will auto-import secrets that are encrypted for a particular nixos machine,
|
||||
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
|
||||
@@ -5,10 +5,6 @@
|
||||
In the `flake.nix` file:
|
||||
|
||||
- [x] set a unique `clanName`.
|
||||
- [ ] set `clanIcon` (optional)
|
||||
- [ ] Set `machineIcon` per machine (optional)
|
||||
|
||||
These icons will be used by our future GUI.
|
||||
|
||||
=== "**buildClan**"
|
||||
|
||||
@@ -16,16 +12,12 @@ These icons will be used by our future GUI.
|
||||
buildClan {
|
||||
# Set a unique name
|
||||
clanName = "Lobsters";
|
||||
# Optional, a path to an image file
|
||||
clanIcon = ./path/to/file;
|
||||
# Should usually point to the directory of flake.nix
|
||||
directory = ./.;
|
||||
|
||||
machines = {
|
||||
jon = {
|
||||
# ...
|
||||
# Optional, a path to an image file
|
||||
clanCore.machineIcon = ./path/to/file;
|
||||
};
|
||||
# ...
|
||||
}
|
||||
@@ -40,14 +32,10 @@ These icons will be used by our future GUI.
|
||||
clan = {
|
||||
# Set a unique name
|
||||
clanName = "Lobsters";
|
||||
# Optional, a path to an image file
|
||||
clanIcon = ./path/to/file;
|
||||
|
||||
machines = {
|
||||
jon = {
|
||||
# ...
|
||||
# Optional, a path to an image file
|
||||
clanCore.machineIcon = ./path/to/file;
|
||||
};
|
||||
# ...
|
||||
}
|
||||
@@ -63,12 +51,15 @@ Adding or configuring a new machine requires two simple steps:
|
||||
1. Find the remote disk id by executing:
|
||||
|
||||
```bash title="setup computer"
|
||||
ssh root@<target-computer> lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Replace `flash-installer.local` with the IP address of the machine if you don't have the avahi service running which resolves mDNS local domains.
|
||||
|
||||
Which should show something like:
|
||||
|
||||
```bash
|
||||
```{.shellSession hl_lines="6" .no-copy}
|
||||
NAME ID-LINK FSTYPE SIZE MOUNTPOINT
|
||||
sda usb-ST_16GB_AA6271026J1000000509-0:0 14.9G
|
||||
├─sda1 usb-ST_16GB_AA6271026J1000000509-0:0-part1 1M
|
||||
@@ -84,67 +75,113 @@ Adding or configuring a new machine requires two simple steps:
|
||||
|
||||
=== "**buildClan**"
|
||||
|
||||
```nix title="clan-core.lib.buildClan"
|
||||
```nix title="clan-core.lib.buildClan" hl_lines="18 23"
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
imports = [
|
||||
# ...
|
||||
./modules/disko.nix
|
||||
./machines/jon/configuration.nix
|
||||
];
|
||||
# ...
|
||||
|
||||
# Change this to the correct ip-address or hostname
|
||||
# The hostname is the machine name by default
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@<hostname>"
|
||||
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"
|
||||
|
||||
# Change this to the ID-LINK of the desired disk shown by 'lsblk'
|
||||
clan.diskLayouts.singleDiskExt4 = {
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
}
|
||||
|
||||
# e.g. > cat ~/.ssh/id_ed25519.pub
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"<YOUR SSH_KEY>"
|
||||
];
|
||||
# ...
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
=== "**flakeParts**"
|
||||
|
||||
|
||||
|
||||
```nix title="clan-core.flakeModules.default"
|
||||
```nix title="clan-core.flakeModules.default" hl_lines="18 23"
|
||||
clan = {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
imports = [
|
||||
# ...
|
||||
./modules/disko.nix
|
||||
./machines/jon/configuration.nix
|
||||
];
|
||||
# ...
|
||||
|
||||
# Change this to the correct ip-address or hostname
|
||||
# The hostname is the machine name by default
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@<hostname>"
|
||||
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"
|
||||
|
||||
# Change this to the ID-LINK of the desired disk shown by 'lsblk'
|
||||
clan.diskLayouts.singleDiskExt4 = {
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
}
|
||||
|
||||
# e.g. > cat ~/.ssh/id_ed25519.pub
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"__YOUR_SSH_KEY__"
|
||||
];
|
||||
# ...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Step 2. Detect hardware specific drivers
|
||||
|
||||
1. Generate a `hardware-configuration.nix` for your target computer
|
||||
!!! Info "Replace `__CHANGE_ME__` with the appropriate identifier, such as `nvme-eui.e8238fa6bf530001001b448b4aec2929`"
|
||||
!!! Info "Replace `__YOUR_SSH_KEY__` with your personal key, like `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILoMI0NC5eT9pHlQExrvR5ASV3iW9+BXwhfchq0smXUJ jon@jon-desktop`"
|
||||
|
||||
```bash
|
||||
ssh root@<target-computer> nixos-generate-config --no-filesystems --show-hardware-config > hardware-configuration.nix
|
||||
```
|
||||
These steps will allow you to update your machine later.
|
||||
|
||||
2. Move the generated file to `machines/jon/hardware-configuration.nix`.
|
||||
### Step 2: Detect Drivers
|
||||
|
||||
### Initialize the facts
|
||||
Generate the `hardware-configuration.nix` file for your machine by executing the following command:
|
||||
|
||||
!!! Info
|
||||
**All facts are automatically initialized.**
|
||||
```bash
|
||||
ssh root@flash-installer.local nixos-generate-config --no-filesystems --show-hardware-config > machines/jon/hardware-configuration.nix
|
||||
```
|
||||
|
||||
If you need additional help see our [facts chapter](./secrets.md)
|
||||
This command connects to `flash-installer.local` as `root`, runs `nixos-generate-config` to detect hardware configurations (excluding filesystems), and writes them to `machines/jon/hardware-configuration.nix`.
|
||||
|
||||
### Step 3: Custom Disk Formatting
|
||||
|
||||
In `./modules/disko.nix`, a simple `ext4` disk partitioning scheme is defined for the Disko module. For more complex disk partitioning setups, refer to the [Disko examples](https://github.com/nix-community/disko/tree/master/example).
|
||||
|
||||
### Step 4: Custom Configuration
|
||||
|
||||
Modify `./machines/jon/configuration.nix` to personalize the system settings according to your requirements.
|
||||
|
||||
### Step 5: Check Configuration
|
||||
|
||||
Validate your configuration by running:
|
||||
|
||||
```bash
|
||||
nix flake check
|
||||
```
|
||||
|
||||
This command helps ensure that your system configuration is correct and free from errors.
|
||||
|
||||
!!! Note
|
||||
|
||||
Integrate this step into your [Continuous Integration](https://en.wikipedia.org/wiki/Continuous_integration) workflow to ensure that only valid Nix configurations are merged into your codebase. This practice helps maintain system stability and reduces integration issues.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Secrets & Facts](secrets.md): Setting up secrets with nix-sops
|
||||
|
||||
---
|
||||
|
||||
231
docs/site/getting-started/deploy.md
Normal file
231
docs/site/getting-started/deploy.md
Normal file
@@ -0,0 +1,231 @@
|
||||
# Deploy Machine
|
||||
|
||||
Integrating a new machine into your Clan environment is an easy yet flexible process, allowing for a straight forward management of multiple NixOS configurations.
|
||||
|
||||
We'll walk you through adding a new computer to your Clan.
|
||||
|
||||
## Installing a New Machine
|
||||
|
||||
Clan CLI, in conjunction with [nixos-anywhere](https://github.com/nix-community/nixos-anywhere), provides a seamless method for installing NixOS on various machines.
|
||||
|
||||
This process involves preparing a suitable hardware and disk partitioning configuration and ensuring the target machine is accessible via SSH.
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
=== "**Physical Hardware**"
|
||||
|
||||
- [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 [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
- [x] **USB Flash Drive**: See [Clan Installer](installer.md)
|
||||
|
||||
!!! Steps
|
||||
|
||||
1. Create a NixOS installer image and transfer it to a bootable USB drive as described in the [installer](./installer.md).
|
||||
|
||||
2. Boot the target machine and connect it to a network that makes it reachable from your setup computer.
|
||||
|
||||
=== "**Remote Machines**"
|
||||
|
||||
- [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 [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
|
||||
!!! Steps
|
||||
|
||||
- Any cloud machine if it is reachable via SSH and supports `kexec`.
|
||||
|
||||
|
||||
### Step 1. Deploy the machine
|
||||
|
||||
**Finally deployment time!** Use the following command to build and deploy the image via SSH onto your machine.
|
||||
|
||||
|
||||
=== "**Image Installer**"
|
||||
|
||||
This method makes use of the image installers of [nixos-images](https://github.com/nix-community/nixos-images).
|
||||
See how to prepare the installer for use [here](./installer.md).
|
||||
|
||||
The installer will randomly generate a password and local addresses on boot, then run ssh with these preconfigured.
|
||||
The installer shows it's deployment relevant information in two formats, a text form, as well as a QR code.
|
||||
|
||||
|
||||
This is an example of the booted installer.
|
||||
|
||||
```{ .bash .annotate .no-copy .nohighlight}
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │███████████████████████████│ # This is the QR Code (1) │
|
||||
│ │██ ▄▄▄▄▄ █▀▄█▀█▀▄█ ▄▄▄▄▄ ██│ │
|
||||
│ │██ █ █ █▀▄▄▄█ ▀█ █ █ ██│ │
|
||||
│ │██ █▄▄▄█ █▀▄ ▀▄▄▄█ █▄▄▄█ ██│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▀ ▀▄▀▄█▄▄▄▄▄▄▄██│ │
|
||||
│ │███▀▀▀ █▄▄█ ▀▄ ▄▀▄█ ███│ │
|
||||
│ │██▄██▄▄█▄▄▀▀██▄▀ ▄▄▄ ▄▀█▀██│ │
|
||||
│ │██ ▄▄▄▄▄ █▄▄▄▄ █ █▄█ █▀ ███│ │
|
||||
│ │██ █ █ █ █ █ ▄▄▄ ▄▀▀ ██│ │
|
||||
│ │██ █▄▄▄█ █ ▄ ▄ ▄ ▀█ ▄███│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▄▄▄▄▄█▄▄▄▄▄█▄███│ │
|
||||
│ │███████████████████████████│ │
|
||||
│ └───────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │Root password: cheesy-capital-unwell # password (2) │ │
|
||||
│ │Local network addresses: │ │
|
||||
│ │enp1s0 UP 192.168.178.169/24 metric 1024 fe80::21e:6ff:fe45:3c92/64 │ │
|
||||
│ │enp2s0 DOWN │ │
|
||||
│ │wlan0 DOWN # connect to wlan (3) │ │
|
||||
│ │Onion address: 6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion │ │
|
||||
│ │Multicast DNS: nixos-installer.local │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Press 'Ctrl-C' for console access │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
1. This is not an actual QR code, because it is displayed rather poorly on text sites.
|
||||
This would be the actual content of this specific QR code prettified:
|
||||
```json
|
||||
{
|
||||
"pass": "cheesy-capital-unwell",
|
||||
"tor": "6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion",
|
||||
"addrs": [
|
||||
"2001:9e8:347:ca00:21e:6ff:fe45:3c92"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To generate the actual QR code, that would be displayed use:
|
||||
```shellSession
|
||||
echo '{"pass":"cheesy-capital-unwell","tor":"6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion","addrs":["2001:9e8:347:ca00:21e:6ff:fe45:3c92"]}' | nix run nixpkgs#qrencode -- -s 2 -m 2 -t utf8
|
||||
```
|
||||
2. The root password for the installer medium.
|
||||
This password is autogenerated and meant to be easily typeable.
|
||||
3. See how to connect the installer medium to wlan [here](./installer.md#optional-connect-to-wifi).
|
||||
4. :man_raising_hand: I'm a code annotation! I can contain `code`, __formatted
|
||||
text__, images, ... basically anything that can be written in Markdown.
|
||||
|
||||
!!!tip
|
||||
For easy sharing of deployment information via QR code, we highly recommend using [KDE Connect](https://apps.kde.org/de/kdeconnect/).
|
||||
|
||||
There are two ways to deploy your machine:
|
||||
|
||||
1. **SSH with Password Authentication**
|
||||
Run the following command to install using SSH:
|
||||
```bash
|
||||
clan machines install [MACHINE] flash-installer.local
|
||||
```
|
||||
|
||||
2. **Scanning a QR Code for Installation Details**
|
||||
You can input the information by following one of these methods:
|
||||
- **Using a JSON String or File Path:**
|
||||
Provide the path to a JSON string or input the string directly:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --json [JSON]
|
||||
```
|
||||
- **Using an Image Containing the QR Code:**
|
||||
Provide the path to an image file containing the relevant QR code:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --png [PATH]
|
||||
```
|
||||
|
||||
=== "**SSH access**"
|
||||
|
||||
Replace `<target_host>` with the **target computers' ip address**:
|
||||
|
||||
```bash
|
||||
clan machines install [MACHINE] <target_host>
|
||||
```
|
||||
|
||||
|
||||
If you are using our template `[MACHINE]` would be `jon`
|
||||
|
||||
|
||||
!!! success
|
||||
Your machine is all set up. 🎉 🚀
|
||||
|
||||
|
||||
## Update Your Machines
|
||||
|
||||
Clan CLI enables you to remotely update your machines over SSH. This requires setting up a target address for each target machine.
|
||||
|
||||
### Setting the Target Host
|
||||
|
||||
Replace `root@jon` with the actual hostname or IP address of your target machine:
|
||||
```{.nix hl_lines="9" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
# "jon" will be the hostname of the machine
|
||||
"jon" = {
|
||||
# Set this for clan commands use ssh i.e. `clan machines update`
|
||||
# If you change the hostname, you need to update this line to root@<new-hostname>
|
||||
# This only works however if you have avahi running on your admin machine else use IP
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
!!! warning
|
||||
The use of `root@` in the target address implies SSH access as the `root` user.
|
||||
Ensure that the root login is secured and only used when necessary.
|
||||
|
||||
### Updating Machine Configurations
|
||||
|
||||
Execute the following command to update the specified machine:
|
||||
|
||||
```bash
|
||||
clan machines update jon
|
||||
```
|
||||
|
||||
You can also update all configured machines simultaneously by omitting the machine name:
|
||||
|
||||
```bash
|
||||
clan machines update
|
||||
```
|
||||
|
||||
### Setting a Build Host
|
||||
|
||||
If the machine does not have enough resources to run the NixOS evaluation or build itself,
|
||||
it is also possible to specify a build host instead.
|
||||
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
|
||||
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
clan.networking.buildHost = "root@<host_or_ip>";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Excluding a machine from `clan machine update`
|
||||
|
||||
To exclude machines from being updated when running `clan machines update` without any machines specified,
|
||||
one can set the `clan.deployment.requireExplicitUpdate` option to true:
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
clan.deployment.requireExplicitUpdate = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
This is useful for machines that are not always online or are not part of the regular update cycle.
|
||||
|
||||
---
|
||||
|
||||
## What's next ?
|
||||
|
||||
- [**Mesh VPN**](./mesh-vpn.md): Configuring a secure mesh network.
|
||||
|
||||
---
|
||||
|
||||
@@ -69,16 +69,16 @@ Below is a guide on how to structure this in your flake.nix:
|
||||
jon = {
|
||||
imports = [
|
||||
./machines/jon/configuration.nix
|
||||
./modules/disko.nix
|
||||
# ... more modules
|
||||
];
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
clanCore.machineIcon = null; # Optional, a path to an image file
|
||||
|
||||
# Set this for clan commands use ssh i.e. `clan machines update`
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
|
||||
|
||||
# remote> lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
clan.diskLayouts.singleDiskExt4 = {
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4aec2929";
|
||||
};
|
||||
|
||||
@@ -94,9 +94,4 @@ Below is a guide on how to structure this in your flake.nix:
|
||||
For detailed information about configuring `flake-parts` and the available options within Clan,
|
||||
refer to the Clan module documentation located [here](https://git.clan.lol/clan/clan-core/src/branch/main/flakeModules/clan.nix).
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Configure Machines](configure.md): Customize machine configuration
|
||||
- [Deploying](machines.md): Deploying a Machine configuration
|
||||
|
||||
---
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Installer
|
||||
|
||||
We offer a dedicated installer to assist remote installations.
|
||||
Our installer image simplifies the process of performing remote installations.
|
||||
|
||||
In this tutorial we will guide you through building and flashing it to a bootable USB drive.
|
||||
Follow our step-by-step guide to create and transfer this image onto a bootable USB drive.
|
||||
|
||||
## Creating and Using the **Clan Installer**
|
||||
!!! info
|
||||
If you already have a NixOS machine you can ssh into (in the cloud for example) you can skip this chapter and go directly to [Configure Machines](configure.md).
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
@@ -21,7 +22,7 @@ In this tutorial we will guide you through building and flashing it to a bootabl
|
||||
lsblk
|
||||
```
|
||||
|
||||
```{.console, .no-copy}
|
||||
```{.shellSession hl_lines="2" .no-copy}
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
sdb 8:0 1 117,2G 0 disk
|
||||
└─sdb1 8:1 1 117,2G 0 part /run/media/qubasa/INTENSO
|
||||
@@ -38,28 +39,44 @@ In this tutorial we will guide you through building and flashing it to a bootabl
|
||||
```shellSession
|
||||
sudo umount /dev/sdb1
|
||||
```
|
||||
=== "**Linux OS**"
|
||||
### Step 2. Flash Custom Installer
|
||||
|
||||
### Step 2. Download the Installer
|
||||
Using clan flash enables the inclusion of ssh public keys and disables ssh password authentication.
|
||||
It also includes the language and keymap currently used into the installer image.
|
||||
|
||||
```shellSession
|
||||
wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso
|
||||
```
|
||||
```bash
|
||||
clan --flake git+https://git.clan.lol/clan/clan-core flash flash-installer --disk main /dev/sd<X>
|
||||
```
|
||||
|
||||
### Step 3. Flash the Installer to the USB Drive
|
||||
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
|
||||
|
||||
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
|
||||
The `clan flash` utility will erase the disk. Make sure to specify the correct device
|
||||
|
||||
The `dd` utility will erase the disk. Make sure to specify the correct device (`of=...`)
|
||||
|
||||
For example if the USB device is `sdb` use `of=/dev/sdb`.
|
||||
|
||||
|
||||
=== "**Other OS**"
|
||||
### Step 2. Download Generic Installer
|
||||
|
||||
Use the `dd` utility to write the NixOS installer image to your USB drive:
|
||||
```shellSession
|
||||
wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso
|
||||
```
|
||||
|
||||
```shellSession
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X>
|
||||
```
|
||||
### Step 3. Flash the Installer to the USB Drive
|
||||
|
||||
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
|
||||
|
||||
The `dd` utility will erase the disk. Make sure to specify the correct device (`of=...`)
|
||||
|
||||
For example if the USB device is `sdb` use `of=/dev/sdb`.
|
||||
|
||||
|
||||
|
||||
Use the `dd` utility to write the NixOS installer image to your USB drive:
|
||||
|
||||
```shellSession
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X>
|
||||
```
|
||||
|
||||
### Step 4. Boot and Connect to your network
|
||||
|
||||
@@ -89,17 +106,6 @@ Select `NixOS` to boot into the clan installer.
|
||||
|
||||
For deploying your configuration the machine needs to be connected via LAN (recommended).
|
||||
|
||||
For connecting via Wifi, please consult the [guide below](#optional-connect-to-wifi).
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Configure Machines](configure.md): Customize machine configuration
|
||||
- [Deploying](machines.md): Deploying a Machine configuration
|
||||
- [WiFi](#optional-connect-to-wifi): Guide for connecting to Wifi.
|
||||
|
||||
---
|
||||
|
||||
## (Optional) Connect to Wifi
|
||||
|
||||
@@ -117,9 +123,10 @@ This will enter `iwd`
|
||||
|
||||
Now run the following command to connect to your Wifi:
|
||||
|
||||
```shellSession
|
||||
```{.shellSession .no-copy}
|
||||
# Identify your network device.
|
||||
device list
|
||||
|
||||
# Replace 'wlan0' with your wireless device name
|
||||
# Find your Wifi SSID.
|
||||
station wlan0 scan
|
||||
@@ -147,3 +154,11 @@ Press `ctrl-d` to exit `IWD`.
|
||||
Press `ctrl-d` **again** to update the displayed QR code and connection information.
|
||||
|
||||
You're all set up
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Configure Machines](configure.md): Customize machine configuration
|
||||
|
||||
---
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
# Deploy Machine
|
||||
|
||||
Integrating a new machine into your Clan environment is an easy yet flexible process, allowing for a straight forward management of multiple NixOS configurations.
|
||||
|
||||
We'll walk you through adding a new computer to your Clan.
|
||||
|
||||
## Installing a New Machine
|
||||
|
||||
Clan CLI, in conjunction with [nixos-anywhere](https://github.com/nix-community/nixos-anywhere), provides a seamless method for installing NixOS on various machines.
|
||||
|
||||
This process involves preparing a suitable hardware and disk partitioning configuration and ensuring the target machine is accessible via SSH.
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
=== "**Physical Hardware**"
|
||||
|
||||
- [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 [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
- [x] **USB Flash Drive**: See [Clan Installer](installer.md)
|
||||
|
||||
!!! Steps
|
||||
|
||||
1. Create a NixOS installer image and transfer it to a bootable USB drive as described in the [installer](./installer.md).
|
||||
|
||||
2. Boot the target machine and connect it to a network that makes it reachable from your setup computer.
|
||||
|
||||
=== "**Baremetal Machines**"
|
||||
|
||||
- [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 [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
|
||||
!!! Steps
|
||||
|
||||
- Any cloud machine if it is reachable via SSH and supports `kexec`.
|
||||
|
||||
Confirm the machine is reachable via SSH from your setup computer.
|
||||
|
||||
```bash
|
||||
ssh root@<your_target_machine_ip>
|
||||
```
|
||||
|
||||
### Step 1. Deploy the machine
|
||||
|
||||
**Finally deployment time!** Use the following command to build and deploy the image via SSH onto your machine.
|
||||
|
||||
=== "**SSH access**"
|
||||
|
||||
|
||||
|
||||
Replace `<target_host>` with the **target computers' ip address**:
|
||||
|
||||
```bash
|
||||
clan machines install my-machine <target_host>
|
||||
```
|
||||
|
||||
!!!note
|
||||
Building and deploying time will depend on hardware and connection speed.
|
||||
|
||||
=== "**Image Installer**"
|
||||
|
||||
This method makes use of the image installers of [nixos-images](https://github.com/nix-community/nixos-images).
|
||||
See how to prepare the installer for use [here](./installer.md).
|
||||
|
||||
The installer will randomly generate a password and local addresses on boot, then run ssh with these preconfigured.
|
||||
The installer shows it's deployment relevant information in two formats, a text form, as well as a QR code.
|
||||
|
||||
???example "An example view of a booted installer."
|
||||
This is an example of the booted installer.
|
||||
|
||||
```{ .bash .annotate }
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │███████████████████████████│ # This is the QR Code (1) │
|
||||
│ │██ ▄▄▄▄▄ █▀▄█▀█▀▄█ ▄▄▄▄▄ ██│ │
|
||||
│ │██ █ █ █▀▄▄▄█ ▀█ █ █ ██│ │
|
||||
│ │██ █▄▄▄█ █▀▄ ▀▄▄▄█ █▄▄▄█ ██│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▀ ▀▄▀▄█▄▄▄▄▄▄▄██│ │
|
||||
│ │███▀▀▀ █▄▄█ ▀▄ ▄▀▄█ ███│ │
|
||||
│ │██▄██▄▄█▄▄▀▀██▄▀ ▄▄▄ ▄▀█▀██│ │
|
||||
│ │██ ▄▄▄▄▄ █▄▄▄▄ █ █▄█ █▀ ███│ │
|
||||
│ │██ █ █ █ █ █ ▄▄▄ ▄▀▀ ██│ │
|
||||
│ │██ █▄▄▄█ █ ▄ ▄ ▄ ▀█ ▄███│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▄▄▄▄▄█▄▄▄▄▄█▄███│ │
|
||||
│ │███████████████████████████│ │
|
||||
│ └───────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │Root password: cheesy-capital-unwell # password (2) │ │
|
||||
│ │Local network addresses: │ │
|
||||
│ │enp1s0 UP 192.168.178.169/24 metric 1024 fe80::21e:6ff:fe45:3c92/64 │ │
|
||||
│ │enp2s0 DOWN │ │
|
||||
│ │wlan0 DOWN # connect to wlan (3) │ │
|
||||
│ │Onion address: 6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion │ │
|
||||
│ │Multicast DNS: nixos-installer.local │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Press 'Ctrl-C' for console access │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
1. This is not an actual QR code, because it is displayed rather poorly on text sites.
|
||||
This would be the actual content of this specific QR code prettified:
|
||||
```json
|
||||
{
|
||||
"pass": "cheesy-capital-unwell",
|
||||
"tor": "6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion",
|
||||
"addrs": [
|
||||
"2001:9e8:347:ca00:21e:6ff:fe45:3c92"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To generate the actual QR code, that would be displayed use:
|
||||
```shellSession
|
||||
echo '{"pass":"cheesy-capital-unwell","tor":"6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion","addrs":["2001:9e8:347:ca00:21e:6ff:fe45:3c92"]}' | nix run nixpkgs#qrencode -- -s 2 -m 2 -t utf8
|
||||
```
|
||||
2. The root password for the installer medium.
|
||||
This password is autogenerated and meant to be easily typeable.
|
||||
3. See how to connect the installer medium to wlan [here](./installer.md#optional-connect-to-wifi).
|
||||
4. :man_raising_hand: I'm a code annotation! I can contain `code`, __formatted
|
||||
text__, images, ... basically anything that can be written in Markdown.
|
||||
|
||||
|
||||
!!!tip
|
||||
We recommend using KDE Connect for sharing the deployment information from the QR code with the deploying machine.
|
||||
|
||||
|
||||
The QR code can be used to deploy either with an image, that is decoded on the fly, or it's contained json information.
|
||||
|
||||
With the path to a `json` string, or the string itself:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --json [JSON]
|
||||
```
|
||||
With the path to an image containing the relevant QR code:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --png [PATH]
|
||||
```
|
||||
|
||||
|
||||
!!! success
|
||||
|
||||
Your machine is all set up. 🎉 🚀
|
||||
|
||||
---
|
||||
|
||||
## What's next ?
|
||||
|
||||
- [**Update a Machine**](#update-your-machines): Learn how to update an existing machine?
|
||||
|
||||
Coming Soon:
|
||||
|
||||
- **Join Your Machines in a Private Network:**: Stay tuned for steps on linking all your machines into a secure mesh network with Clan.
|
||||
|
||||
---
|
||||
|
||||
## Update Your Machines
|
||||
|
||||
Clan CLI enables you to remotely update your machines over SSH. This requires setting up a target address for each target machine.
|
||||
|
||||
### Setting the Target Host
|
||||
|
||||
Replace `host_or_ip` with the actual hostname or IP address of your target machine:
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.networking.targetHost root@host_or_ip
|
||||
```
|
||||
|
||||
!!! warning
|
||||
The use of `root@` in the target address implies SSH access as the `root` user.
|
||||
Ensure that the root login is secured and only used when necessary.
|
||||
|
||||
### Updating Machine Configurations
|
||||
|
||||
Execute the following command to update the specified machine:
|
||||
|
||||
```bash
|
||||
clan machines update my-machine
|
||||
```
|
||||
|
||||
You can also update all configured machines simultaneously by omitting the machine name:
|
||||
|
||||
```bash
|
||||
clan machines update
|
||||
```
|
||||
|
||||
### Setting a Build Host
|
||||
|
||||
If the machine does not have enough resources to run the NixOS evaluation or build itself,
|
||||
it is also possible to specify a build host instead.
|
||||
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.networking.buildHost root@host_or_ip
|
||||
```
|
||||
|
||||
### Excluding a machine from `clan machine update`
|
||||
|
||||
To exclude machines from being updated when running `clan machines update` without any machines specified,
|
||||
one can set the `clan.deployment.requireExplicitUpdate` option to true:
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.deployment.requireExplicitUpdate true
|
||||
```
|
||||
|
||||
This is useful for machines that are not always online or are not part of the regular update cycle.
|
||||
|
||||
---
|
||||
|
||||
# TODO:
|
||||
* TODO: How to join others people zerotier
|
||||
* `services.zerotier.joinNetworks = [ "network-id" ]`
|
||||
* Controller needs to approve over webinterface or cli
|
||||
@@ -1,20 +1,32 @@
|
||||
# Overlay Networks
|
||||
# Mesh VPN
|
||||
|
||||
This guide provides detailed instructions for configuring
|
||||
[ZeroTier VPN](https://zerotier.com) within Clan. Follow the
|
||||
outlined steps to set up a machine as a VPN controller (`<CONTROLLER>`) and to
|
||||
include a new machine into the VPN.
|
||||
|
||||
## 1. Setting Up the VPN Controller
|
||||
## Concept
|
||||
|
||||
By default all machines within one clan are connected via a chosen network technology.
|
||||
|
||||
```{.no-copy}
|
||||
Clan
|
||||
Node A
|
||||
<-> (zerotier / mycelium / ...)
|
||||
Node B
|
||||
```
|
||||
|
||||
If you select multiple network technologies at the same time. e.g. (zerotier + yggdrassil)
|
||||
You must choose one of them as primary network and the machines are always connected via the primary network.
|
||||
|
||||
## 1. Set-Up the VPN Controller
|
||||
|
||||
The VPN controller is initially essential for providing configuration to new
|
||||
peers. Once addresses are allocated, the controller's continuous operation is not essential.
|
||||
|
||||
### Instructions
|
||||
|
||||
1. **Designate a Machine**: Label a machine as the VPN controller in the clan,
|
||||
referred to as `<CONTROLLER>` henceforth in this guide.
|
||||
1. **Add Configuration**: Input the following configuration to the NixOS
|
||||
2. **Add Configuration**: Input the following configuration to the NixOS
|
||||
configuration of the controller machine:
|
||||
```nix
|
||||
clan.networking.zerotier.controller = {
|
||||
@@ -22,18 +34,16 @@ peers. Once addresses are allocated, the controller's continuous operation is no
|
||||
public = true;
|
||||
};
|
||||
```
|
||||
1. **Update the Controller Machine**: Execute the following:
|
||||
3. **Update the Controller Machine**: Execute the following:
|
||||
```bash
|
||||
$ clan machines update <CONTROLLER>
|
||||
clan machines update <CONTROLLER>
|
||||
```
|
||||
Your machine is now operational as the VPN controller.
|
||||
|
||||
## 2. Integrating a New Machine to the VPN
|
||||
## 2. Add Machines to the VPN
|
||||
|
||||
To introduce a new machine to the VPN, adhere to the following steps:
|
||||
|
||||
### Instructions:
|
||||
|
||||
1. **Update Configuration**: On the new machine, incorporate the following to its
|
||||
configuration, substituting `<CONTROLLER>` with the controller machine name:
|
||||
```nix
|
||||
@@ -46,22 +56,25 @@ To introduce a new machine to the VPN, adhere to the following steps:
|
||||
$ clan machines update <NEW_MACHINE>
|
||||
```
|
||||
Replace `<NEW_MACHINE>` with the designated new machine name.
|
||||
1. **Retrieve the ZeroTier ID**: On the `new_machine`, execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
Example Output:
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 OFFLINE
|
||||
```
|
||||
, where `d2c71971db` is the ZeroTier ID.
|
||||
1. **Authorize the New Machine on the Controller**: On the controller machine,
|
||||
execute:
|
||||
```bash
|
||||
$ sudo zerotier-members allow <ID>
|
||||
```
|
||||
Substitute `<ID>` with the ZeroTier ID obtained previously.
|
||||
1. **Verify Connection**: On the `new_machine`, re-execute:
|
||||
|
||||
!!! Note "For Private Networks"
|
||||
1. **Retrieve the ZeroTier ID**: On the `new_machine`, execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
Example Output:
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 OFFLINE
|
||||
```
|
||||
, where `d2c71971db` is the ZeroTier ID.
|
||||
2. **Authorize the New Machine on the Controller**: On the controller machine,
|
||||
execute:
|
||||
```bash
|
||||
$ sudo zerotier-members allow <ID>
|
||||
```
|
||||
Substitute `<ID>` with the ZeroTier ID obtained previously.
|
||||
|
||||
2. **Verify Connection**: On the `new_machine`, re-execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
@@ -74,22 +87,11 @@ To introduce a new machine to the VPN, adhere to the following steps:
|
||||
The new machine is now part of the VPN, and the ZeroTier
|
||||
configuration on NixOS within the Clan project is complete.
|
||||
|
||||
## Decision
|
||||
|
||||
We chose zerotier because in our tests it was the easiest solution to bootstrap. You can selfhost a controller and the controller doesn't need to be globally reachable.
|
||||
## Further
|
||||
|
||||
Currently you can only use **Zerotier** as networking technology because this is the first network stack we aim to support.
|
||||
In the future we plan to add additional network technologies like tinc, head/tailscale, yggdrassil and mycelium.
|
||||
|
||||
## Specification
|
||||
|
||||
By default all machines within one clan are connected via the chosen network technology.
|
||||
|
||||
```
|
||||
Clan
|
||||
Node A
|
||||
<-> (zerotier / mycelium / ...)
|
||||
Node B
|
||||
```
|
||||
|
||||
If you select multiple network technologies at the same time. e.g. (zerotier + yggdrassil)
|
||||
One of them is the primary network and the above statement holds for the primary network.
|
||||
We chose zerotier because in our tests it was a straight forwards solution to bootstrap.
|
||||
It allows you to selfhost a controller and the controller doesn't need to be globally reachable.
|
||||
Which made it a good fit for starting the project.
|
||||
@@ -4,9 +4,6 @@ Clan enables encryption of secrets (such as passwords & keys) ensuring security
|
||||
|
||||
Clan utilizes the [sops](https://github.com/getsops/sops) format and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
|
||||
|
||||
This documentation will guide you through managing secrets with the Clan CLI
|
||||
|
||||
## 1. Initializing Secrets
|
||||
|
||||
### Create Your Master Keypair
|
||||
|
||||
@@ -28,11 +25,11 @@ Generated age private key at '/home/joerg/.config/sops/age/keys.txt' for your us
|
||||
Also add your age public key to the repository with 'clan secrets users add YOUR_USER age1wkth7uhpkl555g40t8hjsysr20drq286netu8zptw50lmqz7j95sw2t3l7' (replace YOUR_USER with your actual username)
|
||||
```
|
||||
|
||||
!!! warning
|
||||
!!! warning
|
||||
Make sure to keep a safe backup of the private key you've just created.
|
||||
If it's lost, you won't be able to get to your secrets anymore because they all need the master key to be unlocked.
|
||||
|
||||
!!! note
|
||||
!!! note
|
||||
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
|
||||
|
||||
### Add Your Public Key
|
||||
@@ -41,8 +38,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
|
||||
clan secrets users add <your_username> <your_public_key>
|
||||
```
|
||||
|
||||
!!! note
|
||||
Choose the same username as on your Setup/Source Machine that you use to control the deployment with.
|
||||
It's best to choose the same username as on your Setup/Admin Machine that you use to control the deployment with.
|
||||
|
||||
Once run this will create the following files:
|
||||
|
||||
@@ -52,112 +48,39 @@ sops/
|
||||
└── <your_username>/
|
||||
└── key.json
|
||||
```
|
||||
If you followed the quickstart tutorial all necessary secrets are initialized at this point.
|
||||
|
||||
## 2. Adding Machine Keys
|
||||
---
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
## Whats next?
|
||||
|
||||
```bash
|
||||
$ clan secrets machines list
|
||||
- [Deployment](deploy.md): How to remotely deploy your machine
|
||||
|
||||
---
|
||||
|
||||
## More on Secrets
|
||||
|
||||
If you want to know more about how to save and share passwords in your clan read further!
|
||||
|
||||
### Adding a Secret
|
||||
|
||||
```shellSession
|
||||
clan secrets set mysecret
|
||||
Paste your secret:
|
||||
```
|
||||
|
||||
For existing machines, add their keys:
|
||||
### Retrieving a Stored Secret
|
||||
|
||||
```bash
|
||||
$ clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
### Advanced
|
||||
|
||||
To fetch an age key from an SSH host key:
|
||||
|
||||
```bash
|
||||
$ ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
## 3. Assigning Access
|
||||
|
||||
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
|
||||
|
||||
```bash
|
||||
$ clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
|
||||
You can add machines/users to existing secrets without modifying the secret:
|
||||
|
||||
```bash
|
||||
$ clan secrets machines add-secret <machine_name> <secret_name>
|
||||
```
|
||||
|
||||
## 4. Adding Secrets
|
||||
|
||||
```bash
|
||||
$ clan secrets set mysecret
|
||||
Paste your secret:
|
||||
```
|
||||
|
||||
!!! note
|
||||
As you type your secret won't be displayed. Press Enter to save the secret.
|
||||
|
||||
## 5. Retrieving Stored Secrets
|
||||
|
||||
```bash
|
||||
$ clan secrets get mysecret
|
||||
clan secrets get mysecret
|
||||
```
|
||||
|
||||
### List all Secrets
|
||||
|
||||
```bash
|
||||
$ clan secrets list
|
||||
clan secrets list
|
||||
```
|
||||
|
||||
## 6. Groups
|
||||
|
||||
Clan CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
All users within a group inherit access to all secrets of the group.
|
||||
|
||||
This feature eases the process of handling permissions for multiple users.
|
||||
|
||||
Here's how to get started:
|
||||
|
||||
1. **Creating Groups**:
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups add admins <username>
|
||||
```
|
||||
|
||||
2. **Listing Groups**:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups list
|
||||
```
|
||||
|
||||
3. **Assigning Secrets to Groups**:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
## Further
|
||||
|
||||
Secrets in the repository follow this structure:
|
||||
|
||||
```{.console, .no-copy}
|
||||
sops/
|
||||
├── secrets/
|
||||
│ └── <secret_name>/
|
||||
│ ├── secret
|
||||
│ └── users/
|
||||
│ └── <your_username>/
|
||||
```
|
||||
|
||||
The content of the secret is stored encrypted inside the `secret` file under `mysecret`.
|
||||
|
||||
By default, secrets are encrypted with your key to ensure readability.
|
||||
|
||||
### NixOS integration
|
||||
|
||||
A NixOS machine will automatically import all secrets that are encrypted for the
|
||||
@@ -176,8 +99,72 @@ In your nixos configuration you can get a path to secrets like this `config.sops
|
||||
}
|
||||
```
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
### Assigning Access
|
||||
|
||||
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
|
||||
|
||||
```bash
|
||||
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
You can also just add machines/users to existing secrets:
|
||||
|
||||
```bash
|
||||
clan secrets machines add-secret <machine_name> <secret_name>
|
||||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
In this section we go into more advanced secret management topics.
|
||||
|
||||
### Groups
|
||||
|
||||
Clan CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
All users within a group inherit access to all secrets of the group.
|
||||
|
||||
This feature eases the process of handling permissions for multiple users.
|
||||
|
||||
Here's how to get started:
|
||||
|
||||
1. **Creating Groups**:
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
clan secrets groups add admins <username>
|
||||
```
|
||||
|
||||
2. **Listing Groups**:
|
||||
|
||||
```bash
|
||||
clan secrets groups list
|
||||
```
|
||||
|
||||
3. **Assigning Secrets to Groups**:
|
||||
|
||||
```bash
|
||||
clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
### Adding Machine Keys
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
|
||||
```bash
|
||||
clan secrets machines list
|
||||
```
|
||||
|
||||
For existing machines, add their keys:
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
To fetch an age key from an SSH host key:
|
||||
|
||||
```bash
|
||||
ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
### Migration: Importing existing sops-based keys / sops-nix
|
||||
|
||||
@@ -194,3 +181,138 @@ Each member of the group `admins` in this case will be able to decrypt the secre
|
||||
|
||||
Since our clan secret module will auto-import secrets that are encrypted for a particular nixos machine,
|
||||
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
|
||||
|
||||
|
||||
|
||||
## Indepth Explanation
|
||||
|
||||
|
||||
|
||||
The secrets system conceptually knows two different entities:
|
||||
|
||||
- **Machine**: consumes secrets
|
||||
- **User**: manages access to secrets
|
||||
|
||||
**A Users** Can add or revoke machines' access to secrets.
|
||||
|
||||
**A machine** Can decrypt secrets that where encrypted specifically for that machine.
|
||||
|
||||
!!! Danger
|
||||
**Always make sure at least one _User_ has access to a secret**. Otherwise you could lock yourself out from accessing the secret.
|
||||
|
||||
### Inherited implications
|
||||
|
||||
By default clan uses [sops](https://github.com/getsops/sops) through [sops-nix](https://github.com/Mic92/sops-nix) for managing its secrets which inherits some implications that are important to understand:
|
||||
|
||||
- **Public/Private keys**: Entities are identified via their public keys. Each Entity can use their respective private key to decrypt a secret.
|
||||
- **Public keys are stored**: All Public keys are stored inside the repository
|
||||
- **Secrets are stored Encrypted**: secrets are stored inside the repository encrypted with the respective public keys
|
||||
- **Secrets are deployed encrypted**: Fully encrypted secrets are deployed to machines at deployment time.
|
||||
- **Secrets are decrypted by sops on-demand**: Each machine decrypts its secrets at runtime and stores them at an ephemeral location.
|
||||
- **Machine key-pairs are auto-generated**: When a machine is created **no user-interaction is required** to setup public/private key-pairs.
|
||||
- **secrets are re-encrypted**: In case machines, users or groups are modified secrets get re-encrypted on demand.
|
||||
|
||||
!!! Important
|
||||
After revoking access to a secret you should also change the underlying secret. i.e. change the API key, or the password.
|
||||
|
||||
---
|
||||
|
||||
### Machine and user keys
|
||||
|
||||
The following diagrams illustrates how a user can provide a secret (i.e. a Password).
|
||||
|
||||
- By using the **Clan CLI** a user encrypts the password with both the **User public-key** and the **machine's public-key**
|
||||
|
||||
- The *Machine* can decrypt the password with its private-key on demand.
|
||||
|
||||
- The *User* is able to decrypt the password to make changes to it.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
|
||||
Person(user, "User", "Someone who manages secrets")
|
||||
ContainerDb(secret, "Secret")
|
||||
Container(machine, "Machine", "A Machine. i.e. Needs the Secret for a given Service." )
|
||||
|
||||
Rel_R(user, secret, "Encrypt", "", "Pubkeys: User, Machine")
|
||||
Rel_L(secret, user, "Decrypt", "", "user privkey")
|
||||
Rel_R(secret, machine, "Decrypt", "", "machine privkey" )
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
|
||||
#### User groups
|
||||
|
||||
Here we illustrate how machine groups work.
|
||||
|
||||
Common use cases:
|
||||
|
||||
- **Shared Management**: Access among multiple users. I.e. a subset of secrets/machines that have two admins
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
|
||||
System_Boundary(c1, "Group") {
|
||||
Person(user1, "User A", "has access")
|
||||
Person(user2, "User B", "has access")
|
||||
}
|
||||
|
||||
ContainerDb(secret, "Secret")
|
||||
Container(machine, "Machine", "A Machine. i.e. Needs the Secret for a given Service." )
|
||||
|
||||
Rel_R(c1, secret, "Encrypt", "", "Pubkeys: User A, User B, Machine")
|
||||
Rel_R(secret, machine, "Decrypt", "", "machine privkey" )
|
||||
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
<!-- TODO: See also [Groups Reference](#groups-reference) -->
|
||||
|
||||
---
|
||||
|
||||
#### Machine groups
|
||||
|
||||
Here we illustrate how machine groups work.
|
||||
|
||||
Common use cases:
|
||||
|
||||
- **Shared secrets**: Among multiple machines such as Wifi passwords
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
!include C4_Deployment.puml
|
||||
|
||||
Person(user, "User", "Someone who manages secrets")
|
||||
ContainerDb(secret, "Secret")
|
||||
System_Boundary(c1, "Group") {
|
||||
Container(machine1, "Machine A", "Both machines need the same secret" )
|
||||
Container(machine2, "Machine B", "Both machines need the same secret" )
|
||||
}
|
||||
|
||||
Rel_R(user, secret, "Encrypt", "", "Pubkeys: machine A, machine B, User")
|
||||
Rel(secret, c1, "Decrypt", "", "Both machine A or B can decrypt using their private key" )
|
||||
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
<!-- TODO: See also [Groups Reference](#groups-reference) -->
|
||||
|
||||
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Deployment](deploy.md): How to remotely deploy your machine
|
||||
|
||||
---
|
||||
|
||||
@@ -1,44 +1,31 @@
|
||||
# Getting Started
|
||||
# Setup
|
||||
|
||||
Welcome to your simple guide on starting a new Clan project.
|
||||
|
||||
## What's Inside
|
||||
|
||||
We've put together a straightforward guide to help you out:
|
||||
|
||||
- [**Starting with a New Clan Project**](#starting-with-a-new-clan-project): Create a new Clan from scratch.
|
||||
- [**Integrating Clan using Flake-Parts**](getting-started/flake-parts.md)
|
||||
|
||||
---
|
||||
|
||||
## **Starting with a New Clan Project**
|
||||
|
||||
Create your own clan with these initial steps.
|
||||
Create your own clan with these initial steps and manage a fleet of machines with one single testable git repository!
|
||||
|
||||
### Prerequisites
|
||||
|
||||
#### Linux
|
||||
=== "**Linux**"
|
||||
|
||||
Clan depends on nix installed on your system. Run the following command to install nix.
|
||||
Clan depends on nix installed on your system. Run the following command to install nix.
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
|
||||
#### NixOS
|
||||
=== "**NixOS**"
|
||||
|
||||
If you run NixOS the `nix` binary is already installed.
|
||||
If you run NixOS the `nix` binary is already installed.
|
||||
|
||||
You will also need to enable the `flakes` and `nix-commands` experimental features.
|
||||
You will also need to enable the `flakes` and `nix-commands` experimental features.
|
||||
|
||||
```bash
|
||||
# /etc/nix/nix.conf or ~/.config/nix/nix.conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
```bash
|
||||
# /etc/nix/nix.conf or ~/.config/nix/nix.conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
#### Other
|
||||
=== "**Other**"
|
||||
|
||||
Clan doesn't offer dedicated support for other operating systems yet.
|
||||
Clan doesn't offer dedicated support for other operating systems yet.
|
||||
|
||||
### Step 1: Add Clan CLI to Your Shell
|
||||
|
||||
@@ -48,6 +35,13 @@ Add the Clan CLI into your development workflow:
|
||||
nix shell git+https://git.clan.lol/clan/clan-core#clan-cli
|
||||
```
|
||||
|
||||
You can find reference documentation for the `clan` cli program [here](./reference/cli/index.md).
|
||||
|
||||
Alternatively you can check out the help pages directly:
|
||||
```terminalSession
|
||||
clan --help
|
||||
```
|
||||
|
||||
### Step 2: Initialize Your Project
|
||||
|
||||
Set the foundation of your Clan project by initializing it as follows:
|
||||
@@ -57,6 +51,7 @@ clan flakes create my-clan
|
||||
```
|
||||
|
||||
This command creates the `flake.nix` and `.clan-flake` files for your project.
|
||||
It will also generate files from a default template, to help show general clan usage patterns.
|
||||
|
||||
### Step 3: Verify the Project Structure
|
||||
|
||||
@@ -102,12 +97,6 @@ sara
|
||||
|
||||
### What's Next?
|
||||
|
||||
- [**Machine Configuration**](getting-started/configure.md): Declare behavior and configuration of machines.
|
||||
|
||||
- [**Deploy Machines**](getting-started/machines.md): Learn how to deploy to any remote machine.
|
||||
|
||||
- [**Installer**](getting-started/installer.md): Setting up new computers remotely is easy with an USB stick.
|
||||
|
||||
- [**Check out our Templates**](templates/index.md)
|
||||
|
||||
---
|
||||
|
||||
2117
docs/site/static/asciinema-player/asciinema-player.css
Normal file
2117
docs/site/static/asciinema-player/asciinema-player.css
Normal file
File diff suppressed because it is too large
Load Diff
1
docs/site/static/asciinema-player/asciinema-player.min.js
vendored
Normal file
1
docs/site/static/asciinema-player/asciinema-player.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
45
docs/site/static/asciinema-player/custom-theme.css
Normal file
45
docs/site/static/asciinema-player/custom-theme.css
Normal file
@@ -0,0 +1,45 @@
|
||||
.asciinema-player-theme-alabaster-auto {
|
||||
--term-color-foreground: #000000; /* Black for foreground text */
|
||||
--term-color-background: #f7f7f7; /* Very light gray for background */
|
||||
|
||||
--term-color-0: #000000; /* Black */
|
||||
--term-color-1: #aa3731; /* Red */
|
||||
--term-color-2: #448c37; /* Green */
|
||||
--term-color-3: #cb9000; /* Yellow */
|
||||
--term-color-4: #325cc0; /* Blue */
|
||||
--term-color-5: #7a3e9d; /* Magenta */
|
||||
--term-color-6: #0083b2; /* Cyan */
|
||||
--term-color-7: #bbbbbb; /* White */
|
||||
--term-color-8: #777777; /* Bright black (gray) */
|
||||
--term-color-9: #f05050; /* Bright red */
|
||||
--term-color-10: #60cb00; /* Bright green */
|
||||
--term-color-11: #ffbc5d; /* Bright yellow */
|
||||
--term-color-12: #007acc; /* Bright blue */
|
||||
--term-color-13: #e64ce6; /* Bright magenta */
|
||||
--term-color-14: #00aacb; /* Bright cyan */
|
||||
--term-color-15: #ffffff; /* Bright white */
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.asciinema-player-theme-solarized-auto {
|
||||
--term-color-foreground: #839496;
|
||||
--term-color-background: #002b36;
|
||||
|
||||
--term-color-0: #073642;
|
||||
--term-color-1: #dc322f;
|
||||
--term-color-2: #859900;
|
||||
--term-color-3: #b58900;
|
||||
--term-color-4: #268bd2;
|
||||
--term-color-5: #d33682;
|
||||
--term-color-6: #2aa198;
|
||||
--term-color-7: #eee8d5;
|
||||
--term-color-8: #002b36;
|
||||
--term-color-9: #cb4b16;
|
||||
--term-color-10: #586e75;
|
||||
--term-color-11: #657b83;
|
||||
--term-color-12: #839496;
|
||||
--term-color-13: #6c71c4;
|
||||
--term-color-14: #93a1a1;
|
||||
--term-color-15: #fdf6e3;
|
||||
}
|
||||
}
|
||||
0
docs/site/static/asciinema-player/v3.7.0
Normal file
0
docs/site/static/asciinema-player/v3.7.0
Normal file
BIN
docs/site/static/clan-dark.png
Normal file
BIN
docs/site/static/clan-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.1 KiB |
BIN
docs/site/static/clan-white.png
Normal file
BIN
docs/site/static/clan-white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
docs/site/static/w_profile.webp
Normal file
BIN
docs/site/static/w_profile.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -1,24 +0,0 @@
|
||||
# Templates
|
||||
|
||||
We provide some starting templates you can easily use one of those via `nix flakes`.
|
||||
|
||||
They showcase best practices and guide you through setting up and using Clan's modules
|
||||
|
||||
I.e. To use the `new-clan` template run the following command:
|
||||
|
||||
```bash
|
||||
nix flake init -t git+https://git.clan.lol/clan/clan-core#new-clan
|
||||
```
|
||||
|
||||
## Available Templates
|
||||
|
||||
We offer the following templates:
|
||||
|
||||
To initialize a clan with one of those run:
|
||||
```bash
|
||||
nix flake init -t git+https://git.clan.lol/clan/clan-core#[TEMPLATE_NAME]
|
||||
```
|
||||
|
||||
Substitute `[TEMPLATE_NAME]` with the name of the template.
|
||||
|
||||
- **new-clan**: Perfect for beginners, this template shows you how to link two machines in a basic setup.
|
||||
80
flake.lock
generated
80
flake.lock
generated
@@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712356478,
|
||||
"narHash": "sha256-kTcEtrQIRnexu5lAbLsmUcfR2CrmsACF1s3ZFw1NEVA=",
|
||||
"lastModified": 1716394172,
|
||||
"narHash": "sha256-B+pNhV8GFeCj9/MoH+qtGqKbgv6fU4hGaw2+NoYYtB0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"rev": "0a17298c0d96190ef3be729d594ba202b9c53beb",
|
||||
"rev": "23c63fb09334c3e8958b57e2ddc3870b75b9111d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -27,11 +27,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"lastModified": 1715865404,
|
||||
"narHash": "sha256-/GJvTdTpuDjNn84j82cU6bXztE0MSkdnTWClUCRub78=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"rev": "8dc45382d5206bd292f9c2768b8058a8fd8311d9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -42,11 +42,11 @@
|
||||
},
|
||||
"nixlib": {
|
||||
"locked": {
|
||||
"lastModified": 1711846064,
|
||||
"narHash": "sha256-cqfX0QJNEnge3a77VnytM0Q6QZZ0DziFXt6tSCV8ZSc=",
|
||||
"lastModified": 1712450863,
|
||||
"narHash": "sha256-K6IkdtMtq9xktmYPj0uaYc8NsIqHuaAoRBaMgu9Fvrw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "90b1a963ff84dc532db92f678296ff2499a60a87",
|
||||
"rev": "3c62b6a12571c9a7f65ab037173ee153d539905f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -55,6 +55,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-2311": {
|
||||
"locked": {
|
||||
"lastModified": 1715818734,
|
||||
"narHash": "sha256-WvAJWCwPj/6quKcsgsvQYyZRxV8ho/yUzj0HZQ34DVU=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "95742536dc6debb5a8b8b78b27001c38f369f1e7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-generators": {
|
||||
"inputs": {
|
||||
"nixlib": "nixlib",
|
||||
@@ -63,11 +79,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712191720,
|
||||
"narHash": "sha256-xXtSSnVHURHsxLQO30dzCKW5NJVGV/umdQPmFjPFMVA=",
|
||||
"lastModified": 1716123454,
|
||||
"narHash": "sha256-U2o4UPM/UsEyIX2p11+YEQgR9HY3PmjZ2mRl/x5e4xo=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-generators",
|
||||
"rev": "0c15e76bed5432d7775a22e8d22059511f59d23a",
|
||||
"rev": "a63e0c83dd83fe28cc571b97129e13373436bd82",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -76,13 +92,34 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-images": {
|
||||
"inputs": {
|
||||
"nixos-2311": "nixos-2311",
|
||||
"nixos-unstable": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1716132123,
|
||||
"narHash": "sha256-rATSWbPaKQfZGaemu0tHL2xfCzVIVwpuTjk+KSBC+k4=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-images",
|
||||
"rev": "8c9cab8c44434c12dafc465fbf61a710c5bceb08",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-images",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1712468661,
|
||||
"narHash": "sha256-n2gVVBs+rV+HzPv/N3QQv5cdAXqSkjmaObvfeMqnw2c=",
|
||||
"lastModified": 1716127062,
|
||||
"narHash": "sha256-2rk8FqB/iQV2d0vQLs684/Tj5PUHaS1sFwG7fng5vXE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "298edc8f1e0dfffce67f50375c9f5952e04a6d02",
|
||||
"rev": "8a2555763c48e2410054de3f52f7310ce3241ec5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -97,6 +134,7 @@
|
||||
"disko": "disko",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixos-generators": "nixos-generators",
|
||||
"nixos-images": "nixos-images",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"sops-nix": "sops-nix",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
@@ -110,11 +148,11 @@
|
||||
"nixpkgs-stable": []
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712458908,
|
||||
"narHash": "sha256-DMgBS+jNHDg8z3g9GkwqL8xTKXCRQ/0FGsAyrniVonc=",
|
||||
"lastModified": 1716087663,
|
||||
"narHash": "sha256-zuSAGlx8Qk0OILGCC2GUyZ58/SJ5R3GZdeUNQ6IS0fQ=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "39191e8e6265b106c9a2ba0cfd3a4dafe98a31c6",
|
||||
"rev": "0bf1808e70ce80046b0cff821c019df2b19aabf5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -130,11 +168,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711963903,
|
||||
"narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=",
|
||||
"lastModified": 1715940852,
|
||||
"narHash": "sha256-wJqHMg/K6X3JGAE9YLM0LsuKrKb4XiBeVaoeMNlReZg=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac",
|
||||
"rev": "2fba33a182602b9d49f0b2440513e5ee091d838b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
|
||||
|
||||
disko.url = "github:nix-community/disko";
|
||||
disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||
sops-nix.url = "github:Mic92/sops-nix";
|
||||
@@ -16,6 +15,8 @@
|
||||
sops-nix.inputs.nixpkgs-stable.follows = "";
|
||||
nixos-generators.url = "github:nix-community/nixos-generators";
|
||||
nixos-generators.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nixos-images.url = "github:nix-community/nixos-images";
|
||||
nixos-images.inputs.nixos-unstable.follows = "nixpkgs";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
treefmt.programs.mypy.directories = {
|
||||
"pkgs/clan-cli".extraPythonPackages = self'.packages.clan-cli.testDependencies;
|
||||
"pkgs/clan-vm-manager".extraPythonPackages =
|
||||
self'.packages.clan-vm-manager.externalTestDeps ++ self'.packages.clan-cli.testDependencies;
|
||||
# clan-vm-manager currently only exists on linux
|
||||
(self'.packages.clan-vm-manager.externalTestDeps or [ ])
|
||||
++ self'.packages.clan-cli.testDependencies;
|
||||
};
|
||||
|
||||
treefmt.settings.formatter.nix = {
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
}:
|
||||
{
|
||||
jsonschema = import ./jsonschema { inherit lib; };
|
||||
|
||||
modules = import ./description.nix { inherit clan-core lib; };
|
||||
buildClan = import ./build-clan { inherit clan-core lib nixpkgs; };
|
||||
}
|
||||
|
||||
33
lib/description.nix
Normal file
33
lib/description.nix
Normal file
@@ -0,0 +1,33 @@
|
||||
{ lib, clan-core, ... }:
|
||||
|
||||
rec {
|
||||
getReadme =
|
||||
modulename:
|
||||
let
|
||||
readme = "${clan-core}/clanModules/${modulename}/README.md";
|
||||
readmeContents =
|
||||
if (builtins.pathExists readme) then
|
||||
(builtins.readFile readme)
|
||||
else
|
||||
throw "No README.md found for module ${modulename}";
|
||||
in
|
||||
readmeContents;
|
||||
|
||||
getShortDescription =
|
||||
modulename:
|
||||
let
|
||||
content = (getReadme modulename);
|
||||
parts = lib.splitString "---" content;
|
||||
description = builtins.head parts;
|
||||
number_of_newlines = builtins.length (lib.splitString "\n" description);
|
||||
in
|
||||
if (builtins.length parts) > 1 then
|
||||
if number_of_newlines > 4 then
|
||||
throw "Short description in README.md for module ${modulename} is too long. Max 3 newlines."
|
||||
else if number_of_newlines <= 1 then
|
||||
throw "Missing short description in README.md for module ${modulename}."
|
||||
else
|
||||
description
|
||||
else
|
||||
throw "Short description delimiter `---` not found in README.md for module ${modulename}";
|
||||
}
|
||||
@@ -17,12 +17,18 @@ let
|
||||
location: ${lib.concatStringsSep "." option.loc}
|
||||
'';
|
||||
|
||||
isExcludedOption = option: (lib.elem (option.type.name or null) excludedTypes);
|
||||
# Exclude the option if its type is in the excludedTypes list
|
||||
# or if the option has a defaultText attribute
|
||||
isExcludedOption =
|
||||
option: ((lib.elem (option.type.name or null) excludedTypes) || (option ? defaultText));
|
||||
|
||||
filterExcluded = lib.filter (opt: !isExcludedOption opt);
|
||||
|
||||
filterExcludedAttrs = lib.filterAttrs (_name: opt: !isExcludedOption opt);
|
||||
|
||||
# Filter out options where the visible attribute is set to false
|
||||
filterInvisibleOpts = lib.filterAttrs (_name: opt: opt.visible or true);
|
||||
|
||||
allBasicTypes = [
|
||||
"boolean"
|
||||
"integer"
|
||||
@@ -47,7 +53,7 @@ rec {
|
||||
parseOptions =
|
||||
options':
|
||||
let
|
||||
options = filterExcludedAttrs (clean options');
|
||||
options = filterInvisibleOpts (filterExcludedAttrs (clean options'));
|
||||
# parse options to jsonschema properties
|
||||
properties = lib.mapAttrs (_name: option: parseOption option) options;
|
||||
# TODO: figure out how to handle if prop.anyOf is used
|
||||
@@ -67,33 +73,37 @@ rec {
|
||||
option:
|
||||
let
|
||||
default = lib.optionalAttrs (option ? default) { inherit (option) default; };
|
||||
example = lib.optionalAttrs (option ? example) {
|
||||
examples =
|
||||
if (builtins.typeOf option.example) == "list" then option.example else [ option.example ];
|
||||
};
|
||||
description = lib.optionalAttrs (option ? description) {
|
||||
description = option.description.text or option.description;
|
||||
};
|
||||
in
|
||||
|
||||
# either type
|
||||
# TODO: if all nested optiosn are excluded, the parent sould be excluded too
|
||||
# TODO: if all nested options are excluded, the parent should be excluded too
|
||||
if
|
||||
option.type.name or null == "either"
|
||||
option.type.name or null == "either" || option.type.name or null == "coercedTo"
|
||||
# return jsonschema property definition for either
|
||||
then
|
||||
let
|
||||
optionsList' = [
|
||||
{
|
||||
type = option.type.nestedTypes.left;
|
||||
type = option.type.nestedTypes.left or option.type.nestedTypes.coercedType;
|
||||
_type = "option";
|
||||
loc = option.loc;
|
||||
}
|
||||
{
|
||||
type = option.type.nestedTypes.right;
|
||||
type = option.type.nestedTypes.right or option.type.nestedTypes.finalType;
|
||||
_type = "option";
|
||||
loc = option.loc;
|
||||
}
|
||||
];
|
||||
optionsList = filterExcluded optionsList';
|
||||
in
|
||||
default // description // { anyOf = map parseOption optionsList; }
|
||||
default // example // description // { anyOf = map parseOption optionsList; }
|
||||
|
||||
# handle nested options (not a submodule)
|
||||
else if !option ? _type then
|
||||
@@ -116,6 +126,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
anyOf = [
|
||||
@@ -128,63 +139,86 @@ rec {
|
||||
option.type.name == "bool"
|
||||
# return jsonschema property definition for bool
|
||||
then
|
||||
default // description // { type = "boolean"; }
|
||||
default // example // description // { type = "boolean"; }
|
||||
|
||||
# parse float
|
||||
else if
|
||||
option.type.name == "float"
|
||||
# return jsonschema property definition for float
|
||||
then
|
||||
default // description // { type = "number"; }
|
||||
default // example // description // { type = "number"; }
|
||||
|
||||
# parse int
|
||||
else if
|
||||
(option.type.name == "int" || option.type.name == "positiveInt")
|
||||
# return jsonschema property definition for int
|
||||
then
|
||||
default // description // { type = "integer"; }
|
||||
default // example // description // { type = "integer"; }
|
||||
|
||||
# TODO: Add support for intMatching in jsonschema
|
||||
# parse port type aka. "unsignedInt16"
|
||||
else if
|
||||
option.type.name == "unsignedInt16"
|
||||
|| option.type.name == "unsignedInt"
|
||||
|| option.type.name == "pkcs11"
|
||||
|| option.type.name == "intBetween"
|
||||
then
|
||||
default // example // description // { type = "integer"; }
|
||||
|
||||
# parse string
|
||||
# TODO: parse more precise string types
|
||||
else if
|
||||
option.type.name == "str"
|
||||
|| option.type.name == "singleLineStr"
|
||||
|| option.type.name == "passwdEntry str"
|
||||
|| option.type.name == "passwdEntry path"
|
||||
# return jsonschema property definition for string
|
||||
then
|
||||
default // description // { type = "string"; }
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# TODO: Add support for stringMatching in jsonschema
|
||||
# parse stringMatching
|
||||
else if lib.strings.hasPrefix "strMatching" option.type.name then
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# TODO: Add support for separatedString in jsonschema
|
||||
else if lib.strings.hasPrefix "separatedString" option.type.name then
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# parse string
|
||||
else if
|
||||
option.type.name == "path"
|
||||
# return jsonschema property definition for path
|
||||
then
|
||||
default // description // { type = "string"; }
|
||||
default // example // description // { type = "string"; }
|
||||
|
||||
# parse anything
|
||||
else if
|
||||
option.type.name == "anything"
|
||||
# return jsonschema property definition for anything
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse unspecified
|
||||
else if
|
||||
option.type.name == "unspecified"
|
||||
# return jsonschema property definition for unspecified
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse raw
|
||||
else if
|
||||
option.type.name == "raw"
|
||||
# return jsonschema property definition for raw
|
||||
then
|
||||
default // description // { type = allBasicTypes; }
|
||||
default // example // description // { type = allBasicTypes; }
|
||||
|
||||
# parse enum
|
||||
else if
|
||||
option.type.name == "enum"
|
||||
# return jsonschema property definition for enum
|
||||
then
|
||||
default // description // { enum = option.type.functor.payload; }
|
||||
default // example // description // { enum = option.type.functor.payload; }
|
||||
|
||||
# parse listOf submodule
|
||||
else if
|
||||
@@ -192,6 +226,7 @@ rec {
|
||||
# return jsonschema property definition for listOf submodule
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "array";
|
||||
@@ -211,6 +246,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "array";
|
||||
@@ -222,7 +258,7 @@ rec {
|
||||
(option.type.name == "listOf") && (option.type.functor.wrapped.name == "unspecified")
|
||||
# return jsonschema property definition for list
|
||||
then
|
||||
default // description // { type = "array"; }
|
||||
default // example // description // { type = "array"; }
|
||||
|
||||
# parse attrsOf submodule
|
||||
else if
|
||||
@@ -230,6 +266,7 @@ rec {
|
||||
# return jsonschema property definition for attrsOf submodule
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
@@ -242,6 +279,7 @@ rec {
|
||||
# return jsonschema property definition for attrs
|
||||
then
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
@@ -262,6 +300,7 @@ rec {
|
||||
};
|
||||
in
|
||||
default
|
||||
// example
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
|
||||
@@ -10,5 +10,11 @@
|
||||
},
|
||||
"services": {
|
||||
"opt": "this option doesn't make sense"
|
||||
},
|
||||
"destinations": {
|
||||
"test-backup": {
|
||||
"name": "John Doe",
|
||||
"repo": "test-backup"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,26 @@
|
||||
];
|
||||
description = "A list of enabled kernel modules";
|
||||
};
|
||||
destinations = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.strMatching "^[a-zA-Z0-9._-]+$";
|
||||
default = name;
|
||||
description = "the name of the backup job";
|
||||
};
|
||||
repo = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "the borgbackup repository to backup to";
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -45,6 +45,27 @@
|
||||
"description": "A submodule option"
|
||||
}
|
||||
}
|
||||
},
|
||||
"destinations": {
|
||||
"additionalProperties": {
|
||||
"properties": {
|
||||
"name": {
|
||||
"default": "‹name›",
|
||||
"description": "the name of the backup job",
|
||||
"type": "string"
|
||||
},
|
||||
"repo": {
|
||||
"description": "the borgbackup repository to backup to",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"repo"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"default": {},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
17
nixosModules/bcachefs.nix
Normal file
17
nixosModules/bcachefs.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# use latest kernel we can support to get more hardware support
|
||||
boot.kernelPackages =
|
||||
lib.mkForce
|
||||
(pkgs.zfs.override { removeLinuxDRM = pkgs.hostPlatform.isAarch64; }).latestCompatibleLinuxPackages;
|
||||
boot.zfs.removeLinuxDRM = lib.mkDefault pkgs.hostPlatform.isAarch64;
|
||||
|
||||
# Enable bcachefs support
|
||||
boot.supportedFilesystems.bcachefs = lib.mkDefault true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
bcachefs-tools
|
||||
keyutils
|
||||
];
|
||||
}
|
||||
@@ -22,8 +22,8 @@
|
||||
'';
|
||||
};
|
||||
clanDir = lib.mkOption {
|
||||
type = lib.types.either lib.types.path lib.types.str;
|
||||
default = ".";
|
||||
type = lib.types.path;
|
||||
default = ./.;
|
||||
description = ''
|
||||
the location of the flake repo, used to calculate the location of facts and secrets
|
||||
'';
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
nix.settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
"repl-flake"
|
||||
];
|
||||
|
||||
# The default at 10 is rarely enough.
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
{
|
||||
flake.nixosModules = {
|
||||
hidden-ssh-announce.imports = [ ./hidden-ssh-announce.nix ];
|
||||
bcachefs.imports = [ ./bcachefs.nix ];
|
||||
installer.imports = [
|
||||
./installer
|
||||
self.nixosModules.hidden-ssh-announce
|
||||
inputs.disko.nixosModules.disko
|
||||
self.nixosModules.bcachefs
|
||||
];
|
||||
clanCore.imports = [
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
inputs.disko.nixosModules.default
|
||||
./clanCore
|
||||
./iso
|
||||
(
|
||||
|
||||
@@ -4,6 +4,38 @@
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
network-status = pkgs.writeShellScript "network-status" ''
|
||||
export PATH=${
|
||||
lib.makeBinPath (
|
||||
with pkgs;
|
||||
[
|
||||
iproute2
|
||||
coreutils
|
||||
gnugrep
|
||||
nettools
|
||||
gum
|
||||
]
|
||||
)
|
||||
}
|
||||
set -efu -o pipefail
|
||||
msgs=()
|
||||
if [[ -e /var/shared/qrcode.utf8 ]]; then
|
||||
qrcode=$(gum style --border-foreground 240 --border normal "$(< /var/shared/qrcode.utf8)")
|
||||
msgs+=("$qrcode")
|
||||
fi
|
||||
network_status="Local network addresses:
|
||||
$(ip -brief -color addr | grep -v 127.0.0.1)
|
||||
$([[ -e /var/shared/onion-hostname ]] && echo "Onion address: $(cat /var/shared/onion-hostname)" || echo "Onion address: Waiting for tor network to be ready...")
|
||||
Multicast DNS: $(hostname).local"
|
||||
network_status=$(gum style --border-foreground 240 --border normal "$network_status")
|
||||
msgs+=("$network_status")
|
||||
msgs+=("Press 'Ctrl-C' for console access")
|
||||
|
||||
gum join --vertical "''${msgs[@]}"
|
||||
'';
|
||||
in
|
||||
{
|
||||
############################################
|
||||
# #
|
||||
@@ -11,19 +43,21 @@
|
||||
# $ qemu-kvm result/stick.raw -snapshot #
|
||||
# #
|
||||
############################################
|
||||
systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ];
|
||||
imports = [
|
||||
(modulesPath + "/profiles/installation-device.nix")
|
||||
(modulesPath + "/profiles/all-hardware.nix")
|
||||
(modulesPath + "/profiles/base.nix")
|
||||
(modulesPath + "/installer/cd-dvd/iso-image.nix")
|
||||
];
|
||||
services.openssh.settings.PermitRootLogin = "yes";
|
||||
system.activationScripts.root-password = ''
|
||||
mkdir -p /var/shared
|
||||
${pkgs.pwgen}/bin/pwgen -s 16 1 > /var/shared/root-password
|
||||
echo "root:$(cat /var/shared/root-password)" | chpasswd
|
||||
'';
|
||||
|
||||
########################################################################################################
|
||||
# #
|
||||
# Copied from: #
|
||||
# https://github.com/nix-community/nixos-images/blob/main/nix/image-installer/module.nix#L46C3-L117C6 #
|
||||
# #
|
||||
########################################################################################################
|
||||
systemd.tmpfiles.rules = [ "d /var/shared 0777 root root - -" ];
|
||||
services.openssh.settings.PermitRootLogin = lib.mkForce "prohibit-password";
|
||||
|
||||
hidden-ssh-announce = {
|
||||
enable = true;
|
||||
script = pkgs.writeShellScript "write-hostname" ''
|
||||
@@ -44,26 +78,48 @@
|
||||
echo "$1" > /var/shared/onion-hostname
|
||||
local_addrs=$(ip -json addr | jq '[map(.addr_info) | flatten | .[] | select(.scope == "global") | .local]')
|
||||
jq -nc \
|
||||
--arg password "$(cat /var/shared/root-password)" \
|
||||
--arg onion_address "$(cat /var/shared/onion-hostname)" \
|
||||
--argjson local_addrs "$local_addrs" \
|
||||
'{ pass: $password, onion_address: $onion_address, addrs: $local_addrs }' \
|
||||
'{ pass: null, tor: $onion_address, addrs: $local_addrs }' \
|
||||
> /var/shared/login.json
|
||||
cat /var/shared/login.json | qrencode -t utf8 -o /var/shared/qrcode.utf8
|
||||
cat /var/shared/login.json | qrencode -s 2 -m 2 -t utf8 -o /var/shared/qrcode.utf8
|
||||
'';
|
||||
};
|
||||
|
||||
services.getty.autologinUser = lib.mkForce "root";
|
||||
|
||||
console.earlySetup = true;
|
||||
console.font = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-u22n.psf.gz";
|
||||
|
||||
# Less ipv6 addresses to reduce the noise
|
||||
networking.tempAddresses = "disabled";
|
||||
|
||||
# Tango theme: https://yayachiken.net/en/posts/tango-colors-in-terminal/
|
||||
console.colors = lib.mkDefault [
|
||||
"000000"
|
||||
"CC0000"
|
||||
"4E9A06"
|
||||
"C4A000"
|
||||
"3465A4"
|
||||
"75507B"
|
||||
"06989A"
|
||||
"D3D7CF"
|
||||
"555753"
|
||||
"EF2929"
|
||||
"8AE234"
|
||||
"FCE94F"
|
||||
"739FCF"
|
||||
"AD7FA8"
|
||||
"34E2E2"
|
||||
"EEEEEC"
|
||||
];
|
||||
|
||||
programs.bash.interactiveShellInit = ''
|
||||
if [[ "$(tty)" =~ /dev/(tty1|hvc0|ttyS0)$ ]]; then
|
||||
echo -n 'waiting for tor to generate the hidden service'
|
||||
until test -e /var/shared/qrcode.utf8; do echo -n .; sleep 1; done
|
||||
echo
|
||||
echo "Root password: $(cat /var/shared/root-password)"
|
||||
echo "Onion address: $(cat /var/shared/onion-hostname)"
|
||||
echo "Local network addresses:"
|
||||
${pkgs.iproute}/bin/ip -brief -color addr | grep -v 127.0.0.1
|
||||
cat /var/shared/qrcode.utf8
|
||||
# workaround for https://github.com/NixOS/nixpkgs/issues/219239
|
||||
systemctl restart systemd-vconsole-setup.service
|
||||
|
||||
watch --no-title --color ${network-status}
|
||||
fi
|
||||
'';
|
||||
isoImage.squashfsCompression = "zstd";
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ let
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
priority = 1; # Needs to be first partition
|
||||
};
|
||||
ESP = {
|
||||
size = "100M";
|
||||
|
||||
13
pkgs/clan-cli/api.py
Normal file
13
pkgs/clan-cli/api.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from clan_cli.api import API
|
||||
|
||||
|
||||
def main() -> None:
|
||||
schema = API.to_json_schema()
|
||||
print(
|
||||
f"""export const schema = {schema} as const;
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -19,7 +19,7 @@ from . import (
|
||||
vms,
|
||||
)
|
||||
from .custom_logger import setup_logging
|
||||
from .dirs import get_clan_flake_toplevel
|
||||
from .dirs import get_clan_flake_toplevel_or_env
|
||||
from .errors import ClanCmdError, ClanError
|
||||
from .profiler import profile
|
||||
from .ssh import cli as ssh_cli
|
||||
@@ -58,6 +58,7 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
||||
"--debug",
|
||||
help="Enable debug logging",
|
||||
action="store_true",
|
||||
default=False,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -77,15 +78,18 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
||||
|
||||
parser.add_argument(
|
||||
"--flake",
|
||||
help="path to the flake where the clan resides in, can be a remote flake or local",
|
||||
default=get_clan_flake_toplevel(),
|
||||
help="path to the flake where the clan resides in, can be a remote flake or local, can be set through the [CLAN_DIR] environment variable",
|
||||
default=get_clan_flake_toplevel_or_env(),
|
||||
metavar="PATH",
|
||||
type=flake_path,
|
||||
)
|
||||
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
parser_backups = subparsers.add_parser(
|
||||
"backups", help="manage backups of clan machines"
|
||||
"backups",
|
||||
help="manage backups of clan machines",
|
||||
description="manage backups of clan machines",
|
||||
)
|
||||
backups.register_parser(parser_backups)
|
||||
|
||||
@@ -107,7 +111,7 @@ def create_parser(prog: str | None = None) -> argparse.ArgumentParser:
|
||||
facts.register_parser(parser_facts)
|
||||
|
||||
parser_machine = subparsers.add_parser(
|
||||
"machines", help="Manage machines and their configuration"
|
||||
"machines", help="manage machines and their configuration"
|
||||
)
|
||||
machines.register_parser(parser_machine)
|
||||
|
||||
|
||||
45
pkgs/clan-cli/clan_cli/api/__init__.py
Normal file
45
pkgs/clan-cli/clan_cli/api/__init__.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from collections.abc import Callable
|
||||
from typing import Any
|
||||
|
||||
|
||||
class _MethodRegistry:
|
||||
def __init__(self) -> None:
|
||||
self._registry: dict[str, Callable] = {}
|
||||
|
||||
def register(self, fn: Callable) -> Callable:
|
||||
self._registry[fn.__name__] = fn
|
||||
return fn
|
||||
|
||||
def to_json_schema(self) -> str:
|
||||
# Import only when needed
|
||||
import json
|
||||
from typing import get_type_hints
|
||||
|
||||
from clan_cli.api.util import type_to_dict
|
||||
|
||||
api_schema: dict[str, Any] = {
|
||||
"$comment": "An object containing API methods. ",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
"required": ["list_machines"],
|
||||
"properties": {},
|
||||
}
|
||||
for name, func in self._registry.items():
|
||||
hints = get_type_hints(func)
|
||||
serialized_hints = {
|
||||
"argument" if key != "return" else "return": type_to_dict(
|
||||
value, scope=name + " argument" if key != "return" else "return"
|
||||
)
|
||||
for key, value in hints.items()
|
||||
}
|
||||
api_schema["properties"][name] = {
|
||||
"type": "object",
|
||||
"required": [k for k in serialized_hints.keys()],
|
||||
"additionalProperties": False,
|
||||
"properties": {**serialized_hints},
|
||||
}
|
||||
|
||||
return json.dumps(api_schema, indent=2)
|
||||
|
||||
|
||||
API = _MethodRegistry()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user