Compare commits

..

4 Commits

Author SHA1 Message Date
6a7cf71f84 Added homepage autodiscovery to helm charts
Some checks are pending
Build containers when image tags change / build-if-image-changed (backend, shorefront-backend, shorefront backend, backend/Dockerfile, git.baumann.gr/adebaumann/shorefront-backend, .backend.image) (push) Waiting to run
Build containers when image tags change / build-if-image-changed (frontend, shorefront-frontend, shorefront frontend, frontend/Dockerfile, git.baumann.gr/adebaumann/shorefront-frontend, .frontend.image) (push) Waiting to run
2026-03-16 00:26:38 +01:00
956f0c2cf5 docs: update README to reflect OIDC auth, secrets management, and CI/CD
Replace admin/admin credentials with Keycloak OIDC flow, fix Kubernetes
deploy section to use create-secrets.sh instead of --set secrets.*, add
CI/CD section, and update domain model references (masq→snat, new hosts/params).
2026-03-07 12:36:11 +01:00
2b9cbfd884 chore: add .gitignore and track frontend/package-lock.json
Some checks failed
Build containers when image tags change / build-if-image-changed (backend, shorefront-backend, shorefront backend, backend/Dockerfile, git.baumann.gr/adebaumann/shorefront-backend, .backend.image) (push) Has been cancelled
Build containers when image tags change / build-if-image-changed (frontend, shorefront-frontend, shorefront frontend, frontend/Dockerfile, git.baumann.gr/adebaumann/shorefront-frontend, .frontend.image) (push) Has been cancelled
2026-03-01 22:07:45 +01:00
6699bf7421 docs: document command-line download via config token in README 2026-03-01 22:03:30 +01:00
9 changed files with 4236 additions and 20 deletions

26
.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# Python
__pycache__/
*.py[cod]
*.pyo
.env
.venv/
venv/
# Frontend
frontend/node_modules/
frontend/dist/
frontend/.env.local
# Generated shorewall output
shorewall/
shorewall.tar.gz
# Secrets
secrets
secrets/
# Editor / OS
.DS_Store
.idea/
.vscode/
*.swp

View File

@@ -6,6 +6,7 @@ A production-ready web application for managing [Shorewall](http://shorewall.net
- **Backend:** Python 3.12, FastAPI, SQLAlchemy 2, Alembic, PostgreSQL 15 - **Backend:** Python 3.12, FastAPI, SQLAlchemy 2, Alembic, PostgreSQL 15
- **Frontend:** React 18, TypeScript, Vite, MUI v5, React Router v6, Axios - **Frontend:** React 18, TypeScript, Vite, MUI v5, React Router v6, Axios
- **Auth:** Keycloak (OIDC), JWT session cookie
- **Infra:** Docker Compose (local dev), Helm + Kubernetes + Traefik (production) - **Infra:** Docker Compose (local dev), Helm + Kubernetes + Traefik (production)
--- ---
@@ -22,7 +23,7 @@ docker compose up --build
# 3. Open http://localhost # 3. Open http://localhost
``` ```
Default credentials: **admin** / **admin** — change on first login. Authentication is handled via Keycloak OIDC. You will be redirected to your Keycloak instance to log in. Your Keycloak user must be a member of the **firewall admins** group.
--- ---
@@ -37,6 +38,11 @@ pip install -r requirements.txt
# Set environment variables # Set environment variables
export DATABASE_URL=postgresql://shorefront:changeme@localhost:5432/shorefront export DATABASE_URL=postgresql://shorefront:changeme@localhost:5432/shorefront
export JWT_SECRET_KEY=dev-secret export JWT_SECRET_KEY=dev-secret
export KEYCLOAK_URL=https://sso.example.com
export KEYCLOAK_REALM=myrealm
export KEYCLOAK_CLIENT_ID=shorefront
export KEYCLOAK_CLIENT_SECRET=<client-secret>
export KEYCLOAK_REDIRECT_URI=http://localhost:8000/auth/oidc/callback
# Run migrations (creates schema + seed data) # Run migrations (creates schema + seed data)
alembic upgrade head alembic upgrade head
@@ -60,12 +66,12 @@ npm run dev
## First Steps After Login ## First Steps After Login
1. Log in at `/login` with **admin** / **admin**. 1. Log in — you will be redirected to Keycloak. Your account must be in the **firewall admins** group.
2. A sample **homelab** config is pre-loaded with: 2. A sample **homelab** config is pre-loaded with:
- Zones: `fw` (firewall), `net` (ipv4), `loc` (ipv4) - Zones: `fw` (firewall), `net` (ipv4), `loc` (ipv4)
- Interface: `eth0` → zone `net` - Interface: `eth0` → zone `net`
- Policies: loc→net ACCEPT, net→fw DROP, etc. - Policies: loc→net ACCEPT, net→fw DROP, etc.
- Masq: `192.168.1.0/24` via `eth0` - SNAT: `192.168.1.0/24` via `eth0`
3. Click **homelab** to open the Config Detail page. 3. Click **homelab** to open the Config Detail page.
4. Click **Generate Config** to preview or download the Shorewall files. 4. Click **Generate Config** to preview or download the Shorewall files.
5. Create your own configs from the **Configurations** page. 5. Create your own configs from the **Configurations** page.
@@ -76,8 +82,33 @@ npm run dev
On the Config Detail page, click **Generate Config**: On the Config Detail page, click **Generate Config**:
- **Preview:** File contents appear in a tabbed modal (zones / interfaces / policy / rules / masq) with copy-to-clipboard buttons. - **Preview:** File contents appear in a tabbed modal (zones / interfaces / policy / rules / snat) with copy-to-clipboard buttons.
- **Download ZIP:** Downloads `<config-name>-shorewall.zip` with all five files ready to copy to `/etc/shorewall/`. - **Download ZIP:** Downloads `<config-name>-shorewall.zip` with all files ready to copy to `/etc/shorewall/`.
---
## Command-Line Download
Each config has a **Download Token** — a secret string that allows downloading the generated ZIP without an active session. Useful for automation scripts and CI pipelines.
### Finding your token
Open a config in the UI. The **Download Token** field is shown above the tabs. Click the copy icon to copy it.
### Downloading via curl
```bash
curl -X POST "https://<host>/api/configs/<config-id>/generate?format=zip" \
-H 'Content-Type: application/json' \
-d '{"token": "<your-download-token>"}' \
-o shorewall.zip
```
Replace `<config-id>` with the numeric ID visible in the URL when you open a config (e.g. `/configs/1`).
### Rotating the token
Click the **Regenerate** button (⟳) next to the token field. The old token is immediately invalidated. Update any scripts that use it.
--- ---
@@ -96,30 +127,34 @@ FastAPI generates interactive docs automatically:
- Kubernetes cluster with Traefik as the ingress controller - Kubernetes cluster with Traefik as the ingress controller
- NFS share accessible at `192.168.17.199:/mnt/user/kubernetesdata/shorefront` - NFS share accessible at `192.168.17.199:/mnt/user/kubernetesdata/shorefront`
- Images pushed to a container registry - Keycloak instance with a `shorefront` client configured
- Images available in the container registry (see CI/CD below)
### Build and Push Images ### 1. Create Secrets
Helm does **not** manage the Kubernetes secret. Run this once before the first deploy (and whenever credentials change):
```bash ```bash
docker build -t <registry>/shorefront-backend:latest ./backend export POSTGRES_PASSWORD=<strong-password>
docker build -t <registry>/shorefront-frontend:latest ./frontend export JWT_SECRET_KEY=<strong-jwt-secret>
docker push <registry>/shorefront-backend:latest export KEYCLOAK_CLIENT_SECRET=<keycloak-client-secret>
docker push <registry>/shorefront-frontend:latest
bash scripts/create-secrets.sh
``` ```
### Deploy This creates/updates the `shorefront-secret` Secret in the `shorefront` namespace.
### 2. Deploy
```bash ```bash
helm upgrade --install shorefront ./helm/shorefront \ helm upgrade --install shorefront ./helm/shorefront \
--values ./helm/shorefront/values-prod.yaml \ --namespace shorefront \
--set backend.image=<registry>/shorefront-backend \ --create-namespace
--set frontend.image=<registry>/shorefront-frontend \
--set ingress.host=shorefront.yourdomain.com \
--set secrets.postgresPassword=<strong-password> \
--set secrets.jwtSecretKey=<strong-jwt-secret>
``` ```
### Verify Rollout Override values as needed (e.g. ingress host, Keycloak URL) via `--set` or a custom values file.
### 3. Verify Rollout
```bash ```bash
kubectl rollout status deployment/backend -n shorefront kubectl rollout status deployment/backend -n shorefront
@@ -142,6 +177,18 @@ kubectl delete pv shorefront-postgres-pv
--- ---
## CI/CD
A Gitea Actions workflow (`.gitea/workflows/build-containers-on-demand.yml`) automatically builds and pushes images when `helm/shorefront/values.yaml`, `frontend/Dockerfile`, or `backend/Dockerfile` change.
- Image tag is read from `containers.version` in `values.yaml`
- Images are pushed to `git.baumann.gr/adebaumann/shorefront-{frontend,backend}:<version>`
- Requires a `REGISTRY_TOKEN` secret configured in Gitea
**To release a new version:** bump `containers.version` in `values.yaml` and push. The workflow builds and pushes both images. Then run `helm upgrade` to deploy.
---
## Project Structure ## Project Structure
``` ```
@@ -154,9 +201,18 @@ shorefront/
│ ├── main.py # FastAPI app │ ├── main.py # FastAPI app
│ ├── models.py # SQLAlchemy ORM models │ ├── models.py # SQLAlchemy ORM models
│ ├── schemas.py # Pydantic schemas │ ├── schemas.py # Pydantic schemas
│ ├── auth.py # JWT auth │ ├── auth.py # JWT + OIDC auth
│ ├── shorewall_generator.py │ ├── shorewall_generator.py
│ └── api/ # Route handlers │ └── api/ # Route handlers
│ ├── auth.py # OIDC login/callback/logout
│ ├── configs.py # Config CRUD + generate
│ ├── zones.py
│ ├── interfaces.py
│ ├── policies.py
│ ├── rules.py
│ ├── snat.py
│ ├── hosts.py
│ └── params.py
├── frontend/ ├── frontend/
│ ├── Dockerfile │ ├── Dockerfile
│ ├── nginx.conf │ ├── nginx.conf
@@ -166,6 +222,8 @@ shorefront/
│ ├── routes/ # Page components │ ├── routes/ # Page components
│ └── components/ # Shared UI components │ └── components/ # Shared UI components
├── helm/shorefront/ # Kubernetes Helm chart ├── helm/shorefront/ # Kubernetes Helm chart
├── scripts/
│ └── create-secrets.sh # Creates k8s Secret before deploy
├── docker-compose.yml ├── docker-compose.yml
└── README.md └── README.md
``` ```

4112
frontend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,3 +7,7 @@ app.kubernetes.io/name: {{ include "shorefront.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }} {{- end }}
{{- define "shorefront.podLabels" -}}
app.kubernetes.io/name: {{ include "shorefront.name" . }}
{{- end }}

View File

@@ -15,6 +15,7 @@ spec:
metadata: metadata:
labels: labels:
app: backend app: backend
{{- include "shorefront.podLabels" . | nindent 8 }}
spec: spec:
initContainers: initContainers:
- name: migrate - name: migrate

View File

@@ -15,6 +15,7 @@ spec:
metadata: metadata:
labels: labels:
app: frontend app: frontend
{{- include "shorefront.podLabels" . | nindent 8 }}
spec: spec:
containers: containers:
- name: frontend - name: frontend

View File

@@ -7,6 +7,9 @@ metadata:
{{- include "shorefront.labels" . | nindent 4 }} {{- include "shorefront.labels" . | nindent 4 }}
annotations: annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
{{- with .Values.ingress.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec: spec:
ingressClassName: {{ .Values.ingress.ingressClassName }} ingressClassName: {{ .Values.ingress.ingressClassName }}
rules: rules:

View File

@@ -15,6 +15,7 @@ spec:
metadata: metadata:
labels: labels:
app: postgres app: postgres
{{- include "shorefront.podLabels" . | nindent 8 }}
spec: spec:
securityContext: securityContext:
runAsUser: {{ .Values.postgres.runAsUser }} runAsUser: {{ .Values.postgres.runAsUser }}

View File

@@ -34,6 +34,16 @@ nfs:
ingress: ingress:
host: shorefront.baumann.gr host: shorefront.baumann.gr
ingressClassName: traefik ingressClassName: traefik
annotations:
gethomepage.dev/enabled: "true"
gethomepage.dev/name: "Shorefront"
gethomepage.dev/description: "Shorewall management system"
gethomepage.dev/group: "Kubernetes"
gethomepage.dev/icon: ""
gethomepage.dev/href: "https://shorefront.baumann.gr"
gethomepage.dev/ping: "https://shorefront.baumann.gr"
gethomepage.dev/pod-selector: "app.kubernetes.io/name=shorefront"
keycloak: keycloak:
url: https://sso.baumann.gr url: https://sso.baumann.gr