diff --git a/README.md b/README.md index c66022e..4c93de4 100644 --- a/README.md +++ b/README.md @@ -35,14 +35,16 @@ | **No flakes** | Simplify onboarding and avoid a steep learning curve. | Configuration via `configuration.nix` + `callPackage`. | | **Modular structure** | Separate configurations by machine type and service. | Clear and maintainable directory tree. | | **Servers named by service, not by application** | Indicate what the machine does (git01 = Git forge) rather than the software (Gitea). Allows changing the underlying app without renaming. | Hosts under `hosts/servers/01` (e.g. `git01`, `pass01`, `dns01`). | -| **Modules** | Make modules autonomous, portable, and reusable. | Each module is an independent Nix package. | +| **Modules** | Make modules autonomous, portable, and reusable. | Each module is an independent Nix package. | | **Separation of `user-profiles/` and `users/`** | Distinguish generic roles (e.g., `admin`) from concrete users (e.g., `xavier`). | Flexibility to apply profiles to multiple users. | | **`deploy.sh` script** | Automate deployment on existing machines. | Clone/update the repo + `nixos-rebuild switch`. | | **`create-lxc-nixos.sh` script** | Automate the creation of NixOS LXC containers on Proxmox. | Ready-to-use container with initial configuration. | | **Initial configuration (`initial-configuration.nix`)** | Prepare an LXC container so it can update itself via Git. | Self-sufficient containers. | | **Secret management with `agenix`** | Encrypt secrets (passwords, keys) for secure storage. | Enhanced security for sensitive data. | | **Unprivileged LXC containers (`--unprivileged 0`)** | NixOS requires privileges to function correctly in LXC. | Functional containers with NixOS. | -| **IPv4, IPv6, VLAN support** | Final target is IPv6-first, or even IPv6-only. | IP plan management to be designed. | +| **Centralised network data** | A single declarative network data source (`network/`) consumed by NixOS configs and scripts. | VLANs, subnets, host addresses defined once in `network/hosts.nix`. | +| **IPv6-first with dual-stack** | Both ULA (fdb2:) and GUA (2a01:) prefixes defined per VLAN. | Consistent internal addressing + global reachability for DMZ services. | +| **DHCP-based IPv4 assignment** | LXC containers use `useDHCP = true`. Addresses are reserved in `hosts.nix` as source of truth. | Centralised address management, no static IPs in per-host configs. | --- @@ -82,6 +84,13 @@ nixos-infra/ │ └── gaia/ # Xavier's laptop (audio) │ └── configuration.nix │ +├── network/ # Centralised network data (VLANs, subnets, hosts) +│ ├── default.nix # Aggregator — imports vlans, subnets, hosts +│ ├── vlans.nix # VLAN definitions +│ ├── subnets.nix # Subnet prefix allocations +│ ├── hosts.nix # Per-machine IP/address assignments +│ └── README.md # Network architecture documentation +│ ├── modules/ # Autonomous modules │ ├── machine-types/ # Machine types │ │ ├── hypervisor.nix # Module for hypervisors @@ -157,20 +166,35 @@ nixos-infra/ ### **1. Machine List** -| Name | Machine Type | Services | IPv4 | IPv6 Token | -| ----------| --------------------| -------------| ------| ------------| -| hyper01 | Hypervisor | Proxmox | | | -| hyper02 | Hypervisor | Proxmox | | | -| dns01 | LXC Container | DNS | | | -| git01 | LXC Container | Git forge | | | -| pass01 | LXC Container | Password mgr| | | -| rp01 | LXC Container | Reverse proxy| | | -| sting | Workstation | | | | -| PC-FRIDA | Workstation | | | | +| Name | Machine Type | VLAN | IPv4 | IPv6 Token | +| ----------| --------------------| ---------| ------------------| ------------| +| hyper01 | Hypervisor | ADMIN | 10.10.128.10/16 | ::10 | +| hyper02 | Hypervisor | ADMIN | 10.10.128.11/16 | ::11 | +| dns01 | LXC Container | DMZ | 10.40.128.10/16 | ::10 | +| dns02 | LXC Container | DMZ | 10.40.128.11/16 | ::11 | +| git01 | LXC Container | DMZ | 10.40.128.20/16 | ::20 | +| pass01 | LXC Container | DMZ | 10.40.128.30/16 | ::30 | +| rp01 | LXC Container | DMZ | 10.40.128.199/16 | ::199 | +| sting | Workstation | INTERNAL | 10.50.128.10/16 | ::10 | +| PC-FRIDA | Workstation | INTERNAL | 10.50.128.11/16 | ::11 | +| gaia | Workstation | INTERNAL | 10.50.128.12/16 | ::12 | --- -### **2. List of User Profiles** +### **2. VLANs** + +| VLAN | ID | Effective ID | IPv4 Prefix | IPv6 ULA | IPv6 GUA | +| ----------| ---| --------------| -----------------| ----------------------------------| ----------------------------------| +| INET | 1 | 1 | Out of scope | Out of scope | Out of scope | +| ADMIN | 90 | **100** | 10.10.0.0/16 | fdb2:ae63:d45:d941::/64 | 2a01:e0a:2ea:d941::/64 | +| IOT | 200| 200 | 10.20.0.0/16 | fdb2:ae63:d45:d942::/64 | 2a01:e0a:2ea:d942::/64 | +| GUEST | 300| 300 | 10.30.0.0/16 | fdb2:ae63:d45:d943::/64 | 2a01:e0a:2ea:d943::/64 | +| DMZ | 400| 400 | 10.40.0.0/16 | fdb2:ae63:d45:d944::/64 | 2a01:e0a:2ea:d944::/64 | +| INTERNAL | 500| 500 | 10.50.0.0/16 | fdb2:ae63:d45:d945::/64 | 2a01:e0a:2ea:d945::/64 | + +--- + +### **3. List of User Profiles** | Name | Role | @@ -183,7 +207,7 @@ nixos-infra/ --- -### **3. User List** +### **4. User List** | Name | Role | SSH Access | | --------| -----------------------| -----------| | root | Superuser | ❌ | @@ -194,7 +218,7 @@ nixos-infra/ --- -### **4. User/Machine/Profile Mappings** +### **5. User/Machine/Profile Mappings** | User | Machine | Applied Profiles | Role | @@ -214,6 +238,43 @@ nixos-infra/ --- +## **🌐 Network Architecture** + +The network topology and addressing are defined **declaratively** in `network/`, the single source of truth for: +- VLANs (`network/vlans.nix`) +- Subnet prefixes (`network/subnets.nix`) +- Host address assignments (`network/hosts.nix`) + +### Prefix rules + +| Type | Formula | Example (DMZ, effectiveId=400) | +|--------|-----------------------------------------------------------|--------------------------------| +| IPv4 | `10..0.0/16` — hosts in `10..128.0/17` | `10.40.0.0/16` | +| IPv6 ULA | `fdb2:ae63:d45:d94::/64` where N = effectiveId/100 | `fdb2:ae63:d45:d944::/64` | +| IPv6 GUA | `2a01:e0a:2ea:d94::/64` where N = effectiveId/100 | `2a01:e0a:2ea:d944::/64` | + +> **ADMIN exception:** VLAN ID is 90 but treated as effective ID 100 for +> prefix computation. This avoids a risky production renumbering. + +### Consumption + +**From a NixOS configuration:** +```nix +let network = import ../../network { }; +in { + networking.hostName = "dns01"; + networking.useDHCP = true; +} +``` + +**From a shell script:** +```bash +nix eval --json -f network/default.nix hosts | jq '.dns01.ipv4' +# → "10.40.128.10" +``` + +--- + ## **🔄 Deployment Workflow** ### **For LXC containers (Proxmox)** @@ -276,6 +337,7 @@ nixos-infra/ | Write the DNS module | Module for the DNS service (Bind). | ⬜ | ⭐⭐⭐ | | Configure `agenix` | Encrypt the first secrets. | ⬜ | ⭐⭐ | | Document the process | `README.md` to explain deployment. | ⬜ | ⭐⭐ | +| DHCP service module | Kea or ISC DHCP consuming `network/hosts.nix` | ⬜ | ⭐⭐ | | Automate with Ansible | Playbook to create multiple containers. | ⬜ | ⭐ | | Integrate CI/CD | Test configurations before deployment. | ⬜ | ⭐ | @@ -293,6 +355,10 @@ nixos-infra/ - **Security** : - Disable root SSH access once deployment is complete. - Use SSH keys for authentication. +- **Network** : + - IPv4 addresses are allocated from the upper half of each VLAN (`10..128.0/17`). + - Addresses are assigned via DHCP reservations — `network/hosts.nix` is the source of truth. + - See `network/README.md` for the complete architecture documentation. - **Maintenance** : - Update `nixpkgs` regularly (`nix-channel --update`). - Document changes in the `CHANGELOG.md`. diff --git a/nixos-infra/hosts/servers/dns01/configuration.nix b/nixos-infra/hosts/servers/dns01/configuration.nix index e69de29..01ce40d 100644 --- a/nixos-infra/hosts/servers/dns01/configuration.nix +++ b/nixos-infra/hosts/servers/dns01/configuration.nix @@ -0,0 +1,19 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + # Module for LXC containers + ../../../modules/machine-types/lxc.nix + ]; + + # Explicitly enable LXC machine type + lxc.enable = true; + + # Host identity (IP address 10.40.128.10/16 assigned via DHCP reservation) + networking.hostName = "dns01"; + networking.useDHCP = true; + + # TODO: Add DNS service module import and configuration + # imports = [ ../../../modules/services/dns/default.nix ]; + # services.dns.enable = true; +} \ No newline at end of file diff --git a/nixos-infra/hosts/servers/dns02/configuration.nix b/nixos-infra/hosts/servers/dns02/configuration.nix index e69de29..ca236f2 100644 --- a/nixos-infra/hosts/servers/dns02/configuration.nix +++ b/nixos-infra/hosts/servers/dns02/configuration.nix @@ -0,0 +1,19 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + # Module for LXC containers + ../../../modules/machine-types/lxc.nix + ]; + + # Explicitly enable LXC machine type + lxc.enable = true; + + # Host identity (IP address 10.40.128.11/16 assigned via DHCP reservation) + networking.hostName = "dns02"; + networking.useDHCP = true; + + # TODO: Add DNS service module import and configuration + # imports = [ ../../../modules/services/dns/default.nix ]; + # services.dns.enable = true; +} \ No newline at end of file diff --git a/nixos-infra/hosts/servers/git01/configuration.nix b/nixos-infra/hosts/servers/git01/configuration.nix index e69de29..f450b65 100644 --- a/nixos-infra/hosts/servers/git01/configuration.nix +++ b/nixos-infra/hosts/servers/git01/configuration.nix @@ -0,0 +1,20 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + # Module for LXC containers + ../../../modules/machine-types/lxc.nix + # Module for the git forge service + ../../../modules/services/git-forge/default.nix + ]; + + # Explicitly enable LXC machine type + lxc.enable = true; + + # Host identity (IP address 10.40.128.20/16 assigned via DHCP reservation) + networking.hostName = "git01"; + networking.useDHCP = true; + + # TODO: Enable and configure the git forge service + # services.git-forge.enable = true; +} \ No newline at end of file diff --git a/nixos-infra/hosts/servers/pass01/configuration.nix b/nixos-infra/hosts/servers/pass01/configuration.nix index e69de29..309550c 100644 --- a/nixos-infra/hosts/servers/pass01/configuration.nix +++ b/nixos-infra/hosts/servers/pass01/configuration.nix @@ -0,0 +1,20 @@ +{ config, pkgs, lib, ... }: + +{ + imports = [ + # Module for LXC containers + ../../../modules/machine-types/lxc.nix + # Module for password manager service + ../../../modules/services/password-manager/default.nix + ]; + + # Explicitly enable LXC machine type + lxc.enable = true; + + # Host identity (IP address 10.40.128.30/16 assigned via DHCP reservation) + networking.hostName = "pass01"; + networking.useDHCP = true; + + # TODO: Enable and configure the password manager service + # services.password-manager.enable = true; +} \ No newline at end of file diff --git a/nixos-infra/hosts/servers/rp01/configuration.nix b/nixos-infra/hosts/servers/rp01/configuration.nix index 0ebcc6a..6ddcc29 100644 --- a/nixos-infra/hosts/servers/rp01/configuration.nix +++ b/nixos-infra/hosts/servers/rp01/configuration.nix @@ -2,31 +2,25 @@ { imports = [ - # Module pour les conteneurs LXC + # Module for LXC containers ../../../modules/machine-types/lxc.nix - # Module pour le reverse proxy + # Module for the reverse proxy ../../../modules/services/reverse-proxy/default.nix ]; - # Configuration réseau (IPv4 + IPv6) + # Host identity (IP address assigned via DHCP reservation) networking.hostName = "rp01"; - networking.interfaces.eth0.ipv4.addresses = [ - { address = "10.40.0.199"; prefixLength = 24; } - ]; - # networking.interfaces.eth0.ipv6.addresses = [ - # { address = "2001:db8::1"; prefixLength = 64; } - # ]; + networking.useDHCP = true; - # Liste des services à exposer via le reverse proxy + # Services to expose via the reverse proxy services.reverse-proxy.publicServices = [ { host = "git"; internalHost = "git01"; port = 3000; } { host = "pass"; internalHost = "pass01"; port = 80; } - # Ajoutez ici d'autres services (ex: dns01, etc.) + # Add other services here (e.g. dns01, etc.) ]; - # Configuration spécifique à Caddy (optionnelle) + # Caddy-specific configuration (optional) services.caddy = { - # Vous pouvez surcharger des paramètres ici si besoin - email = "xavier@lagraula.fr"; # Email pour Let's Encrypt + email = "xavier@lagraula.fr"; # Email for Let's Encrypt }; } \ No newline at end of file diff --git a/nixos-infra/network/README.md b/nixos-infra/network/README.md new file mode 100644 index 0000000..c07158e --- /dev/null +++ b/nixos-infra/network/README.md @@ -0,0 +1,123 @@ +# Network Architecture + +This directory contains the centralised, declarative network topology data for +the infrastructure. It is the single source of truth for VLANs, subnets, and +host addresses, consumable both by NixOS configurations (via `import`) and by +external scripts (via `nix eval --json`). + +## Files + +| File | Purpose | +|------|---------| +| `vlans.nix` | VLAN definitions (ID, name, effective ID, description) | +| `subnets.nix` | IPv4 and IPv6 prefix allocations per VLAN | +| `hosts.nix` | Per-machine address assignments | +| `default.nix` | Aggregator — imports all three files | + +## Consumption + +### From a NixOS configuration + +```nix +{ config, pkgs, lib, ... }: +let + network = import ../../network { }; +in { + networking.hostName = "dns01"; + networking.useDHCP = true; +} +``` + +### From a shell script + +```bash +# Export all host data as JSON +nix eval --json -f nixos-infra/network/default.nix hosts + +# Get a specific host's IPv4 address +nix eval -f nixos-infra/network/default.nix 'hosts.dns01.ipv4' + +# Use with jq +nix eval --json -f nixos-infra/network/default.nix hosts | jq '.dns01' +``` + +## VLANs + +| VLAN | ID | Effective ID | Description | +|------|----|--------------|-------------| +| INET | 1 | 1 | ISP uplink — untagged, out of project scope | +| ADMIN | 90 | **100** | Management / hypervisors | +| IOT | 200 | 200 | IoT devices | +| GUEST | 300 | 300 | Guest network | +| DMZ | 400 | 400 | Public-facing servers (LXC containers) | +| INTERNAL | 500 | 500 | Internal workstations | + +> **ADMIN exception:** VLAN 90 is treated as effective ID 100 for prefix +> computation. This is a documented exception to avoid a risky production +> change. A future renumbering may bring `id` and `effectiveId` into line. + +## Addressing Scheme + +### IPv4 + +The formula is `10..0.0/16` per VLAN. + +To avoid conflicts with the lower half (DHCP pools, infrastructure +services), **all static host addresses are allocated from the upper half**: +`10..128.0/17`. + +The gateway (`.1`) is distributed by DHCPv4 and is not statically assigned. + +### IPv6 + +IPv6 prefixes are derived from `effectiveId / 100`: + +| Type | Formula | Example (DMZ, effectiveId=400) | +|------|---------|-------------------------------| +| ULA | `fdb2:ae63:d45:d94::/64` | `fdb2:ae63:d45:d944::/64` | +| GUA | `2a01:e0a:2ea:d94::/64` | `2a01:e0a:2ea:d944::/64` | + +where `` = `effectiveId / 100` (so 1 for ADMIN, 2 for IOT, …, 5 for +INTERNAL). + +IPv6 addresses are formed by appending the host's 64-bit token to the +prefix, e.g. `fdb2:ae63:d45:d944::10` for dns01. + +The gateway (`::1` in each subnet) is distributed via Router Advertisement. + +### Host Address Allocation + +IPv4 addresses are reserved via DHCP reservations. The `hosts.nix` file is +the source of truth for these reservations and is intended to drive DHCP +server configuration (Kea, ISC DHCP, or similar) in a future iteration. + +IPv6 tokens are the last 64 bits of the host's address (expressed as `::XX` +shorthand) and are expected to be distributed via SLAAC with the corresponding +prefix. + +## Key Design Decisions + +1. **Why effectiveId?** The ADMIN VLAN has ID 90 but its IP prefixes are + computed as if ID were 100. Rather than fixing the VLAN ID in production, + the `effectiveId` field captures the exception explicitly and documents it. + +2. **Why /16 per VLAN?** Each VLAN has a full `/16` IPv4 prefix, which is + larger than typical container/workstation subnets. This is intentional: + it simplifies VLAN-level routing and leaves room for future growth. + +3. **Why DHCP and not static?** IPv4 addresses are distributed by DHCP, not + statically configured on each host. This centralises address management + and makes it easier to audit and change. The `hosts.nix` file is the + source of truth for the DHCP server's configuration. + +4. **Why NO static IP in configuration.nix?** In the current state, LXC + containers have no static IP configuration at all — they rely entirely on + DHCP. This is intentional: the addressing plan lives centrally in + `network/hosts.nix` and the per-host `.nix` files only set `hostName` and + `useDHCP = true`. A future DHCP service module (Kea, etc.) will consume + `hosts.nix` to generate reservations. + +5. **Why ULA + GUA for IPv6?** Both ULA (fd prefix) and GUA (2a01 prefix) + are defined for each VLAN. ULA provides stable internal addressing + independent of ISP changes; GUA provides global reachability for DMZ + services and outbound connectivity for workstations. \ No newline at end of file diff --git a/nixos-infra/network/default.nix b/nixos-infra/network/default.nix new file mode 100644 index 0000000..816eabc --- /dev/null +++ b/nixos-infra/network/default.nix @@ -0,0 +1,14 @@ +# Central network data source. +# +# Usage from a configuration.nix: +# network = import ../../network { }; +# network.hosts.rp01.ipv4 → "10.40.128.199" +# +# Usage from a shell script (via `nix eval`): +# nix eval --json -f network/default.nix hosts + +{ + vlans = (import ./vlans.nix).vlans; + subnets = (import ./subnets.nix).subnets; + hosts = (import ./hosts.nix).hosts; +} \ No newline at end of file diff --git a/nixos-infra/network/hosts.nix b/nixos-infra/network/hosts.nix new file mode 100644 index 0000000..0f35b8b --- /dev/null +++ b/nixos-infra/network/hosts.nix @@ -0,0 +1,87 @@ +{ + # Host-to-network assignments. + # + # Each entry has: + # vlan - Key referencing the VLAN in vlans.nix + # type - Host role (hypervisor, lxc, workstation) + # ipv4 - Static IPv4 address (reserved via DHCP reservation) + # ipv6Token - Last 64-bit suffix of the IPv6 address (::XX notation) + # + # IPv4 addresses are allocated from the 10..128.0/17 upper-half + # range to avoid conflicts with lower-half DHCP pools. + # + # IPv6 addresses are formed by appending the token to the VLAN's + # ULA or GUA prefix, e.g. fdb2:ae63:d45:d944::10 for dns01. + + hosts = { + hyper01 = { + vlan = "admin"; + type = "hypervisor"; + ipv4 = "10.10.128.10"; + ipv6Token = "::10"; + }; + + hyper02 = { + vlan = "admin"; + type = "hypervisor"; + ipv4 = "10.10.128.11"; + ipv6Token = "::11"; + }; + + rp01 = { + vlan = "dmz"; + type = "lxc"; + ipv4 = "10.40.128.199"; + ipv6Token = "::199"; + }; + + dns01 = { + vlan = "dmz"; + type = "lxc"; + ipv4 = "10.40.128.10"; + ipv6Token = "::10"; + }; + + dns02 = { + vlan = "dmz"; + type = "lxc"; + ipv4 = "10.40.128.11"; + ipv6Token = "::11"; + }; + + git01 = { + vlan = "dmz"; + type = "lxc"; + ipv4 = "10.40.128.20"; + ipv6Token = "::20"; + }; + + pass01 = { + vlan = "dmz"; + type = "lxc"; + ipv4 = "10.40.128.30"; + ipv6Token = "::30"; + }; + + gaia = { + vlan = "internal"; + type = "workstation"; + ipv4 = "10.50.128.10"; + ipv6Token = "::10"; + }; + + "PC-FRIDA" = { + vlan = "internal"; + type = "workstation"; + ipv4 = "10.50.128.11"; + ipv6Token = "::11"; + }; + + sting = { + vlan = "internal"; + type = "workstation"; + ipv4 = "10.50.128.12"; + ipv6Token = "::12"; + }; + }; +} \ No newline at end of file diff --git a/nixos-infra/network/subnets.nix b/nixos-infra/network/subnets.nix new file mode 100644 index 0000000..c6f7248 --- /dev/null +++ b/nixos-infra/network/subnets.nix @@ -0,0 +1,141 @@ +{ + # Subnet definitions per VLAN. + # + # Prefix rules: + # IPv4: 10..0.0/16 (hosts in the 10..128.0/17 range) + # IPv6 ULA: fdb2:ae63:d45:d94::/64 + # IPv6 GUA: 2a01:e0a:2ea:d94::/64 + # + # Gateways (.1 on each subnet) are distributed by DHCPv4 and Router + # Advertisement (SLAAC). They are listed in comments for documentation. + # + # Minimum host prefix is /16 for IPv4 (the whole VLAN). Host addresses + # are allocated from the upper half (10..128.0/17) to avoid conflicts + # with future lower-half allocations (DHCP pools, etc.). + # + # INET (VLAN 1) is the untagged ISP uplink. It is out of scope of this + # project and is listed for documentation only. + + subnets = { + inet = { + vlan = "inet"; + description = "ISP uplink — out of scope"; + # No prefixes defined: inet is outside this project's addressing plan. + }; + + admin = { + vlan = "admin"; + description = "Management / hypervisors"; + ipv4 = { + prefix = "10.10.0.0"; + prefixLength = 16; + hostRange = "10.10.128.0/17"; + # gateway = "10.10.128.1"; + }; + ipv6 = { + ula = { + prefix = "fdb2:ae63:d45:d941::"; + prefixLength = 64; + # gateway = "fdb2:ae63:d45:d941::1"; + }; + gua = { + prefix = "2a01:e0a:2ea:d941::"; + prefixLength = 64; + # gateway = "2a01:e0a:2ea:d941::1"; + }; + }; + }; + + iot = { + vlan = "iot"; + description = "IoT devices"; + ipv4 = { + prefix = "10.20.0.0"; + prefixLength = 16; + hostRange = "10.20.128.0/17"; + # gateway = "10.20.128.1"; + }; + ipv6 = { + ula = { + prefix = "fdb2:ae63:d45:d942::"; + prefixLength = 64; + # gateway = "fdb2:ae63:d45:d942::1"; + }; + gua = { + prefix = "2a01:e0a:2ea:d942::"; + prefixLength = 64; + # gateway = "2a01:e0a:2ea:d942::1"; + }; + }; + }; + + guest = { + vlan = "guest"; + description = "Guest network"; + ipv4 = { + prefix = "10.30.0.0"; + prefixLength = 16; + hostRange = "10.30.128.0/17"; + # gateway = "10.30.128.1"; + }; + ipv6 = { + ula = { + prefix = "fdb2:ae63:d45:d943::"; + prefixLength = 64; + # gateway = "fdb2:ae63:d45:d943::1"; + }; + gua = { + prefix = "2a01:e0a:2ea:d943::"; + prefixLength = 64; + # gateway = "2a01:e0a:2ea:d943::1"; + }; + }; + }; + + dmz = { + vlan = "dmz"; + description = "Public-facing servers (LXC containers)"; + ipv4 = { + prefix = "10.40.0.0"; + prefixLength = 16; + hostRange = "10.40.128.0/17"; + # gateway = "10.40.128.1"; + }; + ipv6 = { + ula = { + prefix = "fdb2:ae63:d45:d944::"; + prefixLength = 64; + # gateway = "fdb2:ae63:d45:d944::1"; + }; + gua = { + prefix = "2a01:e0a:2ea:d944::"; + prefixLength = 64; + # gateway = "2a01:e0a:2ea:d944::1"; + }; + }; + }; + + internal = { + vlan = "internal"; + description = "Internal workstations and trusted devices"; + ipv4 = { + prefix = "10.50.0.0"; + prefixLength = 16; + hostRange = "10.50.128.0/17"; + # gateway = "10.50.128.1"; + }; + ipv6 = { + ula = { + prefix = "fdb2:ae63:d45:d945::"; + prefixLength = 64; + # gateway = "fdb2:ae63:d45:d945::1"; + }; + gua = { + prefix = "2a01:e0a:2ea:d945::"; + prefixLength = 64; + # gateway = "2a01:e0a:2ea:d945::1"; + }; + }; + }; + }; +} \ No newline at end of file diff --git a/nixos-infra/network/vlans.nix b/nixos-infra/network/vlans.nix new file mode 100644 index 0000000..aa76916 --- /dev/null +++ b/nixos-infra/network/vlans.nix @@ -0,0 +1,59 @@ +{ + # VLANs used in the infrastructure. + # + # Each VLAN entry has: + # id - The actual IEEE 802.1Q VLAN ID on the network equipment + # name - Short label + # effectiveId - The numeric value used to compute IPv4/IPv6 prefixes. + # This matches `id` for most VLANs, but can differ when + # the VLAN ID does not follow the mathematical scheme. + # e.g. ADMIN is VLAN 90 but prefixes are computed as if VLAN 100. + # description - Free-text purpose of the VLAN + # + # VLAN ID 1 (INET) is the untagged ISP uplink. It is listed here for + # documentation only and is out of scope of this project. + + vlans = { + inet = { + id = 1; + name = "INET"; + effectiveId = 1; + description = "ISP uplink — untagged, out of project scope"; + }; + + admin = { + id = 90; + name = "ADMIN"; + effectiveId = 100; # Exception: treated as 100 for prefix computation + description = "Management / hypervisors"; + }; + + iot = { + id = 200; + name = "IOT"; + effectiveId = 200; + description = "IoT devices"; + }; + + guest = { + id = 300; + name = "GUEST"; + effectiveId = 300; + description = "Guest network"; + }; + + dmz = { + id = 400; + name = "DMZ"; + effectiveId = 400; + description = "Public-facing servers (LXC containers)"; + }; + + internal = { + id = 500; + name = "INTERNAL"; + effectiveId = 500; + description = "Internal workstations and trusted devices"; + }; + }; +} \ No newline at end of file