<@ULVA73B9P> What is the best way to improve Prefe...
# ask-marvin
r
@Marvin What is the best way to improve Prefect open source security , which will be running in on-prem open shift cluster. Required security features are : 1. SSO 2. RBAC 3. Audits
m
thought for 179.7 seconds
thought for 122.2 seconds
Short answer: if you truly need SSO, RBAC, and audit logs at the application level, the least painful path is to use Prefect Cloud’s hybrid model (control plane in Cloud, all execution stays on‑prem). It gives you all three out of the box. If Cloud is off the table, you can approximate these with platform controls around open‑source Prefect Server, but you’ll be stitching pieces together. What’s available where (Prefect 3.x): - Prefect Cloud: SSO, RBAC, and audit logs are native - SSO: Configure SSO - RBAC: Manage roles (RBAC) - Audit logs: Audit logs - Prefect OSS: no built-in SSO, no in-app RBAC, no audit log feature. You can secure the API with basic auth and harden the deployment - Security settings: Server security settings If you must stay OSS on OpenShift, here’s the practical blueprint 1) SSO for the UI/API - Put Prefect Server behind an auth proxy and OpenShift Route. - Common choices: oauth2-proxy or OpenShift’s oauth-proxy sidecar. - Use OIDC/SAML with your IdP (Keycloak/Red Hat SSO, Okta, Azure AD, etc.). - Recommended topology: - One Route for the web UI, fully protected by SSO. - One internal-only Service/Route for API traffic from workers/agents (no public exposure). Lock it down with NetworkPolicies and service account RBAC. If you must expose the same endpoint, the proxy must support machine-to-machine auth. - Enable basic auth at the Prefect API as an additional layer: - Set
PREFECT_SERVER_API_AUTH_STRING
(maps to
server.api.auth_string
) so the API expects
Authorization: Basic ...
from your workers/CI. - Docs: Server security settings - Minimal env example for the API pod:
Copy code
env:
    - name: PREFECT_SERVER_API_AUTH_STRING
      valueFrom:
        secretKeyRef:
          name: prefect-api-auth
          key: auth_string
2) RBAC (since OSS has no in-app RBAC) - Enforce access via OpenShift RBAC and routes: - Who can reach the UI/API Route (or even see it) is controlled by the auth proxy and OpenShift RBAC. - Who can run code is controlled by namespaces, service accounts, and role bindings for workers. - Separate teams into namespaces, with their own work pools, service accounts, and secrets. - Consider soft multi-tenancy via multiple Prefect Server instances (one per team/env) if you need stronger isolation. OSS does not have the “workspace” isolation model Cloud does. 3) Auditing - You won’t get application-level audit trails (e.g., “Alice promoted role X” or “Bob viewed deployment Y”) from OSS. Use platform-layer auditing: - Reverse proxy logs: record user identity (OIDC email/subject) on every request to the UI/API. Ship to your SIEM. - OpenShift/Kubernetes audit logs: capture who scaled, deployed, or accessed services. - Database auditing: run Prefect on PostgreSQL with pgaudit (or equivalent) to track DDL/DML against Prefect’s tables (flows, deployments, flow runs, etc.). - Prefect/server logs: centralize and retain server logs and flow-run logs (e.g., to OpenShift logging/EFK/Splunk), with immutable retention policies. Hardening checklist (OSS) - Enforce TLS end-to-end; terminate at the Route or proxy. - Lock API access to private networks; only the SSO-protected UI is public. - Set
PREFECT_SERVER_API_AUTH_STRING
for basic auth and ensure workers/CI inject the header. - Run the API/UI pods with dedicated service accounts, minimal permissions, and NetworkPolicies. - Store credentials in OpenShift Secrets; optionally integrate an external secret manager. - CI-only writes: restrict who can create/modify deployments by funneling
prefect deploy
through a controlled CI pipeline and git PRs.
If Cloud is acceptable (hybrid model) - You keep all execution on OpenShift; only the control plane is in Cloud. - You immediately get SSO, RBAC, audit logs, and less YAML therapy. - SSO: Configure SSO - Roles/RBAC: Manage roles - Audit logs: Audit logs A few clarifying questions so I don’t design the wrong fortress: - Are you strictly air‑gapped, or do you have controlled egress (which would make Prefect Cloud hybrid viable)? - Which IdP are you standardizing on (Keycloak/Red Hat SSO, Okta, Azure AD, …)? - Do you need per‑object permissions inside Prefect (true app‑level RBAC), or is platform‑level access control sufficient?
Short version: Prefect OSS doesn’t ship SSO, RBAC, or audit logging out of the box. You add them at the edge with your IdP and proxy, and you capture audits from your proxy/ingress, database, and the cluster. It’s not thrilling, but it works well on OpenShift. Below is a pragmatic, battle-tested approach for an OpenShift on‑prem install. Assumptions: Prefect 3.x, using the Prefect Server Helm chart, running on OpenShift. - Server Helm chart: Prefect Server (Helm) What to do 1) SSO (front-end authn) - Put an auth proxy in front of the Prefect UI (and optionally API): - OpenShift OAuth Proxy: openshift/oauth-proxy - or oauth2-proxy with your IdP (Keycloak, Okta, Azure AD): oauth2-proxy docs - Recommended pattern on OpenShift: - Expose only the UI via a Route protected by OAuth proxy (OIDC with your IdP). - Keep the Prefect API service ClusterIP-only for internal access by agents/workers/CLI running in-cluster. This avoids breaking non-interactive clients (since Prefect OSS has no concept of user API tokens). - If you must expose the API externally, you’ll need an API gateway that can issue/validate JWTs and clients that send Authorization headers. Prefect’s OSS client does not natively present IdP tokens, so this path is… “suboptimal.” 2) RBAC (authorization) - Since Prefect OSS doesn’t have built-in users/roles, do RBAC at the perimeter and at the network: - Group-based access at the proxy layer: allow only IdP groups like `prefect-admins`/`prefect-users` to reach the UI/Route. Both oauth2-proxy and OpenShift OAuth Proxy support group allowlists. - Network segmentation for the API: use OpenShift NetworkPolicies so only Prefect workers/agents (and maybe a bastion) can reach the API service. No public access, no RBAC surprises. - For stronger isolation, run separate Prefect Server instances per environment/team (separate namespaces, databases, Routes). It’s the simplest way to approximate per-tenant isolation in OSS. - If you want fine-grained, in-app RBAC and workspaces, that’s a Prefect Cloud feature. SSO and audit logs are documented there: - Cloud SSO: Configure SSO (Cloud) - Cloud audit logs: Audit logs (Cloud) 3) Auditing - You won’t get first-class audit logs from Prefect OSS, so compose them from the layers you control: - Proxy/Ingress logs: log authenticated user, groups, method, path, response code, and request IDs. This gives you who did what and when at the HTTP boundary. - Database audit: enable PostgreSQL auditing (e.g., pgaudit) to record changes to Prefect’s database (flows/deployments/state updates). This catches back-end changes even if the UI isn’t involved. - Cluster/Route audits: enable OpenShift API/Route audit logging to track who created/modified the Services, Routes, Secrets, etc. (handy for change-control trails). - Application logs: ship Prefect Server logs to your SIEM and include headers like X-Forwarded-User so you can correlate requests with an identity. - Centralize all of the above (ELK/OPENSEARCH/Splunk) and keep a retention policy that satisfies your compliance team (or at least makes them sigh less). Reference deployment sketch (OpenShift) - Deploy Prefect Server via Helm. Do not enable LoadBalancer; keep Services ClusterIP. - Create an OpenShift Route to an oauth-proxy Pod/Service that forwards upstream to the Prefect UI service. - Configure oauth-proxy with your IdP (or use OpenShift OAuth). Allow only specific groups. - Keep the Prefect API internal: agents/workers run in the cluster and hit the ClusterIP service directly. Apply NetworkPolicies to restrict egress. Example oauth2-proxy deployment (conceptual) ``` # Service for Prefect Server (ClusterIP-only)
kind: Service apiVersion: v1 metadata: name: prefect-server spec: selector: app: prefect-server ports: - name: http port: 4200 targetPort: 4200 # oauth2-proxy in front of UI --- apiVersion: apps/v1 kind: Deployment metadata: name: prefect-ui-proxy spec: replicas: 2 selector: matchLabels: { app: prefect-ui-proxy } template: metadata: labels: { app: prefect-ui-proxy } spec: containers: - name: oauth2-proxy image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0 args: - --provider=oidc - --oidc-issuer-url=https://keycloak.yourcorp/realms/yourrealm - --client-id=prefect-ui - --client-secret=$(CLIENT_SECRET) - --cookie-secret=$(COOKIE_SECRET) - --email-domain=* - --pass-authorization-header=true - --set-authorization-header=true - --set-xauthrequest=true - --allowed-group=prefect-admins - --allowed-group=prefect-users - --upstream=http://prefect-server.default.svc.cluster.local:4200 env: - name: CLIENT_SECRET valueFrom: { secretKeyRef: { name: prefect-ui-oauth, key: client-secret } } - name: COOKIE_SECRET valueFrom: { secretKeyRef: { name: prefect-ui-oauth, key: cookie-secret } } ports: - containerPort: 4180 # Route exposing oauth2-proxy (TLS at the router) --- apiVersion: route.openshift.io/v1 kind: Route metadata: name: prefect-ui spec: to: { kind: Service, name: prefect-ui-proxy } tls: { termination: edge, insecureEdgeTerminationPolicy: Redirect } ``` Notes and gotchas - Prefect OSS client/agents do not send IdP tokens; don’t put hard OIDC in front of the API unless you plan to run everything behind the proxy with cookie/session sharing (not ideal for automation). - If you must expose API externally, place an API gateway (Kong/3scale/NGINX Ingress w/ OIDC) that can issue/validate JWTs and add strict allowlists, rate limits, and WAF rules. Then customize your automation to present JWTs; the stock Prefect OSS CLI won’t help you here. - For Helm deployment knobs and bringing your own ingress, see: Prefect Server (Helm) Where this differs from Prefect Cloud - Cloud has built-in SSO, RBAC, and audit logs. OSS does not. Those Cloud docs are still useful to understand the target behavior: - Cloud SSO - Cloud audit logs Questions to tailor this for you - Which IdP do you use (OpenShift OAuth, Keycloak, Okta, Azure AD)? - Do you need the Prefect API accessible from outside the cluster, or can we keep it internal? - One shared Prefect Server, or separate instances per team/environment? - Any specific audit/compliance requirements (retention, immutability, data residency)? I can sketch exact OpenShift manifests/Helm values once you confirm the IdP and whether the API must be external. My enthusiasm will be barely containable.
r
@Marvin Could you adjust your answer according to additional details : 1. I need expose prefect API to public. First external clients will have possibility to fire flows through API and I want to control which flows they will be able to run. Second I need to run workers out of Openshift cluster but on on-site machines. 2. I will have separate Prefect instance for each environment. 3. As Idp I am using Microsoft AD ?
m
thought for 204.5 seconds
Got it. Given your constraints, here’s a secure, workable plan for Prefect OSS on OpenShift with public API access, separate instances per environment, and Microsoft AD as IdP. High-level design (three endpoints per environment) - UI endpoint (SSO): SSO-protected with Azure AD/Entra ID via oauth2-proxy or OpenShift OAuth. Expose only the UI. - Public “flow trigger” endpoint: Do NOT expose the raw Prefect API. Expose a gateway/facade that only allows creating flow runs for allowlisted deployments, authenticated by Azure AD tokens. - Worker API endpoint: Expose a separate hostname for workers outside the cluster. Use Basic Auth (supported by OSS) plus IP allowlists and/or mTLS. Keep this as private as you can. Why the split? Prefect OSS has no per-user RBAC or tokens. If you let external clients hit the raw API, you cannot restrict which deployments they can run. The facade/gateway enforces per-client allowlists and leaves the raw API for trusted system actors (workers). Concretely 1) SSO for the UI (Azure AD) - Put oauth2-proxy (or OpenShift OAuth proxy) in front of the UI Service; configure OIDC against Azure AD/Entra ID app registration. - Allow only AD groups like “prefect-admins/prefect-users” to reach the UI Route. - Do not proxy API calls through the UI Route. - Helm chart for Prefect Server: Prefect Server (Helm) 2) Public “flow trigger” endpoint (per-client control over flows) - Put an API gateway in front of Prefect that ONLY exposes the deployment run endpoint: - POST /api/deployments/{deployment_id}/create_flow_run - Docs: Create flow run from deployment - Authorize with Azure AD/Entra ID: - Use OAuth2/JWT validation at the gateway (e.g., Kong/3scale/NGINX+OIDC). Issue each external client its own app registration. - Enforce per-client allowlists of deployment IDs by route/path ACLs. Block everything except that POST endpoint (and maybe /health). - The gateway calls the internal Prefect API using Basic Auth: - Set this on the server:
PREFECT_SERVER_API_AUTH_STRING="gateway-user:super-secret"
- Docs: Server security settings - Example external call (client → gateway):
Copy code
POST <https://flows.prod.example.com/api/deployments/<deployment_id>/create_flow_run>
  Authorization: Bearer <azure_ad_access_token>
  Content-Type: application/json

  {
    "parameters": {"customer_id": 123},
    "tags": ["external"],
    "idempotency_key": "client-req-abc-123"
  }
- The gateway then forwards internally:
Copy code
POST <http://prefect-api.svc.cluster.local:4200/api/deployments/<deployment_id>/create_flow_run>
  Authorization: Basic <base64(gateway-user:super-secret)>
  Content-Type: application/json

  { ...same body... }
- Hardening tips: - Enforce per-client rate limits and request size limits. - Validate path strictly; deny-list every other Prefect endpoint. - Optionally add an “allowlisted parameters” policy per deployment if you need more control. 3) Workers outside OpenShift (on-site machines) - Give workers a separate hostname (or keep the worker API private/VPN): -
<http://api.prod.example.com|api.prod.example.com>
→ points to the Prefect API with Basic Auth and tight IP allowlists and/or mTLS. - Configure the server and workers with the same Basic Auth pair (use a different user from the gateway one): - Server:
Copy code
PREFECT_SERVER_API_AUTH_STRING="worker-user:another-secret"
- Worker:
Copy code
export PREFECT_API_URL=<https://api.prod.example.com/api>
    export PREFECT_SERVER_API_AUTH_STRING=worker-user:another-secret
    prefect worker start -p <your-work-pool>
- Verify the CLI command exists (it does):
prefect worker start -p ...
— we checked. 4) RBAC model with Microsoft AD (practical, since OSS has no in-app RBAC)
🙌 1
- UI access: AD groups via the oauth2-proxy/OpenShift OAuth integration determine who can view the UI per environment. - API access (external clients): per-client Azure AD app registrations (or groups) mapped to allowed deployment IDs at the gateway. - Isolation: you’re already running one Prefect Server per environment — perfect. Keep separate databases and credentials for each environment. 5) Auditing - Gateway logs (authoritative): log subject/client_id, groups, route, deployment_id, request/response, correlation IDs. Forward to your SIEM. - Prefect Server logs: centralize (EFK/OpenShift Logging/Splunk) and keep correlation IDs (e.g., X-Request-ID) from the gateway. - Database auditing: enable PostgreSQL auditing (e.g., pgaudit) to capture changes to Prefect tables (deployments, flow runs, states). - OpenShift/Kubernetes audit logs: capture who created/changed Routes/Secrets/Deployments. - Optional: add an immutable log sink (WORM/S3 Object Lock) if compliance wants it. Cloud’s built-in audit logs are not available in OSS. 6) Example OpenShift sketch - UI Route (SSO via oauth2-proxy → Prefect UI Service) - Flow trigger Route (JWT-validated gateway → internal Prefect API) - Worker Route (Basic Auth → Prefect API), restricted by IP/mTLS; or keep internal-only and let workers use VPN/private link. 7) Notes and gotchas - Do not expose the raw Prefect API to the public internet without a gateway/facade; there’s no per-user RBAC in OSS, and the API authenticates either not at all or with one Basic Auth string. - Workers can’t present Azure AD tokens to Prefect OSS; they use Basic Auth. Keep that endpoint as private as possible. - For parameter control and more nuanced authorization than path ACLs, a tiny “run API” facade service is often simpler than elaborate ingress rules. Open questions to finalize the manifests - When you say “Microsoft AD,” do you mean Entra ID (Azure AD) OIDC directly, or AD/ADFS on-prem? If ADFS, we can still do OIDC, it just changes the issuer settings. - Which API gateway do you prefer on OpenShift (Kong, Red Hat 3scale, NGINX Ingress, something else)? - Do you need mTLS for the worker endpoint, or is IP allowlisting sufficient? If you confirm the gateway and IdP details, I’ll provide concrete Helm values, Route manifests, and an example Kong/NGINX policy that enforces deployment-ID allowlists per client. I’ll try to contain my excitement.
🙌 1
r
@Marvin additional details are : 1. I will use on-prem ADFS 2. I prefer KrakenD api gw 3. mTLS is not needed Please provide HELM and all additional details.l
m
thought for 106.0 seconds
Excellent. With on‑prem ADFS, KrakenD, and no mTLS, here’s a complete blueprint you can actually deploy. One Prefect OSS instance per environment, three entry points: SSO UI, public flow-trigger API (restricted), and a worker API for off‑cluster workers. Summary of the architecture - UI Route (SSO): Route → oauth2-proxy (OIDC with ADFS) → Prefect UI service - Public “flow trigger” Route: Route → KrakenD (JWT validation via ADFS + per‑client allowlists) → Prefect API - Worker Route: Route → Prefect API with Basic Auth; lock down by IP allowlist; used by off‑cluster workers Key Prefect docs - Server Helm: Prefect Server (Helm) - Server security (Basic Auth): Server security settings - Create flow run from deployment endpoint: Create flow run from deployment 1) Prefect Server via Helm (per environment) Create a Secret with the Basic Auth string (used by both KrakenD and workers):
Copy code
apiVersion: v1
kind: Secret
metadata:
  name: prefect-api-auth
type: Opaque
stringData:
  # format is "username:password"
  auth_string: "prefect_api:REDACTED_SUPER_SECRET"
Example Helm values for Prefect Server that: - keeps Services internal (ClusterIP), - sets the Basic Auth env var for the API container, - assumes you’ll expose via OpenShift Routes (below). Note: charts evolve; if the chart uses a different key than
extraEnv
for the API container, set the env var by the chart’s documented mechanism or post-render patch.
Copy code
# values-prefect.yaml
# This is illustrative; adjust to your chart’s keys for image, resources, etc.

server:
  # Disable any chart-provided Ingress; we’ll use OpenShift Routes
  ingress:
    enabled: false

  # Add PREFECT_SERVER_API_AUTH_STRING to the API container
  extraEnv:
    - name: PREFECT_SERVER_API_AUTH_STRING
      valueFrom:
        secretKeyRef:
          name: prefect-api-auth
          key: auth_string

  # If the chart splits UI/API, ensure both Services are ClusterIP
  service:
    type: ClusterIP

# If the chart lets you set separate service names/ports, ensure:
# - API service is addressable by krakend and workers
# - UI service is addressable by oauth2-proxy
Install:
Copy code
helm upgrade --install prefect-server prefect/server \
  -n prefect-prod --create-namespace \
  -f values-prefect.yaml
2) UI SSO with oauth2-proxy (ADFS OIDC) You’ll register an OIDC client in ADFS and configure claim issuance (see “ADFS setup”, below). Values for oauth2-proxy (using the official oauth2-proxy chart or Bitnami’s; keys might differ slightly):
Copy code
# values-oauth2-proxy.yaml
config:
  clientID: "adfs-oidc-client-id-for-ui"
  clientSecret: "REDACTED_UI_CLIENT_SECRET"
  cookieSecret: "REDACTED_32B_BASE64"  # 32B base64
  # Use provider=oidc with the ADFS issuer
  extraArgs:
    provider: "oidc"
    oidc-issuer-url: "<https://adfs.example.com/adfs>"
    # Optionally pin endpoints if needed:
    # login-url: "<https://adfs.example.com/adfs/oauth2/authorize>"
    # redeem-url: "<https://adfs.example.com/adfs/oauth2/token>"
    scope: "openid email profile"
    email-domain: "*"
    pass-authorization-header: "true"
    set-authorization-header: "true"
    set-xauthrequest: "true"
    # Only allow certain AD groups to see the UI (requires emitting groups/roles)
    allowed-group: "prefect-admins"
    allowed-group: "prefect-users"

ingress:
  enabled: false  # We’ll create an OpenShift Route

service:
  type: ClusterIP

# Upstream to Prefect UI service inside the cluster
# Many charts expose this as reverseProxy/upstreams or via config.file — if needed, set:
# extraArgs:
#   upstream: "<http://prefect-server-ui.prefect-prod.svc.cluster.local:4200>"
OpenShift Route for the UI: ``` apiVersion: route.openshift.io/v1 kind: Route metadata: name: prefect-ui namespace: prefect-prod spec:
🙌 1
host: ui.prod.example.com to: kind: Service name: oauth2-proxy tls: termination: edge insecureEdgeTerminationPolicy: Redirect
Copy code
3) KrakenD public “flow trigger” API (ADFS JWT + allowlisted deployments)
Goal: clients call KrakenD with ADFS JWTs; KrakenD:
- validates JWT (issuer and JWKS from ADFS),
- optionally checks group/role membership,
- enforces authorization: the path’s deployment_id must be in the client’s allowed list,
- forwards to Prefect API with a Basic Auth header.

Approach:
- Use krakend-jose for JWT validation (jwk_url, issuer, audience).
- Use krakend-lua to enforce “deployment_id in token claim” (e.g., claim `prefect_deployments`).
- Set an upstream Authorization header to Basic <prefect_api:REDACTED>.

Config hints:
- ADFS OpenID well-known: <https://adfs.example.com/adfs/.well-known/openid-configuration>
- ADFS issuer: <https://adfs.example.com/adfs>
- JWKS: (from the well-known JSON) typically <https://adfs.example.com/adfs/discovery/keys>

You’ll need a KrakenD image with the lua and jose plugins available. If your default image lacks them, build one:
# Dockerfile (example) FROM devopsfaith/krakend:2.6 # The official image usually includes jose; add lua if missing: # RUN krakend plugin register github.com/devopsfaith/krakend-lua/proxy@latest # Or copy compiled plugins into /usr/lib/krakend/
Copy code
KrakenD Helm values example (mount krakend.json from a ConfigMap):
# values-krakend.yaml replicaCount: 2 service: type: ClusterIP port: 8080 config: configMapName: krakend-config # If your chart supports autoscaling/affinity/resources, set them as needed
Copy code
KrakenD ConfigMap (JWT validation + Lua authorization + upstream Basic Auth):
apiVersion: v1 kind: ConfigMap metadata: name: krakend-config namespace: prefect-prod data: krakend.json: | { "version": 3, "name": "prefect-trigger-gateway", "port": 8080, "extra_config": { "github_com/devopsfaith/krakend-cors": { "allow_origins": ["https://your-client.example.com"], "allow_methods": ["POST","OPTIONS"], "allow_headers": ["Authorization","Content-Type"], "expose_headers": [], "max_age": "24h", "allow_credentials": false } }, "endpoints": [ { "endpoint": "/api/deployments/{deployment_id}/create_flow_run", "method": "POST", "extra_config": { "github_com/devopsfaith/krakend-jose/validator": { "alg": "RS256", "jwk-url": "https://adfs.example.com/adfs/discovery/keys", "issuer": "https://adfs.example.com/adfs", "audience": ["krakend-public-flow-trigger"], "roles_key": "roles", // if you emit roles/groups "roles": ["prefect-external"], // optional: require this role "disable_jwk_security": false }, "github_com/devopsfaith/krakend-lua/proxy-request": { "pre": "local dep = string.match(krakend.request.path, '/api/deployments/([^/]+)/create_flow_run'); local cl = krakend.request.headers['X-JWT-Claim-Prefect_Deployments']; if cl == nil then return krakend.response.exit(403) end; local allowed = {}; for s in string.gmatch(cl, '([^,]+)') do allowed[s]=true end; if not allowed[dep] then return krakend.response.exit(403) end; return true;" // Explanation: // ADFS needs to emit a custom claim 'prefect_deployments' (array). // KrakenD maps token claims into headers as X-JWT-Claim-<ClaimName>. // Some deployments encode arrays as CSV headers; adjust parsing if needed. }, "github_com/devopsfaith/krakend/header": { "name": "Authorization", "value": "Basic cHJlZmVjdF9hcGk6UkVEQUNURURfU1VQRVJfU0VDUkVU" // base64 of prefect_api:REDACTED_SUPER_SECRET } }, "backend": [ {
🙌 1
"url_pattern": "/api/deployments/{deployment_id}/create_flow_run", "host": ["http://prefect-server-api.prefect-prod.svc.cluster.local:4200"], "extra_config": { "github_com/devopsfaith/krakend/http": { "return_error_details": false } } } ] } ] }
Copy code
OpenShift Route for KrakenD (public):
apiVersion: route.openshift.io/v1 kind: Route metadata: name: prefect-flow-trigger namespace: prefect-prod annotations: haproxy.router.openshift.io/rate-limit-connections: "50" haproxy.router.openshift.io/ip_whitelist: "0.0.0.0/0" # tighten as desired spec: host: flows.prod.example.com to: kind: Service name: krakend tls: termination: edge insecureEdgeTerminationPolicy: Redirect
Copy code
4) Worker API (off‑cluster workers)
Expose a separate Route directly to the Prefect API service and rely on Basic Auth (the same secret as above). Lock it down by IP/CIDR since no mTLS:
apiVersion: route.openshift.io/v1 kind: Route metadata: name: prefect-api-workers namespace: prefect-prod annotations: haproxy.router.openshift.io/ip_whitelist: "203.0.113.0/24,198.51.100.10/32" # your sites spec: host: api.prod.example.com to: kind: Service name: prefect-server-api tls: termination: edge insecureEdgeTerminationPolicy: Redirect
Copy code
Worker hosts (on-site machines) configure:
export PREFECT_API_URL=https://api.prod.example.com/api export PREFECT_SERVER_API_AUTH_STRING=prefect_api:REDACTED_SUPER_SECRET prefect worker start -p your-work-pool
Copy code
5) NetworkPolicies (defense in depth)
Only allow Prefect API service to be reached by:
- KrakenD pods
- oauth2-proxy pods (if they need API)
- cluster-internal agents/workers (if any)

Example:
apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-from-gateway-and-proxy namespace: prefect-prod spec: podSelector: matchLabels: app: prefect-server-api policyTypes: ["Ingress"] ingress: - from: - podSelector: matchLabels: app: krakend - podSelector: matchLabels: app: prefect-ui-proxy ports: - protocol: TCP port: 4200 ``` 6) ADFS setup (OIDC) essentials - Create two App Registrations (Relying Parties): - UI app (for oauth2-proxy), redirect URI: https://ui.prod.example.com/oauth2/callback - KrakenD app (for API), audience must match
aud
in KrakenD jose config (e.g., “krakend-public-flow-trigger”) - Issuance transform rules: - Emit
email
or
upn
claim (oauth2-proxy likes one of these) - Emit
roles
or
groups
for UI SSO group gating (e.g., “prefect-admins”, “prefect-users”) - Emit a custom claim
prefect_deployments
(array/string list) for each client of the KrakenD app, listing the deployment IDs they may trigger - Alternatively, emit per-client group/role names and maintain a mapping in the KrakenD Lua script instead of pushing the list in the token - Well-known configuration should be available at: - https://adfs.example.com/adfs/.well-known/openid-configuration - JWKS: the
jwks_uri
URL in that document 7) Auditing (since OSS has no first-class audit logs) - KrakenD: enable access logs with user identity (subject, client_id, roles); forward to SIEM - Prefect Server: centralize and retain logs; include X-Request-ID headers propagated by KrakenD - PostgreSQL: enable pgaudit to record DDL/DML in Prefect DB (deployments, flow runs, states) - OpenShift: enable audit logs for changes to Routes/Secrets/Deployments; keep retention per your policy 8) Why the gateway works for per-client control - Prefect OSS has no RBAC. KrakenD enforces that a client can only call POST /api/deployments/{deployment_id}/create_flow_run and only for deployment IDs listed in their token (or mapped in Lua). Everything else is denied.
🙌 1
- The upstream Basic Auth keeps your Prefect API private to trusted frontends (KrakenD and your workers). Open questions to finalize knobs - Do you prefer embedding the allowed deployments in the ADFS token (claim
prefect_deployments
), or do you want KrakenD to maintain a static map of client_id → allowed deployments? - Do you also want to rate-limit per client? KrakenD can apply per-endpoint quotas. - Any additional Routes (e.g., read-only metadata) needed for your clients beyond trigger? If you confirm the ADFS claim shape you’ll emit, I can adapt the KrakenD config (Lua snippet and header mapping) precisely. I’ll try to contain my excitement, but, well, you know me.
🙌 1
1