Files
home-server/clusters/noble/bootstrap/newt/README.md

113 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Newt (Pangolin) — noble
This is the **primary** automation path for **public** hostnames to workloads in this cluster (it **replaces** in-cluster ExternalDNS). [Newt](https://github.com/fosrl/newt) is the on-prem agent that connects your cluster to a **Pangolin** site (WireGuard tunnel). The [Fossorial Helm chart](https://github.com/fosrl/helm-charts) deploys one or more instances.
**Secrets:** Never commit endpoint, Newt ID, or Newt secret in **plain** YAML. If credentials were pasted into chat or CI logs, **rotate them** in Pangolin and recreate the Kubernetes Secret.
## 1. Create the Secret
Keys must match `values.yaml` (`PANGOLIN_ENDPOINT`, `NEWT_ID`, `NEWT_SECRET`).
### Option A — SOPS (safe for GitOps)
Encrypt a normal **`Secret`** with [Mozilla SOPS](https://github.com/getsops/sops) and **age** (see **`clusters/noble/secrets/README.md`** and **`.sops.yaml`**). The repo includes an encrypted example at **`clusters/noble/secrets/newt-pangolin-auth.secret.yaml`** — edit with `sops` after exporting **`SOPS_AGE_KEY_FILE`** to your **`age-key.txt`**, or create a new file and encrypt it.
```bash
export SOPS_AGE_KEY_FILE=/absolute/path/to/home-server/age-key.txt
sops clusters/noble/secrets/newt-pangolin-auth.secret.yaml
# then:
sops -d clusters/noble/secrets/newt-pangolin-auth.secret.yaml | kubectl apply -f -
```
**Ansible** (`noble.yml`) applies all **`clusters/noble/secrets/*.yaml`** automatically when **`age-key.txt`** exists at the repo root.
### Option B — Imperative Secret (not in git)
```bash
kubectl apply -f clusters/noble/bootstrap/newt/namespace.yaml
kubectl -n newt create secret generic newt-pangolin-auth \
--from-literal=PANGOLIN_ENDPOINT='https://pangolin.pcenicni.dev' \
--from-literal=NEWT_ID='YOUR_NEWT_ID' \
--from-literal=NEWT_SECRET='YOUR_NEWT_SECRET'
```
Use the Pangolin UI or [Integration API](https://docs.pangolin.net/manage/common-api-routes) (`pick-site-defaults` + `create site`) to obtain a Newt ID and secret for a new site if you are not reusing an existing pair.
## 2. Install the chart
```bash
helm repo add fossorial https://charts.fossorial.io
helm repo update
helm upgrade --install newt fossorial/newt \
--namespace newt \
--version 1.5.0 \
-f clusters/noble/bootstrap/newt/values.yaml \
--wait
```
## 3. DNS: CNAME at your DNS host + Pangolin API for routes
Pangolin does not replace your public DNS provider. Typical flow:
1. **Link a domain** in Pangolin (organization **Domains**). For **CNAME**-style domains, Pangolin shows the hostname you must **CNAME** to at Cloudflare / your registrar (see [Domains](https://docs.pangolin.net/manage/common-api-routes#list-domains)).
2. **Create public HTTP resources** (and **targets** to your Newt **site**) via the [Integration API](https://docs.pangolin.net/manage/integration-api) — same flows as the UI. Swagger: `https://<your-api-host>/v1/docs` (self-hosted: enable `enable_integration_api` and route `api.example.com` → integration port per [docs](https://docs.pangolin.net/self-host/advanced/integration-api)).
Minimal patterns (Bearer token = org or root API key):
```bash
export API_BASE='https://api.example.com/v1' # your Pangolin Integration API base
export ORG_ID='your-org-id'
export TOKEN='your-integration-api-key'
# Domains already linked to the org (use domainId when creating a resource)
curl -sS -H "Authorization: Bearer ${TOKEN}" \
"${API_BASE}/org/${ORG_ID}/domains"
# Create an HTTP resource on a domain (FQDN = subdomain + base domain for NS/wildcard domains)
curl -sS -X PUT -H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
"${API_BASE}/org/${ORG_ID}/resource" \
-d '{
"name": "Example app",
"http": true,
"domainId": "YOUR_DOMAIN_ID",
"protocol": "tcp",
"subdomain": "my-app"
}'
# Point the resource at your Newt site backend (siteId from list sites / create site; ip:port inside the tunnel)
curl -sS -X PUT -H "Authorization: Bearer ${TOKEN}" -H 'Content-Type: application/json' \
"${API_BASE}/resource/RESOURCE_ID/target" \
-d '{
"siteId": YOUR_SITE_ID,
"ip": "10.x.x.x",
"port": 443,
"method": "http"
}'
```
Exact JSON fields and IDs differ by domain type (**ns** vs **cname** vs **wildcard**); see [Common API routes](https://docs.pangolin.net/manage/common-api-routes) and Swagger.
### Authentik on a public name
Use **`noble_authentik_ingress_extra_hosts`** (see **`ansible/roles/noble_authentik/README.md`**) so the Authentik Ingress (and **cert-manager** SANs) include your public FQDN, then create the Pangolin **HTTP** resource + **target** to the same Traefik **:443** endpoint as other apps. One Newt site can carry many hostnames.
### What to put in Pangolin (resource + target)
1. **Public hostname** — the FQDN users type in the browser (must match **`noble_authentik_ingress_extra_hosts`** and your **CNAME** at the DNS host Pangolin documents for that domain).
2. **Site** — the Pangolin **site** that owns your **Newt** pair (same **`NEWT_ID`** / **`NEWT_SECRET`** as the cluster Secret). In the UI: **Sites** → pick the site connected to this cluster.
3. **Target `ip`** — an address **reachable from inside the tunnel** to **Traefik HTTPS**. On noble this is usually the Traefik **LoadBalancer** IP (repo pins **`192.168.50.211`** in **`clusters/noble/bootstrap/traefik/values.yaml`**). Confirm live:
`kubectl -n traefik get svc -l app.kubernetes.io/name=traefik -o wide`
Use **`EXTERNAL-IP`** (or **`LOAD_BALANCER_IP`** from the Service status) as **`ip`**. If Newt runs **in** the cluster, that MetalLB/LAN VIP is correct; if you run Newt elsewhere, use whatever L3 path reaches Traefik from that host.
4. **Target `port`****`443`** (TLS to Traefik; SNI carries the public hostname).
5. **Target `method`****`http`** in the Integration API examples above (TLS is still terminated at Traefik; Pangolins field names follow their docs).
Discovery in Pangolins UI: **Domains** (see required CNAME) → **Resources****Add** HTTP resource for the subdomain/FQDN → **Targets** / **Backends** → attach **site** + **ip:port**. Official flow: [Domains](https://docs.pangolin.net/manage/common-api-routes#list-domains), [Integration API](https://docs.pangolin.net/manage/integration-api), and your deployments **Swagger** at **`https://<integration-api-host>/v1/docs`** when enabled.
## LAN vs internet
- **LAN / VPN:** point **`*.apps.noble.lab.pcenicni.dev`** at the Traefik **LoadBalancer** (**`192.168.50.211`**) with local or split-horizon DNS if you want direct in-lab access.
- **Internet-facing:** use Pangolin **resources** + **targets** to the Newt **site**; public names rely on **CNAME** records at your DNS provider per Pangolins domain setup, not on ExternalDNS in the cluster.