Skip to content

Repository files navigation

Network

Phorge logo

OpenTofu configuration and bootstrap scripts of the edge router of the Phorge infrastructure, a MikroTik RB3011UiAS running RouterOS 7.19. The router owns the VLANs, addressing, DHCP, DNS, firewall and NAT, and runs the HAProxy container that publishes the services to the Internet.

Documentation:

Sibling repositories: FrontPlane (Kubernetes clusters), Ansible (storage, HPC and compute nodes).

Repository layout

versions.tf          OpenTofu and provider version constraints
providers.tf         Provider settings
variables.tf         Input variables, with validation
locals.tf            Values derived from the networks variable
interfaces.tf        VLANs, veth, bridges, interface lists, VXLAN
addressing.tf        IP addresses and DHCP pools
dhcp.tf              DHCP networks and servers
dns.tf               DNS records
firewall.tf          Filter rules, NAT rules, address lists
routing.tf           BGP connections
users.tf             RouterOS user groups and users (passwords from .env, never from the tfvars)
containers.tf        Container runtime, mounts, uploaded files, containers
encryption.tf        State and plan encryption; the passphrase comes from TF_ENCRYPTION
terraform.tfvars     Values: networks, DNS records, firewall, NAT, containers
.terraform.lock.hcl  Pinned provider version and hashes (committed)
templates/           HAProxy configuration template and the script that reloads it
certs/               Local trust anchor: the router CA (ignored by git, see the runbook)
defaults/            RouterOS scripts: factory defaults, base configuration, Phorge.dpk
docs/                Architecture and runbooks

One entry in networks (name, VLAN ID, CIDR, optionally a DHCP pool, node ranges and the host number of the public ingress) creates the VLAN, the router address (the last usable address of the subnet), the DHCP pool, network and server, the membership of the phorge interface list and the <name>-nodes address list. The ingress addresses also feed the HAProxy configuration and the rules that let the container reach them, so they exist in one place.

Requirements

  • OpenTofu 1.12 or later
  • RouterOS 7.19 or later with the container package and the container feature enabled in device-mode
  • Access to the router's REST API (HTTPS, management LAN)

Usage

  1. Create your environment file and restrict it:

    cp .env.example .env
    chmod 600 .env

    Then set TF_VAR_hosturl, TF_VAR_username and TF_VAR_password, and replace the passphrase in TF_ENCRYPTION (at least 16 random characters). Keep a copy of that passphrase outside this machine: without it the state cannot be read.

    The passwords of the extra RouterOS users declared in users go in TF_VAR_user_passwords, a JSON object keyed by user name (at least 24 random characters each). They never go in terraform.tfvars. A service that reads one of them keeps its own copy: the mktxp password is also stored SOPS-encrypted in the Frontplane repository.

    The provider verifies the router certificate against certs/router-ca.pem, a local file that is not committed. Fetch it as described in the runbook. The first run after a router reset can use TF_VAR_insecure_tls=true instead.

  2. Initialize:

    source .env
    tofu init
  3. Plan, read the plan, then apply:

    tofu plan
    tofu apply

Run every command from the repository root so that terraform.tfvars is loaded. Without it the plan stops on missing required variables.

The HAProxy configuration is templates/haproxy.cfg.tftpl. Edit it and run tofu apply: the container reloads it by itself within about 15 seconds, without dropping connections (see the runbook, including how to check that HAProxy accepted it). Do not edit the file on the router, the next apply would overwrite it.

The uploaded HAProxy configuration is adopted automatically (import block in containers.tf) because RouterOS file IDs shift when other files change.

The VLANs, IP addresses, bridges and bridge ports have prevent_destroy: a plan that would delete them fails. To delete one on purpose, remove its lifecycle block first.

Conventions

  • Every object created by OpenTofu carries a comment starting with tofu;;;.
  • Firewall rules have a stable id and are placed on the router in list order by routeros_move_items. A rule with before sits right above the factory rule of that name in the same chain, the others go to the end of the chain. See the runbook.
  • The state is local (terraform.tfstate, ignored by git) and encrypted with OpenTofu's native state encryption. Every command needs source .env, otherwise it stops with Reference to undeclared key provider. Keep a copy of the state after every apply.
  • All three Phorge repositories are public. Never commit .env, the state (not even encrypted), a reset-edited base_configuration.rsc or any other plaintext secret.
  • Commit messages follow Conventional Commits (fix(fw): ..., chore(haproxy): ...).

Setting up the router for the first time

Follow the runbook. In short: replace the placeholders in defaults/base_configuration.rsc, reset the router with the factory defaults, upload defaults/Phorge.dpk, import the base configuration, then run OpenTofu.

About

Network configuration files & OpenTofu plans for @phorge-fr

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages