An OpenShift-oriented Kubernetes operator that manages OpenClaw instances. It handles deployment, credential injection for LLM providers, HTTPS routing, and gateway authentication through a single Claw custom resource. While the operator can run on vanilla Kubernetes, it is designed for OpenShift where the restricted Security Context Constraint (SCC) provides the primary pod security boundary -- non-root UID enforcement, SELinux confinement, seccomp filtering, and privilege escalation prevention are all handled by the platform.
The easiest way to try an OpenClaw instance managed by this operator is on the Red Hat Developer Sandbox. You can get a live environment running for free with zero cluster setup. Read more about the Dev Sandbox deployment in our launch blog post.
The operator applies multiple layers of defense:
- OpenShift restricted SCC -- each pod runs under the restricted SCC which enforces non-root UIDs, SELinux labels, seccomp
RuntimeDefault, and blocks privilege escalation. All containers additionally drop all Linux capabilities and disable service account token mounting. - Secret isolation -- OpenClaw pods never see API keys or tokens. Credentials are stored in user-managed Kubernetes Secrets and injected by the proxy (a separate Deployment) into outbound requests.
- External secret management -- credential Secrets are user-managed and fully compatible with External Secrets Operator, Sealed Secrets, or HashiCorp Vault. Using an external secret manager is recommended for production.
- Network isolation -- OpenClaw pods cannot reach the internet directly; all outbound traffic is forced through the credential proxy via NetworkPolicy. The proxy only allows HTTPS (port 443) egress and rejects any domain not explicitly configured.
- Ingress restriction -- only the OpenShift router namespace can reach the gateway port (NetworkPolicy on ingress).
- Gateway authentication -- two modes:
token(default) auto-generates a 256-bit token per instance;passworduses a shared password from a Kubernetes Secret. Seespec.authin the CRD reference. - Device pairing -- when enabled via
spec.auth.disableDevicePairing: false, remote browser connections require a one-time approval via CLI before they can interact with the instance. Disabled by default.
The recommended way to install the operator on an OpenShift cluster with OLM.
oc create namespace claw-operatoroc apply -f - <<EOF
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
name: claw-operator-catalog
namespace: openshift-marketplace
spec:
sourceType: grpc
image: quay.io/codeready-toolchain/claw-operator-catalog:latest
displayName: Claw Operator
publisher: Red Hat
updateStrategy:
registryPoll:
interval: 15m
EOFoc apply -f - <<EOF
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: claw-operator
namespace: claw-operator
spec:
targetNamespaces:
- claw-operator
EOFoc apply -f - <<EOF
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: claw-operator
namespace: claw-operator
spec:
channel: staging
name: claw-operator
source: claw-operator-catalog
sourceNamespace: openshift-marketplace
installPlanApproval: Automatic
EOFoc get csv -n claw-operator
oc get pods -n claw-operatorOnce the CSV phase shows Succeeded and the controller pod is running, proceed to Set Up Your Namespace to create a Claw instance.
- OpenShift cluster (or Kubernetes with manual port-forward)
ocCLI logged into the clusterpodmaninstalled locally- A container registry accessible from your cluster (e.g.,
quay.io)
Log in to your container registry and OpenShift cluster:
podman login quay.io
oc login --server=https://api.your-cluster.example.com:6443Make sure the claw-operator and claw-proxy repositories on quay.io are set to public (or configure a pull secret), so the cluster can pull the images.
Then build, push, and deploy in one command:
make dev-setup REGISTRY=quay.io/<your-user>This builds both images (operator + proxy), pushes them, installs CRDs, and deploys the controller into the claw-operator namespace.
The operator runs in claw-operator, but user workloads (Claw instances, secrets) go in your own namespace. Set NS once and all commands below will use it (Makefile targets also default to my-claw):
export NS=my-claw # or pick your own name
oc create namespace $NSDo not use the
defaultnamespace. On OpenShift, thedefaultnamespace uses a different SCC assignment that may not inject a numericrunAsUserinto pods. This causes containers whose image declares a non-numericUSER(e.g.,node) to fail withrunAsNonRootverification errors. Always create a dedicated namespace for your Claw instance.
Get your API key from Google AI Studio.
oc create secret generic gemini-api-key \
--from-literal=api-key=YOUR_GEMINI_API_KEY \
-n $NSGet your API key from the OpenAI Platform.
oc create secret generic openai-api-key \
--from-literal=api-key=YOUR_OPENAI_API_KEY \
-n $NSApply the sample CR, or use the inline version below:
oc apply -f config/samples/claw_v1alpha1_claw.yaml -n $NSoc apply -f - <<EOF
apiVersion: claw.sandbox.redhat.com/v1alpha1
kind: Claw
metadata:
name: instance
namespace: $NS
spec:
credentials:
- name: gemini
provider: google
secretRef:
- name: gemini-api-key
key: api-key
EOFoc apply -f - <<EOF
apiVersion: claw.sandbox.redhat.com/v1alpha1
kind: Claw
metadata:
name: instance
namespace: $NS
spec:
credentials:
- name: openai
provider: openai
secretRef:
- name: openai-api-key
key: api-key
EOFFor known providers (google, anthropic, openai, xai), the operator infers type and domain automatically. For other LLM providers, messaging channels, MCP servers, and more, see the User Guide.
Wait for it to become ready and get the URL and gateway token:
make wait-ready NS=$NS
# or, for a non-default instance name:
# make wait-ready NS=$NS CLAW=my-instanceOpen the URL printed above and enter the gateway token to log in.
On vanilla Kubernetes (no Route), use port-forwarding instead:
oc port-forward svc/instance 18789:18789 -n $NS
# Then open http://localhost:18789
# Replace "instance" with your Claw CR name if differentPassword mode: If you prefer shared password access (useful for workshops, demos, or shared team instances), create a Secret with the password and set spec.auth.mode: password on the Claw CR. Users enter the password in the browser instead of using a token. See ADR-0011 for details.
Device pairing is disabled by default. To enable it, set spec.auth.disableDevicePairing: false on the Claw CR.
When enabled, on first connection you'll see "pairing required". With the browser tab open, approve the request:
make approve-pairing NS=$NS
# or, for a non-default instance name:
# make approve-pairing NS=$NS CLAW=my-instanceThis picks the first pending request and asks for confirmation.
Refresh the browser after approval. The device is remembered across sessions.
Note: Device pairing is disabled by default in all auth modes. Set
spec.auth.disableDevicePairing: falseto enable it.
Run make help for a full list. Key targets:
| Target | Description |
|---|---|
make dev-setup REGISTRY=... |
Full dev cycle: build, push, deploy |
make dev-build dev-push dev-deploy REGISTRY=... |
Step-by-step dev iteration |
make dev-cleanup |
Tear down deployed controller and CRDs |
make wait-ready NS=... [CLAW=...] |
Wait for ready, print URL + token |
make approve-pairing NS=... [CLAW=...] |
List & approve a device pairing request |
make test |
Run unit tests |
make test-e2e |
Run e2e tests (requires Kind) |
make lint |
Run golangci-lint |
make build |
Build manager binary locally |
make run |
Run controller locally against cluster |
make manifests |
Regenerate CRD YAML and RBAC from markers |
make generate |
Regenerate DeepCopy methods |
Override the container tool with CONTAINER_TOOL=docker if needed. Default is podman.