# T02 — K8s Foundations Phase 1 of NK-WP-0001: namespaces, NetworkPolicies, cert-manager, StorageClass. ## Prerequisites - K3s cluster running (ThreePhoenix HA or single-node dev) - T01 Phase 0a complete (KeePassXC vault populated, ops bundle exported) - `kubectl` configured with cluster access ## Apply order ```bash # 1. Install cert-manager (if not already on cluster) helm repo add jetstack https://charts.jetstack.io helm repo update helm install cert-manager jetstack/cert-manager \ --namespace cert-manager --create-namespace \ --set crds.enabled=true # Wait for cert-manager to be ready kubectl rollout status deployment/cert-manager -n cert-manager # 2. Create namespaces kubectl apply -f namespaces/namespaces.yaml # 3. Apply NetworkPolicies kubectl apply -f network-policies/netpol-sso.yaml kubectl apply -f network-policies/netpol-mfa.yaml kubectl apply -f network-policies/netpol-databases.yaml # 4. Create ClusterIssuers # Edit issuers.yaml first: replace ACME_EMAIL with your address kubectl apply -f cert-manager/issuers.yaml # 5. Verify cert-manager with test certificate kubectl apply -f cert-manager/test-certificate.yaml kubectl wait --for=condition=Ready certificate/selfsigned-test \ -n cert-manager-test --timeout=60s kubectl delete namespace cert-manager-test # 6. Verify StorageClass kubectl apply -f storage/verify-pvc.yaml kubectl wait --for=condition=Ready pod/storage-test \ -n storage-test --timeout=60s kubectl logs -n storage-test storage-test kubectl delete namespace storage-test # 7. Run the full verification script chmod +x verify-t02.sh ./verify-t02.sh ``` ## NetworkPolicy design All three namespaces follow a default-deny-all posture. Only the minimal required paths are opened: | Source | Destination | Port | Purpose | |--------|-------------|------|---------| | Traefik (kube-system) | Keycloak (sso) | 8080 | OIDC/SAML ingress | | Traefik (kube-system) | privacyIDEA (mfa) | 8080 | MFA portal ingress | | Keycloak (sso) | privacyIDEA (mfa) | 8080 | Provider API calls | | Keycloak (sso) | PostgreSQL (databases) | 5432 | DB | | privacyIDEA (mfa) | PostgreSQL (databases) | 5432 | DB | | CNPG operator (cnpg-system) | PostgreSQL (databases) | 5432/9187 | Operator + metrics | | All pods | kube-dns (kube-system) | 53 | DNS resolution | | CNPG pods | K8s API | 6443 | Status updates | ## Verifying denied paths (manual) After applying NetworkPolicies, confirm that illegal paths are blocked: ```bash # Test: Keycloak → databases direct (should be ALLOWED) kubectl run test-allowed -n sso --rm -it --image=busybox --restart=Never \ -- nc -zv net-kingdom-pg-rw.databases.svc.cluster.local 5432 # Test: mfa → sso (should be DENIED — privacyIDEA must not reach Keycloak directly) kubectl run test-denied -n mfa --rm -it --image=busybox --restart=Never \ -- nc -zv -w3 keycloak.sso.svc.cluster.local 8080 # Test: databases → sso (should be DENIED — DB pods must not initiate connections) kubectl run test-denied2 -n databases --rm -it --image=busybox --restart=Never \ -- nc -zw3 keycloak.sso.svc.cluster.local 8080 ``` ## Notes - `net-kingdom/component` labels on namespaces are used by NetworkPolicy `namespaceSelector` rules. Do not remove them. - `cnpg.io/cluster: net-kingdom-pg` in `netpol-databases.yaml` must match the name of the CloudNativePG `Cluster` CR you create in T03. - The `letsencrypt-prod` ClusterIssuer requires public DNS and port 80 open to Let's Encrypt servers. Update `ACME_EMAIL` before applying.