Cluster permissions
Before deploying AI Gateway, ensure you have the appropriate RBAC permissions in your Kubernetes cluster. This section is written so your security team can pre-review the full permission surface before any install runs.
Bootstrap vs steady-state permissions
There are two distinct permission scopes. Treat them differently in your security review.
| Phase | Who needs it | What it covers | Scope | When it's used |
|---|---|---|---|---|
| Bootstrap (one-time) | The human or service account running aigateway deploy install | Creating the target namespace (if absent), the Operator's ServiceAccount + Role + RoleBinding (skipped if a service account is provided in pool config), the API-auth Secret, the optional registry-credentials Secret, and the initial Operator Deployment | Namespace-scoped | Once per pool, at install. Can be revoked afterwards. |
| Steady-state (ongoing) | The Operator's own ServiceAccount | Reconciling Armor, Redis (when auto-installed), ingress, HPAs, PDBs, leader-election leases, and MCP server deployments inside the pool's namespace | Namespace-scoped only (Role, not ClusterRole) | Continuously, as the Operator runs |
The Operator never needs cluster-admin. Once the bootstrap is complete, all reconciliation happens inside the pool's namespace.
For security review: generate the exact deployer Role manifest with
aigateway cluster permissions --generate-role --namespace <ns>and share it with your platform/security team before scheduling the install.
What changes when you use a pool-provided ServiceAccount
If you set Service Account on the pool (Basic Information tab) to a pre-provisioned SA name, the bootstrap path skips creating the Operator's ServiceAccount, Role, and RoleBinding. It only verifies that the ServiceAccount exists in the namespace and prints the RBAC rules the ServiceAccount must already have bound. That changes what the deployer (the principal running aigateway deploy install) needs:
| Deployer permission | Default (CLI creates ServiceAccount + RBAC) | Pool-provided ServiceAccount |
|---|---|---|
serviceaccounts create/update/patch | Required | Not required |
rbac.authorization.k8s.io/roles create/update/patch | Required | Not required |
rbac.authorization.k8s.io/rolebindings create/update/patch | Required | Not required |
serviceaccounts get | Required (verify) | Required (verify ServiceAccount exists) |
| Everything else in Deployer Permissions below | Required | Required |
When you use a pool-provided ServiceAccount, the responsibility for binding the Operator's runtime Role to the ServiceAccount shifts to your platform team. Use the Operator runtime Role section below as the source of truth for what the ServiceAccount must be able to do.
Deployer Permissions
These are the namespace-scoped permissions the deployer needs to run aigateway deploy install. This matches what aigateway cluster permissions --generate-role --namespace <ns> outputs.
Core workload resources
| Resource | API Group | Verbs | Purpose |
|---|---|---|---|
deployments | apps | get, list, watch, create, update, patch, delete | Deploy Operator, Armor, and SIEM components |
statefulsets | apps | get, list, watch, create, update, patch, delete | Manage Redis (auto-install mode) |
services | core | get, list, watch, create, update, patch, delete | Create service endpoints |
secrets | core | get, list, watch, create, update, patch, delete | Manage API credentials and registry secrets |
configmaps | core | get, list, watch, create, update, patch, delete | Store configuration data |
persistentvolumeclaims | core | get, list, watch, create, update, patch, delete | Persistent storage for Redis (auto-install mode) |
pods | core | get, list, watch | Monitor pod health and status |
pods/exec | core | create | Operator runtime operations |
events | core | get, list | View Kubernetes events for troubleshooting |
Scaling
| Resource | API Group | Verbs | Purpose |
|---|---|---|---|
horizontalpodautoscalers | autoscaling | get, list, watch, create, update, patch, delete | Auto-scale Armor and MCP deployments |
Networking
| Resource | API Group | Verbs | Purpose |
|---|---|---|---|
ingresses | networking.k8s.io | get, list, watch, create, update, patch, delete | Expose MCP servers externally |
RBAC (required unless using a pool-provided ServiceAccount)
| Resource | API Group | Verbs | Purpose |
|---|---|---|---|
serviceaccounts | core | get, create, update, patch (or just get with a pool-provided ServiceAccount) | Create or verify the Operator's ServiceAccount |
roles | rbac.authorization.k8s.io | get, create, update, patch (omitted with a pool-provided ServiceAccount) | Create the Operator's Role |
rolebindings | rbac.authorization.k8s.io | get, create, update, patch (omitted with a pool-provided ServiceAccount) | Bind the Operator's Role to its ServiceAccount |
Operator runtime Role
The Operator's runtime Role is created automatically by the bootstrap step (or, when a pool-provided ServiceAccount is used, must be pre-bound by your platform team). It is broader than the deployer's permissions because it also covers what the Operator needs during steady-state reconciliation. The full set of rules is:
| Resource | API Group | Verbs | Purpose |
|---|---|---|---|
pods, services, configmaps, secrets, persistentvolumeclaims | core | get, list, watch, create, update, patch, delete | Manage Armor, Redis (auto-install), and MCP workloads + their config/state |
events | core | get, list, watch | Surface cluster events into pool diagnostics |
pods/exec | core | create | Operator-side maintenance into pods |
deployments, statefulsets | apps | get, list, watch, create, update, patch, delete | Manage Armor, Redis StatefulSet (auto-install), MCP Deployments |
ingresses | networking.k8s.io | get, list, watch, create, update, patch, delete | Default ingress mode |
horizontalpodautoscalers | autoscaling | get, list, watch, create, update, patch, delete | Auto-scale Armor and MCP deployments |
poddisruptionbudgets | policy | get, list, watch, create, update, patch, delete | HA safeguards on Armor / Redis (auto-install) / MCP deployments |
leases | coordination.k8s.io | get, list, watch, create, update, patch, delete | Operator leader election |
gateways, virtualservices | networking.istio.io | get, list, watch, create, update, patch, delete | Istio ingress mode |
ingressroutes | traefik.io | get, list, watch, create, update, patch, delete | Traefik ingress mode |
httproutes | gateway.networking.k8s.io | get, list, watch, create, update, patch, delete | Kubernetes Gateway API ingress mode |
routes | route.openshift.io | get, list, watch, create, update, patch, delete | OpenShift routes |
The four ingress-provider rules (Istio, Traefik, Gateway API, OpenShift) are granted unconditionally even if your pool currently uses a different mode. The Operator reads them at startup, and ingress mode can be changed later from the portal without re-rolling RBAC. Granting them on a cluster that doesn't have those CRDs installed is harmless — RBAC rules for absent resources are simply unused.
The bootstrap step creates this Role and a RoleBinding to the Operator's ServiceAccount. When you use a pool-provided ServiceAccount, you must create this Role yourself and bind it to your ServiceAccount before running aigateway deploy install — the CLI verifies the ServiceAccount exists but does not create or modify any RBAC for it.
Example Operator runtime Role (verified against a live aigw-operator Role; all four ingress-provider rules included because the CLI and Operator support all of them — keep the ones that match your ingress mode and comment out the rest if your platform team prefers a narrower manifest):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: aigw-operator
namespace: ai-gateway
rules:
# Core workload resources
- apiGroups: [""]
resources: ["pods", "services", "configmaps", "secrets", "persistentvolumeclaims"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
- apiGroups: ["apps"]
resources: ["deployments", "statefulsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Scaling and high availability
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["policy"]
resources: ["poddisruptionbudgets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# --- Ingress: default (Kubernetes Ingress, includes AWS ALB / nginx / GKE / AKS / Azure App Gateway) ---
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# --- Ingress: Istio service mesh ---
- apiGroups: ["networking.istio.io"]
resources: ["gateways", "virtualservices"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# --- Ingress: Traefik ---
- apiGroups: ["traefik.io"]
resources: ["ingressroutes"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# --- Ingress: Kubernetes Gateway API ---
- apiGroups: ["gateway.networking.k8s.io"]
resources: ["httproutes"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# --- Ingress: OpenShift routes ---
- apiGroups: ["route.openshift.io"]
resources: ["routes"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
The bootstrap creates this Role with all ingress-provider rules included regardless of which mode your pool currently uses — that's the safest default (changing ingress mode later from the portal doesn't require re-rolling RBAC). If your platform team prefers a tighter manifest, comment out the rule groups for ingress providers you're not using; just remember to re-apply if you ever change the pool's ingress mode.
Bind the Role to your ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: aigw-operator
namespace: ai-gateway
subjects:
- kind: ServiceAccount
name: <your-pool-service-account-name>
namespace: ai-gateway
roleRef:
kind: Role
name: aigw-operator
apiGroup: rbac.authorization.k8s.io
Checking Permissions
Use the CLI to verify you have the required permissions:
# Check permissions for specific namespace
aigateway cluster permissions --namespace ai-gateway
# JSON output for automation
aigateway cluster permissions --namespace ai-gateway --json
Setting Up RBAC
If you lack sufficient permissions, generate and apply the deployer Role:
Step 1: Generate the deployer Role
aigateway cluster permissions --generate-role --namespace ai-gateway > aigateway-deployer-role.yaml
Example output (verified against CLI v1.0.10):
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: aigateway-deployer
namespace: ai-gateway
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
resources: ["statefulsets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "create", "update", "patch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list"]
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
resources: ["serviceaccounts"]
verbs: ["get", "create", "update", "patch"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["roles"]
verbs: ["get", "create", "update", "patch"]
- apiGroups: ["rbac.authorization.k8s.io"]
resources: ["rolebindings"]
verbs: ["get", "create", "update", "patch"]
This is the deployer Role only — namespace-scoped, used to run aigateway deploy install. It does not include the Operator's runtime resources (policy/poddisruptionbudgets, coordination.k8s.io/leases, and the Istio/Traefik/Gateway-API/OpenShift ingress-provider resources). Those go in the separate Operator runtime Role, which the bootstrap creates automatically when it provisions the Operator's ServiceAccount.
If you provide a pre-existing ServiceAccount on the pool (set on the Basic Information tab), the bootstrap does not create or modify any Role/RoleBinding — you must construct the Operator runtime Role yourself based on the table in Operator runtime Role and bind it to your ServiceAccount before running aigateway deploy install.
Note: The CLI's emitted YAML uses unquoted flow-style verb lists (for example
verbs: [get list watch ...]). That's valid syntactically in some YAML parsers but not in others — ifkubectl applyrejects it, normalise the verbs into a quoted comma-separated list as shown above (verbs: ["get", "list", "watch", ...]). The semantics are identical.
Step 2: Create RoleBinding
Bind the Role to your user or service account:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: aigateway-deployer-binding
namespace: ai-gateway
subjects:
- kind: User
name: your-username@company.com # Replace with your username
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: aigateway-deployer
apiGroup: rbac.authorization.k8s.io
Step 3: Apply
kubectl apply -f aigateway-deployer-role.yaml
kubectl apply -f aigateway-deployer-rolebinding.yaml
For CI/CD: Use a ServiceAccount instead of User in the RoleBinding:
subjects:
- kind: ServiceAccount
name: aigateway-deployer
namespace: ai-gateway
Skipping Permission Checks
Use the --skip-permission-checks flag if permission validation fails but you know you have the necessary permissions:
aigateway deploy install --skip-permission-checks
Warning: Only use this if you've verified your permissions. Deployment will fail if you lack required permissions.
What to share with your security team
For a pre-install review, the artifacts to hand over are:
- The deployer Role manifest — generate with
aigateway cluster permissions --generate-role --namespace <ns>(see Setting Up RBAC for an example). - The Operator runtime Role — the table in Operator runtime Role lists everything the Operator's ServiceAccount gets bound to (created automatically by the bootstrap, or constructed manually when a pool-provided ServiceAccount is used).
- The full set of manifests the Operator would apply —
aigateway deploy install --dry-run --show-manifests. This is for review only, not a fork-and-maintain path; see Deployment Model. - The image list (or release path) for supply-chain review — see Mirroring images from your internal artifact registry on the pool's image fields.
- The list of egress endpoints the Operator and Armor need to reach — see the egress allowlist.
Troubleshooting
Common Issues:
| Issue | Solution |
|---|---|
namespace not found | Have admin create namespace: kubectl create namespace ai-gateway |
roles.rbac.authorization.k8s.io is forbidden | Use existing service account or ask admin to create RBAC resources |
storageclasses is forbidden | Use --skip-permission-checks flag |
| Permissions not working after applying Role | Verify RoleBinding references correct user/namespace, wait for RBAC cache update |
Tips
- Store credentials securely (use Kubernetes secrets, not plain text)
- Use least-privilege RBAC (generate roles with
aigateway cluster permissions --generate-role) - Enable TLS for all production deployments
- Regularly rotate API credentials and registry secrets
Cequence AI Gateway