diff --git a/README.md b/README.md index 336af9f..694e4f2 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Belangrijk: | 01 | ArgoCD bootstrappen | [docs/01-argocd-bootstrap.md](docs/01-argocd-bootstrap.md) | Kern | 30 min | | 02 | podinfo deployen via GitOps | [docs/02-deploy-podinfo.md](docs/02-deploy-podinfo.md) | Kern | 30 min | | 03 | MetalLB + Ingress-Nginx | [docs/03-metallb-ingress.md](docs/03-metallb-ingress.md) | Kern | 45 min | +| 03b | Cloudflare Tunnel (webhooks) | [docs/03b-cloudflare-tunnel.md](docs/03b-cloudflare-tunnel.md) | Bonus | 30–45 min | | 04 | Tekton pipeline | [docs/04-tekton-pipeline.md](docs/04-tekton-pipeline.md) | Kern | 45 min | | 05 | App upgrade + reflectie | [docs/05-app-upgrade.md](docs/05-app-upgrade.md) | Kern | 15 min | | 06 | Prometheus + Grafana | [docs/06-monitoring.md](docs/06-monitoring.md) | Bonus | 60 min | @@ -127,6 +128,7 @@ om precies te zien wat er in die specifieke oefening mist. | `solution/01-argocd-bootstrap` | ArgoCD draait | | `solution/02-deploy-podinfo` | podinfo gesynchroniseerd via ArgoCD | | `solution/03-metallb-ingress` | LAN-toegang via MetalLB + Ingress | +| `solution/03b-cloudflare-tunnel` | Cloudflare tunnel connector (token placeholders) | | `solution/04-tekton-pipeline` | Volledige GitOps CI-loop | | `solution/05-app-upgrade` | podinfo op v6.7.0 | | `solution/06-monitoring` | Prometheus + Grafana actief | diff --git a/docs/03b-cloudflare-tunnel.md b/docs/03b-cloudflare-tunnel.md new file mode 100644 index 0000000..16f0e75 --- /dev/null +++ b/docs/03b-cloudflare-tunnel.md @@ -0,0 +1,252 @@ +# Oefening 03b (Bonus) — Cloudflare Tunnel voor webhooks + +**Tijd**: ~30–45 minuten +**Doel**: Je lokale workshop-cluster vanaf internet bereikbaar maken voor inkomende webhooks (bijv. GitHub -> Tekton). + +--- + +## Wat je leert + +- Waarom host-only networking (`192.168.56.x`) niet direct bereikbaar is vanaf internet +- Hoe Cloudflare Tunnel verkeer van internet veilig naar een interne Kubernetes-service brengt +- Hoe je dit later gebruikt in Oefening 04 voor echte GitHub webhooks + +--- + +## Leeswijzer + +> **Voor beginners (optioneel):** +> Zie Cloudflare Tunnel als een "uitgaande connector": +> een pod in jouw cluster belt zelf uit naar Cloudflare. +> Daarna kan Cloudflare inkomend verkeer over die bestaande verbinding terugsturen. +> Je hoeft dus geen poorten op je laptop/router open te zetten. + +--- + +## Vereisten + +- Oefening 03 afgerond (Ingress-Nginx werkt) +- Een Cloudflare account +- Een domein dat je in Cloudflare beheert +- Je repo/fork op `main` + +--- + +## Architectuur (hoog niveau) + +```text +GitHub webhook + | + v +https://tekton-webhook. + | + v +Cloudflare Edge + | + v +Cloudflare Tunnel (cloudflared pod in cluster) + | + v +el-github-push-listener.tekton-pipelines.svc:8080 +``` + +Belangrijk: +- Dit werkt ook als je cluster alleen op host-only netwerk draait. +- Cloudflare bereikt je cluster via de actieve tunnelverbinding, niet via je LAN-IP. + +--- + +## Stappen + +### 1. Tunnel in Cloudflare aanmaken + +In Cloudflare dashboard: + +1. Ga naar **Zero Trust** (of **Cloudflare One**) +2. Ga naar **Networks -> Tunnels** +3. Klik **Create a tunnel** +4. Kies **Cloudflared** +5. Geef een naam, bijvoorbeeld `ops-demo-workshop` +6. Cloudflare toont een **Tunnel Token** (lange string) — bewaar deze veilig + +> **Voor beginners (optioneel):** +> Die token is het wachtwoord waarmee jouw `cloudflared` pod zich aanmeldt. +> Iedereen met deze token kan jouw tunnel gebruiken; behandel hem als secret. + +--- + +### 2. Public hostname in Cloudflare configureren + +In dezelfde tunnel: + +1. Ga naar **Public Hostnames** +2. Voeg een hostname toe, bijvoorbeeld: + - Subdomain: `tekton-webhook` + - Domain: `` +3. Service type: `HTTP` +4. URL: `http://el-github-push-listener.tekton-pipelines.svc.cluster.local:8080` +5. Sla op + +> **Voor beginners (optioneel):** +> Deze URL is expres een interne Kubernetes-service. +> Alleen de cloudflared pod hoeft die te kunnen bereiken; internet ziet alleen de publieke hostname. + +--- + +### 3. Kubernetes manifests toevoegen + +Maak de volgende bestanden. + +**`manifests/networking/cloudflared/namespace.yaml`** + +```yaml +apiVersion: v1 +kind: Namespace +metadata: + name: cloudflare +``` + +**`manifests/networking/cloudflared/token.secret.yaml`** + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: cloudflared-token + namespace: cloudflare +type: Opaque +stringData: + token: "PLAK_HIER_JE_CLOUDFLARE_TUNNEL_TOKEN" +``` + +**`manifests/networking/cloudflared/deployment.yaml`** + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: cloudflared + namespace: cloudflare +spec: + replicas: 1 + selector: + matchLabels: + app: cloudflared + template: + metadata: + labels: + app: cloudflared + spec: + containers: + - name: cloudflared + image: cloudflare/cloudflared:2025.2.1 + args: + - tunnel + - --no-autoupdate + - run + - --token + - $(TUNNEL_TOKEN) + env: + - name: TUNNEL_TOKEN + valueFrom: + secretKeyRef: + name: cloudflared-token + key: token + resources: + requests: + cpu: 20m + memory: 64Mi +``` + +**`apps/networking/cloudflared.yaml`** + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cloudflared + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "4" +spec: + project: workshop + source: + repoURL: JOUW_FORK_URL + targetRevision: HEAD + path: manifests/networking/cloudflared + destination: + server: https://kubernetes.default.svc + namespace: cloudflare + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true +``` + +Vervang: +- `PLAK_HIER_JE_CLOUDFLARE_TUNNEL_TOKEN` +- `JOUW_FORK_URL` + +--- + +### 4. Committen en pushen + +> **HOST** +> ```bash +> git add apps/networking/cloudflared.yaml manifests/networking/cloudflared/ +> git commit -m "feat: add cloudflared tunnel connector" +> git push +> ``` + +Wacht daarna op `Synced/Healthy`: + +> **VM** +> ```bash +> kubectl get application cloudflared -n argocd +> kubectl get pods -n cloudflare +> ``` + +--- + +### 5. Tunnel-status controleren + +> **VM** +> ```bash +> kubectl logs -n cloudflare deploy/cloudflared --tail=100 +> ``` + +Zoek op regels zoals "connected" of "registered tunnel connection". + +--- + +### 6. Voorbereiden op Oefening 04 webhook + +Als je in Oefening 04 Tekton Triggers hebt geïnstalleerd, gebruik in GitHub: + +- **Payload URL**: `https://tekton-webhook.` + +Dus niet meer de host-only URL met `192.168.56.200.nip.io`. + +--- + +## Probleemoplossing + +| Symptoom | Oplossing | +|---|---| +| cloudflared pod blijft CrashLoopBackOff | Controleer of de tunnel token klopt en niet verlopen/ingetrokken is | +| Tunnel lijkt up, maar webhook geeft 502/504 | Controleer of `el-github-push-listener` service bestaat in `tekton-pipelines` | +| Geen verkeer in Tekton na GitHub push | Controleer GitHub webhook deliveries + event type `push` + secret | +| Argo app `cloudflared` blijft `Unknown` | Controleer of `repoURL` in `apps/networking/cloudflared.yaml` naar jouw fork wijst | + +--- + +## Security-opmerking + +Gebruik in een echte omgeving liever: +- externe secret manager voor tunnel token +- aparte Cloudflare tunnel per omgeving +- least-privilege Cloudflare account/API instellingen + +Voor deze workshop is één token in een Kubernetes Secret voldoende. diff --git a/docs/04-tekton-pipeline.md b/docs/04-tekton-pipeline.md index 70f7b3c..fb68dec 100644 --- a/docs/04-tekton-pipeline.md +++ b/docs/04-tekton-pipeline.md @@ -475,6 +475,9 @@ Gebruik je GitLab/Gitea/Bitbucket, dan blijft het patroon hetzelfde maar de inte > - een publieke tunnel (`ngrok`, `cloudflared tunnel`) > - een webhook relay (`smee.io`) > - of een publiek bereikbare cluster endpoint (geen host-only-only setup) +> +> Als je **Oefening 03b** hebt gedaan, gebruik dan je Cloudflare Tunnel URL +> (bijv. `https://tekton-webhook.`) als webhook endpoint. ### 1. Triggers resources toevoegen diff --git a/roadmap.md b/roadmap.md index 1801083..0af716f 100644 --- a/roadmap.md +++ b/roadmap.md @@ -7,6 +7,7 @@ | 01 | Bootstrap ArgoCD | Core | 30 min | ✅ Implemented | | 02 | Deploy podinfo via GitOps | Core | 30 min | ✅ Implemented | | 03 | MetalLB + Ingress-Nginx (LAN exposure) | Core | 45 min | ✅ Implemented | +| 03b | Cloudflare Tunnel voor webhooks | Bonus | 30–45 min | ✅ Implemented | | 04 | Tekton pipeline (image tag bump → GitOps loop) | Core | 45 min | ✅ Implemented | | 05 | App upgrade via GitOps | Core | 15 min | ✅ Implemented | | 06 | Monitoring: Prometheus + Grafana | Bonus | 60 min | ✅ Implemented | @@ -24,6 +25,7 @@ Model: solution branches are **standalone per exercise** (not cumulative). | `solution/01-argocd-bootstrap` | ArgoCD running, root app applied | | `solution/02-deploy-podinfo` | podinfo synced via ArgoCD | | `solution/03-metallb-ingress` | MetalLB + Ingress-Nginx + podinfo reachable on LAN; CRD `caBundle` drift handling included | +| `solution/03b-cloudflare-tunnel` | Cloudflared tunnel connector manifests met token placeholders | | `solution/04-tekton-pipeline` | Full Tekton GitOps loop working | | `solution/05-app-upgrade` | deployment.yaml bumped to 6.7.0 | | `solution/06-monitoring` | Prometheus + Grafana running |