kubectl auth can-i: Test RBAC Permissions
kubectl auth can-i answers yes or no for whether the current identity is allowed to run a verb on a resource, with an exit code to match.
Rather than running a privileged action and catching the Forbidden, you can ask the API server up front whether it is allowed.
What it does
kubectl auth can-i performs a SelfSubjectAccessReview: it asks the API server whether the caller may run <verb> <resource> (optionally in a namespace). It prints "yes" or "no" and sets the exit code accordingly. --as/--as-group test another identity, and --list dumps all permissions.
Common usage
kubectl auth can-i create deployments -n staging
# quiet: exit code only, for scripts
kubectl auth can-i create deployments -n staging -q && deploy.sh
# what can a service account do?
kubectl auth can-i --list \
--as=system:serviceaccount:ci:deployer -n stagingOptions
| Flag | What it does |
|---|---|
| <verb> <resource> | Action to test (e.g. create deployments) |
| -n, --namespace | Namespace scope for the check |
| --list | List all permissions for the identity |
| --as / --as-group | Impersonate a user or group for the check |
| -q, --quiet | Suppress yes/no output, return only an exit code |
| --subresource=<sub> | Check a subresource such as pods/log |
In CI
Use -q to gate a deploy on permissions: kubectl auth can-i ... -q || { echo "missing RBAC"; exit 1; } fails fast with a clear message instead of a cryptic Forbidden mid-run. Combine with --as=system:serviceaccount:<ns>:<sa> to verify the pipeline service account, not just your admin token.
Common errors in CI
A plain "no" with exit code 1 is the answer, not an error, so do not let set -e mask it. "Warning: resource \"<x>\" is not namespace scoped" means you scoped a cluster-wide resource with -n. "the server doesn\'t have a resource type \"<x>\"" means the resource name is wrong or its CRD is not installed.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes