Instructions and plan
This commit is contained in:
210
docs/plans/2026-02-28-shorewall-manager-design.md
Normal file
210
docs/plans/2026-02-28-shorewall-manager-design.md
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
# Shorefront — Shorewall Configuration Manager: Design Document
|
||||||
|
|
||||||
|
**Date:** 2026-02-28
|
||||||
|
**Status:** Approved
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Shorefront is a production-ready web application for managing Shorewall firewall configurations. Users manage zones, interfaces, policies, rules, and masquerade/NAT entries through a browser UI backed by a PostgreSQL database, and can generate Shorewall config files on demand.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
**Option A (selected):** Monorepo with separate Docker services. Frontend and backend are independently containerized. In production, Nginx serves the React bundle and reverse-proxies `/api` to the FastAPI backend. In development, the Vite dev server proxies `/api`. Clean separation between frontend, backend API, and the Shorewall generator module.
|
||||||
|
|
||||||
|
**Deployment targets:**
|
||||||
|
- Local dev: Docker Compose
|
||||||
|
- Production: Kubernetes (Traefik ingress) with Helm charts
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
shorefront/
|
||||||
|
├── backend/
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ ├── alembic/
|
||||||
|
│ │ ├── env.py
|
||||||
|
│ │ └── versions/
|
||||||
|
│ │ └── 0001_initial.py # schema + seed data
|
||||||
|
│ └── app/
|
||||||
|
│ ├── main.py # FastAPI app, CORS, lifespan
|
||||||
|
│ ├── database.py # SQLAlchemy engine + session
|
||||||
|
│ ├── models.py # ORM models
|
||||||
|
│ ├── schemas.py # Pydantic schemas
|
||||||
|
│ ├── auth.py # JWT logic, password hashing
|
||||||
|
│ ├── shorewall_generator.py # ShorewallGenerator class
|
||||||
|
│ └── api/
|
||||||
|
│ ├── auth.py # /auth/*
|
||||||
|
│ ├── configs.py # CRUD + /generate
|
||||||
|
│ ├── zones.py
|
||||||
|
│ ├── interfaces.py
|
||||||
|
│ ├── policies.py
|
||||||
|
│ ├── rules.py
|
||||||
|
│ └── masq.py
|
||||||
|
├── frontend/
|
||||||
|
│ ├── Dockerfile
|
||||||
|
│ ├── nginx.conf # prod: serve static + proxy /api
|
||||||
|
│ ├── vite.config.ts # dev: proxy /api → backend:8000
|
||||||
|
│ ├── package.json
|
||||||
|
│ └── src/
|
||||||
|
│ ├── main.tsx
|
||||||
|
│ ├── App.tsx
|
||||||
|
│ ├── api.ts # axios wrapper, withCredentials, 401 redirect
|
||||||
|
│ ├── routes/
|
||||||
|
│ │ ├── Login.tsx
|
||||||
|
│ │ ├── ConfigList.tsx
|
||||||
|
│ │ └── ConfigDetail.tsx # tabbed: zones/interfaces/policies/rules/masq
|
||||||
|
│ └── components/
|
||||||
|
│ ├── Layout.tsx # dark sidebar + top bar
|
||||||
|
│ ├── DataTable.tsx # reusable table w/ edit/delete
|
||||||
|
│ ├── EntityForm.tsx # reusable MUI Dialog form
|
||||||
|
│ └── GenerateModal.tsx # file preview tabs + ZIP download
|
||||||
|
├── helm/
|
||||||
|
│ └── shorefront/
|
||||||
|
│ ├── Chart.yaml
|
||||||
|
│ ├── values.yaml
|
||||||
|
│ ├── values-prod.yaml
|
||||||
|
│ └── templates/
|
||||||
|
│ ├── _helpers.tpl
|
||||||
|
│ ├── namespace.yaml
|
||||||
|
│ ├── secret.yaml
|
||||||
|
│ ├── configmap.yaml
|
||||||
|
│ ├── pv.yaml # NFS PersistentVolume
|
||||||
|
│ ├── pvc.yaml
|
||||||
|
│ ├── postgres-deployment.yaml
|
||||||
|
│ ├── postgres-service.yaml
|
||||||
|
│ ├── backend-deployment.yaml
|
||||||
|
│ ├── backend-service.yaml
|
||||||
|
│ ├── frontend-deployment.yaml
|
||||||
|
│ ├── frontend-service.yaml
|
||||||
|
│ └── ingress.yaml # Traefik, networking.k8s.io/v1
|
||||||
|
├── docker-compose.yml
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
| Model | Key Fields |
|
||||||
|
|-------|-----------|
|
||||||
|
| `User` | `id`, `username`, `email`, `hashed_password`, `is_active` |
|
||||||
|
| `Config` | `id`, `name`, `description`, `is_active`, `created_at`, `updated_at`, `owner_id FK→User` |
|
||||||
|
| `Zone` | `id`, `config_id FK`, `name` (unique per config), `type` (ipv4/ipv6/firewall), `options` |
|
||||||
|
| `Interface` | `id`, `config_id FK`, `name`, `zone_id FK→Zone`, `options` |
|
||||||
|
| `Policy` | `id`, `config_id FK`, `src_zone_id FK`, `dst_zone_id FK`, `policy` (ACCEPT/DROP/REJECT/CONTINUE), `log_level`, `comment`, `position` |
|
||||||
|
| `Rule` | `id`, `config_id FK`, `action`, `src_zone_id FK`, `dst_zone_id FK`, `src_ip`, `dst_ip`, `proto`, `dport`, `sport`, `comment`, `position` |
|
||||||
|
| `Masq` | `id`, `config_id FK`, `source_network`, `out_interface`, `to_address`, `comment` |
|
||||||
|
|
||||||
|
**Constraints:** Foreign keys enforced. Zone name unique per config. Position/order fields for policies and rules to preserve Shorewall file ordering semantics.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Seed Data (Initial Alembic Migration)
|
||||||
|
|
||||||
|
- User: `admin` / `admin` (must change on first login)
|
||||||
|
- Config: `homelab`
|
||||||
|
- Zones: `fw` (firewall), `net` (ipv4), `loc` (ipv4)
|
||||||
|
- Interface: `eth0` → zone `net`
|
||||||
|
- Policies: `loc→net ACCEPT`, `net→all DROP info`, `all→all REJECT info`
|
||||||
|
- Masq: `192.168.1.0/24` via `eth0`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API Surface
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /auth/register
|
||||||
|
POST /auth/login → sets httpOnly JWT cookie
|
||||||
|
POST /auth/logout → clears cookie
|
||||||
|
GET /auth/me
|
||||||
|
|
||||||
|
GET /configs
|
||||||
|
POST /configs
|
||||||
|
GET /configs/{id}
|
||||||
|
PUT /configs/{id}
|
||||||
|
DELETE /configs/{id}
|
||||||
|
POST /configs/{id}/generate # ?format=zip for ZIP, JSON default
|
||||||
|
|
||||||
|
GET /configs/{id}/zones
|
||||||
|
POST /configs/{id}/zones
|
||||||
|
GET /configs/{id}/zones/{zone_id}
|
||||||
|
PUT /configs/{id}/zones/{zone_id}
|
||||||
|
DELETE /configs/{id}/zones/{zone_id}
|
||||||
|
# same pattern for interfaces, policies, rules, masq
|
||||||
|
```
|
||||||
|
|
||||||
|
**Auth:** JWT in `httpOnly` cookie. `passlib` + `bcrypt` for password hashing. All `/configs/*` routes require valid JWT.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Shorewall Generator
|
||||||
|
|
||||||
|
`app/shorewall_generator.py` — `ShorewallGenerator` class:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class ShorewallGenerator:
|
||||||
|
def __init__(self, config: Config): ...
|
||||||
|
def zones(self) -> str: ...
|
||||||
|
def interfaces(self) -> str: ...
|
||||||
|
def policy(self) -> str: ...
|
||||||
|
def rules(self) -> str: ...
|
||||||
|
def masq(self) -> str: ...
|
||||||
|
def as_json(self) -> dict: ... # { zones, interfaces, policy, rules, masq }
|
||||||
|
def as_zip(self) -> bytes: ... # in-memory ZIP
|
||||||
|
```
|
||||||
|
|
||||||
|
Each method produces a Shorewall-formatted string with a comment header:
|
||||||
|
```
|
||||||
|
# zones — generated by shorefront | config: homelab | 2026-02-28T18:00:00Z
|
||||||
|
#ZONE TYPE OPTIONS
|
||||||
|
fw firewall
|
||||||
|
net ipv4
|
||||||
|
```
|
||||||
|
|
||||||
|
The `/generate` endpoint returns JSON by default; appending `?format=zip` streams a ZIP archive. The frontend uses JSON for the in-browser preview modal and triggers a separate `?format=zip` request for the download button.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Frontend Design
|
||||||
|
|
||||||
|
**Theme:** MUI with custom dark sidebar (`#1a1f2e`), light main content (`#f5f7fa`), white cards.
|
||||||
|
|
||||||
|
**Pages:**
|
||||||
|
- **Login** — centered card, username/password
|
||||||
|
- **Config List** — data table with name, description, active badge, created date, edit/delete actions. FAB to create.
|
||||||
|
- **Config Detail** — breadcrumb, 5 tabs (Zones / Interfaces / Policies / Rules / Masq/NAT). Each tab: `DataTable` + "Add" button → `EntityForm` dialog. Top-right: "Generate Config" button → `GenerateModal`.
|
||||||
|
- **Generate Modal** — 5 tabs with monospace code blocks, copy-to-clipboard per file, Download ZIP button.
|
||||||
|
|
||||||
|
**Key implementation:**
|
||||||
|
- `api.ts`: Axios instance, `baseURL=/api`, `withCredentials: true`, 401 interceptor → redirect to `/login`
|
||||||
|
- `DataTable.tsx`: Generic, accepts column defs + row data, reused across all tabs
|
||||||
|
- `EntityForm.tsx`: Generic MUI Dialog, field config passed per entity type
|
||||||
|
- React Router v6 with `<ProtectedRoute>` checking `GET /auth/me`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Infrastructure
|
||||||
|
|
||||||
|
### Docker Compose (local dev)
|
||||||
|
- Services: `postgres`, `backend`, `frontend`
|
||||||
|
- Backend runs `alembic upgrade head` on startup
|
||||||
|
- Local named volume for postgres data
|
||||||
|
- Backend on port 8000, frontend (Nginx) on port 80
|
||||||
|
|
||||||
|
### Kubernetes / Helm
|
||||||
|
- **Namespace:** `shorefront`
|
||||||
|
- **Ingress:** Traefik (`ingressClassName: traefik`), standard `networking.k8s.io/v1` Ingress
|
||||||
|
- `shorefront.example.com/api/*` → backend service
|
||||||
|
- `shorefront.example.com/*` → frontend service
|
||||||
|
- Hostname configurable in `values.yaml`
|
||||||
|
- **Storage:** Static NFS PersistentVolume at `192.168.17.199:/mnt/user/kubernetesdata/shorefront`, `ReadWriteOnce`, bound via PVC to Postgres deployment
|
||||||
|
- **Secrets:** DB password + JWT secret key in `secret.yaml`, set via `values.yaml` (override at deploy time)
|
||||||
|
- **Migrations:** `alembic upgrade head` runs as an `initContainer` in the backend Deployment
|
||||||
|
- **values.yaml** configures: image tags, replicas, hostname, resource requests/limits, NFS server/path
|
||||||
149
instructions.md
Normal file
149
instructions.md
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
Here’s a Claude Code prompt you can paste as-is and then tweak to taste:
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
You are an expert full‑stack developer.
|
||||||
|
Build a small but production‑ready web application to manage Shorewall firewall configurations with a browser frontend and a database backend. The app should NOT be a toy example but a clean, modular implementation that I can extend.
|
||||||
|
|
||||||
|
## High‑level requirements
|
||||||
|
|
||||||
|
- Purpose: Let users manage Shorewall configurations (zones, interfaces, policies, rules, masq, nat, hosts, etc.) in a web UI and generate the corresponding Shorewall config files on demand.
|
||||||
|
- Stack:
|
||||||
|
- Backend: Python with FastAPI (preferred) or Django, using SQLAlchemy (or the framework’s ORM).
|
||||||
|
- Frontend: React + TypeScript with a simple component structure, using a UI library like MUI or Tailwind for basic styling.
|
||||||
|
- Database: PostgreSQL (but keep ORM models portable).
|
||||||
|
- Architecture:
|
||||||
|
- Clean separation: frontend, backend API, and a “shorewall generator” module that knows how to render the text files.
|
||||||
|
- Use a REST or JSON API between frontend and backend.
|
||||||
|
- Use Docker Compose to run web + db.
|
||||||
|
|
||||||
|
## Domain model and database
|
||||||
|
|
||||||
|
Design a minimal but sensible schema to model Shorewall configs:
|
||||||
|
|
||||||
|
- Core entities:
|
||||||
|
- Config: top‑level object (name, description, created_at, updated_at, is_active).
|
||||||
|
- Zone: belongs to Config (name, type, options).
|
||||||
|
- Interface: belongs to Config (name, zone_id FK, options).
|
||||||
|
- Policy: belongs to Config (src_zone_id, dst_zone_id, policy (ACCEPT/DROP/REJECT), log_level, comment, position/order).
|
||||||
|
- Rule: belongs to Config (action, src_zone_id, dst_zone_id, src_ip/cidr, dst_ip/cidr, proto, dport, sport, comment, position/order).
|
||||||
|
- Masq/NAT entry: belongs to Config (source_network, out_interface, to_address, comment).
|
||||||
|
- Constraints:
|
||||||
|
- Foreign keys for relationships.
|
||||||
|
- Reasonable non‑null constraints.
|
||||||
|
- Basic uniqueness where it makes sense (e.g., zone name per config).
|
||||||
|
|
||||||
|
Generate:
|
||||||
|
- ORM models.
|
||||||
|
- Database migration setup (e.g. Alembic) with an initial migration.
|
||||||
|
|
||||||
|
## Shorewall file generation
|
||||||
|
|
||||||
|
Implement a separate Python module that converts a Config from the database into Shorewall text files:
|
||||||
|
|
||||||
|
- Target files (as functions or one class with multiple methods):
|
||||||
|
- zones
|
||||||
|
- interfaces
|
||||||
|
- policy
|
||||||
|
- rules
|
||||||
|
- masq
|
||||||
|
- Each generator should:
|
||||||
|
- Accept a Config ID (or ORM object) and query all related entities.
|
||||||
|
- Produce a string that matches Shorewall file syntax, with headers like `#ZONE TYPE`, `#ACTION SOURCE DEST`, etc. [wiki.calculate-linux](https://wiki.calculate-linux.org/shorewall)
|
||||||
|
- Include a small comment header at the top with config name and a generated timestamp.
|
||||||
|
- Implement one function that bundles all generated file contents into:
|
||||||
|
- Either a ZIP archive in memory, or
|
||||||
|
- A JSON object `{ zones: "...", interfaces: "...", policy: "...", rules: "...", masq: "..." }`
|
||||||
|
- We can later write this to `/etc/shorewall/` manually.
|
||||||
|
|
||||||
|
## Backend API
|
||||||
|
|
||||||
|
Use FastAPI (or Django REST) to implement these endpoints:
|
||||||
|
|
||||||
|
- Auth (simple for now):
|
||||||
|
- POST /auth/register
|
||||||
|
- POST /auth/login
|
||||||
|
- Use JWT or simple session cookie; protect config management endpoints.
|
||||||
|
- Config management:
|
||||||
|
- GET /configs
|
||||||
|
- POST /configs
|
||||||
|
- GET /configs/{id}
|
||||||
|
- PUT /configs/{id}
|
||||||
|
- DELETE /configs/{id}
|
||||||
|
- Nested resources:
|
||||||
|
- CRUD for zones, interfaces, policies, rules, masq entries under a given config ID.
|
||||||
|
- Generation:
|
||||||
|
- POST /configs/{id}/generate
|
||||||
|
- Returns the generated Shorewall files as JSON or as a ZIP download.
|
||||||
|
- Implementation details:
|
||||||
|
- Pydantic models for request/response schemas.
|
||||||
|
- Proper error handling (404 if config not found, 400 on validation errors).
|
||||||
|
- Type hints everywhere.
|
||||||
|
|
||||||
|
## Frontend
|
||||||
|
|
||||||
|
Create a small React + TypeScript SPA:
|
||||||
|
|
||||||
|
- Pages:
|
||||||
|
- Login/register page.
|
||||||
|
- Config list page.
|
||||||
|
- Config detail/edit page with tabs for:
|
||||||
|
- Zones
|
||||||
|
- Interfaces
|
||||||
|
- Policies
|
||||||
|
- Rules
|
||||||
|
- Masq/NAT
|
||||||
|
- Each tab:
|
||||||
|
- Shows a table of existing entries.
|
||||||
|
- Has forms to create/edit/delete entries.
|
||||||
|
- Generation UI:
|
||||||
|
- On the config detail page, add a “Generate Shorewall config” button that calls `/configs/{id}/generate`.
|
||||||
|
- Show the generated file contents in a modal dialog or separate view with tabs for zones/interfaces/policy/rules/masq.
|
||||||
|
- Add a button to download the ZIP (if you implement ZIP) or copy text.
|
||||||
|
- Implementation details:
|
||||||
|
- Use React Router for navigation.
|
||||||
|
- API client:
|
||||||
|
- Centralized `api.ts` that wraps fetch/axios calls with the correct base URL and auth headers.
|
||||||
|
- Minimal styling with MUI or Tailwind; keep it functional, not pretty.
|
||||||
|
|
||||||
|
## Project structure and tooling
|
||||||
|
|
||||||
|
Provide:
|
||||||
|
|
||||||
|
- A clear project layout, e.g.:
|
||||||
|
|
||||||
|
- backend/
|
||||||
|
- app/main.py
|
||||||
|
- app/models.py
|
||||||
|
- app/schemas.py
|
||||||
|
- app/api/
|
||||||
|
- app/services/
|
||||||
|
- app/shorewall_generator.py
|
||||||
|
- alembic/…
|
||||||
|
- frontend/
|
||||||
|
- src/App.tsx
|
||||||
|
- src/routes/…
|
||||||
|
- src/components/…
|
||||||
|
- src/api.ts
|
||||||
|
- docker-compose.yml
|
||||||
|
- README.md
|
||||||
|
|
||||||
|
- Docker:
|
||||||
|
- `docker-compose.yml` to run:
|
||||||
|
- backend service
|
||||||
|
- frontend service
|
||||||
|
- postgres
|
||||||
|
- Provide Dockerfiles for backend and frontend.
|
||||||
|
|
||||||
|
## What to output
|
||||||
|
|
||||||
|
- All core backend files (FastAPI app, models, schemas, routers, shorewall generator).
|
||||||
|
- All core frontend files (entry, routes, main pages, key components).
|
||||||
|
- Database and migration setup.
|
||||||
|
- Dockerfiles and docker-compose.yml.
|
||||||
|
- A concise README with:
|
||||||
|
- How to start dev environment.
|
||||||
|
- How to create the first user.
|
||||||
|
- How to create a config and generate Shorewall files.
|
||||||
|
|
||||||
|
Focus on correctness, a clean structure, and code that I can copy into a repo and run with minimal adjustments.
|
||||||
Reference in New Issue
Block a user