Compare commits

...

28 commits

Author SHA1 Message Date
ed285ba79d feat(scripts/liminix): fail HARD and support root prefixes
Now that we possess the levitation technology, it's necessary to support
root prefixes for rebuild otherwise we will just overwrite our RAM disk
configuration.

Also, to avoid any issue, let's fail hard and avoid rebooting while
being in levitation for nothing.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:50:33 +02:00
d29deeae56 feat(ap01): use levitation for mass rebuilds
To deal with mass rebuild disk space requirements, we can just levitate.

In the future, we will use levitation as a general-purpose mechanism for
partition layout migration, etc.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:50:33 +02:00
4ed0c435ba feat(ap01): write nixpkgs version in /etc
It's useful for debugging.
We should also track our own revisions at some point.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:50:33 +02:00
c08d6c464f feat(ap01): re-enable 2GHz
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:50:33 +02:00
46d07da404 fix(hive): misc fixes regarding the nixpkgs usage
Previously, we were using <nixpkgs> actually, we fixed liminix and this
file to ensure that we are instantiating the right nixpkgs.

This helps to deal with unexpected mass rebuilds.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:50:33 +02:00
99902d2bb8 chore: upgrade liminix
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-08 00:48:12 +02:00
c0ec57ef22 fix(ap01): bridge only once the WLAN is in operational state
It required a lot of technology, but hey, we now have it.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-07 21:14:27 +02:00
337a71a169 feat(scripts): add Android profile building via Nix
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-05 17:06:40 +02:00
9bf83a60fe fix(ap01): fix _one_ race condition when bridging the LAN
The remaining is hostapd notification that the WLAN interface is ready
to bridge.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-05 14:59:16 +02:00
994e593d3b chore(ap01): cleanup
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-05 14:58:44 +02:00
adb843dd8b feat(ap01): add ubus
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-05 14:58:38 +02:00
45b106190f feat(ap01): disable IPv6
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-01 18:08:41 +02:00
0b94fb5ba7 feat(ap01): external RADIUS + DHCPv4 + jitterRNGd + stable bridge + default route
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-01 18:08:41 +02:00
4fb39070bb fix(sources): update to the latest version of Liminix
With bridge fixes and many other things.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-01 18:08:41 +02:00
47231417cc feat(liminix-rebuild): support hive names directly
Thanks @catvayor, I'm so dumb.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-09-01 17:20:37 +02:00
afd92ab203 feat(devshell): add kanidm & freeradius
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-31 22:38:07 +02:00
270eb4b106 chore(ap01): cleanup
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-31 22:37:46 +02:00
04cb0a9f04 feat(scripts): add liminix-oriented scripts
- extraction for manual recovery via nandwrite
- liminix rebuild to interactively develop the AP

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-31 22:23:04 +02:00
c4d9d6d000 feat(ap01): enable fully RADIUS via internal RADIUS server
This adds two public keys.

For the private keys, heh…

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-31 22:23:04 +02:00
be1673c6aa feat(devshell): add liminix-related tools
serial console, deployment tools and TFTP tool

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-31 22:20:24 +02:00
8b66b2b7c3 feat: add access control for APs via our custom modules
It works!

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-22 18:45:40 +02:00
3ed6ecba31 feat: ensure that colmena repl can evaluate nodes.ap01
Bump to latest Liminix and use the new `defaults` function.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-08-22 15:28:34 +02:00
5a8fe24dce feat: achieve custom evaluation in the framework
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-05-24 18:46:13 +02:00
0a948e6148 feat: Specialize nixpkgs as a function of the system 2024-05-24 18:46:13 +02:00
41ca207b41 feat: wip! wip! wip! 2024-05-24 18:46:01 +02:00
aa6b082b81 feat: enable liminix-rebuild
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-05-24 18:46:01 +02:00
17b2345a02 feat: add liminix-rebuild in the shell
Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-05-24 18:46:01 +02:00
fde8f66ea7 feat: init Liminix evaluation system
Very rudimentary; undocumented, untested in production. This is for testing purposes.

Signed-off-by: Ryan Lahfa <ryan@dgnum.eu>
2024-05-24 18:46:01 +02:00
18 changed files with 662 additions and 87 deletions

View file

@ -37,7 +37,6 @@
let
sources = import ./npins;
pkgs = import sources.nixpkgs { };
pre-commit-check = (import sources.pre-commit-hooks).run {
src = ./.;
@ -71,18 +70,19 @@ in
name = "dgnum-infra";
packages =
(
with pkgs;
[
npins
nixos-generators
attic-client
]
++ (builtins.map (p: callPackage p { }) [
(sources.disko + "/package.nix")
./lib/colmena
])
)
(with pkgs; [
npins
nixos-generators
attic-client
picocom
kanidm # for remote SSO operations
freeradius # for radtest
(callPackage (sources.liminix + "/pkgs/min-copy-closure") { nix = pkgs.lix; })
(callPackage (sources.liminix + "/pkgs/min-collect-garbage") { nix = pkgs.lix; })
(callPackage (sources.liminix + "/pkgs/tufted") { })
(callPackage (sources.disko + "/package.nix") { })
(callPackage ./lib/colmena { colmena = import sources.colmena; })
])
++ (import ./scripts { inherit pkgs; });
shellHook = ''

169
hive.nix
View file

@ -2,6 +2,7 @@ let
sources = import ./npins;
lib = import (sources.nix-lib + "/src/trivial.nix");
lib' = (import sources.nixos-unstable { }).lib;
patch = import sources.nix-patches { patchFile = ./patches; };
@ -14,15 +15,25 @@ let
"_configuration.nix"
"_hardware-configuration.nix"
];
deployment.systemType = systemType node;
};
nixpkgs' = import ./meta/nixpkgs.nix;
# All supported nixpkgs versions, instanciated
nixpkgs = lib.mapSingleFuse mkNixpkgs nixpkgs'.supported;
nixpkgs = lib.mapSingleFuse (
s: lib.mapSingleFuse (mkSystemNixpkgs s) nixpkgs'.versions.supported
) nixpkgs'.systems.supported;
# Get the configured nixos version for the node,
# defaulting to the one defined in meta/nixpkgs
version = node: nodes'.${node}.nixpkgs or nixpkgs'.default;
version = node: nodes'.${node}.nixpkgs or nixpkgs'.versions.default;
system = node: nodes'.${node}.system or nixpkgs'.systems.default;
systemType =
node:
nodes'.${node}.system
or (lib'.warn "Not specifying the `deployment.systemType` is deprecated!" "nixos");
# Builds a patched version of nixpkgs, only as the source
mkNixpkgs' =
@ -35,67 +46,129 @@ let
inherit version;
};
# Instanciates the required nixpkgs version
mkNixpkgs = version: import (mkNixpkgs' version) { };
mkNixpkgsConfigPerSystem =
system: _:
if system == "nixos" then
{ }
else
(import "${sources.liminix}/devices/${system}").system
// {
overlays = [ (import "${sources.liminix}/overlay.nix") ];
config = {
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.8" # Python < 3 is needed for kernel backports.
];
};
};
# Instanciate a specialized version of nixpkgs
mkSystemNixpkgs =
system: version:
let
args = mkNixpkgsConfigPerSystem system version;
in
import (mkNixpkgs' version) args;
###
# Function to create arguments based on the node
#
mkArgs = node: rec {
lib = import sources.nix-lib {
inherit (nixpkgs.${version node}) lib;
mkArgs =
node:
let
pkgs = nixpkgs.${system node};
in
rec {
lib = import sources.nix-lib {
inherit (pkgs.${version node}) lib;
keysRoot = ./keys;
nixpkgs = pkgs;
keysRoot = ./keys;
};
meta = (import ./meta) lib;
nodeMeta = meta.nodes.${node};
};
meta = (import ./meta) lib;
nodeMeta = meta.nodes.${node};
};
in
{
registry = {
zyxel-nwa50ax = {
evalConfig = import "${sources.liminix}/lib/eval-config.nix" {
nixpkgs = sources.nixos-unstable;
};
defaults = _: {
nixpkgs = {
source = sources.nixos-unstable;
config = {
allowUnsupportedSystem = true; # mipsel
permittedInsecurePackages = [
"python-2.7.18.8" # Python < 3 is needed for kernel backports.
];
};
hostPlatform = {
config = "mipsel-unknown-linux-musl";
gcc = {
abi = "32";
arch = "mips32"; # mips32r2?
};
};
# It's impure, but who cares?
# Can Flakes do that?
buildPlatform = builtins.currentSystem;
};
};
};
nixos = {
evalConfig = import "${sources.nixos-unstable}/nixos/lib/eval-config.nix";
defaults =
{ nodeMeta, name, ... }:
{
# Import the default modules
imports = [ ./modules ];
# Include default secrets
age-secrets.sources = [ ./machines/${name}/secrets ];
# Deployment config is specified in meta.nodes.${node}.deployment
inherit (nodeMeta) deployment;
nix = {
# Set NIX_PATH to the patched version of nixpkgs
nixPath = [ "nixpkgs=${mkNixpkgs' (version name)}" ];
optimise.automatic = true;
gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
};
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Use the stateVersion declared in the metadata
system = {
inherit (nodeMeta) stateVersion;
};
};
};
};
meta = {
nodeNixpkgs = lib.mapSingleFuse (n: nixpkgs.${version n}) nodes;
nodeNixpkgs = lib.mapSingleFuse (n: nixpkgs.${system n}.${version n}) nodes;
specialArgs = {
inherit nixpkgs sources;
inherit sources;
};
nodeSpecialArgs = lib.mapSingleFuse mkArgs nodes;
};
defaults =
{ name, nodeMeta, ... }:
{
# Import the default modules
imports = [ ./modules ];
# Include default secrets
age-secrets.sources = [ ./machines/${name}/secrets ];
# Deployment config is specified in meta.nodes.${node}.deployment
inherit (nodeMeta) deployment;
nix = {
# Set NIX_PATH to the patched version of nixpkgs
nixPath = [ "nixpkgs=${mkNixpkgs' (version name)}" ];
optimise.automatic = true;
gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
};
# Allow unfree packages
nixpkgs.config.allowUnfree = true;
# Use the stateVersion declared in the metadata
system = {
inherit (nodeMeta) stateVersion;
};
};
}
// (lib.mapSingleFuse mkNode nodes)

View file

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC6TCCAdECFEbjeqNNzKWyfs2GJekipWK+yO4uMA0GCSqGSIb3DQEBCwUAMHMx
NDAyBgNVBAMMK0RHTnVtIFRlc3QgQVAgQ0EgLS0gRE8gTk9UIFVTRSBPUiBHRVQg
RklSRUQxCzAJBgNVBAYTAkZSMQ4wDAYDVQQIDAVQYXJpczEOMAwGA1UEBwwFUGFy
aXMxDjAMBgNVBAoMBURHTnVtMB4XDTI0MDgyNjE5MDQxMFoXDTI2MDgyNjE5MDQx
MFowdzE4MDYGA1UEAwwvREdOdW0gVGVzdCBBUCBzZXJ2ZXIgLS0gRE8gTk9UIFVT
RSBPUiBHRVQgRklSRUQxCzAJBgNVBAYTAkZSMQ4wDAYDVQQIDAVQYXJpczEOMAwG
A1UEBwwFUGFyaXMxDjAMBgNVBAoMBURHTnVtMIGbMBAGByqGSM49AgEGBSuBBAAj
A4GGAAQBDrTf0SH/YOkOfvOSnB3BbICb80jSsxwQH50y4jylbXcrUZnegLYjW/lF
QknuMBzzE5fnE9lAeOxqsn0ec+sL3zEBrV0LSG2LgxhAkahZS9U4Spt9Qc84U7cG
AFQ3GXDMTEb/COHJSu7sIfV4gFRVesFez30gb94lMxckkq/6nkXXaEUwDQYJKoZI
hvcNAQELBQADggEBAEfPHMAXwftYQ0lDYPlr9b+GZDl7/JAavEfBXKzj1U8O0sJz
daNOHEX3a5ZOaQoean2zmBLROgQpDlwsjAFNA9dg0ef2f4RgJvr/l2fspHwG0Uaq
4JEOKTj3htd8aZX2i6AR02UC2oxCtf7ZVa+a6NOeeKl53QPzjduPO60ruz8tD2Xr
YnQwVinQX0fJo7TmyQKDIxwld/Q5pMoDMfVlS71M/vISFfQ/Rx1PqYvBQyG1dvIA
qn9cNNVnjEGrk7zXjCfehMYiCtDZ+D3VyXeZ6A7YZNpc6RUj8rbWcOtKLayRFlwf
DTjV3/nPqV0M2nU6jXFBMfQ47VSfB7ibINt94xo=
-----END CERTIFICATE-----

View file

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDxzCCAq+gAwIBAgIUPuHEZeZoCidp+w5ME2CrkZEn3T8wDQYJKoZIhvcNAQEL
BQAwczE0MDIGA1UEAwwrREdOdW0gVGVzdCBBUCBDQSAtLSBETyBOT1QgVVNFIE9S
IEdFVCBGSVJFRDELMAkGA1UEBhMCRlIxDjAMBgNVBAgMBVBhcmlzMQ4wDAYDVQQH
DAVQYXJpczEOMAwGA1UECgwFREdOdW0wHhcNMjQwODI2MTg1ODQ4WhcNMjkwODI2
MTg1ODQ4WjBzMTQwMgYDVQQDDCtER051bSBUZXN0IEFQIENBIC0tIERPIE5PVCBV
U0UgT1IgR0VUIEZJUkVEMQswCQYDVQQGEwJGUjEOMAwGA1UECAwFUGFyaXMxDjAM
BgNVBAcMBVBhcmlzMQ4wDAYDVQQKDAVER051bTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKLgCNXLI6FQWJY5JQDqZcO1hmZpp0upT59/JvJXmEl4St1O
FF3frSAoFcgn2Bv3kYQQ6wEhD3S7JBxRmoDtx/7sqsXthNpBaymVdphb9XhnVOC2
NDBKV4WH06Hr06oKVfDSBhIldPJr1vfQLehOnz6uqK7walqPvid3tMv0lwt7mHZ9
qQpgC2C/tkHwD1kh1RszoIZKIQWDnSNXPhYnB3X/DMCUWIKiz6P/0rVANEDDZER6
b6eJRjv2l8jPlOt7CUTAOrsoJGCnSg2SV4lgr1u3mE/2AvmLdO0l5Dz0qCuQNbb3
uWqYUonooR8rox171On/Rd0zvtihycSDxofVJ+MCAwEAAaNTMFEwHQYDVR0OBBYE
FIPUT3v8AoeBS6VbcEvgVc1dC38hMB8GA1UdIwQYMBaAFIPUT3v8AoeBS6VbcEvg
Vc1dC38hMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACX1aqYU
9PIwZ/dBS7cpsBsCm9M0ueInTlQpvv6xioKuPhIet40YgawTRakxniAr0WXHTBV5
a8ZQ4ff4uI+sdaxN7Ueufr4ltWVLuSc9DfIxjLVZ+41G6Ehy9Xc2zoDBfYURrXjd
ISvPSXIKjM0yuS/249C77HOdzwbliS65Io2zubQStGfSaZ3sLAfPJoig+QiVyOtG
sPoYzzrjXDBym+plfGTWqHv+gwo6DZarXrK4yaMn4hYkkf95NsY2ywwHzcy/4hsu
+bMm4IeCrB9uNOZtQrqW81/+4oxjGiKLbhnFPNQOg2pzb+iOJTPKVicAqKDSCnou
WXG5pjBKzojPvxU=
-----END CERTIFICATE-----

1
liminix-rebuild.nix Normal file
View file

@ -0,0 +1 @@
{ liminix-system }: (import ./liminix-hive.nix { }).${liminix-system}.primary

View file

@ -0,0 +1,259 @@
{
config,
pkgs,
modulesPath,
...
}:
let
inherit (pkgs.liminix.services) oneshot;
inherit (pkgs.pseudofile) symlink dir;
inherit (pkgs) serviceFns;
svc = config.system.service;
secrets-1 = {
ssid = "DGNum 2G prototype (N)";
};
secrets-2 = {
ssid = "DGNum 5G prototype (AX)";
};
baseParams = {
country_code = "FR";
hw_mode = "g";
channel = 6;
wmm_enabled = 1;
ieee80211n = 1;
ht_capab = "[LDPC][GF][HT40-][HT40+][SHORT-GI-40][MAX-AMSDU-7935][TX-STBC]";
auth_algs = 1;
wpa = 2;
wpa_pairwise = "TKIP CCMP";
rsn_pairwise = "CCMP";
};
radiusKeyMgmt = {
wpa_key_mgmt = "WPA-EAP";
};
modernParams = {
hw_mode = "a";
he_su_beamformer = 1;
he_su_beamformee = 1;
he_mu_beamformer = 1;
preamble = 1;
# Allow radar detection.
ieee80211d = 1;
ieee80211h = 1;
ieee80211ac = 1;
ieee80211ax = 1;
vht_capab = "[MAX-MPDU-7991][SU-BEAMFORMEE][SU-BEAMFORMER][RXLDPC][SHORT-GI-80][MAX-A-MPDU-LEN-EXP3][RX-ANTENNA-PATTERN][TX-ANTENNA-PATTERN][TX-STBC-2BY1][RX-STBC-1][MU-BEAMFORMER]";
vht_oper_chwidth = 1;
he_oper_chwidth = 1;
channel = 36;
vht_oper_centr_freq_seg0_idx = 42;
he_oper_centr_freq_seg0_idx = 42;
require_vht = 1;
};
clientRadius = {
ieee8021x = 1;
eapol_version = 2;
use_pae_group_addr = 1;
dynamic_vlan = 0;
vlan_tagged_interface = "lan";
};
externalRadius = {
# TODO: when we have proper IPAM, set the right value here.
own_ip_addr = "127.0.0.1";
nas_identifier = "ap01.dgnum.eu";
# No DNS here, hostapd do not support this mode.
auth_server_addr = "129.199.195.129";
auth_server_port = 1812;
auth_server_shared_secret = "read it online";
};
mkWifiSta =
params: interface: secrets:
svc.hostapd.build {
inherit interface;
package = pkgs.hostapd-radius;
params = params // secrets;
dependencies = [ config.services.jitter ];
};
in
rec {
imports = [
"${modulesPath}/wlan.nix"
"${modulesPath}/network"
"${modulesPath}/dhcp6c"
"${modulesPath}/hostapd"
"${modulesPath}/ssh"
"${modulesPath}/ntp"
"${modulesPath}/vlan"
"${modulesPath}/bridge"
"${modulesPath}/jitter-rng"
"${modulesPath}/pki"
"${modulesPath}/ubus"
../../modules/dgn-access-control.nix
# TODO: god that's so a fucking hack.
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
];
hostname = "ap01-prototype";
# Get moar random please
services.jitter = svc.jitter-rng.build { };
services.ubus = svc.ubus.build { };
# SSH keys are handled by the access control module.
dgn-access-control.enable = true;
users.root = {
passwd = "$6$jVXFFOp8HBYmgINR$lutB4kvw.W1jlXRby9ZYAgBitQ32RxQdYAGN.s2x4ris8J07vM6tzlRBQoeLELOIEMClDzbciQV0itfHQnTqd1";
};
services.int = svc.bridge.primary.build {
ifname = "int";
macAddressFromInterface = config.hardware.networkInterfaces.lan;
};
services.bridge = svc.bridge.members.build {
primary = services.int;
members = {
lan.member = config.hardware.networkInterfaces.lan;
wlan0 = {
member = config.hardware.networkInterfaces.wlan0;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-1-ready ];
};
wlan1 = {
member = config.hardware.networkInterfaces.wlan1;
# Bridge only once hostapd is ready.
dependencies = [ config.services.hostap-2-ready ];
};
};
};
services.resolvconf = oneshot rec {
name = "resolvconf";
up = ''
. ${serviceFns}
( in_outputs ${name}
for i in $(output ${services.dhcpv4} dns); do
echo "nameserver $i" >> resolv.conf
done
)
'';
dependencies = [
config.services.dhcpv4
];
};
filesystem = dir {
etc = dir {
"resolv.conf" = symlink "${config.services.resolvconf}/.outputs/resolv.conf";
"nixpkgs.version" = {
type = "f";
file = "${pkgs.lib.version}";
mode = "0444";
};
};
};
services.dhcpv4 = svc.network.dhcp.client.build {
interface = config.services.int;
dependencies = [
config.services.hostname
config.services.bridge.components.lan
];
};
# TODO(raito): these won't work with RAs
# fix them in Liminix directly and re-enable.
# services.dhcpv6 = svc.dhcp6c.client.build {
# interface = config.services.int;
# dependencies = [
# config.services.hostname
# config.services.bridge
# ];
# };
# services.ipv6 = svc.dhcp6c.address.build {
# interface = config.services.int;
# client = config.services.dhcpv6;
# dependencies = [ config.services.hostname ];
# };
services.defaultroute4 = svc.network.route.build {
via = "$(output ${services.dhcpv4} router)";
target = "default";
dependencies = [ services.dhcpv4 ];
};
services.packet_forwarding = svc.network.forward.build { };
services.sshd = svc.ssh.build { allowRoot = true; };
services.ntp = config.system.service.ntp.build {
pools = {
"pool.ntp.org" = [ "iburst" ];
};
dependencies = [ config.services.jitter ];
};
boot.tftp = {
serverip = "192.0.2.10";
ipaddr = "192.0.2.12";
};
# wlan0 is the 2.4GHz interface.
services.hostap-1 = mkWifiSta (
baseParams // radiusKeyMgmt
) config.hardware.networkInterfaces.wlan0 secrets-1;
services.hostap-1-ready = svc.hostapd-ready.build {
interface = config.hardware.networkInterfaces.wlan0;
};
# wlan1 is the 5GHz interface, e.g. AX capable.
services.hostap-2 = mkWifiSta (
baseParams // clientRadius // externalRadius // radiusKeyMgmt // modernParams
) config.hardware.networkInterfaces.wlan1 secrets-2;
# Oneshot that waits until the hostapd has set the interface in operational state.
services.hostap-2-ready = svc.hostapd-ready.build {
interface = config.hardware.networkInterfaces.wlan1;
};
defaultProfile.packages = with pkgs; [
zyxel-bootconfig
min-collect-garbage
iwinfo
ifwait
# Levitate enable us to mass-reinstall the system on the fly.
(levitate.override {
config = {
imports = [
"${modulesPath}/network"
"${modulesPath}/ssh"
"${modulesPath}/hardware.nix"
"${modulesPath}/kernel"
"${modulesPath}/outputs/tftpboot.nix"
"${modulesPath}/outputs.nix"
];
services = {
# Simplest DHCPv4 we can find.
dhcpv4 = svc.network.dhcp.client.build {
interface = config.hardware.networkInterfaces.lan;
};
inherit (config.services) sshd;
defaultroute4 = svc.network.route.build {
via = "$(output ${services.dhcpv4} router)";
target = "default";
dependencies = [ config.services.dhcpv4 ];
};
};
defaultProfile.packages = [ mtdutils ];
# Only keep root, which should inherit from DGN access control's root permissions.
users.root = config.users.root;
};
})
];
}

View file

@ -0,0 +1 @@
{ }

View file

@ -1,10 +1,23 @@
{
# Default version of nixpkgs to use
default = "23.11";
versions = {
# Default version of nixpkgs to use
default = "23.11";
# Supported nixpkgs versions
supported = [
"unstable"
"23.11"
];
# Supported nixpkgs versions
supported = [
"unstable"
"23.11"
];
};
systems = {
# Default target system
default = "nixos";
# Supported target systems
supported = [
"nixos"
"zyxel-nwa50ax"
];
};
}

View file

@ -86,4 +86,12 @@
stateVersion = "23.11";
vm-cluster = "Hyperviseur Luj";
};
# Access points definition
ap01 = {
site = "unknown";
adminGroups = [ "fai" ];
system = "zyxel-nwa50ax";
};
}

View file

@ -11,6 +11,7 @@ let
inherit (lib.types)
attrs
attrsOf
enum
ints
listOf
nullOr
@ -35,6 +36,7 @@ let
};
org = config.organization;
nixpkgs = import ./nixpkgs.nix;
in
{
@ -124,8 +126,8 @@ in
};
nixpkgs = mkOption {
type = str;
inherit (import ./nixpkgs.nix) default;
type = enum nixpkgs.versions.supported;
inherit (nixpkgs.versions) default;
description = ''
Version of nixpkgs to use.
'';
@ -167,6 +169,14 @@ in
default = null;
description = "VM cluster where the VM is located";
};
system = mkOption {
type = enum nixpkgs.systems.supported;
inherit (nixpkgs.systems) default;
description = ''
Type of system for the node, will impact how it is evaluated and deployed.
'';
};
};
config = {

View file

@ -87,6 +87,12 @@
"fai"
];
# AP administration DGNum
ap.adminGroups = [
"root"
"fai"
];
# Videos DGNum
peertube.admins = [ "thubrecht" ];
};

View file

@ -44,6 +44,7 @@ let
mkDefault
mkEnableOption
mkIf
mkMerge
mkOption
types
@ -78,12 +79,20 @@ in
};
};
config = mkIf cfg.enable {
# Admins have root access to the node
dgn-access-control.users.root = mkDefault admins;
users.users = builtins.mapAttrs (_: members: {
openssh.authorizedKeys.keys = lib.extra.getAllKeys members;
}) cfg.users;
};
config = mkIf cfg.enable (mkMerge [
{
# Admins have root access to the node
dgn-access-control.users.root = mkDefault admins;
}
(mkIf (nodeMeta.system == "nixos") {
users.users = builtins.mapAttrs (_: members: {
openssh.authorizedKeys.keys = lib.extra.getAllKeys members;
}) cfg.users;
})
(mkIf (nodeMeta.system == "zyxel-nwa50ax") {
users = builtins.mapAttrs (_: members: {
openssh.authorizedKeys.keys = lib.extra.getAllKeys members;
}) cfg.users;
})
]);
}

View file

@ -42,6 +42,7 @@ let
builtins.fetchGit {
inherit (repository) url;
rev = revision;
allRefs = true;
# hash = hash;
};

View file

@ -9,6 +9,7 @@
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "0.15.0",
"revision": "564595d0ad4be7277e07fa63b5a991b3c645655d",
"url": "https://api.github.com/repos/ryantm/agenix/tarball/0.15.0",
@ -38,6 +39,17 @@
"url": "https://github.com/zhaofengli/attic/archive/4dbdbee45728d8ce5788db6461aaaa89d98081f0.tar.gz",
"hash": "1iri77pbf0gvas93zra29qy1c3l61n97z84xblqxmmhsxvljzvnh"
},
"colmena": {
"type": "Git",
"repository": {
"type": "Git",
"url": "https://git.dgnum.eu/DGNum/colmena.git"
},
"branch": "custom-activation",
"revision": "1037471d800d3db42ec85b89787bec5472f5e574",
"url": null,
"hash": "0k287292yr78zymdglppa8jd0b4kh0x277d4bycwcdsqprw00a4x"
},
"disko": {
"type": "GitRelease",
"repository": {
@ -47,6 +59,7 @@
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "v1.6.0",
"revision": "5eaf747af38dd272e1ab28a8ec4bd972424b07cf",
"url": "https://api.github.com/repos/nix-community/disko/tarball/v1.6.0",
@ -60,6 +73,7 @@
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "v1.2.1",
"revision": "66979725afe2164491be38ffff78460cc9b0ffd7",
"url": null,
@ -68,14 +82,13 @@
"liminix": {
"type": "Git",
"repository": {
"type": "GitHub",
"owner": "RaitoBezarius",
"repo": "liminix"
"type": "Git",
"url": "https://git.dgnum.eu/DGNum/liminix.git"
},
"branch": "nwa50ax",
"revision": "a4aa10dcc30225a8bb8eb465abfe908629175f2c",
"url": "https://github.com/RaitoBezarius/liminix/archive/a4aa10dcc30225a8bb8eb465abfe908629175f2c.tar.gz",
"hash": "1m1sc6agg5z65lmyjl48i7sddlwm8d0zgvs8z81iammfy4jpy7qd"
"branch": "main",
"revision": "6970d811e87a3a99a093705cb089a5a63961cfe7",
"url": null,
"hash": "08fwry3zkhlkcl1lrqhhhqj3a47mgc41bvfv518zg8xhwzg7ifnz"
},
"linkal": {
"type": "Git",
@ -108,6 +121,7 @@
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "0.1.6",
"revision": "ffb3dfa4c146d48300bd4fa625acfe48e091a734",
"url": null,
@ -132,6 +146,7 @@
},
"pre_releases": false,
"version_upper_bound": null,
"release_prefix": null,
"version": "v0.5.0",
"revision": "e11ba20945f4a867f09d84343c37328288f274b4",
"url": null,
@ -152,8 +167,8 @@
"nixpkgs": {
"type": "Channel",
"name": "nixpkgs-unstable",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.05pre622672.ad7efee13e0d/nixexprs.tar.xz",
"hash": "0ng26dp73sd5dffw8wl4pwfmrgp2p03xbp4l1lxwlhcw6874fk4l"
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-24.11pre670424.5de1564aed41/nixexprs.tar.xz",
"hash": "1m31bsq9mawjgbxzg4mihk9blfm419451vdsk30llbrj4w4s159w"
},
"pre-commit-hooks": {
"type": "Git",

View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="US-ASCII"?>
<WLANProfile xmlns="https://www.microsoft.com/networking/WLAN/profile/v1">
<name>DGNumRadius</name>
<SSIDConfig>
<SSID>
<name>@SSID@</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>auto</connectionMode>
<MSM>
<security>
<authEncryption>
<authentication>WPA2</authentication>
<encryption>AES</encryption>
<useOneX>true</useOneX>
</authEncryption>
<OneX xmlns="https://www.microsoft.com/networking/OneX/v1">
<EAPConfig>
<EapHostConfig xmlns="https://www.microsoft.com/provisioning/EapHostConfig"
xmlns:eapCommon="https://www.microsoft.com/provisioning/EapCommon"
xmlns:baseEap="https://www.microsoft.com/provisioning/BaseEapMethodConfig">
<EapMethod>
<eapCommon:Type>25</eapCommon:Type>
<eapCommon:AuthorId>0</eapCommon:AuthorId>
</EapMethod>
<Config xmlns:baseEap="https://www.microsoft.com/provisioning/BaseEapConnectionPropertiesV1"
xmlns:msPeap="https://www.microsoft.com/provisioning/MsPeapConnectionPropertiesV1"
xmlns:msChapV2="https://www.microsoft.com/provisioning/MsChapV2ConnectionPropertiesV1"
xmlns:msChapV2User="https://www.microsoft.com/provisioning/MsChapV2UserPropertiesV1">
<baseEap:Eap>
<baseEap:Type>25</baseEap:Type>
<msPeap:EapType>
<msPeap:ServerValidation>
<msPeap:DisableUserPromptForServerValidation>false</msPeap:DisableUserPromptForServerValidation>
<msPeap:TrustedRootCA />
</msPeap:ServerValidation>
<msPeap:FastReconnect>true</msPeap:FastReconnect>
<msPeap:InnerEapOptional>0</msPeap:InnerEapOptional>
<msPeap:ServerNames>radius.dgnum.eu</msPeap:ServerNames>
<baseEap:Eap>
<baseEap:Type>26</baseEap:Type>
<msChapV2:EapType>
<msChapV2:UseWinLogonCredentials>false</msChapV2:UseWinLogonCredentials>
</msChapV2:EapType>
<msChapV2User:EapType>
<msChapV2User:Username>@USERNAME@</msChapV2User:Username>
<msChapV2User:Password>@PASSWORD@</msChapV2User:Password>
</msChapV2User>
</baseEap:Eap>
<msPeap:EnableQuarantineChecks>false</msPeap:EnableQuarantineChecks>
<msPeap:RequireCryptoBinding>false</msPeap:RequireCryptoBinding>
<msPeap:PeapExtensions />
</msPeap:EapType>
</baseEap:Eap>
</Config>
</EapHostConfig>
</EAPConfig>
</OneX>
</security>
</MSM>
</WLANProfile>

View file

@ -0,0 +1,19 @@
{
pkgs ? import <nixpkgs> { },
username,
domain ? "sso.dgnum.eu",
ssid ? "DGNum 5G prototype (AX)",
password,
}:
pkgs.runCommand "connection-${username}-android-profile.xml"
{
SSID = ssid;
USERNAME = "${username}@${domain}";
PASSWORD = password;
}
''
substitute ${./android-profile-template.xml} $out \
--subst-var SSID \
--subst-var USERNAME \
--subst-var PASSWORD
''

View file

@ -0,0 +1,12 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p ubootTools
usage() {
echo "extract the firmware part to write it manually from a Zyxel NWA FIT image"
echo "$0 <zyxel_nwa_fit_image_path> <firmware_output_file>"
}
ZYXEL_NWA_FIT="$1"
FIRMWARE_OUTPUT="$2"
dumpimage -T flat_dt -p 0 $ZYXEL_NWA_FIT -o $FIRMWARE_OUTPUT

45
scripts/liminix-rebuild.sh Executable file
View file

@ -0,0 +1,45 @@
#!/usr/bin/env bash
set -Eeuo pipefail
ssh_command=${SSH_COMMAND-ssh}
root_prefix=${ROOT_PREFIX-/}
reboot="reboot"
case "$1" in
"--no-reboot")
unset reboot
shift
;;
"--fast")
reboot="soft"
shift
;;
esac
target_host=$1
shift
if [ -z "$target_host" ] ; then
echo Usage: liminix-rebuild \[--no-reboot\] target-host params
exit 1
fi
if toplevel="$(nom-build $(colmena eval -E "{ nodes, ... }: nodes.$@.config.system.outputs.systemConfiguration" --instantiate))"; then
echo systemConfiguration $toplevel aimed at $root_prefix
sleep 3
min-copy-closure --root "$root_prefix" $target_host $toplevel
$ssh_command $target_host "$root_prefix/$toplevel/bin/install" "$root_prefix"
case "$reboot" in
reboot)
$ssh_command $target_host "sync; source /etc/profile; reboot"
;;
soft)
$ssh_command $target_host $toplevel/bin/restart-services
;;
*)
;;
esac
else
echo Rebuild failed
fi