diff --git a/apps/base/kustomization.yaml b/apps/base/kustomization.yaml index 25ead86..5029cf7 100644 --- a/apps/base/kustomization.yaml +++ b/apps/base/kustomization.yaml @@ -4,4 +4,5 @@ resources: - dot-ai-stack.yaml - mcp10x.yaml - musicman.yaml +- ts-mcp.yaml - argo-mcp.yaml diff --git a/apps/base/ts-mcp.yaml b/apps/base/ts-mcp.yaml new file mode 100644 index 0000000..70752ff --- /dev/null +++ b/apps/base/ts-mcp.yaml @@ -0,0 +1,40 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: ts-mcp + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "11" + notifications.argoproj.io/subscribe.on-sync-succeeded.slack: "" + notifications.argoproj.io/subscribe.on-sync-failed.slack: "" + notifications.argoproj.io/subscribe.on-degraded.slack: "" + labels: + app.kubernetes.io/name: ts-mcp + app.kubernetes.io/part-of: apps + app.kubernetes.io/managed-by: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + sources: + - repoURL: ssh://git@git.forteapps.net:2222/Forte/forte-helm.git + path: forteapp + targetRevision: HEAD + helm: + valueFiles: + - $values/ts-mcp/values.yaml + + - repoURL: ssh://git@git.forteapps.net:2222/Forte/helm-prod-values.git + targetRevision: HEAD + ref: values + + destination: + server: https://kubernetes.default.svc + namespace: ts-mcp + + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/docs/DEVELOPER-GUIDE.md b/docs/DEVELOPER-GUIDE.md index 8f4402f..7ec2605 100644 --- a/docs/DEVELOPER-GUIDE.md +++ b/docs/DEVELOPER-GUIDE.md @@ -962,6 +962,46 @@ User sees application (authenticated) --- +### Accessing Authenticated User Information + +The auth sidecar handles all authentication before requests reach your application. Your app never sees unauthenticated traffic — the sidecar returns 401 or redirects to the IdP first. + +After successful authentication, the sidecar forwards the request to your application with user identity injected as HTTP headers: + +| Header | Description | Available in | +|--------|-------------|-------------| +| `X-Auth-User` | Username or display name | Token, OIDC, MCP | +| `X-Auth-Email` | User email address | OIDC | +| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP | +| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if scope includes `groups`) | +| `X-Auth-Token` | The validated access token | All modes | + +**Your application reads these headers — no auth library needed:** + +```javascript +// Express.js example +app.get('/profile', (req, res) => { + const user = req.headers['x-auth-user']; + const email = req.headers['x-auth-email']; + res.json({ user, email }); +}); +``` + +```python +# Flask example +@app.route('/profile') +def profile(): + user = request.headers.get('X-Auth-User') + email = request.headers.get('X-Auth-Email') + return jsonify(user=user, email=email) +``` + +**Why this is safe**: The Kyverno-generated NetworkPolicy restricts ingress to the sidecar port only. Traffic cannot bypass the sidecar to reach the application port directly, so the `X-Auth-*` headers can be trusted unconditionally. + +**Key principle**: Your application is zero-trust-unaware by design. It reads headers and renders UI. All authentication complexity lives in the sidecar and Kyverno policy. + +--- + ### Authentication Configuration Reference #### Helm Values Schema diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md index e3ad7bc..075141b 100644 --- a/docs/REFERENCE.md +++ b/docs/REFERENCE.md @@ -649,6 +649,15 @@ retry: 4. 40 seconds 5. 80 seconds (capped at 3 minutes) +### Global Settings (`argocd-cm`) + +| Setting | Value | Purpose | +|---------|-------|---------| +| `application.resourceTrackingMethod` | `annotation` | Track resources via annotations | +| `timeout.reconciliation` | `60s` | Reconciliation interval | +| `admin.enabled` | `true` | Enable admin account | +| `git.submodule.enabled` | `false` | Disable git submodule checkout — submodules are not needed for manifest generation | + --- ## Infrastructure Components @@ -1120,6 +1129,33 @@ kubectl get secret keycloak-client- -n keycloak -o jsonpath='{.metadata.ann **See**: [Developer Guide - Adding a New Keycloak Client](DEVELOPER-GUIDE.md#adding-a-new-keycloak-client) +### Karpor + +**Chart**: `karpor` from `https://kusionstack.github.io/charts` +**Version**: 0.7.6 (app v0.6.4) +**Namespace**: `karpor` +**Sync Wave**: 1 + +**Purpose**: Kubernetes visualization and intelligence tool. Provides cross-cluster resource search, compliance checking, and topology visualization. Gives platform engineers a unified view of all cluster resources and their relationships. + +**Architecture** (4 components): +- **Server** — main Karpor API/UI (port 7443) +- **Syncer** — syncs cluster state into the search index +- **ElasticSearch** — search backend for resource indexing +- **etcd** — persistent key-value store (10Gi PVC) + +**Configuration** (`infra/values/base/karpor-values.yaml`): +- `namespaceEnabled: false` — ArgoCD manages namespace creation +- Default resource limits tuned for small clusters +- ElasticSearch: 2 CPU / 4Gi memory (the heaviest component) +- AI features available but not enabled (requires `server.ai.authToken` + backend config) + +**Access**: Port-forward to reach the UI: +```bash +kubectl port-forward svc/karpor-release-server -n karpor 7443:7443 +# Open https://localhost:7443 +``` + ### Renovate **Chart**: `renovate` (OCI: `ghcr.io/renovatebot/charts`) @@ -1567,7 +1603,23 @@ Forward to Application (localhost:3000) Application processes request ``` -**See**: [Developer Guide - Enabling Authentication](DEVELOPER-GUIDE.md#enabling-authentication-for-applications) for usage examples. +#### Forwarded Headers + +After successful authentication, the sidecar injects user identity as HTTP headers before forwarding the request to the application container: + +| Header | Description | Auth Modes | +|--------|-------------|------------| +| `X-Auth-User` | Username or display name | Token, OIDC, MCP | +| `X-Auth-Email` | User email address | OIDC | +| `X-Auth-Subject` | OIDC `sub` claim (stable user ID) | OIDC, MCP | +| `X-Auth-Groups` | Comma-separated group memberships | OIDC (if `groups` scope) | +| `X-Auth-Token` | The validated access token | All modes | + +These headers are trustworthy because the auto-generated `NetworkPolicy` restricts pod ingress to the sidecar port only — external traffic cannot reach the application container directly, so headers cannot be spoofed. + +Applications should read these headers to obtain authenticated user information (e.g. for display, authorisation decisions, or audit logging) instead of implementing their own authentication. + +**See**: [Developer Guide - Accessing Authenticated User Information](DEVELOPER-GUIDE.md#accessing-authenticated-user-information) for code examples. --- diff --git a/infra/base/karpor.yaml b/infra/base/karpor.yaml new file mode 100644 index 0000000..dc15e59 --- /dev/null +++ b/infra/base/karpor.yaml @@ -0,0 +1,48 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: karpor + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "1" + labels: + app.kubernetes.io/name: karpor + app.kubernetes.io/part-of: developer-portal + app.kubernetes.io/managed-by: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + + sources: + - repoURL: https://kusionstack.github.io/charts + chart: karpor + targetRevision: "0.7.6" + helm: + releaseName: karpor + valueFiles: + - $values/infra/values/base/karpor-values.yaml + + - repoURL: ssh://git@git.forteapps.net:2222/Forte/launchpad.git + targetRevision: HEAD + ref: values + + destination: + server: https://kubernetes.default.svc + namespace: karpor + + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: false + syncOptions: + - CreateNamespace=true + - Validate=true + - ServerSideApply=true + + ignoreDifferences: + - group: apps + kind: StatefulSet + jsonPointers: + - /spec/volumeClaimTemplates diff --git a/infra/base/kustomization.yaml b/infra/base/kustomization.yaml index 5c1beb1..a88000f 100644 --- a/infra/base/kustomization.yaml +++ b/infra/base/kustomization.yaml @@ -22,3 +22,4 @@ resources: - tempo.yaml - grafana-dashboards.yaml - network-policies-application.yaml +- karpor.yaml diff --git a/infra/values/base/argocd-values.yaml b/infra/values/base/argocd-values.yaml index 83dc1b3..4bfa6df 100644 --- a/infra/values/base/argocd-values.yaml +++ b/infra/values/base/argocd-values.yaml @@ -2,12 +2,21 @@ configs: secret: createSecret: true argocdServerAdminPassword: "$2b$12$Tmb1jH7ADvwWoUoNPXXsfOf6JqEluqhq8mL06a8DGT2AP1GzbNsCm" + ssh: + knownHosts: | + [git.forteapps.net]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDTwi40de8yTGUuRT0i/XGicQ672BLhYR6D/lDquJrp/tdrWoZhVVPy0wxSkWsq1V92iiAUuQnXagOGsLBGZT9uDLWKvEmNDnCfjzTMq3J1iA3vk2rQ8WBlCzhvmeCV/r0ufl6vsgfwxSRomLZeqa2UkLHx69gy2Njb1S2/aZK1Q53f466hCUfDULZrTn2Nn5Sj8cEbJ8EyvVN2YG9HYBxQdzKRPZEmS1vyzmn8YrYIkZseIRQElabzWGh86owuaaqnwJhTJj1j2sEUeIet04sGKJcnxx2UL4H90N66LKMldmMiuli+ve/CjJmMwDl0zGkjIniT3XR8CyEXYHli7B1hR8Z+dbK6DBgjz+28lFgMIRY70KkZJNsJcBNZLZ5fHwCI13a9U3Uhg3Pu/6s0zlosM4CrAQNQCRe95ZPtCpdFhlGrOl4m1rdSK2meL6rND0TBBuZbaFF6Py7TawLCAiO2KRaVqhu9OFVjwJ/nifgLzFGwWj+WcYmpuR+DwozrF/Hl7QYsz1x4GO1SONY07KbIFkUCHOMAh0AELY5YE4eGI4mtG6SecdPaAdLREGZYK4IcyP5i1QW9g0wmfRSsV9jy+r0ivBxixxh4yJiNpkg6NXak40gQtGIme9EJ+DxrRLruNsfDILWcdSuH/wvuorv56NpQFGB0FzB6LXMloSYptQ== cm: application.resourceTrackingMethod: annotation timeout.reconciliation: 60s admin.enabled: "true" params: "server.insecure": true +repoServer: + env: + # Disable git submodule checkout - submodules (e.g. shared-prompts) + # are not needed for K8s manifest generation + - name: ARGOCD_GIT_MODULES_ENABLED + value: "false" server: ingress: enabled: false diff --git a/infra/values/base/karpor-values.yaml b/infra/values/base/karpor-values.yaml new file mode 100644 index 0000000..3f67b15 --- /dev/null +++ b/infra/values/base/karpor-values.yaml @@ -0,0 +1,44 @@ +# Karpor - Kubernetes Visualization & Intelligence Tool +# Helm chart: https://github.com/KusionStack/charts/tree/master/charts/karpor + +# Let the ArgoCD Application manage the namespace +namespaceEnabled: false + +server: + replicas: 1 + port: 7443 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 500m + memory: 1Gi + +syncer: + replicas: 1 + port: 7443 + resources: + requests: + cpu: 250m + memory: 256Mi + limits: + cpu: 500m + memory: 1Gi + +elasticsearch: + replicas: 1 + port: 9200 + resources: + requests: + cpu: 500m + memory: 2Gi + limits: + cpu: "2" + memory: 4Gi + +etcd: + replicas: 1 + port: 2379 + persistence: + size: 5Gi