Added network management.
This commit is contained in:
@@ -35,14 +35,16 @@
|
|||||||
| **No flakes** | Simplify onboarding and avoid a steep learning curve. | Configuration via `configuration.nix` + `callPackage`. |
|
| **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. |
|
| **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/<service>01` (e.g. `git01`, `pass01`, `dns01`). |
|
| **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/<service>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. |
|
| **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`. |
|
| **`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. |
|
| **`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. |
|
| **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. |
|
| **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. |
|
| **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)
|
│ └── gaia/ # Xavier's laptop (audio)
|
||||||
│ └── configuration.nix
|
│ └── 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
|
├── modules/ # Autonomous modules
|
||||||
│ ├── machine-types/ # Machine types
|
│ ├── machine-types/ # Machine types
|
||||||
│ │ ├── hypervisor.nix # Module for hypervisors
|
│ │ ├── hypervisor.nix # Module for hypervisors
|
||||||
@@ -157,20 +166,35 @@ nixos-infra/
|
|||||||
### **1. Machine List**
|
### **1. Machine List**
|
||||||
|
|
||||||
|
|
||||||
| Name | Machine Type | Services | IPv4 | IPv6 Token |
|
| Name | Machine Type | VLAN | IPv4 | IPv6 Token |
|
||||||
| ----------| --------------------| -------------| ------| ------------|
|
| ----------| --------------------| ---------| ------------------| ------------|
|
||||||
| hyper01 | Hypervisor | Proxmox | | |
|
| hyper01 | Hypervisor | ADMIN | 10.10.128.10/16 | ::10 |
|
||||||
| hyper02 | Hypervisor | Proxmox | | |
|
| hyper02 | Hypervisor | ADMIN | 10.10.128.11/16 | ::11 |
|
||||||
| dns01 | LXC Container | DNS | | |
|
| dns01 | LXC Container | DMZ | 10.40.128.10/16 | ::10 |
|
||||||
| git01 | LXC Container | Git forge | | |
|
| dns02 | LXC Container | DMZ | 10.40.128.11/16 | ::11 |
|
||||||
| pass01 | LXC Container | Password mgr| | |
|
| git01 | LXC Container | DMZ | 10.40.128.20/16 | ::20 |
|
||||||
| rp01 | LXC Container | Reverse proxy| | |
|
| pass01 | LXC Container | DMZ | 10.40.128.30/16 | ::30 |
|
||||||
| sting | Workstation | | | |
|
| rp01 | LXC Container | DMZ | 10.40.128.199/16 | ::199 |
|
||||||
| PC-FRIDA | Workstation | | | |
|
| 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 |
|
| Name | Role |
|
||||||
@@ -183,7 +207,7 @@ nixos-infra/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### **3. User List**
|
### **4. User List**
|
||||||
| Name | Role | SSH Access |
|
| Name | Role | SSH Access |
|
||||||
| --------| -----------------------| -----------|
|
| --------| -----------------------| -----------|
|
||||||
| root | Superuser | ❌ |
|
| root | Superuser | ❌ |
|
||||||
@@ -194,7 +218,7 @@ nixos-infra/
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### **4. User/Machine/Profile Mappings**
|
### **5. User/Machine/Profile Mappings**
|
||||||
|
|
||||||
|
|
||||||
| User | Machine | Applied Profiles | Role |
|
| 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.<effectiveId>.0.0/16` — hosts in `10.<v>.128.0/17` | `10.40.0.0/16` |
|
||||||
|
| IPv6 ULA | `fdb2:ae63:d45:d94<N>::/64` where N = effectiveId/100 | `fdb2:ae63:d45:d944::/64` |
|
||||||
|
| IPv6 GUA | `2a01:e0a:2ea:d94<N>::/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**
|
## **🔄 Deployment Workflow**
|
||||||
|
|
||||||
### **For LXC containers (Proxmox)**
|
### **For LXC containers (Proxmox)**
|
||||||
@@ -276,6 +337,7 @@ nixos-infra/
|
|||||||
| Write the DNS module | Module for the DNS service (Bind). | ⬜ | ⭐⭐⭐ |
|
| Write the DNS module | Module for the DNS service (Bind). | ⬜ | ⭐⭐⭐ |
|
||||||
| Configure `agenix` | Encrypt the first secrets. | ⬜ | ⭐⭐ |
|
| Configure `agenix` | Encrypt the first secrets. | ⬜ | ⭐⭐ |
|
||||||
| Document the process | `README.md` to explain deployment. | ⬜ | ⭐⭐ |
|
| 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. | ⬜ | ⭐ |
|
| Automate with Ansible | Playbook to create multiple containers. | ⬜ | ⭐ |
|
||||||
| Integrate CI/CD | Test configurations before deployment. | ⬜ | ⭐ |
|
| Integrate CI/CD | Test configurations before deployment. | ⬜ | ⭐ |
|
||||||
|
|
||||||
@@ -293,6 +355,10 @@ nixos-infra/
|
|||||||
- **Security** :
|
- **Security** :
|
||||||
- Disable root SSH access once deployment is complete.
|
- Disable root SSH access once deployment is complete.
|
||||||
- Use SSH keys for authentication.
|
- Use SSH keys for authentication.
|
||||||
|
- **Network** :
|
||||||
|
- IPv4 addresses are allocated from the upper half of each VLAN (`10.<v>.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** :
|
- **Maintenance** :
|
||||||
- Update `nixpkgs` regularly (`nix-channel --update`).
|
- Update `nixpkgs` regularly (`nix-channel --update`).
|
||||||
- Document changes in the `CHANGELOG.md`.
|
- Document changes in the `CHANGELOG.md`.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -2,31 +2,25 @@
|
|||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
# Module pour les conteneurs LXC
|
# Module for LXC containers
|
||||||
../../../modules/machine-types/lxc.nix
|
../../../modules/machine-types/lxc.nix
|
||||||
# Module pour le reverse proxy
|
# Module for the reverse proxy
|
||||||
../../../modules/services/reverse-proxy/default.nix
|
../../../modules/services/reverse-proxy/default.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
# Configuration réseau (IPv4 + IPv6)
|
# Host identity (IP address assigned via DHCP reservation)
|
||||||
networking.hostName = "rp01";
|
networking.hostName = "rp01";
|
||||||
networking.interfaces.eth0.ipv4.addresses = [
|
networking.useDHCP = true;
|
||||||
{ address = "10.40.0.199"; prefixLength = 24; }
|
|
||||||
];
|
|
||||||
# networking.interfaces.eth0.ipv6.addresses = [
|
|
||||||
# { address = "2001:db8::1"; prefixLength = 64; }
|
|
||||||
# ];
|
|
||||||
|
|
||||||
# Liste des services à exposer via le reverse proxy
|
# Services to expose via the reverse proxy
|
||||||
services.reverse-proxy.publicServices = [
|
services.reverse-proxy.publicServices = [
|
||||||
{ host = "git"; internalHost = "git01"; port = 3000; }
|
{ host = "git"; internalHost = "git01"; port = 3000; }
|
||||||
{ host = "pass"; internalHost = "pass01"; port = 80; }
|
{ 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 = {
|
services.caddy = {
|
||||||
# Vous pouvez surcharger des paramètres ici si besoin
|
email = "xavier@lagraula.fr"; # Email for Let's Encrypt
|
||||||
email = "xavier@lagraula.fr"; # Email pour Let's Encrypt
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -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.<effectiveId>.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.<effectiveId>.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<N>::/64` | `fdb2:ae63:d45:d944::/64` |
|
||||||
|
| GUA | `2a01:e0a:2ea:d94<N>::/64` | `2a01:e0a:2ea:d944::/64` |
|
||||||
|
|
||||||
|
where `<N>` = `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.
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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.<v>.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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
{
|
||||||
|
# Subnet definitions per VLAN.
|
||||||
|
#
|
||||||
|
# Prefix rules:
|
||||||
|
# IPv4: 10.<effectiveId>.0.0/16 (hosts in the 10.<effectiveId>.128.0/17 range)
|
||||||
|
# IPv6 ULA: fdb2:ae63:d45:d94<effectiveId/100>::/64
|
||||||
|
# IPv6 GUA: 2a01:e0a:2ea:d94<effectiveId/100>::/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.<v>.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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user