docs: README, role README, CLAUDE.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3fef7ba9e5
commit
12001abac6
3 changed files with 196 additions and 0 deletions
49
CLAUDE.md
Normal file
49
CLAUDE.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# MakerFLOSS_Mikrotik
|
||||||
|
|
||||||
|
Ansible IaC for one **MikroTik CRS310-8G+2S+IN** switch (RouterOS 7) at the makerspace,
|
||||||
|
managed over SSH with `community.routeros`. Sibling project to AnsibleBaobabV4 (whose
|
||||||
|
conventions this repo copies); independent repo on `forgejo.makerfloss.eu`.
|
||||||
|
|
||||||
|
## Tech stack
|
||||||
|
|
||||||
|
- Ansible 10.x / ansible-core 2.17, `community.routeros` 3.x + `ansible.netcommon`
|
||||||
|
- Connection: `ansible.netcommon.network_cli`, `ansible_network_os: community.routeros.routeros`, SSH **key** auth
|
||||||
|
- Vault identity **`makerfloss`** (`~/.ansible/vault-keys/makerfloss.txt`)
|
||||||
|
- Lint: `ansible-lint` (profile: production), `yamllint`
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
- `inventories/prod/hosts.yml` — group `mikrotik`, host `crs310-maker`
|
||||||
|
- `group_vars/mikrotik.yml` — connection vars + `switch_*_enabled` flags
|
||||||
|
- `group_vars/mikrotik.vault.yml` — encrypted password (excluded from linters)
|
||||||
|
- `host_vars/crs310-maker.yml` — device facts, real addressing, VLAN/port map
|
||||||
|
- `roles/makerfloss.mikrotik_switch/` — one role, per-domain task files gated by flags
|
||||||
|
- `play_switch.yml` (day-2), `play_bootstrap.yml` / `play_backup.yml` (to implement)
|
||||||
|
- `docs/` — field guide, design spec, implementation plan
|
||||||
|
|
||||||
|
## Essential commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yamllint . && ansible-lint && ansible-playbook play_switch.yml --syntax-check
|
||||||
|
ansible-playbook play_switch.yml # day-2 (key auth)
|
||||||
|
ansible-playbook play_switch.yml --tags vlans # one domain
|
||||||
|
ansible-vault view group_vars/mikrotik.vault.yml # read a secret
|
||||||
|
```
|
||||||
|
|
||||||
|
## Rules
|
||||||
|
|
||||||
|
- **Idempotency:** RouterOS tasks use `community.routeros.command` with `:if [find]`
|
||||||
|
guards. Run every device-touching play **twice**; the second run must report no changes.
|
||||||
|
- **Lockout safety:** keep an independent recovery channel (serial/WinBox-MAC) when
|
||||||
|
touching mgmt/services/VLANs; enable `vlan-filtering` **last**.
|
||||||
|
- **All real values go in `host_vars`;** the role holds only mechanism + placeholders.
|
||||||
|
- **Secrets** go to the `makerfloss` vault, never plaintext. Encrypt with
|
||||||
|
`ansible-vault encrypt --encrypt-vault-id makerfloss <file>`.
|
||||||
|
- **New work:** branch first, implement, verify (lint + syntax + run-twice), then merge.
|
||||||
|
|
||||||
|
## Status / next
|
||||||
|
|
||||||
|
Bootstrap is done (user `sjat` + key + identity `crs310-maker`, RouterOS 7.19.6 pinned).
|
||||||
|
The per-domain task files are **stubs**; implement them per
|
||||||
|
`docs/superpowers/plans/2026-06-07-mikrotik-crs310-ansible.md` (Tasks 5–9), reading the
|
||||||
|
"carry-over notes" at the end of that plan first.
|
||||||
87
README.md
Normal file
87
README.md
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
# MakerFLOSS_Mikrotik
|
||||||
|
|
||||||
|
Infrastructure-as-Code for the makerspace's **MikroTik CRS310-8G+2S+IN** switch
|
||||||
|
(8× 2.5GbE + 2× SFP+ 10G, RouterOS 7). Configuration is managed declaratively with
|
||||||
|
Ansible over SSH using the `community.routeros` collection — identity, management
|
||||||
|
access, users/keys, VLAN switching, backups, and firmware — so the switch can be
|
||||||
|
rebuilt from this repo instead of by hand in WinBox.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
| Area | State |
|
||||||
|
|---|---|
|
||||||
|
| Repo scaffolding, role skeleton, vault | ✅ done |
|
||||||
|
| On-site device prep + **bootstrap** (named user + SSH key + identity) | ✅ done (2026-06-08) |
|
||||||
|
| Day-2 config: `identity` / `users` / `vlans` / `backup` / `firmware` tasks | ⏳ **stubs** — to implement (see `docs/superpowers/plans/`) |
|
||||||
|
|
||||||
|
The switch is reachable today by key auth as user `sjat`; the per-domain task files
|
||||||
|
still need their real RouterOS logic written and idempotency-tested.
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
inventories/prod/hosts.yml # group `mikrotik` -> the switch host
|
||||||
|
group_vars/mikrotik.yml # connection vars (network_cli + community.routeros) + enable-flags
|
||||||
|
group_vars/mikrotik.vault.yml # encrypted admin/user password (makerfloss vault id)
|
||||||
|
host_vars/crs310-maker.yml # device facts + real addressing + VLAN/port map
|
||||||
|
roles/makerfloss.mikrotik_switch/ # the role: defaults + per-domain task files
|
||||||
|
play_switch.yml # day-2 run (key auth), applies all enabled domains
|
||||||
|
docs/makerspace-switch-fieldguide.md # on-site, printable prep checklist
|
||||||
|
docs/superpowers/specs|plans/ # design spec + implementation plan
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup (control node)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
direnv allow # or: python3 -m venv .venv && . .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
ansible-galaxy collection install -r requirements.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Vault:** secrets use a dedicated vault identity `makerfloss`, keyed by
|
||||||
|
`~/.ansible/vault-keys/makerfloss.txt` (referenced in `ansible.cfg`, kept outside the
|
||||||
|
repo). View a secret with `ansible-vault view group_vars/mikrotik.vault.yml`.
|
||||||
|
|
||||||
|
## Connectivity
|
||||||
|
|
||||||
|
The role connects with `ansible.netcommon.network_cli` + `ansible_network_os:
|
||||||
|
community.routeros.routeros`, authenticating with the operator SSH key
|
||||||
|
(`~/.ssh/id_ed25519`). Day-2 needs no password.
|
||||||
|
|
||||||
|
> **Bench note:** while the switch sits on an isolated bench reachable only through a
|
||||||
|
> jump host, Ansible's paramiko transport won't traverse `ProxyJump`. Run Ansible from a
|
||||||
|
> host on the switch's network, or forward the port:
|
||||||
|
> `ssh -J <jump> <user>@<jump-lan> -L 2222:192.168.88.1:22 -N` then set
|
||||||
|
> `ansible_host=127.0.0.1 ansible_port=2222`. In production (switch directly reachable)
|
||||||
|
> this is a non-issue.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Validate
|
||||||
|
yamllint . && ansible-lint && ansible-playbook play_switch.yml --syntax-check
|
||||||
|
|
||||||
|
# First contact on a fresh/reset device (password auth, one time)
|
||||||
|
ansible-playbook play_bootstrap.yml --ask-pass # (play to be implemented)
|
||||||
|
|
||||||
|
# Day-2 configuration (key auth, idempotent)
|
||||||
|
ansible-playbook play_switch.yml
|
||||||
|
ansible-playbook play_switch.yml --tags vlans # one domain
|
||||||
|
ansible-playbook play_switch.yml --limit crs310-maker
|
||||||
|
|
||||||
|
# Backup config into the repo
|
||||||
|
ansible-playbook play_backup.yml # (play to be implemented)
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠️ Lockout safety
|
||||||
|
|
||||||
|
When changing management, services, or VLAN/bridge settings, keep an independent
|
||||||
|
recovery channel open (serial console, or WinBox MAC-telnet) and enable
|
||||||
|
`vlan-filtering` **last**, after the management path is proven. RouterOS config tasks
|
||||||
|
use `:if [find]` guards for idempotency; **run every device-touching play twice** and
|
||||||
|
confirm the second run reports no changes.
|
||||||
|
|
||||||
|
## Preparing a switch on-site
|
||||||
|
|
||||||
|
See **`docs/makerspace-switch-fieldguide.md`** — a printable checklist for what to do
|
||||||
|
physically at the makerspace before Ansible takes over.
|
||||||
60
roles/makerfloss.mikrotik_switch/README.md
Normal file
60
roles/makerfloss.mikrotik_switch/README.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# makerfloss.mikrotik_switch
|
||||||
|
|
||||||
|
Configure a MikroTik RouterOS switch (CRS310) over SSH with `community.routeros`.
|
||||||
|
The role provides the *mechanism*; real values live in `host_vars`. Each domain is
|
||||||
|
gated by an enable-flag (defined in `group_vars/mikrotik.yml`) so you can apply a
|
||||||
|
subset with `--tags`.
|
||||||
|
|
||||||
|
## Domains (enable-flags)
|
||||||
|
|
||||||
|
| Flag | Task file | Tag | Does |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `switch_identity_enabled` | `identity.yml` | `identity` | identity, mgmt IP, DNS/NTP, SSH on, disable unused services |
|
||||||
|
| `switch_users_enabled` | `users.yml` | `users` | named admin user, import SSH key, disable default `admin` |
|
||||||
|
| `switch_vlans_enabled` | `vlans.yml` | `vlans` | VLAN-aware bridge, access/trunk ports, mgmt VLAN iface |
|
||||||
|
| `switch_backup_enabled` | `backup.yml` | `backup` | `/export` + binary backup, fetched into the repo |
|
||||||
|
| `switch_firmware_enabled` | `firmware.yml` | `firmware` | RouterOS + RouterBOOT upgrade to `switch_firmware_target` (opt-in) |
|
||||||
|
|
||||||
|
> The per-domain task files are currently **stubs** pending implementation (see the
|
||||||
|
> plan in `docs/superpowers/plans/`).
|
||||||
|
|
||||||
|
## Variables (`defaults/main.yml`)
|
||||||
|
|
||||||
|
| Variable | Default | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `switch_identity_name` | `{{ inventory_hostname }}` | system identity |
|
||||||
|
| `switch_mgmt_vlan_id` | `99` | management VLAN id |
|
||||||
|
| `switch_mgmt_address` | placeholder | mgmt IP `addr/cidr` (override in host_vars) |
|
||||||
|
| `switch_mgmt_gateway` | placeholder | default gateway |
|
||||||
|
| `switch_dns_servers` | placeholder | DNS server(s) |
|
||||||
|
| `switch_ntp_servers` | placeholder | NTP server(s) |
|
||||||
|
| `switch_disabled_services` | telnet,ftp,www,www-ssl,api,api-ssl | services to disable (winbox kept for recovery) |
|
||||||
|
| `switch_ssh_port` | `22` | SSH service port |
|
||||||
|
| `switch_admin_user` | `sjat` | named admin user |
|
||||||
|
| `switch_admin_group` | `full` | RouterOS group for the admin user |
|
||||||
|
| `switch_admin_ssh_pubkey_file` | `~/.ssh/id_ed25519.pub` | operator public key to import |
|
||||||
|
| `switch_disable_default_admin` | `true` | disable the built-in `admin` after key login works |
|
||||||
|
| `switch_bridge_name` | `bridge` | bridge to manage |
|
||||||
|
| `switch_vlans` | example | list of `{id, name}` |
|
||||||
|
| `switch_bridge_ports` | example | list of port definitions (see below) |
|
||||||
|
| `switch_firmware_target` | `""` | RouterOS version to pin/upgrade to |
|
||||||
|
|
||||||
|
### Data shapes
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
switch_vlans:
|
||||||
|
- {id: 99, name: "mgmt"}
|
||||||
|
- {id: 10, name: "members"}
|
||||||
|
|
||||||
|
switch_bridge_ports:
|
||||||
|
# access port: untagged member of one VLAN (pvid)
|
||||||
|
- {interface: "ether1", pvid: 10, mode: access}
|
||||||
|
# trunk port: carries tagged VLANs; pvid sets the untagged/native VLAN
|
||||||
|
- {interface: "sfp-sfpplus1", pvid: 1, mode: trunk, tagged_vlans: [99, 10]}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Idempotency
|
||||||
|
|
||||||
|
RouterOS has no rich declarative module set over `network_cli`, so tasks use
|
||||||
|
`community.routeros.command` with `:if ([:len [... find ...]] = 0) do={ ... }` guards.
|
||||||
|
Always run twice and confirm the second run is a no-op.
|
||||||
Loading…
Add table
Reference in a new issue