RBAC and Security Reference#
This page documents the exact Kubernetes permissions Reloader requires, the pod security context it runs with, and the options available for hardening the deployment.
All information on this page is derived from the Reloader Helm chart.
How RBAC is provisioned#
The Helm chart creates RBAC resources automatically. The type depends on reloader.watchGlobally:
watchGlobally |
RBAC resources created |
|---|---|
true (default) |
ClusterRole + ClusterRoleBinding |
false |
Role + RoleBinding (scoped to the deployment namespace) |
RBAC creation is controlled by reloader.rbac.enabled (default: true). To bring your own RBAC and skip chart-managed resources, set it to false — but you must then create the Role/ClusterRole manually using the rules below.
ClusterRole rules (default mode)#
These are the exact rules the chart creates when watchGlobally: true.
Core resources (read)#
- apiGroups: [""]
resources: ["secrets", "configmaps"]
verbs: ["list", "get", "watch"]
Reloader watches Secrets and ConfigMaps for data changes. These are read-only permissions.
- The
secretsrule is omitted whenreloader.ignoreSecrets: true. - The
configmapsrule is omitted whenreloader.ignoreConfigMaps: true.
Namespaces (read) — only when namespaceSelector is set#
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get", "list", "watch"]
Required so Reloader can evaluate namespace labels when filtering with namespaceSelector. Not added to the ClusterRole when namespaceSelector is unset.
Workloads (patch)#
- apiGroups: ["apps"]
resources: ["deployments", "daemonsets", "statefulsets"]
verbs: ["list", "get", "update", "patch"]
- apiGroups: ["extensions"]
resources: ["deployments", "daemonsets"]
verbs: ["list", "get", "update", "patch"]
Reloader patches the pod template of matching workloads to trigger a rolling restart. The extensions rules are retained for compatibility with older Kubernetes versions where these resources existed under the extensions API group.
CronJobs and Jobs#
- apiGroups: ["batch"]
resources: ["cronjobs"]
verbs: ["list", "get"]
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["create"]
list/get on CronJobs allows Reloader to find and evaluate CronJob workloads. create on Jobs is required for the CronJob restart mechanism.
Leader election — only when enableHA: true#
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["create", "get", "update"]
Required when running multiple replicas with HA mode. The active leader holds a Lease; standby replicas poll it. Not added to the ClusterRole when enableHA: false.
Events#
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
Reloader emits Kubernetes Events when it triggers a restart. These appear in kubectl describe output for the workload.
Argo Rollouts — only when isArgoRollouts: true#
- apiGroups: ["argoproj.io"]
resources: ["rollouts"]
verbs: ["list", "get", "update", "patch"]
Only added when isArgoRollouts: true and the Argo Rollouts CRD (argoproj.io/v1alpha1) is detected in the cluster.
OpenShift DeploymentConfigs — only when isOpenshift: true#
- apiGroups: ["apps.openshift.io"]
resources: ["deploymentconfigs"]
verbs: ["list", "get", "update", "patch"]
Only added when isOpenshift: true and the OpenShift API (apps.openshift.io/v1) is detected.
Role rules (namespace-scoped mode)#
When watchGlobally: false, the chart creates a Role in the deployment namespace instead of a ClusterRole. The rules are identical to the ClusterRole above, except:
- The
namespacesrule is never added (not applicable to a Role).
This mode restricts Reloader to watching only the namespace it is deployed in.
Disabling RBAC creation#
If your organisation manages RBAC outside of Helm (for example via OPA/Gatekeeper, a centralised RBAC controller, or a GitOps pipeline), disable chart-managed RBAC:
reloader:
rbac:
enabled: false
You must then create the Role or ClusterRole manually with the rules listed above, and bind it to the ServiceAccount Reloader uses.
ServiceAccount#
The chart creates a ServiceAccount in the deployment namespace by default.
reloader:
serviceAccount:
create: true
name: "" # auto-generated if empty
annotations: {} # use for IRSA, Workload Identity, etc.
To disable ServiceAccount creation and supply your own:
reloader:
serviceAccount:
create: false
name: my-existing-sa
To control whether the token is auto-mounted:
reloader:
deployment:
automountServiceAccountToken: false
Pod security context#
The chart sets the following pod-level security context by default:
securityContext:
runAsNonRoot: true
runAsUser: 65534
seccompProfile:
type: RuntimeDefault
runAsNonRoot: true— the container must not run as root; Kubernetes enforces this.runAsUser: 65534— thenobodyuser; no special privileges.seccompProfile: RuntimeDefault— uses the node's default seccomp profile, which restricts syscalls to the safe default set.
On OpenShift 4.13.3 and later, the platform assigns UIDs dynamically. Set runAsUser to null to allow this:
reloader:
deployment:
securityContext:
runAsUser: null
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
Container security context#
The container-level security context is empty by default. To harden it:
reloader:
deployment:
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
readOnlyRootFilesystem: true can also be set via the top-level shorthand:
reloader:
readOnlyRootFileSystem: true
When readOnlyRootFileSystem: true is set (either way), the chart automatically mounts an emptyDir volume at /tmp/ so Reloader can write temporary files.
Network policy#
The chart includes an optional NetworkPolicy that restricts ingress and egress for the Reloader pod. Disabled by default.
reloader:
netpol:
enabled: true
When enabled, the policy allows:
- Ingress on port
9090— for Prometheus metrics scraping - Egress on port
443— to reach the Kubernetes API server (https)
You can further restrict the ingress source with netpol.from and the egress destination with netpol.to:
reloader:
netpol:
enabled: true
from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
to:
- ipBlock:
cidr: 10.96.0.1/32 # cluster API server IP
Verifying RBAC in a running cluster#
Check what ClusterRole or Role was created:
# Global mode
kubectl get clusterrole -l app=reloader-reloader
kubectl describe clusterrole reloader-reloader-role
# Namespace-scoped mode
kubectl get role -n reloader -l app=reloader-reloader
kubectl describe role reloader-reloader-role -n reloader
Check the binding:
kubectl get clusterrolebinding -l app=reloader-reloader
kubectl describe clusterrolebinding reloader-reloader-role-binding
Confirm the ServiceAccount:
kubectl get serviceaccount -n reloader
If Reloader logs show failed to update deployment, check that its ServiceAccount has update and patch on apps/deployments:
kubectl auth can-i patch deployments \
--as=system:serviceaccount:reloader:reloader-reloader \
--all-namespaces