WIP: ap01-prepare-poc #280
24 changed files with 422 additions and 201 deletions
|
@ -187,11 +187,17 @@ in
|
|||
}))
|
||||
pkgs.npins
|
||||
|
||||
pkgs.rage
|
||||
|
||||
# SSO testing
|
||||
pkgs.kanidm
|
||||
pkgs.freeradius
|
||||
pkgs.picocom # for serial access
|
||||
|
||||
# Daemon-less copy closure for Liminix systems.
|
||||
(pkgs.callPackage (sources.liminix + "/pkgs/min-copy-closure") { nix = pkgs.lix; })
|
||||
# Daemon-less garbage collection for Liminix systems.
|
||||
(pkgs.callPackage (sources.liminix + "/pkgs/min-collect-garbage") { nix = pkgs.lix; })
|
||||
(pkgs.callPackage ./lib/colmena {
|
||||
colmena = pkgs.callPackage "${sources.colmena}/package.nix" { };
|
||||
})
|
||||
|
|
4
hive.nix
4
hive.nix
|
@ -111,12 +111,12 @@ in
|
|||
args;
|
||||
|
||||
defaults =
|
||||
{ name, nodePath, ... }:
|
||||
{ name, ... }:
|
||||
{
|
||||
# Import the default modules
|
||||
imports = [
|
||||
# Import the base configuration for each node
|
||||
./${nodePath}/_configuration.nix
|
||||
./machines/liminix/ap-v01/_configuration.nix
|
||||
./modules/generic
|
||||
./modules/${category name}
|
||||
];
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
{
|
||||
modulesPath,
|
||||
sourcePkgs,
|
||||
name,
|
||||
...
|
||||
}:
|
||||
{
|
||||
|
@ -12,6 +13,7 @@
|
|||
"${modulesPath}/wlan.nix"
|
||||
"${modulesPath}/network"
|
||||
"${modulesPath}/hostapd"
|
||||
"${modulesPath}/usteer"
|
||||
"${modulesPath}/ssh"
|
||||
"${modulesPath}/ntp"
|
||||
"${modulesPath}/vlan"
|
||||
|
@ -29,6 +31,8 @@
|
|||
./addresses.nix
|
||||
# Configures a basic local DNS.
|
||||
./dns.nix
|
||||
# Add ubus daemon
|
||||
./ipc.nix
|
||||
# Configures our management layer, e.g. SSH server + DGNum FAI keys.
|
||||
./management.nix
|
||||
# Configures our recovery system, e.g. a levitation script.
|
||||
|
@ -39,6 +43,6 @@
|
|||
(import "${modulesPath}/../devices/zyxel-nwa50ax").module
|
||||
];
|
||||
|
||||
hostname = "ap01-prototype";
|
||||
hostname = name;
|
||||
nixpkgs.source = sourcePkgs.path;
|
||||
}
|
25
machines/liminix/ap-v01/addresses.nix
Normal file
25
machines/liminix/ap-v01/addresses.nix
Normal file
|
@ -0,0 +1,25 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, nodeMeta, ... }:
|
||||
let
|
||||
svc = config.system.service;
|
||||
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
|
||||
# FIXME switch to ipv6 tu be able to scale
|
||||
adminIp = "10.0.253.${builtins.toString (ap-no + floor * 8 + building * 32 + 2)}";
|
||||
in
|
||||
{
|
||||
services.admin-ip = svc.network.address.build {
|
||||
interface = config.services.admin-vlan;
|
||||
address = adminIp;
|
||||
prefixLength = 24;
|
||||
family = "inet";
|
||||
};
|
||||
|
||||
services.admin-defaultroute4 = svc.network.route.build {
|
||||
via = "10.0.253.1";
|
||||
target = "default";
|
||||
dependencies = [ config.services.admin-ip ];
|
||||
};
|
||||
}
|
25
machines/liminix/ap-v01/dns.nix
Normal file
25
machines/liminix/ap-v01/dns.nix
Normal file
|
@ -0,0 +1,25 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ pkgs, lib, ... }:
|
||||
let
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
# TODO: imho, DNS should be static and provided by the router?
|
||||
dns = [
|
||||
"8.8.8.8"
|
||||
"8.8.4.4"
|
||||
"1.0.0.1"
|
||||
];
|
||||
resolvconf = pkgs.writeText "resolv.conf" (
|
||||
lib.concatMapStringsSep "\n" (dns: ''echo "nameserver ${dns}" >> resolv.conf'') dns
|
||||
);
|
||||
in
|
||||
{
|
||||
# TODO: support dynamic reconfiguration once we are in the target VLAN?
|
||||
filesystem = dir {
|
||||
etc = dir {
|
||||
"resolv.conf" = symlink "${resolvconf}";
|
||||
};
|
||||
};
|
||||
}
|
20
machines/liminix/ap-v01/lan.nix
Normal file
20
machines/liminix/ap-v01/lan.nix
Normal file
|
@ -0,0 +1,20 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, ... }:
|
||||
let
|
||||
svc = config.system.service;
|
||||
in
|
||||
{
|
||||
# Our bridging is a bit complicated, therefore, we need iproute2.
|
||||
programs.iproute2.enable = true;
|
||||
|
||||
services = {
|
||||
admin-vlan = svc.vlan.build {
|
||||
ifname = "admin";
|
||||
primary = config.hardware.networkInterfaces.lan;
|
||||
vid = "3001";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -10,6 +10,7 @@ in
|
|||
# SSH keys are handled by the access control module.
|
||||
dgn-access-control.enable = true;
|
||||
users.root = {
|
||||
# TODO: Change this well-known password
|
||||
passwd = "$6$Z2MiaMXkpUJRPl2/$fxVE3iD/n208CISM2F6OnWj0Qq0QG2tTQqLCjU80PFJJGIwNLLyOp6SeYH3dH20OvJX1loZRETrThZfIPw.rb/";
|
||||
};
|
||||
services.sshd = svc.ssh.build { allowRoot = true; };
|
68
machines/liminix/ap-v01/recovery.nix
Normal file
68
machines/liminix/ap-v01/recovery.nix
Normal file
|
@ -0,0 +1,68 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
let
|
||||
svc = config.system.service;
|
||||
parentConfig = config;
|
||||
in
|
||||
{
|
||||
defaultProfile.packages = [
|
||||
# Levitate enable us to mass-reinstall the system on the fly.
|
||||
# TODO: Test levitation
|
||||
(pkgs.levitate.override {
|
||||
config = {
|
||||
imports = [
|
||||
"${modulesPath}/network"
|
||||
"${modulesPath}/ssh"
|
||||
"${modulesPath}/hardware.nix"
|
||||
"${modulesPath}/kernel"
|
||||
"${modulesPath}/outputs/tftpboot.nix"
|
||||
"${modulesPath}/outputs.nix"
|
||||
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
|
||||
"${modulesPath}/iproute2.nix"
|
||||
(
|
||||
{ config, ... }:
|
||||
{
|
||||
# FIXME: DHCP has a hidden deps on this, shoud be done in a more intelligent way upstream
|
||||
programs.iproute2.enable = true;
|
||||
services = {
|
||||
# In this situation, we fallback to the appro VLAN but keep admin vlan.
|
||||
# Simplest DHCPv4 we can find.
|
||||
dhcpv4 = svc.network.dhcp.client.build {
|
||||
interface = parentConfig.hardware.networkInterfaces.lan;
|
||||
};
|
||||
inherit (parentConfig.services)
|
||||
sshd
|
||||
admin-vlan
|
||||
admin-ip
|
||||
admin-defaultroute4
|
||||
;
|
||||
defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${config.services.dhcpv4} router)";
|
||||
target = "default";
|
||||
dependencies = [ config.services.dhcpv4 ];
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
];
|
||||
hostname = "${parentConfig.hostname}-live";
|
||||
nixpkgs.buildPlatform = builtins.currentSystem;
|
||||
|
||||
defaultProfile.packages = with pkgs; [
|
||||
mtdutils
|
||||
zyxel-bootconfig
|
||||
];
|
||||
# Only keep root, which should inherit from DGN access control's root permissions.
|
||||
users.root = config.users.root;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
|
@ -2,14 +2,28 @@
|
|||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
nodeMeta,
|
||||
...
|
||||
}:
|
||||
let
|
||||
svc = config.system.service;
|
||||
|
||||
inherit (nodeMeta.extraNodeSettings) building floor ap-no;
|
||||
|
||||
hex = x: lib.fixedWidthString 2 "0" (lib.toHexString x);
|
||||
|
||||
mac-1 = "02:5B:6A:${hex (building * 4)}:${hex floor}:${hex ap-no}";
|
||||
mac-2 = "02:5B:6A:${hex (building * 4 + 1)}:${hex floor}:${hex ap-no}";
|
||||
|
||||
secrets-1 = {
|
||||
ssid = "DGNum 2G (N)";
|
||||
ssid = "DGNum";
|
||||
};
|
||||
secrets-2 = {
|
||||
ssid = "DGNum 5G (AX)";
|
||||
ssid = "DGNum";
|
||||
};
|
||||
baseParams = {
|
||||
country_code = "FR";
|
||||
|
@ -42,7 +56,7 @@ let
|
|||
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;
|
||||
channel = 36; # TODO understand interferences
|
||||
vht_oper_centr_freq_seg0_idx = 42;
|
||||
he_oper_centr_freq_seg0_idx = 42;
|
||||
require_vht = 1;
|
||||
|
@ -52,7 +66,7 @@ let
|
|||
ieee8021x = 1;
|
||||
eapol_version = 2;
|
||||
use_pae_group_addr = 1;
|
||||
dynamic_vlan = 0;
|
||||
dynamic_vlan = 3;
|
||||
vlan_tagged_interface = "lan";
|
||||
};
|
||||
|
||||
|
@ -64,7 +78,14 @@ let
|
|||
# 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";
|
||||
auth_server_shared_secret =
|
||||
let
|
||||
secret = builtins.getEnv "RADIUS_SECRET";
|
||||
in
|
||||
if secret == "" then
|
||||
lib.warn "Using a dummy RADIUS secret. Please do not use in production" "DUMMYSECRET"
|
||||
else
|
||||
secret;
|
||||
};
|
||||
|
||||
mkWifiSta =
|
||||
|
@ -77,10 +98,14 @@ let
|
|||
};
|
||||
in
|
||||
{
|
||||
hardware.wlanMacAddresses = {
|
||||
wlan0 = mac-1;
|
||||
wlan1 = mac-2;
|
||||
};
|
||||
services = {
|
||||
# wlan0 is the 2.4GHz interface.
|
||||
hostap-1 = mkWifiSta (
|
||||
baseParams // radiusKeyMgmt
|
||||
baseParams // clientRadius // externalRadius // radiusKeyMgmt
|
||||
) config.hardware.networkInterfaces.wlan0 secrets-1;
|
||||
hostap-1-ready = svc.hostapd-ready.build {
|
||||
interface = config.hardware.networkInterfaces.wlan0;
|
||||
|
@ -93,5 +118,14 @@ in
|
|||
hostap-2-ready = svc.hostapd-ready.build {
|
||||
interface = config.hardware.networkInterfaces.wlan1;
|
||||
};
|
||||
usteer = svc.usteer.build {
|
||||
ifname = "lan";
|
||||
dependencies = with config.services; [
|
||||
# FIXME: is it the right stuff to depend on
|
||||
hostap-1-ready
|
||||
hostap-2-ready
|
||||
admin-defaultroute4
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, ... }:
|
||||
let
|
||||
svc = config.system.service;
|
||||
in
|
||||
{
|
||||
services.dhcpv4 = svc.network.dhcp.client.build {
|
||||
interface = config.services.int;
|
||||
dependencies = [
|
||||
config.services.bridge.components.lan
|
||||
];
|
||||
};
|
||||
|
||||
services.defaultroute4 = svc.network.route.build {
|
||||
via = "$(output ${config.services.dhcpv4} router)";
|
||||
target = "default";
|
||||
dependencies = [ config.services.dhcpv4 ];
|
||||
};
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
inherit (pkgs.liminix.services) oneshot;
|
||||
inherit (pkgs.pseudofile) dir symlink;
|
||||
inherit (pkgs) serviceFns;
|
||||
in
|
||||
{
|
||||
# TODO: support dynamic reconfiguration once we are in the target VLAN?
|
||||
services.resolvconf = oneshot rec {
|
||||
name = "resolvconf";
|
||||
up = ''
|
||||
. ${serviceFns}
|
||||
( in_outputs ${name}
|
||||
for i in $(output ${config.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";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{ config, ... }:
|
||||
let
|
||||
svc = config.system.service;
|
||||
in
|
||||
{
|
||||
services.int = svc.bridge.primary.build {
|
||||
ifname = "int";
|
||||
macAddressFromInterface = config.hardware.networkInterfaces.lan;
|
||||
};
|
||||
|
||||
services.bridge = svc.bridge.members.build {
|
||||
primary = config.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 ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Default VLAN
|
||||
# services.vlan-apro = svc.vlan.build {
|
||||
# vlanId = 0;
|
||||
# interface = config.services.int;
|
||||
# };
|
||||
|
||||
# # Administration VLAN
|
||||
# services.vlan-admin = svc.vlan.build {
|
||||
# vlan = 3001;
|
||||
# interface = config.services.int;
|
||||
# };
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
let
|
||||
svc = config.system.service;
|
||||
in
|
||||
{
|
||||
defaultProfile.packages = with pkgs; [
|
||||
# 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"
|
||||
];
|
||||
nixpkgs.buildPlatform = builtins.currentSystem;
|
||||
services = {
|
||||
# In this situation, we fallback to the appro VLAN.
|
||||
# TODO: add support for the admin VLAN.
|
||||
# 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 ${config.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;
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
|
@ -1,32 +1,32 @@
|
|||
age-encryption.org/v1
|
||||
-> ssh-ed25519 jIXfPA 2nFaxyP7O4GWU7U3wmET5sNrnFq72b9DEhiKEgWVrFk
|
||||
l8uXfCBkTHogzVoUY0WOYhA99fodoT+N0HunacULydI
|
||||
-> ssh-ed25519 QlRB9Q qDalihZE404oPOVHYQR5GIvozXNh4wNxhUa5Zwfz2DU
|
||||
X8qvWf7qprbh0xu/uOHGsNLTQc8efYsgveH9R9kZZZw
|
||||
-> ssh-ed25519 r+nK/Q mksHDhPoKKxQpk4sQPHapdq87EaJmgdmoVxMYjsAang
|
||||
FTYHyxLp4nGOWJu1135yN/lQkGgAD9Jy4JJpMKFktrk
|
||||
-> ssh-ed25519 jIXfPA TdfYeqsPJBf26CO1Bh74K8qxqR1MX3VUvZ/e73+oDXQ
|
||||
KoA/I5kVXxryQ86qjfzq67Aiar+qDZF9OoF4MsNDqe4
|
||||
-> ssh-ed25519 QlRB9Q ZaPziTdzqf0vCkCiLWAUJbnROaZ7Mz+Xgw1viEMWM2s
|
||||
I0peAEQPbaXL9eHQ/OraNuqJPCxIwjpxIxhvgAifATY
|
||||
-> ssh-ed25519 r+nK/Q kgmK60IgdW4QFdKqBQ6S9JmQVoRvpmffVaoNWzfV5Bc
|
||||
ru8etu+7QOmnAoJv8BLtEK0SuDfhB75l525ORrDirvM
|
||||
-> ssh-rsa krWCLQ
|
||||
jEPt5eWP6NmpOikLhs1uPVo7kxHgg1y7WwdOPyR0z2vpFD2BWGlIi/BvnlE3OO5n
|
||||
jtvDjAauWU0X2JarfdY9mY8MoPjT9qQ/ukxuVAHi5CoL/I1JCqcbuftssYY0B7Ab
|
||||
SMfbyxjK8aIT1/4EQhMoWm0tuIylvgTBagL03Lw5mbyRqDkbpI/6YC9401YjT7Ts
|
||||
dCDGIFAYM2BA7TuJiZr881ypUdU9rlm5rss1ZLMj90jyJPJC4SDYbzE0BoBat9l0
|
||||
dYUrYGhGgZ1cDd6D6mPf6H95muiGHIhxaE8c+LdK/rKCSH9Rf6mfn/Ab/xvnaDNn
|
||||
GW/WD0EpmdzpWVPby68+KA
|
||||
-> ssh-ed25519 /vwQcQ 5DoMxdoK+KiHXKwwOpb7/1FZIEzAa/2/1l8yyxey6iw
|
||||
RzmUkqZQLM5/jDXG9fxhZmfAywgVMjH9Y3O66BnhCSQ
|
||||
-> ssh-ed25519 0R97PA g+uW/jfwHB3m0AdWxb9vPRjeaowhEx1Uoc2R0CVStlA
|
||||
m5XvSEVQ8DiA7BSTsxVn6S1zv92CpbyZxSgUI3ObE4c
|
||||
-> ssh-ed25519 JGx7Ng BtdJpskbfPyywYeFbmQw3HGPTLv5ri6x4bFocr9l6H8
|
||||
88aFw+MCJLqMU/W/ikYDUZEAi0ImaPVbSc7cAZPbs/I
|
||||
-> ssh-ed25519 5SY7Kg +JUMQfaxl7Orym43LVeqUyno0JfUbVnB+xv7smpdRhE
|
||||
6K+Ewq1FhrXB2eYdljlsYpIfmVv49E4jSBsphgDpRJk
|
||||
-> ssh-ed25519 p/Mg4Q AITnEN+Q41fEA2tkvVOKGCDZiuCXanG+qaiF5X4ukiA
|
||||
NvP/HXOliNvi8tngH9PU90E616CPlh/QgkZ052H8wtk
|
||||
-> ssh-ed25519 +mFdtQ RuaXIQNZ3s9C27XtpVTExJlAhYDYXRQni+Hwot0wrzU
|
||||
WctqqoGS2hVfOZSU3ihCg5eI7PnxM7dkOJKM9DJ90Wk
|
||||
-> ssh-ed25519 5rrg4g cAqJQ8z6T46YwzahtcTJxXZHklCGrupVCja5U/g+ZmM
|
||||
wERu5T6rOi5/0qPSXeOnfA0Szg7/pbYFTW0Ys1yWq40
|
||||
-> ssh-ed25519 oRtTqQ NF73c0d1qM4nVt2bEdWTEDjDcz/ZMCObn/7cDZfkVGA
|
||||
Mivm+WWVqAfNs5pLwGmINIsmxlEZi7m7bQIRxGkf3/Q
|
||||
--- 8R1h+xsovrLq+5QI1CoTXc9TBTQugnROZpOAHWBwG1w
|
||||
G“Þ"û¤‡ã8ƒÈî‚&NF}x£ksyÖ\£.i§<69>קF¢‹¯}ê-ÍÁÓšLbì;{
|
||||
QsgW7OvOB3cOz9MZI1PQ6Fe208WS+Sv/TWcucjD9i28U6Bty1KYeSwMH/zyzLuSe
|
||||
51TqJTnkb+xGcqw3RvKiM58HMFcl6INmOI8otGxfCQSX7p3/QxiGQBbIgRblxtWB
|
||||
8Jf55hgfh+1+vwTcM+BlBRWz4K581MeQiF2jj6ihfJNwTZ7Q9jNvgzF42znEyZyE
|
||||
QTHoR9ROA/HqLgcrui1L7QnBlP1Y9Bt/oMCh4jFwHfcc6NeHF+I6AEeQNAHH9iNX
|
||||
2+1RsJnQrTM+H204GrpVK78e1B5uCjvq/LeoWSQ3pFD9PwdM6JW2WfkB4FSCriAI
|
||||
7ZAg64qNahyjX+J+KDlrwQ
|
||||
-> ssh-ed25519 /vwQcQ MBPiBQdz65VVKMxJDlTCFUfG084K0ZcGpPJc5RKKND4
|
||||
jH9fRJ/tcGQpZQ+pGNw9lXcRbPS8LLsuwe4EUsaFGDM
|
||||
-> ssh-ed25519 0R97PA bvY5a3GO1CfVmCPJwBfFGJcS+Zkr2QRENa0WyzqspGc
|
||||
YgxthAE4TIPlweuH8cWaOmVGqomc2yfLdzjO8G8bytw
|
||||
-> ssh-ed25519 JGx7Ng 11We2girRvmkDm8eWkTZnazm7Ly0tmECFTdSFnBKIQQ
|
||||
VQ+jlP1sk+SPkHARgAly9U7W0HVbpvZvxLN4V5l6JwE
|
||||
-> ssh-ed25519 bUjjig Zt2Br6ls9INAJ5aQZ/az+6+rIpDCf/NCJP2zusdggms
|
||||
3k0NOSVDpbQFEflEvyTzKv1/zXUBVN5ub9jjOe4EybM
|
||||
-> ssh-ed25519 +mFdtQ inTgQzJVaYt8JZjtrjVzZzW9PscvBnZWkXIpEQYtdFI
|
||||
O/Z7ccZam386C6r2UVJS+OMwG8nZ57RmUy+VJEgWJEY
|
||||
-> ssh-ed25519 5rrg4g ApGMepP+32epekSxCfLGJs6uI38WPjWxtdk+q1Lvx0I
|
||||
huEBiiNzTcz5hPUs+INfDyfeqKtl+mYE38PUizHktyI
|
||||
-> ssh-ed25519 oRtTqQ QBBeZ0kLMPuDmO0hT7LvMs31WuVZATUSyxtCxgMzHgQ
|
||||
HooCKv78+xzYnOwaYXbRNVH1XpG1e8tY0PB246nkFU8
|
||||
-> G8<-grease
|
||||
58RFQqg54Xu8pavoh6wbEnJl7J8XJ5rgaVq1bxokhQ
|
||||
--- +gYhV/IjEqBw3YKDEeSbepgAIIO6A/BcpsYrwCy+Ezs
|
||||
萠%C7図殤チx盟~YヨワZチ{儖情リM<EFBE98>Hハ<48>欷ソXセ<58>ナk@モ9<EFBE93>
|
|
@ -14,19 +14,77 @@
|
|||
# deployment = {}; # Colmena deployment options
|
||||
# nixpkgs = "unstable" or "22.11"; # nixpkgs version
|
||||
# }
|
||||
let
|
||||
nix-lib = import ../../lib/nix-lib;
|
||||
inherit (nix-lib) mapFuse;
|
||||
|
||||
{
|
||||
ap01 = {
|
||||
site = "unknown";
|
||||
adminGroups = [ "fai" ];
|
||||
mkAP' = building: floor: ap-no: {
|
||||
"ap-v01-${builtins.toString building}-${builtins.toString floor}-${builtins.toString ap-no}" = {
|
||||
site = "unknown";
|
||||
adminGroups = [ "fai" ];
|
||||
|
||||
hashedPassword = "$y$j9T$DMOQEWOYFHjNS0myrXp4x/$MG33VSdXGvib.99eN.AbvyVdNNJw4ERjAwK4.ULJe/A";
|
||||
hashedPassword = "$y$j9T$DMOQEWOYFHjNS0myrXp4x/$MG33VSdXGvib.99eN.AbvyVdNNJw4ERjAwK4.ULJe/A";
|
||||
|
||||
stateVersion = null;
|
||||
stateVersion = null;
|
||||
|
||||
nixpkgs = {
|
||||
system = "zyxel-nwa50ax";
|
||||
version = "24.05";
|
||||
nixpkgs = {
|
||||
system = "zyxel-nwa50ax";
|
||||
version = "24.05";
|
||||
};
|
||||
|
||||
extraNodeSettings = {
|
||||
inherit building floor ap-no;
|
||||
vendor-mac = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
Generate all APs nodes for a building. It takes a building definition and returns
|
||||
an attributes set containing all nodes of the AP for the building.
|
||||
|
||||
Building definition:
|
||||
* building-no is the index of the building
|
||||
* floors is the range {from, to{ of floors that contains an AP
|
||||
* ap-nos is the range [from, to{ of AP numbers
|
||||
|
||||
Type: AttrSet -> AttrSet
|
||||
*/
|
||||
mkAPs-building =
|
||||
{
|
||||
building-no,
|
||||
floors,
|
||||
ap-nos,
|
||||
}:
|
||||
mapFuse (f: mapFuse (mkAP' building-no f) (mkRange ap-nos)) (mkRange floors);
|
||||
|
||||
APs = {
|
||||
hypnos-1 = {
|
||||
building-no = 0;
|
||||
floors = {
|
||||
from = 0;
|
||||
to = 3;
|
||||
};
|
||||
ap-nos = {
|
||||
from = 1;
|
||||
to = 7;
|
||||
};
|
||||
};
|
||||
|
||||
hypnos-2 = {
|
||||
building-no = 1;
|
||||
floors = {
|
||||
from = 0;
|
||||
to = 3;
|
||||
};
|
||||
ap-nos = {
|
||||
from = 1;
|
||||
to = 3;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mkRange = { from, to }: builtins.genList (x: x + from) (to - from);
|
||||
in
|
||||
{ }
|
||||
// builtins.foldl' (nodes: building: nodes // mkAPs-building building) { } (builtins.attrValues APs)
|
||||
|
|
|
@ -210,6 +210,12 @@ in
|
|||
default = null;
|
||||
description = "VM cluster where the VM is located";
|
||||
};
|
||||
|
||||
extraNodeSettings = mkOption {
|
||||
type = attrs;
|
||||
default = { };
|
||||
description = "Freeform attribute set to customize the node";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
|
|
|
@ -153,10 +153,10 @@
|
|||
"type": "Git",
|
||||
"url": "https://git.dgnum.eu/DGNum/liminix"
|
||||
},
|
||||
"branch": "main",
|
||||
"revision": "1322de1ee0cdb19fead79e12ab279ee0b575019a",
|
||||
"branch": "mdebray/usteer",
|
||||
"revision": "420b1764c5b5b91c3ddada6dec9bc594847b3cc5",
|
||||
"url": null,
|
||||
"hash": "07nk6nik97k8a57cf17dcj3gn2lbhw1myymrxpqc2aqa3haj754k"
|
||||
"hash": "168qhll6qw5x9v9300mizpshhgmsvvwzp6786z7l1s3jqk3ygf6d"
|
||||
},
|
||||
"linkal": {
|
||||
"type": "Git",
|
||||
|
|
13
scripts/export_secret.sh
Executable file
13
scripts/export_secret.sh
Executable file
|
@ -0,0 +1,13 @@
|
|||
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
DECRYPT=()
|
||||
if [ -f "$HOME/.ssh/id_rsa" ]; then
|
||||
DECRYPT+=(-i "$HOME/.ssh/id_rsa")
|
||||
fi
|
||||
if [ -f "$HOME/.ssh/id_ed25519" ]; then
|
||||
DECRYPT+=(-i "$HOME/.ssh/id_ed25519")
|
||||
fi
|
||||
|
||||
export RADIUS_SECRET=$(rage "${DECRYPT[@]}" -d ./machines/nixos/vault01/secrets/radius-ap-radius-secret_file)
|
16
scripts/extract-firmware-from-zyxel-nwa-fit.sh
Executable file
16
scripts/extract-firmware-from-zyxel-nwa-fit.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p ubootTools
|
||||
|
||||
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
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
|
35
scripts/ftp_zeroday.sh
Executable file
35
scripts/ftp_zeroday.sh
Executable file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -p inetutils -i bash
|
||||
# SPDX-FileCopyrightText: 2024 Maurice Debray <maurice.debray@dgnum.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: EUPL-1.2
|
||||
#
|
||||
# Tribute to RaitoBezarius for finding the exploit
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
usage() {
|
||||
echo "./ftp_zeroday.sh [FIT-IMAGE] [IP]"
|
||||
}
|
||||
if [ "$#" -ne 2 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if ! [ -e "$1" ]; then
|
||||
echo "$1 not found" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
IMAGE="$1"
|
||||
IP="$2"
|
||||
|
||||
echo "Trying to flash $IMAGE to $IP..."
|
||||
|
||||
# TODO: make it exit cleanly
|
||||
ftp -niv <<EOF
|
||||
open $IP
|
||||
user admin 1234
|
||||
binary
|
||||
put $IMAGE
|
||||
EOF
|
||||
|
58
scripts/liminix-rebuild.sh
Executable file
58
scripts/liminix-rebuild.sh
Executable file
|
@ -0,0 +1,58 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# SPDX-FileCopyrightText: 2024 Daniel Barlow <dan@telent.net>
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# TODO: support automatic levitation when the rebuild counts does not fit in the target.
|
||||
# TODO: support preflight checks where we detect the environment we are booted in (this requires the levitation to write a special file).
|
||||
# TODO: use colmena to know the target host and focus on the node name.
|
||||
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
|
||||
;;
|
||||
"--live")
|
||||
echo "Root prefix changed from $root_prefix to /mnt"
|
||||
root_prefix="/mnt"
|
||||
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
|
Loading…
Add table
Reference in a new issue