Validated Patterns

Ideas for customizing the Secure Agent Workspace pattern

Everything in this pattern is configured in Git: who gets a workspace, what each workspace contains, which providers and hosts agents can use, and which OpenShell release the VMs run. Commit and push a change to the branch that the pattern deploys, and Red Hat OpenShift GitOps applies it.

Adding and removing users

Each entry in overrides/saw-users.yaml is one workspace:

users:
  - name: alice
    profiles:
      - data-science
  - name: bob
    profiles:
      - data-science
    # Optional:
    vaultPrefix: secret/data/hub/saw-bob   # bob's own API keys in Vault
    ownerSubject: <keycloak-subject>       # from `openshell whoami` after bob's first sign-in
  • name is the user’s Keycloak user name, the VM name, and the namespace suffix (saw-<name>). It must be a lowercase DNS label of at most 19 characters.

  • profiles lists the SAW-BOM profiles the workspace gets (default: data-science).

  • ownerSubject makes that Keycloak user an administrator of the workspaces in the VM.

  • vaultPrefix points the workspace at its own API keys. Load them into Vault under that prefix, as the commented example in values-secret.yaml.template shows. By default all workspaces share the keys under secret/data/hub.

The pattern does not create Keycloak users. Create each user in the openshell realm of the Keycloak instance in the saw-keycloak namespace, and give them the openshell-user role.

Removing an entry deletes that user’s Argo CD applications but keeps the VM and the namespace. To delete them as well, first set pruneOnRemove: true on the entry and push, then remove the entry and push.

Changing what a workspace contains

SAW-BOM profiles are directories in charts/saw-bom/profiles/<profile>/<workspace>/, one per OpenShell workspace, with three files:

workspace.yaml

The workspace name and description.

providers.yaml

The providers: a type from the governance catalog, the Secret and key that hold the API key, and for model providers the model name.

sandbox.yaml

The sandboxes: name, type (openclaw, nemoclaw, or generic), container image, and the providers to attach.

To add a profile, copy data-science, change it, and list it under profiles for the users that need it. A workspace VM applies profile changes on its next restart:

$ make openshell-saw-restart OPENSHELL_SAW_NAME=alice

Changing the model provider

The default profile uses NVIDIA Nemotron on build.nvidia.com. To use another provider, change the inference secret in your values-secret file (the provider, model, and api_key fields) and a matching provider in the profile. Then load the secrets again:

$ ./pattern.sh make load-secrets

To use an alternative model server on your cluster, such as vLLM or Ollama, give users the custom-inference profile and complete the details of the inference example in values-secret.yaml.template. This section is commented out by default. You must specify provider: openai, and must provide valid values for the model, url, and api_key parameters. The URL must be reachable from the workspace VMs, for example a cluster Service. It cannot be localhost.

Agents call the model endpoint directly, and the sandbox’s egress proxy allows only the hosts that the provider profile names. For a custom endpoint, set the endpoint’s host and port in charts/governance-policy/profiles/openai.yaml. Without that change, requests to your server are denied.

Changing the governance policy and provider profiles

The governance interceptor serves two things from the governance-policy chart:

policy.yaml

The sandbox policy: filesystem paths that are read-only or writable, the user that agents run as, and Landlock settings. It applies to every sandbox.

profiles/<id>.yaml

The provider profiles. You must define a provider profile in this directory before you can create a provider of that type. You cannot create providers whose type has no profile here. Each profile lists the credentials, the endpoints (hosts, ports, and protocols) that sandboxes can reach with it, and the binaries that can connect, for example node for OpenClaw or curl.

For example, to let agents use GitHub, keep the github profile and add a provider of type github to a profile. To allow a new API, add a profile file with its hosts and binaries.

A profile that does not list binaries blocks all connections. List the real path of each program: the egress proxy resolves symbolic links before it matches a program, and you can use wildcards. For example, in the default image /usr/bin/node is a link to /usr/bin/node-<version>, so for OpenClaw the profile must list /usr/bin/node-*.

Changes take effect when Red Hat OpenShift GitOps syncs the chart. Profile changes affect running sandboxes without restarting the sandbox.

Upgrading OpenShell

The OpenShell release that the VMs run is pinned by image digest in the InstallerBOM, the bom block in charts/openshell-saw/values.yaml. To upgrade OpenShell, complete the following steps:

  1. Change the component versions and digests in the bom block. All components (gateway, CLI, supervisor, and sandbox runtime) must come from the same release.

  2. Build the governance interceptor from the same OpenShell release. It is set as source.git.ref in image-builder-charts/helm/governance-interceptor-image/values.yaml, and the chart’s image tag must match.

  3. Push, and restart the VMs. Each VM installs the new release on boot.

Updating to a new release series, for example from 0.0.x to 0.1.x, causes the gateway to lose its state, and the data in the /sandbox directory of each sandbox is lost. This occurs because the OpenShell installer moves the old gateway database aside and creates fresh workspaces, providers, and sandboxes. After an update to a new release series, users also need to update to a compatible version of the openshell CLI.

Additional customization options

  • Custom container images: sandbox images are set per sandbox in the profile’s sandbox.yaml. The VM pulls them from their registry.

  • Custom VM size: vm.cores, vm.memory, and vm.diskSize in charts/openshell-saw/values.yaml, or per user under values in overrides/saw-users.yaml.

  • Signing: the installer can require signed OpenShell images (signing.mode: enforce in charts/openshell-saw/values.yaml) after the images you pin are signed.