diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e29b895..74d6457 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,50 +1,43 @@ -name: Build - +name: "Build" on: - push: - branches: - - main - - 'test-*' pull_request: + push: jobs: - # Job to find all hosts that should be built - get-hosts: + determine-hosts: + name: "Determining hosts to build" runs-on: ubuntu-latest container: catthehacker/ubuntu:act-24.04 outputs: - hosts: ${{ steps.set-hosts.outputs.hosts }} + hosts: ${{ steps.hosts.outputs.hostnames }} steps: - - uses: actions/checkout@v4 - - name: Install Nix - uses: cachix/install-nix-action@v27 - - id: set-hosts - run: | - # Extract host names from nixosConfigurations - HOSTS=$(nix eval .#nixosConfigurations --apply "builtins.attrNames" --json) - echo "hosts=$HOSTS" >> $GITHUB_OUTPUT - - build: - needs: get-hosts - runs-on: ubuntu-latest - container: catthehacker/ubuntu:act-24.04 - strategy: - fail-fast: false - matrix: - host: ${{ fromJson(needs.get-hosts.outputs.hosts) }} - steps: - - uses: actions/checkout@v4 - - name: Install Nix - uses: cachix/install-nix-action@v27 + - uses: actions/checkout@v5 + - uses: https://github.com/cachix/install-nix-action@v31 with: nix_path: nixpkgs=channel:nixos-unstable - - name: Build NixOS configuration + - name: "Determine hosts" + id: hosts run: | - nix build .#nixosConfigurations.${{ matrix.host }}.config.system.build.toplevel - - name: "Push to Attic" - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - run: | - nix profile install nixpkgs#attic-client - attic login homelab http://192.168.0.25:8080 "${{ secrets.ATTIC_TOKEN }}" - attic push homelab result + hostnames="$(nix eval .#nixosConfigurations --apply builtins.attrNames --json)" + printf "hostnames=%s\n" "${hostnames}" >> "${GITHUB_OUTPUT}" + + build: + runs-on: ubuntu-latest + container: catthehacker/ubuntu:act-24.04 + needs: determine-hosts + strategy: + matrix: + hostname: [ + Development, + Testing + ] + + steps: + - uses: actions/checkout@v5 + - uses: https://github.com/cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: "Build host" + run: | + nix build ".#nixosConfigurations.${{ matrix.hostname }}.config.system.build.toplevel" --verbose diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml deleted file mode 100644 index 4cc892e..0000000 --- a/.github/workflows/check.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Check - -on: - push: - branches: - - '**' - pull_request: - -jobs: - check: - runs-on: ubuntu-latest - container: catthehacker/ubuntu:act-24.04 - steps: - - uses: actions/checkout@v4 - - - name: Install Nix - uses: cachix/install-nix-action@v27 - with: - extra_nix_config: | - experimental-features = nix-command flakes - access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} - - - name: Flake check - run: nix flake check diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index a037a7a..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,81 +0,0 @@ -name: Deploy - -on: - push: - branches: - - main - - 'test-*' - workflow_dispatch: - inputs: - mode: - description: 'Activation mode (switch, boot, test)' - default: 'switch' - required: true - -jobs: - deploy: - runs-on: ubuntu-latest - container: catthehacker/ubuntu:act-24.04 - steps: - - uses: actions/checkout@v4 - - - name: Install Nix - uses: cachix/install-nix-action@v27 - with: - extra_nix_config: | - experimental-features = nix-command flakes - - - name: Setup SSH - run: | - mkdir -p ~/.ssh - echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - ssh-keyscan -H 192.168.0.0/24 >> ~/.ssh/known_hosts || true - # Disable strict host key checking for the local network if needed, - # or rely on known_hosts. For homelab, we can be slightly more relaxed - # but let's try to be secure. - echo "StrictHostKeyChecking no" >> ~/.ssh/config - - - name: Verify Commit Signature - if: github.event.sender.login != 'renovate[bot]' - run: | - # TODO Hugo: Export your public GPG/SSH signing keys to a runner secret named 'TRUSTED_SIGNERS'. - # For GPG: gpg --export --armor | base64 -w0 - - if [ -z "${{ secrets.TRUSTED_SIGNERS }}" ]; then - echo "::error::TRUSTED_SIGNERS secret is missing. Deployment aborted for safety." - exit 1 - fi - - # Implementation note: This step expects a keyring in the TRUSTED_SIGNERS secret. - # We use git to verify the signature of the current commit. - echo "${{ secrets.TRUSTED_SIGNERS }}" | base64 -d > /tmp/trusted_keys.gpg - gpg --import /tmp/trusted_keys.gpg - - if ! git verify-commit HEAD; then - echo "::error::Commit signature verification failed. Only signed commits from trusted maintainers can be deployed." - exit 1 - fi - echo "Commit signature verified successfully." - - - name: Install deploy-rs - run: nix profile install github:serokell/deploy-rs - - - name: Deploy to hosts - run: | - # Determine profile based on branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - # Main site: persistent deployment - deploy . --skip-checks --targets $(deploy . --list | grep '.system$' | tr '\n' ' ') - elif [[ "${{ github.ref }}" == "refs/heads/test-"* ]]; then - # Test branch: non-persistent deployment (test profile) - # The branch name should be test- - HOSTNAME="${GITHUB_REF#refs/heads/test-}" - deploy .#${HOSTNAME}.test --skip-checks - fi - - - name: Manual Deploy - if: github.event_name == 'workflow_dispatch' - run: | - # TODO: Implement manual dispatch logic if needed - deploy . --skip-checks diff --git a/README.md b/README.md deleted file mode 100644 index 19f9892..0000000 --- a/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Bos55 NixOS Config - -Automated CI/CD deployment for NixOS homelab using `deploy-rs`. - -## Repository Structure - -- `hosts/`: Host-specific configurations. -- `modules/`: Shared NixOS modules. -- `users/`: User definitions (including the `deploy` user). -- `secrets/`: Encrypted secrets via `sops-nix`. - -## Deployment Workflow - -### Prerequisites -- SSH access to the `deploy` user on target hosts. -- `deploy-rs` installed locally (`nix profile install github:serokell/deploy-rs`). - -### Deployment Modes - -1. **Production Deployment (main branch):** - Triggered on push to `main`. Automatically builds and switches all hosts. bootloader is updated. - Manual: `deploy .` - -2. **Test Deployment (test- branch):** - Triggered on push to `test-`. Builds and activates the configuration on the specific host **without** updating the bootloader. Reboots will revert to the previous generation. - Manual: `deploy .#.test` - -3. **Kernel Upgrades / Maintenance:** - Use `deploy .#.system --boot` to update the bootloader without immediate activation, followed by a manual reboot. - -## Local Development - -### 1. Developer Shell -This repository includes a standardized development environment containing all necessary tools (`deploy-rs`, `sops`, `age`, etc.). -```bash -nix develop -# or if using direnv -direnv allow -``` - -### 2. Build a host VM -You can build a QEMU VM for any host configuration to test changes locally: -```bash -nix build .#nixosConfigurations..config.system.build.vm -./result/bin/run--vm -``` - -> [!WARNING] -> **Network Conflict**: Default VMs use user-mode networking (NAT) which is safe. However, if you configure the VM to use bridge networking, it will attempt to use the static IP defined in `hostIp`. Ensure you do not have a physical host with that IP active on the same bridge to avoid network interference. - -### 3. Run Integration Tests -Run the automated test suite: -```bash -nix-build test/vm-test.nix -``` - -### 3. Test CI Workflows Locally -Use `act` to test the GitHub Actions workflows: -```bash -act -W .github/workflows/check.yml -``` - -## Security -See [SECURITY.md](SECURITY.md) for details on the trust model and secret management. diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index ca1c208..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,93 +0,0 @@ -# Security and Trust Model - -This document outlines the security architecture, trust boundaries, and assumptions of the Bos55 NixOS deployment pipeline. This model is designed to support a multi-member infrastructure team and remains secure even if the repository is published publicly. - -## Trust Zones - -The system is partitioned into three distinct trust zones, each with specific controls to prevent lateral movement and privilege escalation. - -### 🔴 Zone 1: Trusted Maintainers (Source of Truth) -* **Actors:** Infrastructure Team / Maintainers. -* **Capabilities:** - * Full access to the Git repository. - * Ownership of `sops-nix` master keys (GPG or Age). - * Direct root access to NixOS hosts via personal SSH keys for emergency maintenance. -* **Trust:** Root of trust. All changes must originate from or be approved by a Trusted Maintainer. -* **Security Controls:** - * **Signed Commits:** All contributions must be cryptographically signed by a trusted GPG/SSH key to be eligible for deployment. - - **MFA:** Hardware-based multi-factor authentication for repository access. - - **Metadata Redaction:** Sensitive identifiers like SSH `authorizedKeys` are stored in `sops-nix`. This prevents **infrastructure fingerprinting**, where an attacker could link your public keys to your personal identities or other projects. - -### 🟡 Zone 2: CI/CD Pipeline (Automation Layer) -* **Actor:** GitHub Actions / Forgejo Runners. -* **Capabilities:** - * Builds Nix derivations from the repository. - * Access to the `DEPLOY_SSH_KEY` (allowing SSH access to the `deploy` user on target hosts). - * **Trusted Signers:** The public keys for verifying signatures are stored as a **Runner Secret** (`TRUSTED_SIGNERS`). This hides the identities of the infrastructure team even in a public repository. - * **NO ACCESS** to `sops-nix` decryption keys. Secrets remain encrypted during the build. -* **Security Controls:** - * **Signature Enforcement:** The `deploy.yml` workflow verifies the cryptographic signature of every maintainer commit. Deployment is aborted if the signature is missing or untrusted. - * **Sandboxing:** Runners execute in ephemeral, isolated containers. - * **Branch Protection:** Deployments to production (`main`) require approved Pull Requests. - * **Fork Protection:** CI workflows (and secrets) are explicitly disabled for forks. - -### 🟢 Zone 3: Target NixOS Hosts (Runtime) -* **Actor:** Production, Testing, and Service nodes. -* **Capabilities:** Decrypt secrets locally using host-specific `age` keys. -* **Trust:** Consumers of builds. They trust Zone 2 only for the pushing of store paths and triggering activation scripts. -* **Security Controls:** - * **Restricted `deploy` User:** The SSH user for automation is non-root. Sudo access is strictly policed via `sudoers` rules to allow only `nix-env` and `switch-to-configuration`. - * **Immutable Store:** Building on Nix ensures that the system state is derived from a cryptographically hashed store, preventing unauthorized local modifications from persisting across reboots. - ---- - -## Security Assumptions & Policies - -### 1. Public Repository Safety -The repository is designed to be safe for public viewing. No unencrypted secrets should ever be committed. The deployment pipeline is protected against "malicious contributors" via: -- **Mandatory PR Reviews:** No code can reach the `main` branch without peer review. -- **Secret Scoping:** Deployment keys are only available to authorized runs on protected branches. - -### 2. Supply Chain & Dependencies -- **Flake Lockfiles:** All dependencies (Nixpkgs, `deploy-rs`, etc.) are pinned to specific git revisions. -- **Renovate Bot:** Automated version upgrades allow for consistent tracking of upstream changes, though they require manual review or successful status checks for minor/patch versions. - -### 3. Signed Commit Enforcement -To prevent "force-push" attacks or runner compromises from injecting malicious code into the history, the pipeline should be configured to only deploy commits signed by a known "Trusted Maintainer" key. This ensures that even if a git account is compromised, the attacker cannot deploy code without the physical/cryptographic signing key. - ---- - -## Trust Boundary Diagram - -```mermaid -graph TD - subgraph "Zone 1: Trusted Workstations" - DEV["Maintainers (Team)"] - SOPS_KEYS["Master SOPS Keys"] - SIGN_KEYS["Signing Keys (GPG/SSH)"] - end - - subgraph "Zone 2: CI/CD Runner (Sandboxed)" - CI["Automated Runner"] - SSH_KEY["Deploy SSH Key"] - end - - subgraph "Zone 3: NixOS Target Hosts" - HOST["Target Host"] - HOST_AGE["Host Age Key"] - end - - DEV -- "Signed Push / PR" --> CI - CI -- "Push Store Paths & Activate" --> HOST - HOST_AGE -- "Local Decrypt" --> HOST - - style DEV fill:#f96,stroke:#333 - style CI fill:#ff9,stroke:#333 - style HOST fill:#9f9,stroke:#333 -``` - -## Security Best Practices for Maintainers - -1. **Keep Master Keys Offline:** Never store `sops-nix` master keys on the CI runner or public servers. -2. **Audit Runner Logs:** Periodically review CI execution logs for unexpected behavior. -3. **Rotate Deployment Keys:** Rotate the `DEPLOY_SSH_KEY` if maintainer membership changes significantly. diff --git a/flake.nix b/flake.nix index 8438f11..446f4ce 100644 --- a/flake.nix +++ b/flake.nix @@ -13,78 +13,52 @@ url = "github:gytis-ivaskevicius/flake-utils-plus"; inputs.flake-utils.follows = "flake-utils"; }; - deploy-rs = { - url = "github:serokell/deploy-rs"; - inputs.nixpkgs.follows = "nixpkgs"; - }; }; outputs = inputs@{ self, nixpkgs, - flake-utils, sops-nix, utils, deploy-rs, + flake-utils, sops-nix, utils, ... }: let system = utils.lib.system.x86_64-linux; - lib = nixpkgs.lib; in - utils.lib.mkFlake { - inherit self inputs; + utils.lib.mkFlake { + inherit self inputs; - hostDefaults.modules = [ + hostDefaults = { + inherit system; + + modules = [ ./modules ./users + sops-nix.nixosModules.sops ]; - - hosts = { - # Infrastructure - Niko.modules = [ ./hosts/Niko ]; - Ingress.modules = [ ./hosts/Ingress ]; - Gitea.modules = [ ./hosts/Gitea ]; - Vaultwarden.modules = [ ./hosts/Vaultwarden ]; - BinaryCache.modules = [ ./hosts/BinaryCache ]; - - # Production - Binnenpost.modules = [ ./hosts/Binnenpost ]; - Production.modules = [ ./hosts/Production ]; - ProductionGPU.modules = [ ./hosts/ProductionGPU ]; - ProductionArr.modules = [ ./hosts/ProductionArr ]; - ACE.modules = [ ./hosts/ACE ]; - - # Lab - Template.modules = [ ./hosts/Template ]; - Development.modules = [ ./hosts/Development ]; - Testing.modules = [ ./hosts/Testing ]; - }; - - deploy.nodes = let - pkg = deploy-rs.lib.${system}; - isDeployable = nixos: (nixos.config.homelab.users.deploy.enable or false) && (nixos.config.homelab.networking.hostIp != null); - in - builtins.mapAttrs (_: nixos: { - hostname = nixos.config.homelab.networking.hostIp; - sshUser = "deploy"; - user = "root"; - profiles.system.path = pkg.activate.nixos nixos; - profiles.test.path = pkg.activate.custom nixos.config.system.build.toplevel '' - $PROFILE/bin/switch-to-configuration test - ''; - }) (lib.filterAttrs (_: isDeployable) self.nixosConfigurations); - - checks = builtins.mapAttrs (_: lib: lib.deployChecks self.deploy) deploy-rs.lib; - - outputsBuilder = channels: { - formatter = channels.nixpkgs.alejandra; - devShells.default = channels.nixpkgs.mkShell { - name = "homelab-dev"; - buildInputs = [ - deploy-rs.packages.${system}.deploy-rs - channels.nixpkgs.sops - channels.nixpkgs.age - ]; - shellHook = "echo '🛡️ Homelab Development Shell Loaded'"; - }; - }; }; + + hosts = { + # Physical hosts + Niko.modules = [ ./hosts/Niko ]; + + # Virtual machines + + # Single-service + Ingress.modules = [ ./hosts/Ingress ]; + Gitea.modules = [ ./hosts/Gitea ]; + Vaultwarden.modules = [ ./hosts/Vaultwarden ]; + + # Production multi-service + Binnenpost.modules = [ ./hosts/Binnenpost ]; + Production.modules = [ ./hosts/Production ]; + ProductionGPU.modules = [ ./hosts/ProductionGPU ]; + ProductionArr.modules = [ ./hosts/ProductionArr ]; + ACE.modules = [ ./hosts/ACE ]; + + # Others + Template.modules = [ ./hosts/Template ]; + Development.modules = [ ./hosts/Development ]; + Testing.modules = [ ./hosts/Testing ]; + }; + }; } diff --git a/hosts/ACE/default.nix b/hosts/ACE/default.nix index 094b077..04aa284 100644 --- a/hosts/ACE/default.nix +++ b/hosts/ACE/default.nix @@ -1,12 +1,10 @@ -{ config, pkgs, ... }: +{ pkgs, ... }: { config = { homelab = { - networking.hostIp = "192.168.0.41"; services.actions.enable = true; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -26,7 +24,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.41"; prefixLength = 24; } ]; diff --git a/hosts/BinaryCache/default.nix b/hosts/BinaryCache/default.nix deleted file mode 100644 index e651599..0000000 --- a/hosts/BinaryCache/default.nix +++ /dev/null @@ -1,49 +0,0 @@ -{ config, pkgs, lib, system, ... }: - -let - hostIp = "192.168.0.25"; -in { - config = { - homelab = { - services.attic = { - enable = true; - enableRemoteBuilder = true; - openFirewall = true; - }; - virtualisation.guest.enable = true; - }; - - networking = { - hostName = "BinaryCache"; - hostId = "100002500"; - domain = "depeuter.dev"; - - useDHCP = false; - - enableIPv6 = true; - - defaultGateway = { - address = "192.168.0.1"; - interface = "ens18"; - }; - - interfaces.ens18 = { - ipv4.addresses = [ - { - address = hostIp; - prefixLength = 24; - } - ]; - }; - - nameservers = [ - "1.1.1.1" # Cloudflare - "1.0.0.1" # Cloudflare - ]; - }; - - # Sops configuration for this host is now handled by the common module - - system.stateVersion = "24.05"; - }; -} diff --git a/hosts/Binnenpost/default.nix b/hosts/Binnenpost/default.nix index e325980..561fbe1 100644 --- a/hosts/Binnenpost/default.nix +++ b/hosts/Binnenpost/default.nix @@ -1,4 +1,4 @@ -{ config, inputs, pkgs, ... }: +{ pkgs, ... }: { config = { @@ -13,14 +13,12 @@ }; homelab = { - networking.hostIp = "192.168.0.89"; apps = { speedtest.enable = true; technitiumDNS.enable = true; traefik.enable = true; }; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -45,7 +43,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.89"; prefixLength = 24; } ]; @@ -85,14 +83,6 @@ "traefik.http.routers.hugo.rule" = "Host(`hugo.depeuter.dev`)"; "traefik.http.services.hugo.loadbalancer.server.url" = "https://192.168.0.11:444"; - - "traefik.http.routers.attic.rule" = "Host(`${inputs.self.nixosConfigurations.BinaryCache.config.homelab.services.attic.domain}`)"; - "traefik.http.services.attic.loadbalancer.server.url" = - let - bcConfig = inputs.self.nixosConfigurations.BinaryCache.config; - bcIp = (pkgs.lib.head bcConfig.networking.interfaces.ens18.ipv4.addresses).address; - bcPort = bcConfig.homelab.services.attic.port; - in "http://${bcIp}:${toString bcPort}"; }; system.stateVersion = "24.05"; diff --git a/hosts/Gitea/default.nix b/hosts/Gitea/default.nix index d6996b2..c6c9b43 100644 --- a/hosts/Gitea/default.nix +++ b/hosts/Gitea/default.nix @@ -3,12 +3,9 @@ { config = { homelab = { - networking.hostIp = "192.168.0.24"; apps.gitea.enable = true; virtualisation.guest.enable = true; - users.deploy.enable = true; - users.admin = { enable = true; authorizedKeys = [ @@ -31,7 +28,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.24"; prefixLength = 24; } ]; diff --git a/hosts/Ingress/default.nix b/hosts/Ingress/default.nix index c16f151..c0a3ac9 100644 --- a/hosts/Ingress/default.nix +++ b/hosts/Ingress/default.nix @@ -2,11 +2,7 @@ { config = { - homelab = { - networking.hostIp = "192.168.0.10"; - virtualisation.guest.enable = true; - users.deploy.enable = true; - }; + homelab.virtualisation.guest.enable = true; networking = { hostName = "Ingress"; @@ -23,8 +19,8 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; - prefixLength = 24; + address = "192.168.0.10"; +prefixLength = 24; } ]; }; @@ -43,7 +39,6 @@ }; }; - security.acme = { acceptTerms = true; defaults = { @@ -51,7 +46,7 @@ dnsPropagationCheck = true; dnsProvider = "cloudflare"; dnsResolver = "1.1.1.1:53"; - email = config.sops.placeholder.acme_email or "acme-email@example.com"; + email = "tibo.depeuter@telenet.be"; credentialFiles = { CLOUDFLARE_DNS_API_TOKEN_FILE = "/var/lib/secrets/depeuter-dev-cloudflare-api-token"; }; diff --git a/hosts/Niko/default.nix b/hosts/Niko/default.nix index c08ccdc..910f325 100644 --- a/hosts/Niko/default.nix +++ b/hosts/Niko/default.nix @@ -7,7 +7,6 @@ ]; homelab = { - networking.hostIp = "192.168.0.11"; apps = { technitiumDNS.enable = true; traefik.enable = true; diff --git a/hosts/Production/default.nix b/hosts/Production/default.nix index a4ebc75..9bb565d 100644 --- a/hosts/Production/default.nix +++ b/hosts/Production/default.nix @@ -3,13 +3,11 @@ { config = { homelab = { - networking.hostIp = "192.168.0.31"; apps = { calibre.enable = true; traefik.enable = true; }; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -33,7 +31,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.31"; prefixLength = 24; } ]; diff --git a/hosts/ProductionArr/default.nix b/hosts/ProductionArr/default.nix index 1168bc8..ff4f4c2 100644 --- a/hosts/ProductionArr/default.nix +++ b/hosts/ProductionArr/default.nix @@ -3,13 +3,11 @@ { config = { homelab = { - networking.hostIp = "192.168.0.33"; apps = { arr.enable = true; traefik.enable = true; }; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -33,7 +31,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.33"; prefixLength = 24; } ]; diff --git a/hosts/ProductionGPU/default.nix b/hosts/ProductionGPU/default.nix index 5f8ad82..fa9ca8c 100644 --- a/hosts/ProductionGPU/default.nix +++ b/hosts/ProductionGPU/default.nix @@ -3,10 +3,8 @@ { config = { homelab = { - networking.hostIp = "192.168.0.94"; apps.jellyfin.enable = true; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -30,7 +28,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.94"; prefixLength = 24; } ]; diff --git a/hosts/Testing/default.nix b/hosts/Testing/default.nix index cc4efcf..cc353f6 100644 --- a/hosts/Testing/default.nix +++ b/hosts/Testing/default.nix @@ -3,13 +3,11 @@ { config = { homelab = { - networking.hostIp = "192.168.0.92"; apps = { freshrss.enable = true; traefik.enable = true; }; virtualisation.guest.enable = true; - users.deploy.enable = true; }; networking = { @@ -34,7 +32,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.92"; prefixLength = 24; } ]; diff --git a/hosts/Vaultwarden/default.nix b/hosts/Vaultwarden/default.nix index b24ef6d..5ded575 100644 --- a/hosts/Vaultwarden/default.nix +++ b/hosts/Vaultwarden/default.nix @@ -3,7 +3,6 @@ { config = { homelab = { - networking.hostIp = "192.168.0.22"; apps.vaultwarden = { enable = true; domain = "https://vault.depeuter.dev"; @@ -11,15 +10,11 @@ }; virtualisation.guest.enable = true; - users = { - deploy.enable = true; - - admin = { - enable = true; - authorizedKeys = [ - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJnihoyozOCnm6T9OzL2xoMeMZckBYR2w43us68ABA93" - ]; - }; + users.admin = { + enable = true; + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJnihoyozOCnm6T9OzL2xoMeMZckBYR2w43us68ABA93" + ]; }; }; @@ -37,7 +32,7 @@ interfaces.ens18 = { ipv4.addresses = [ { - address = config.homelab.networking.hostIp; + address = "192.168.0.22"; prefixLength = 24; } ]; diff --git a/modules/apps/bind9/db.depeuter.dev b/modules/apps/bind9/db.depeuter.dev index 413adfe..72f3825 100644 --- a/modules/apps/bind9/db.depeuter.dev +++ b/modules/apps/bind9/db.depeuter.dev @@ -1,6 +1,6 @@ $TTL 604800 @ IN SOA ns1 admin ( - 16 ; Serial + 15 ; Serial 604800 ; Refresh 86400 ; Retry 2419200 ; Expire @@ -40,9 +40,6 @@ sonarr IN A 192.168.0.33 ; Development VM plex IN A 192.168.0.91 -; Binary Cache (via Binnenpost proxy) -nix-cache IN A 192.168.0.89 - ; Catchalls *.production IN A 192.168.0.31 *.development IN A 192.168.0.91 diff --git a/modules/common/default.nix b/modules/common/default.nix index 03fe2dd..746d1c1 100644 --- a/modules/common/default.nix +++ b/modules/common/default.nix @@ -1,15 +1,12 @@ { imports = [ - ./networking.nix ./secrets.nix - ./substituters.nix ]; config = { homelab = { services.openssh.enable = true; users.admin.enable = true; - common.substituters.enable = true; }; nix.settings.experimental-features = [ diff --git a/modules/common/networking.nix b/modules/common/networking.nix deleted file mode 100644 index 837684e..0000000 --- a/modules/common/networking.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ config, lib, ... }: - -{ - options.homelab.networking = { - hostIp = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = '' - The primary IP address of the host. - Used for automated deployment and internal service discovery. - ''; - }; - }; - - config = lib.mkIf (config.homelab.networking.hostIp != null) { - # If a hostIp is provided, we can potentially use it to configure - # networking interfaces or firewall rules automatically here in the future. - }; -} diff --git a/modules/common/substituters.nix b/modules/common/substituters.nix deleted file mode 100644 index bb8e564..0000000 --- a/modules/common/substituters.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ config, lib, pkgs, inputs, ... }: - -let - cfg = config.homelab.common.substituters; -in { - options.homelab.common.substituters = { - enable = lib.mkEnableOption "Binary cache substituters"; - domain = lib.mkOption { - type = lib.types.str; - default = inputs.self.nixosConfigurations.BinaryCache.config.homelab.services.attic.domain; - description = "The domain name of the binary cache."; - }; - publicKey = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "The public key of the Attic cache (e.g., 'homelab:...')"; - }; - }; - - config = lib.mkIf cfg.enable { - nix.settings = { - substituters = [ - "https://${cfg.domain}" - ]; - trusted-public-keys = lib.optional (cfg.publicKey != null) cfg.publicKey; - }; - }; -} diff --git a/modules/services/attic/default.nix b/modules/services/attic/default.nix deleted file mode 100644 index 6241748..0000000 --- a/modules/services/attic/default.nix +++ /dev/null @@ -1,119 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.homelab.services.attic; -in { - options.homelab.services.attic = { - enable = lib.mkEnableOption "Attic binary cache server"; - domain = lib.mkOption { - type = lib.types.str; - default = "nix-cache.depeuter.dev"; - description = "The domain name for the Attic server."; - }; - port = lib.mkOption { - type = lib.types.port; - default = 8080; - description = "The port Attic server listens on."; - }; - databaseName = lib.mkOption { - type = lib.types.str; - default = "attic"; - description = "The name of the PostgreSQL database."; - }; - dbContainerName = lib.mkOption { - type = lib.types.str; - default = "attic-db"; - description = "The name of the PostgreSQL container."; - }; - storagePath = lib.mkOption { - type = lib.types.str; - default = "/var/lib/atticd/storage"; - description = "The path where Attic store's its blobs."; - }; - openFirewall = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to open the firewall port for Attic."; - }; - enableRemoteBuilder = lib.mkOption { - type = lib.types.bool; - default = false; - description = "Whether to enable remote build capabilities on this host."; - }; - }; - - config = lib.mkIf cfg.enable { - sops.secrets = { - "attic/db-password" = { }; - "attic/server-token-secret" = { }; - }; - - services.atticd = { - enable = true; - environmentFile = config.sops.secrets."attic/server-token-secret".path; - - settings = { - listen = "[::]:${toString cfg.port}"; - allowed-hosts = [ cfg.domain ]; - api-endpoint = "https://${cfg.domain}/"; - - database.url = "postgresql://${cfg.databaseName}@${cfg.dbContainerName}:5432/${cfg.databaseName}"; - - storage = { - type = "local"; - path = cfg.storagePath; - }; - - chunking = { - min-size = 16384; # 16 KiB - avg-size = 65536; # 64 KiB - max-size = 262144; # 256 KiB - }; - }; - }; - - homelab.virtualisation.containers.enable = true; - - virtualisation.oci-containers.containers."${cfg.dbContainerName}" = { - image = "postgres:15-alpine"; - autoStart = true; - # We still map it to host for Attic (running on host) to connect to it via bridge IP or name - # if we set up networking/DNS correctly. - ports = [ - "5432:5432/tcp" - ]; - environment = { - POSTGRES_USER = cfg.databaseName; - POSTGRES_PASSWORD_FILE = config.sops.secrets."attic/db-password".path; - POSTGRES_DB = cfg.databaseName; - }; - volumes = [ - "attic-db:/var/lib/postgresql/data" - ]; - }; - - # Map the container name to localhost if Attic is on the host - networking.extraHosts = '' - 127.0.0.1 ${cfg.dbContainerName} - ''; - - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; - - # Remote build host configuration - nix.settings.trusted-users = lib.mkIf cfg.enableRemoteBuilder [ "root" "@wheel" "builder" ]; - - users.users.builder = lib.mkIf cfg.enableRemoteBuilder { - isNormalUser = true; - group = "builder"; - openssh.authorizedKeys.keys = [ - # Placeholders - user should provide actual keys - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFrp6aM62Bf7bj1YM5AlAWuNrANU3N5e8+LtbbpmZPKS" - ]; - }; - users.groups.builder = lib.mkIf cfg.enableRemoteBuilder {}; - - # Only open SSH if remote builder is enabled - services.openssh.ports = lib.mkIf cfg.enableRemoteBuilder [ 22 ]; - networking.firewall.allowedTCPPorts = lib.mkIf cfg.enableRemoteBuilder [ 22 ]; - }; -} diff --git a/modules/services/default.nix b/modules/services/default.nix index 81e0042..f70bc54 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -1,7 +1,6 @@ { imports = [ ./actions - ./attic ./openssh ]; } diff --git a/users/deploy/default.nix b/users/deploy/default.nix index 5c28561..93505fc 100644 --- a/users/deploy/default.nix +++ b/users/deploy/default.nix @@ -3,19 +3,7 @@ let cfg = config.homelab.users.deploy; in { - options.homelab.users.deploy = { - enable = lib.mkEnableOption "user Deploy"; - - authorizedKeys = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = []; - description = '' - Additional SSH public keys authorized for the deploy user. - The CI runner key should be provided as a base key; personal - workstation keys can be appended here per host or globally. - ''; - }; - }; + options.homelab.users.deploy.enable = lib.mkEnableOption "user Deploy"; config = lib.mkIf cfg.enable { users = { @@ -33,9 +21,6 @@ in { }; }; - # Allow the deploy user to push closures to the nix store - nix.settings.trusted-users = [ "deploy" ]; - security.sudo.extraRules = [ { groups = [