CEL Built-in Variables Reference
CEL Built-in Variables Reference
When writing CEL expressions in Kyverno v1alpha1 policy types (ValidatingPolicy, ImageValidatingPolicy, etc.), you have access to several built-in variables that provide context about the Kubernetes resource, request, and environment.
Important
This documentation is specifically for CEL expressions in v1alpha1 policy types. For traditional ClusterPolicy/Policy with JMESPath variables using {{ ... }} syntax, see the Variables documentation.
The variable syntax and availability differs between traditional policies and CEL-based policies.
This page documents all CEL variables with their data types, usage examples, and availability across different policy types.
Standard Kubernetes Variables
object
Type: Object
Description: The incoming Kubernetes resource being processed
1# Access resource metadata
2object.metadata.name
3object.metadata.namespace
4object.metadata.labels['app']
5
6# Access spec fields
7object.spec.replicas
8object.spec.template.spec.containers[0].image
9
10# Check if field exists
11has(object.metadata.labels.app)
oldObject
Type: Object (update operations only)
Description: The existing Kubernetes resource before modification
1# Compare old and new values
2object.spec.replicas != oldObject.spec.replicas
3
4# Check what changed
5object.metadata.labels != oldObject.metadata.labels
request
Type: Object
Description: Information about the admission request
1# Basic request info
2request.operation # "CREATE", "UPDATE", "DELETE"
3request.kind.kind # "Pod", "Deployment", etc.
4request.namespace
5
6# User information
7request.userInfo.username
8request.userInfo.uid
9request.userInfo.groups
10
11# Service account context (if applicable)
12request.userInfo.username.startsWith("system:serviceaccount:")
Kyverno-Specific Variables
serviceAccountName
Type: String
Description: Name of the service account associated with the request
1# Validate service account naming
2serviceAccountName.startsWith('allowed-prefix-')
3
4# Check against allowed list
5serviceAccountName in ['default', 'kyverno', 'system']
serviceAccountNamespace
Type: String
Description: Namespace of the service account
1# Ensure service account is in same namespace
2serviceAccountNamespace == object.metadata.namespace
3
4# Restrict cross-namespace service accounts
5serviceAccountNamespace == 'system-namespace'
images
Type: List<Object>
Description: List of container images from the resource (Pods, Deployments, etc.)
1# Check all images come from allowed registry
2images.all(image, image.registry == 'allowed-registry.com')
3
4# Ensure no latest tags
5images.all(image, image.tag != 'latest')
6
7# Validate image naming
8images.all(image, image.name.matches('^[a-z0-9-]+$'))
request.roles
Type: List<String>
Description: List of Role names the user has access to
1# Check if user has specific role
2'pod-reader' in request.roles
3
4# Ensure user has required roles
5['developer', 'deployer'].all(role, role in request.roles)
request.clusterRoles
Type: List<String>
Description: List of ClusterRole names the user has access to
1# Check cluster-level permissions
2'cluster-admin' in request.clusterRoles
3
4# Validate minimum permissions
5request.clusterRoles.exists(role, role.startsWith('system:'))
Context Variables
params
Type: Object
Description: Policy parameters passed from PolicyBinding or ClusterPolicyBinding
1# Access policy parameters
2params.allowedRegistries.exists(registry,
3 images.all(img, img.registry == registry))
4
5# Use parameter defaults
6has(params.maxReplicas) ? params.maxReplicas : 10
namespaceObject
Type: Object
Description: The Namespace object (when applicable)
1# Check namespace labels
2namespaceObject.metadata.labels['environment'] == 'production'
3
4# Validate namespace annotations
5has(namespaceObject.metadata.annotations['policy.kyverno.io/exclude'])
authorizer
Type: Object
Description: Authorization interface for checking permissions
1# Check if user can perform action
2authorizer.check({
3 'group': 'apps',
4 'version': 'v1',
5 'resource': 'deployments',
6 'verb': 'create',
7 'namespace': object.metadata.namespace
8}).allowed
9
10# Verify additional permissions
11authorizer.check({
12 'resource': 'secrets',
13 'verb': 'get',
14 'name': 'my-secret',
15 'namespace': object.metadata.namespace
16}).allowed
Image Object Structure
When using the images variable, each image object contains:
1# Image object fields
2image.registry # "docker.io"
3image.name # "library/nginx"
4image.tag # "1.21.0"
5image.digest # "sha256:abc123..."
6image.reference # Full image reference
Safe Field Access Patterns
Checking Field Existence
1# Always check if optional fields exist
2has(object.metadata.labels) &&
3has(object.metadata.labels.app)
4
5# Use conditional access
6has(object.spec.template) ?
7 object.spec.template.metadata.labels['version'] : 'unknown'
Handling Lists
1# Check if list exists and has items
2has(object.spec.containers) &&
3size(object.spec.containers) > 0
4
5# Safe list operations
6object.spec.containers.exists(c, c.name == 'main')
Null Safety
1# Handle potentially null values
2object.metadata.labels.orValue({})['app'] == 'myapp'
3
4# Default values for missing fields
5has(object.metadata.annotations.priority) ?
6 int(object.metadata.annotations.priority) : 0
Common Expression Patterns
Resource Validation
1# Require specific labels
2['app', 'version'].all(label,
3 has(object.metadata.labels) &&
4 has(object.metadata.labels[label]))
5
6# Validate naming conventions
7object.metadata.name.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?$')
Image Security
1# Block privileged containers
2object.spec.containers.all(container,
3 !has(container.securityContext) ||
4 !has(container.securityContext.privileged) ||
5 !container.securityContext.privileged)
6
7# Require image scanning
8images.all(image,
9 has(image.registry) &&
10 image.registry in ['secure-registry.com', 'internal-registry.local'])
RBAC Integration
1# Combine authorization checks
2authorizer.check({
3 'resource': 'pods',
4 'verb': 'create',
5 'namespace': object.metadata.namespace
6}).allowed && 'pod-creator' in request.roles
Variable Availability by Policy Type
| Variable | ValidatingPolicy | ImageValidatingPolicy | MutatingPolicy | GeneratingPolicy | DeletingPolicy |
|---|---|---|---|---|---|
object | ✅ | ❌ | ✅ | ✅ | ✅ |
oldObject | ✅ (updates) | ❌ | ✅ (updates) | ❌ | ✅ |
request | ✅ | ✅ | ✅ | ✅ | ✅ |
serviceAccountName | ✅ | ✅ | ✅ | ✅ | ✅ |
serviceAccountNamespace | ✅ | ✅ | ✅ | ✅ | ✅ |
images | ✅ | ✅ | ✅ | ✅ | ❌ |
request.roles | ✅ | ✅ | ✅ | ✅ | ✅ |
request.clusterRoles | ✅ | ✅ | ✅ | ✅ | ✅ |
params | ✅ | ✅ | ✅ | ✅ | ✅ |
namespaceObject | ✅ | ✅ | ✅ | ✅ | ✅ |
authorizer | ✅ | ✅ | ✅ | ✅ | ✅ |
Next Steps
- CEL Expression Cookbook - Common patterns and examples
- Policy Types Overview - Learn about different policy types
- Writing CEL Expressions - Best practices guide
- Traditional Variables Documentation - For JMESPath-based ClusterPolicy/Policy
CEL vs Traditional Variables
CEL expressions use direct variable access (e.g., serviceAccountName) while traditional policies use JMESPath syntax (e.g., {{ serviceAccountName }}). The core variables are the same, but the syntax and some availability rules differ:
| Traditional Syntax | CEL Syntax | Notes |
|---|---|---|
{{ serviceAccountName }} | serviceAccountName | Direct access in CEL |
{{ request.object.metadata.name }} | object.metadata.name | No request. prefix needed |
{{ images }} | images | Same variable, different syntax |
{{ request.roles }} | request.roles | Consistent with request context |
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.