CEL Built-in Variables Reference

Complete reference of all variables available in Kyverno CEL expressions for v1alpha1 policy types

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.

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

VariableValidatingPolicyImageValidatingPolicyMutatingPolicyGeneratingPolicyDeletingPolicy
object
oldObject✅ (updates)✅ (updates)
request
serviceAccountName
serviceAccountNamespace
images
request.roles
request.clusterRoles
params
namespaceObject
authorizer

Next Steps

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 SyntaxCEL SyntaxNotes
{{ serviceAccountName }}serviceAccountNameDirect access in CEL
{{ request.object.metadata.name }}object.metadata.nameNo request. prefix needed
{{ images }}imagesSame variable, different syntax
{{ request.roles }}request.rolesConsistent with request context