An example application showcasing the Quarkus Chicory extension for a WebAssembly-based CEL (Common Expression Language) policy validation of Kubernetes resources use case.
This example implements a Kubernetes-style policy validation by leveraging:
- Google CEL-Go: The popular Go-based CEL library used by many Kubernetes operators
- WebAssembly: Compiling the Go CEL library to WASM for portability
- Quarkus Chicory: Seamlessly integrating WASM execution into Quarkus applications
When building Kubernetes operators in Java (like the Keycloak operator), you might need CEL-based policy validation similar to what Go operators provide. Instead of reimplementing CEL from scratch in Java, this demo shows how to reuse the mature Go CEL library via WebAssembly.
- Java 21 or higher
- Maven 3.9+
- Docker (optional, for rebuilding the WASM module)
# Run unit tests
mvn test
# Run integration tests (packaged mode)
mvn verifymvn quarkus:devThe application will start on http://localhost:8080
# Valid deployment (3 replicas - should ALLOW)
curl -X POST http://localhost:8080/k8s/validate \
-F "resourceJson=$(cat src/test/resources/deployment.json)" \
-F "celPolicy=$(cat src/test/resources/require-replica-count.cel)"
# Invalid deployment (1 replica - should DENY)
curl -X POST http://localhost:8080/k8s/validate \
-F "resourceJson=$(cat src/test/resources/deployment-invalid.json)" \
-F "celPolicy=$(cat src/test/resources/require-replica-count.cel)"K8sCelValidatorService (@ApplicationScoped)
- Manages WASM module lifecycle
- Handles memory allocation and cleanup
- Executes CEL policy evaluation via WASM
- Returns structured validation results
K8sCelValidatorResource (@Path("/k8s"))
- REST endpoint for validation requests
- Delegates to service layer
- Translates validation results to HTTP responses
The main.go file implements a CEL policy evaluator in Go, with exported functions:
//go:wasmexport malloc
func malloc(size uint32) uint32
//go:wasmexport free
func free(ptr uint32)
//go:wasmexport evalPolicy
func evalPolicy(policyPtr, policyLen, inputPtr, inputLen uint32) int32The Go code is compiled to WASM targeting wasip1:
GOOS=wasip1 GOARCH=wasm go build -o go-cel.wasm main.goConfiguration in application.properties:
quarkus.chicory.modules.go-cel.name=io.quarkiverse.chicory.demo.GoCelModule
quarkus.chicory.modules.go-cel.wasm-file=src/main/resources/wasm/go-cel.wasmThis tells Quarkus Chicory to:
- Generate a
GoCelModuleclass and additional classes at build time from the WASM file - Configure the appropriate
MachineFactorybased on the runtime environment - Watch the WASM file for changes in development mode
The service injects the WASM context and manages the validation lifecycle:
@ApplicationScoped
public class K8sCelValidatorService {
@Inject
@Named("go-cel")
WasmQuarkusContext wasmQuarkusContext;
@PostConstruct
public void init() {
// Initialize WASM instance with WASI support
// Export malloc, free, evalPolicy functions
// Start Go runtime (i.e. run the main() function)
}
public ValidationResult validate(String resourceJson, String celPolicy) {
// 1. Allocate WASM memory
// 2. Write data to WASM memory
// 3. Call evalPolicy WASM function
// 4. Interpret result (1=allow, 0=deny, negative=error)
// 5. Free allocated memory
}
}The test suite uses a replica count validation policy:
object.kind != "Deployment" || (has(object.spec.replicas) && object.spec.replicas >= 2)
This policy ensures that Deployments have at least 2 replicas for high availability.
If you modify the Go source code and rebuild the Wasm module:
cd src/main/resources/wasm
./build.shThis will:
- Build a Docker image with Go 1.24 toolchain
- Compile
main.gotogo-cel.wasmwith WASI support - Output the updated WASM module
In development mode (mvn quarkus:dev), changes are automatically detected and reloaded!
IMPORTANT: The output could show the following error as soon as the Wasm module is rebuilt:
java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkiverse.chicory.deployment.QuarkusWasmProcessor#generate threw an exception: com.dylibso.chicory.wasm.MalformedException: section size mismatch, unexpected end of section
or function, length out of bounds
which is due to a known issue that is causing a race condition - the file watcher is too eager and doesn't wait for the file write to complete.
At the moment, just ignore it and re-run the tests, Quarkus Chicory will perform the generation process again.
Validates a Kubernetes resource against a CEL policy.
Request (multipart/form-data):
resourceJson: The Kubernetes resource as JSONcelPolicy: The CEL policy expression to evaluate
Response (application/json):
{
"status": "allowed|denied|error",
"message": "Policy ALLOWS the request",
"policy": "object.kind != \"Deployment\" || ..."
}Status Codes:
200 OK: Policy allows the resource403 Forbidden: Policy denies the resource400 Bad Request: CEL evaluation error (syntax, compilation, runtime)
mvn clean package
java -jar target/quarkus-app/quarkus-run.jarmvn clean package -Pnative
./target/quarkus-cel-k8s-validator-1.0.0-SNAPSHOT-runner