Skip to content

Runtime classes cannot bound privilege escalation or seccomp, only capabilities #313

Description

@scotwells

Summary

A customer can weaken two of the three confinement settings on a sandbox container to any value the API enum allows, and no runtime class can refuse it. Capabilities are bounded — a class publishes grantableCapabilities and a request beyond it is rejected with a reason naming the class. Privilege escalation and the seccomp profile have no equivalent published ceiling, so allowPrivilegeEscalation: true and seccompProfile: Unconfined are accepted by every class in service today.

Separately, a container that both adds and drops the same capability is stored as written instead of being refused or normalised.

This is not presently an exposure. Every runtime class in service is VM-isolated: each instance runs its own guest kernel, so these settings take effect inside the customer's own virtual machine and reach nothing shared. The gap is structural. A future class backed by shared-kernel isolation would inherit the same permissiveness silently, because the class contract has no way to state a limit and validation has nothing to reject against.

Follows #310, which introduced the published security context surface.

Evidence

Verified against the staging datum-cloud project control plane with kubectl apply --dry-run=server, on a sandbox Workload using class: general-purpose.

Input Result Stored as
allowPrivilegeEscalation: true accepted, no warning true
seccompProfile: {type: Unconfined} accepted, no warning Unconfined
capabilities: {add: [CHOWN], drop: [CHOWN]} accepted add: [CHOWN], drop: [CHOWN, ALL]

For contrast, an add beyond the class's grantable set is rejected naming the class and the set it grants.

The gap is deliberate and documented, not accidental. Capabilities are the only security setting checked against the class. A class publishes defaultSecurityContext values for allowPrivilegeEscalation and seccompProfile, and those are explicitly documented as a default rather than a limit — so whatever the container states for either is accepted. grantableCapabilities is the only ceiling the class contract expresses.

For the contradictory add/drop case, each capability name in add and drop is checked on its own and the two lists are never compared, so an overlap passes; ALL is then appended to drop, producing the stored value above.

The question is already recorded as an open question in the runtime classes enhancement, including the note that adding a limit later is a compatible change because it only narrows what is accepted. This issue tracks it as work rather than restating it.

Reproduction

Against a control plane with the RuntimeClasses gate enabled and the general-purpose class published:

apiVersion: compute.datumapis.com/v1alpha
kind: Workload
metadata:
  name: confinement-probe
spec:
  runtimeClass:
    class: general-purpose
  template:
    spec:
      runtime:
        sandbox:
          containers:
            - name: probe
              image: nginx:alpine
              securityContext:
                allowPrivilegeEscalation: true
                seccompProfile:
                  type: Unconfined
                capabilities:
                  add: [CHOWN]
                  drop: [CHOWN]
      placements:
        - name: default
          cityCodes: [DFW]
kubectl apply --dry-run=server -f probe.yaml -o yaml

The object is admitted and the values above are returned in the dry-run result.

Expected behaviour

For maintainers to decide: should a runtime class be able to bound privilege escalation and the seccomp profile the way it bounds capabilities, so a class can refuse a container that asks for less confinement than the class is willing to serve? If so, the class contract needs a published limit for each, and validation needs to reject against it.

The contradictory add/drop case is separable and smaller: a container that both adds and drops the same capability has stated something self-contradictory, and the API should refuse it or normalise it rather than store it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions