mob next [ci-skip] [ci skip] [skip ci]
lastFile:flake.nix
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
{ inputs, self, ... }:
|
||||||
let
|
let
|
||||||
hosts = import ./modules/hosts.nix;
|
hosts = import ./modules/hosts.nix;
|
||||||
|
|
||||||
@@ -17,173 +18,192 @@ let
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Ensure this is unique among all clans you want to use.
|
clan = {
|
||||||
meta.name = "cnx-network-clan";
|
# Ensure this is unique among all clans you want to use.
|
||||||
meta.domain = "cnx-network.internal";
|
meta.name = "cnx-network-clan";
|
||||||
|
meta.domain = "cnx-network.internal";
|
||||||
|
|
||||||
inventory.machines = fleet;
|
specialArgs = { inherit inputs self; };
|
||||||
|
|
||||||
inventory.instances = {
|
# Customize nixpkgs
|
||||||
|
# pkgsForSystem =
|
||||||
|
# system:
|
||||||
|
# import nixpkgs {
|
||||||
|
# inherit system;
|
||||||
|
# config = {
|
||||||
|
# allowUnfree = true;
|
||||||
|
# };
|
||||||
|
# overlays = [];
|
||||||
|
# };
|
||||||
|
secrets.age.plugins = [
|
||||||
|
"age-plugin-yubikey"
|
||||||
|
"age-plugin-fido2-hmac"
|
||||||
|
];
|
||||||
|
|
||||||
# Admin SSH keys + root password, split per the clan-core migration off
|
inventory.machines = fleet;
|
||||||
# the deprecated `admin` service (sshd handles keys, users the password).
|
|
||||||
sshd = {
|
inventory.instances = {
|
||||||
roles.server.tags.all = { };
|
|
||||||
roles.server.settings.authorizedKeys = {
|
# Admin SSH keys + root password, split per the clan-core migration off
|
||||||
"berwn" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIENAjhGQGraQoAjJzsomKP8GAmQPeGL1rNRNHgRcLqtT";
|
# the deprecated `admin` service (sshd handles keys, users the password).
|
||||||
"kurogeek" =
|
sshd = {
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcZ/p1Ofa9liwIzPWzNtONhJ7+FUWd2lCz33r81t8+w kurogeek@kurogeek";
|
roles.server.tags.all = { };
|
||||||
|
roles.server.settings.authorizedKeys = {
|
||||||
|
"berwn" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIENAjhGQGraQoAjJzsomKP8GAmQPeGL1rNRNHgRcLqtT";
|
||||||
|
"kurogeek" =
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcZ/p1Ofa9liwIzPWzNtONhJ7+FUWd2lCz33r81t8+w kurogeek@kurogeek";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
gw-router = {
|
gw-router = {
|
||||||
module = {
|
module = {
|
||||||
name = "gw-router";
|
name = "gw-router";
|
||||||
input = "self";
|
input = "self";
|
||||||
};
|
};
|
||||||
roles.default.machines."gw-cnx-1" = {
|
roles.default.machines."gw-cnx-1" = {
|
||||||
settings = {
|
settings = {
|
||||||
wan = {
|
wan = {
|
||||||
interface = "enp1s0";
|
interface = "enp1s0";
|
||||||
vlanId = null;
|
vlanId = null;
|
||||||
pppInterface = "enp1s0";
|
pppInterface = "enp1s0";
|
||||||
};
|
};
|
||||||
vlans = {
|
vlans = {
|
||||||
mgmt = {
|
mgmt = {
|
||||||
id = 10;
|
id = 10;
|
||||||
address = "10.1.10.1";
|
address = "10.1.10.1";
|
||||||
prefixLength = 24;
|
prefixLength = 24;
|
||||||
subnet = "10.1.10.0/24";
|
subnet = "10.1.10.0/24";
|
||||||
dhcp.fixIPs.storinator01 = {
|
dhcp.fixIPs.storinator01 = {
|
||||||
hwAddress = "7c:c2:55:e0:d6:40";
|
hwAddress = "7c:c2:55:e0:d6:40";
|
||||||
ipAddress = "10.1.10.53";
|
ipAddress = "10.1.10.53";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
lan = {
|
||||||
|
id = 20;
|
||||||
|
address = "10.1.20.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.20.0/24";
|
||||||
|
};
|
||||||
|
iot = {
|
||||||
|
id = 40;
|
||||||
|
address = "10.1.40.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.40.0/24";
|
||||||
|
};
|
||||||
|
voip = {
|
||||||
|
id = 50;
|
||||||
|
address = "10.1.50.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.50.0/24";
|
||||||
|
};
|
||||||
|
dmz = {
|
||||||
|
id = 60;
|
||||||
|
address = "10.1.60.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.60.0/24";
|
||||||
|
};
|
||||||
|
unit1 = {
|
||||||
|
id = 110;
|
||||||
|
address = "10.1.110.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.110.0/24";
|
||||||
|
};
|
||||||
|
unit2 = {
|
||||||
|
id = 120;
|
||||||
|
address = "10.1.120.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.120.0/24";
|
||||||
|
};
|
||||||
|
unit3 = {
|
||||||
|
id = 130;
|
||||||
|
address = "10.1.130.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.130.0/24";
|
||||||
|
};
|
||||||
|
unit4 = {
|
||||||
|
id = 140;
|
||||||
|
address = "10.1.140.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.140.0/24";
|
||||||
|
};
|
||||||
|
unit5 = {
|
||||||
|
id = 150;
|
||||||
|
address = "10.1.150.1";
|
||||||
|
prefixLength = 24;
|
||||||
|
subnet = "10.1.150.0/24";
|
||||||
|
dhcp.fixIPs.newt = {
|
||||||
|
hwAddress = "7c:d3:0a:21:58:0b";
|
||||||
|
ipAddress = "10.1.150.22";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
lan = {
|
trunkPorts = [ "enp2s0" ];
|
||||||
id = 20;
|
accessPorts = {
|
||||||
address = "10.1.20.1";
|
enp4s0.vlanId = 10;
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.20.0/24";
|
|
||||||
};
|
};
|
||||||
iot = {
|
|
||||||
id = 40;
|
|
||||||
address = "10.1.40.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.40.0/24";
|
|
||||||
};
|
|
||||||
voip = {
|
|
||||||
id = 50;
|
|
||||||
address = "10.1.50.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.50.0/24";
|
|
||||||
};
|
|
||||||
dmz = {
|
|
||||||
id = 60;
|
|
||||||
address = "10.1.60.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.60.0/24";
|
|
||||||
};
|
|
||||||
unit1 = {
|
|
||||||
id = 110;
|
|
||||||
address = "10.1.110.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.110.0/24";
|
|
||||||
};
|
|
||||||
unit2 = {
|
|
||||||
id = 120;
|
|
||||||
address = "10.1.120.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.120.0/24";
|
|
||||||
};
|
|
||||||
unit3 = {
|
|
||||||
id = 130;
|
|
||||||
address = "10.1.130.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.130.0/24";
|
|
||||||
};
|
|
||||||
unit4 = {
|
|
||||||
id = 140;
|
|
||||||
address = "10.1.140.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.140.0/24";
|
|
||||||
};
|
|
||||||
unit5 = {
|
|
||||||
id = 150;
|
|
||||||
address = "10.1.150.1";
|
|
||||||
prefixLength = 24;
|
|
||||||
subnet = "10.1.150.0/24";
|
|
||||||
dhcp.fixIPs.newt = {
|
|
||||||
hwAddress = "7c:d3:0a:21:58:0b";
|
|
||||||
ipAddress = "10.1.150.22";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
trunkPorts = [ "enp2s0" ];
|
|
||||||
accessPorts = {
|
|
||||||
enp4s0.vlanId = 10;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
root-user = {
|
root-user = {
|
||||||
module = {
|
module = {
|
||||||
name = "users";
|
name = "users";
|
||||||
input = "clan-core";
|
input = "clan-core";
|
||||||
|
};
|
||||||
|
roles.default.tags.all = { };
|
||||||
|
roles.default.settings = {
|
||||||
|
user = "root";
|
||||||
|
prompt = false; # auto-generate, like the old admin service
|
||||||
|
share = false; # per-machine password, not fleet-wide
|
||||||
|
};
|
||||||
};
|
};
|
||||||
roles.default.tags.all = { };
|
|
||||||
roles.default.settings = {
|
zerotier = {
|
||||||
user = "root";
|
roles.controller.machines."control" = { };
|
||||||
prompt = false; # auto-generate, like the old admin service
|
roles.peer.tags.all = { };
|
||||||
share = false; # per-machine password, not fleet-wide
|
# External members admitted by ZeroTier node id (stable per device).
|
||||||
|
# Inventory machines are auto-accepted; this is only for peers outside the
|
||||||
|
# clan. Node id comes from `zerotier-cli info` on the joining device.
|
||||||
|
roles.controller.settings.allowedIds = [
|
||||||
|
"8802c8d7e0" # alex-nixos
|
||||||
|
"2bd36db8cc" # kurogeek-thinkpad
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
tor = {
|
||||||
|
roles.server.tags.nixos = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
# Direct SSH to public IPs — clan's priority-1 connection path, with the
|
||||||
|
# ZeroTier mesh and Tor kept as automatic fallbacks. Raw IPs (from
|
||||||
|
# modules/hosts.nix, not the ns1/ns2 DNS names) so reaching these hosts never
|
||||||
|
# depends on their own DNS being up.
|
||||||
|
internet.roles.default.machines = builtins.mapAttrs (_: h: {
|
||||||
|
settings.host = h.ipv4;
|
||||||
|
}) hosts;
|
||||||
|
|
||||||
|
# Recovery root password for console access when a machine fails to boot.
|
||||||
|
emergency-access = {
|
||||||
|
roles.default.tags.nixos = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
# Encrypted, deduplicating backups. control hosts the repos; ns1 is the
|
||||||
|
# only client, backing up its declared clan.core.state (the Knot DNSSEC
|
||||||
|
# keystore) over the mesh. Repo lives at /var/lib/borgbackup/ns1 on control.
|
||||||
|
# Cross-host so an ns1 loss is recoverable; repokey encryption means control
|
||||||
|
# never holds plaintext. Run `clan vars generate ns1` (YubiKey) before deploy.
|
||||||
|
borgbackup = {
|
||||||
|
roles.server.machines.control = { };
|
||||||
|
roles.client.machines.ns1 = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
zerotier = {
|
# Fleet-wide baseline applied to every machine. Secrets minted by
|
||||||
roles.controller.machines."control" = { };
|
# `clan vars generate` are encrypted for the admins group from the very
|
||||||
roles.peer.tags.all = { };
|
# first run — generating before this took effect is what forced the
|
||||||
# External members admitted by ZeroTier node id (stable per device).
|
# re-encryption dance (`clan vars fix`) on gw-cnx-1.
|
||||||
# Inventory machines are auto-accepted; this is only for peers outside the
|
machines = builtins.mapAttrs (_: _: {
|
||||||
# clan. Node id comes from `zerotier-cli info` on the joining device.
|
clan.core.sops.defaultGroups = [ "admins" ];
|
||||||
roles.controller.settings.allowedIds = [
|
}) fleet;
|
||||||
"8802c8d7e0" # alex-nixos
|
|
||||||
"2bd36db8cc" # kurogeek-thinkpad
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
tor = {
|
|
||||||
roles.server.tags.nixos = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
# Direct SSH to public IPs — clan's priority-1 connection path, with the
|
|
||||||
# ZeroTier mesh and Tor kept as automatic fallbacks. Raw IPs (from
|
|
||||||
# modules/hosts.nix, not the ns1/ns2 DNS names) so reaching these hosts never
|
|
||||||
# depends on their own DNS being up.
|
|
||||||
internet.roles.default.machines = builtins.mapAttrs (_: h: {
|
|
||||||
settings.host = h.ipv4;
|
|
||||||
}) hosts;
|
|
||||||
|
|
||||||
# Recovery root password for console access when a machine fails to boot.
|
|
||||||
emergency-access = {
|
|
||||||
roles.default.tags.nixos = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
# Encrypted, deduplicating backups. control hosts the repos; ns1 is the
|
|
||||||
# only client, backing up its declared clan.core.state (the Knot DNSSEC
|
|
||||||
# keystore) over the mesh. Repo lives at /var/lib/borgbackup/ns1 on control.
|
|
||||||
# Cross-host so an ns1 loss is recoverable; repokey encryption means control
|
|
||||||
# never holds plaintext. Run `clan vars generate ns1` (YubiKey) before deploy.
|
|
||||||
borgbackup = {
|
|
||||||
roles.server.machines.control = { };
|
|
||||||
roles.client.machines.ns1 = { };
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Fleet-wide baseline applied to every machine. Secrets minted by
|
|
||||||
# `clan vars generate` are encrypted for the admins group from the very
|
|
||||||
# first run — generating before this took effect is what forced the
|
|
||||||
# re-encryption dance (`clan vars fix`) on gw-cnx-1.
|
|
||||||
machines = builtins.mapAttrs (_: _: {
|
|
||||||
clan.core.sops.defaultGroups = [ "admins" ];
|
|
||||||
}) fleet;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,34 +13,10 @@
|
|||||||
inputs@{
|
inputs@{
|
||||||
self,
|
self,
|
||||||
clan-core,
|
clan-core,
|
||||||
nixpkgs,
|
|
||||||
flake-parts,
|
flake-parts,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
# Usage see: https://docs.clan.lol
|
|
||||||
clan = clan-core.lib.clan {
|
|
||||||
inherit self;
|
|
||||||
imports = [
|
|
||||||
./clan.nix
|
|
||||||
];
|
|
||||||
specialArgs = { inherit inputs self; };
|
|
||||||
|
|
||||||
# Customize nixpkgs
|
|
||||||
# pkgsForSystem =
|
|
||||||
# system:
|
|
||||||
# import nixpkgs {
|
|
||||||
# inherit system;
|
|
||||||
# config = {
|
|
||||||
# allowUnfree = true;
|
|
||||||
# };
|
|
||||||
# overlays = [];
|
|
||||||
# };
|
|
||||||
secrets.age.plugins = [
|
|
||||||
"age-plugin-yubikey"
|
|
||||||
"age-plugin-fido2-hmac"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||||
systems = [
|
systems = [
|
||||||
@@ -51,14 +27,12 @@
|
|||||||
];
|
];
|
||||||
|
|
||||||
imports = [
|
imports = [
|
||||||
|
inputs.clan-core.flakeModules.default
|
||||||
|
|
||||||
|
./clan.nix
|
||||||
./modules/clan/flake-module.nix
|
./modules/clan/flake-module.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# flake = {
|
|
||||||
# inherit (clan.config) nixosConfigurations nixosModules clanInternals;
|
|
||||||
# clan = clan.config;
|
|
||||||
# };
|
|
||||||
|
|
||||||
perSystem =
|
perSystem =
|
||||||
{ system, ... }:
|
{ system, ... }:
|
||||||
let
|
let
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
../../modules/router
|
# ../../modules/router
|
||||||
../../modules/monitoring/exporters.nix
|
../../modules/monitoring/exporters.nix
|
||||||
(import ../../modules/dns/acme-gw-secret.nix "gw-cnx-1")
|
(import ../../modules/dns/acme-gw-secret.nix "gw-cnx-1")
|
||||||
];
|
];
|
||||||
@@ -20,60 +20,60 @@
|
|||||||
builtins.hashString "sha256" config.networking.hostName
|
builtins.hashString "sha256" config.networking.hostName
|
||||||
);
|
);
|
||||||
|
|
||||||
cnx.router = {
|
# cnx.router = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
site = "cnx";
|
# site = "cnx";
|
||||||
siteId = 1;
|
# siteId = 1;
|
||||||
wan.interface = "enp1s0";
|
# wan.interface = "enp1s0";
|
||||||
wan.vlanId = null; # this ISP runs PPPoE untagged on the port
|
# wan.vlanId = null; # this ISP runs PPPoE untagged on the port
|
||||||
trunkPorts = [
|
# trunkPorts = [
|
||||||
"enp2s0"
|
# "enp2s0"
|
||||||
# "enp3s0" # STAGING: serves as the uplink below until cutover
|
# # "enp3s0" # STAGING: serves as the uplink below until cutover
|
||||||
];
|
# ];
|
||||||
# Dedicated on-site recovery port: untagged mgmt, always available even
|
# # Dedicated on-site recovery port: untagged mgmt, always available even
|
||||||
# if the switch config is broken.
|
# # if the switch config is broken.
|
||||||
accessPorts.enp4s0 = "mgmt";
|
# accessPorts.enp4s0 = "mgmt";
|
||||||
# Replaces the newedge.house OPNsense box; renumbered to the fleet
|
# # Replaces the newedge.house OPNsense box; renumbered to the fleet
|
||||||
# convention (10.1.<vlanId>.0/24, router .1, pool .100-.199). The old
|
# # convention (10.1.<vlanId>.0/24, router .1, pool .100-.199). The old
|
||||||
# untagged LAN becomes tagged mgmt — infra switch ports get PVID 10.
|
# # untagged LAN becomes tagged mgmt — infra switch ports get PVID 10.
|
||||||
vlans = {
|
# vlans = {
|
||||||
mgmt = {
|
# mgmt = {
|
||||||
id = 10; # 10.1.10.0/24 — servers, APs, switches, Omada, admin
|
# id = 10; # 10.1.10.0/24 — servers, APs, switches, Omada, admin
|
||||||
dhcp.reservations.storinator01 = {
|
# dhcp.reservations.storinator01 = {
|
||||||
hwAddress = "7c:c2:55:e0:d6:40";
|
# hwAddress = "7c:c2:55:e0:d6:40";
|
||||||
ipAddress = "10.1.10.53";
|
# ipAddress = "10.1.10.53";
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
lan.id = 20; # 10.1.20.0/24 — trusted clients
|
# lan.id = 20; # 10.1.20.0/24 — trusted clients
|
||||||
iot.id = 40; # 10.1.40.0/24
|
# iot.id = 40; # 10.1.40.0/24
|
||||||
voip.id = 50; # 10.1.50.0/24
|
# voip.id = 50; # 10.1.50.0/24
|
||||||
dmz.id = 60; # 10.1.60.0/24
|
# dmz.id = 60; # 10.1.60.0/24
|
||||||
unit1.id = 110; # 10.1.110.0/24
|
# unit1.id = 110; # 10.1.110.0/24
|
||||||
unit2.id = 120; # 10.1.120.0/24
|
# unit2.id = 120; # 10.1.120.0/24
|
||||||
unit3.id = 130; # 10.1.130.0/24
|
# unit3.id = 130; # 10.1.130.0/24
|
||||||
unit4.id = 140; # 10.1.140.0/24
|
# unit4.id = 140; # 10.1.140.0/24
|
||||||
unit5 = {
|
# unit5 = {
|
||||||
id = 150; # 10.1.150.0/24
|
# id = 150; # 10.1.150.0/24
|
||||||
dhcp.reservations.newt = {
|
# dhcp.reservations.newt = {
|
||||||
hwAddress = "7c:d3:0a:21:58:0b";
|
# hwAddress = "7c:d3:0a:21:58:0b";
|
||||||
ipAddress = "10.1.150.22";
|
# ipAddress = "10.1.150.22";
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
# This site runs the Omada controller for its APs/switches.
|
# # This site runs the Omada controller for its APs/switches.
|
||||||
omada.enable = true;
|
# omada.enable = true;
|
||||||
|
#
|
||||||
# Internal reverse proxy: real wildcard cert *.cnx1.cnx.network; Blocky
|
# # Internal reverse proxy: real wildcard cert *.cnx1.cnx.network; Blocky
|
||||||
# resolves the names to the router's LAN address for mgmt+lan clients.
|
# # resolves the names to the router's LAN address for mgmt+lan clients.
|
||||||
proxy = {
|
# proxy = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
services.omada = {
|
# services.omada = {
|
||||||
# Omada's UI is HTTPS with a self-signed cert on the host network.
|
# # Omada's UI is HTTPS with a self-signed cert on the host network.
|
||||||
backend = "https://127.0.0.1:8043";
|
# backend = "https://127.0.0.1:8043";
|
||||||
insecureSkipVerify = true;
|
# insecureSkipVerify = true;
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
};
|
# };
|
||||||
|
|
||||||
# STAGING (remove at cutover, and restore enp3s0 to trunkPorts): DHCP-client
|
# STAGING (remove at cutover, and restore enp3s0 to trunkPorts): DHCP-client
|
||||||
# uplink into the existing OPNsense LAN so the box has internet + mesh while
|
# uplink into the existing OPNsense LAN so the box has internet + mesh while
|
||||||
|
|||||||
Reference in New Issue
Block a user