Tenants

A complete Tenant combining the workload and networking best-practice baseline

Use this complete Tenant as a starting point for application namespaces. It combines the compatible baseline policies from Workloads and Networking into one ordered spec.rules list. All namespaces in this Tenant receive the same baseline.

Included Policies

AreaCombined configuration
ResourcesDefault CPU, memory, and ephemeral-storage requests; remove CPU limits; match memory limits to requests; default ephemeral-storage limits.
CapacityShare one illustrative quota across all Tenant namespaces.
QoSDeny BestEffort after resource mutation.
PlacementUse the default scheduler, exclude control-plane nodes, deny control-plane and wildcard tolerations, and reject Pods created with nodeName.
Workload typesDeny DaemonSets.
Pod isolationSet hostUsers: false and manage the namespace’s Pod Security labels at restricted.
ImagesAllow the approved registry path and require Always pull policy.
PriorityDefault to and allow only tenant-standard.
ServicesAllow only ClusterIP and deny every external IP.
Namespace trustDeny adding or changing company.com/system on Tenant namespaces.

Before Applying

  • Replace solar, solar-owner, and registry.example.com/solar with your Tenant, owner, and approved registry path. Publish immutable image references in that registry; the example’s registry matcher does not require a digest.
  • Size requests, storage defaults, and the shared quota from measured usage and available capacity. The numbers below illustrate a profile, not a universal production budget. There is deliberately no CPU-limit quota.
  • Create the non-preempting tenant-standard PriorityClass before admitting workloads that use this Tenant. The Tenant references the class; it does not create it.
  • Use Linux nodes with user namespace support. Review kernel, runtime, and volume support before enabling hostUsers: false. For incompatible workloads, define a separate, reviewed namespace profile.
  • Set all three Pod Security version labels to a version supported by your cluster. This example pins them to v1.36. Applications must supply security contexts that satisfy restricted; these rules do not generate those fields.

Reference

Explore the ordered rules below. Select a card to open its documentation, or view, copy, and download the complete Tenant YAML, including ownership and PriorityClass settings.

tenants.yamlTenant · solar · 13 rules
Download YAML

View complete Tenant YAML Owners, priority settings, and all rules
apiVersion: capsule.clastix.io/v1beta2
kind: Tenant
metadata:
  name: solar
spec:
  owners:
    - kind: User
      name: solar-owner
  # Default and allow the tenant-standard PriorityClass.
  priorityClasses:
    default: tenant-standard
    allowed: [tenant-standard]
  rules:

    # One shared budget across all namespaces in this Tenant.
    - quota:
        - name: application-budget
          hard:
            requests.cpu: "20"
            requests.memory: 40Gi
            limits.memory: 40Gi
            requests.ephemeral-storage: 100Gi
            limits.ephemeral-storage: 200Gi
            pods: "100"
            services: "100"

    # Apply placement and user-namespace settings on Pod creation.
    - mutate:
        - action: merge
          workloads:
            security:
              hostUsers: false
            placement:
              affinity:
                nodeAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                    nodeSelectorTerms:
                      - matchExpressions:
                          - key: node-role.kubernetes.io/control-plane
                            operator: DoesNotExist
                          - key: node-role.kubernetes.io/master
                            operator: DoesNotExist
      enforce:
        action: allow
        workloads:
          targets: [pod]
          placement:
            schedulers:
              - exact: [default-scheduler]

    # Defaults for application containers, sidecars, and init containers.
    - enforce:
        action: deny
        workloads:
          targets: [pod/containers, pod/initcontainers]
          resources:
            requests:
              cpu:
                policy: Default
                value: 250m
              memory:
                policy: Default
                value: 512Mi
              ephemeral-storage:
                policy: Default
                value: 1Gi
            limits:
              cpu:
                policy: Remove
              memory:
                policy: MatchRequest
              ephemeral-storage:
                policy: Default
                value: 2Gi

    # Normalize limits when a workload supplies Pod-level resources.
    - enforce:
        action: deny
        workloads:
          targets: [pod]
          resources:
            limits:
              cpu:
                policy: Remove
              memory:
                policy: MatchRequest

    # Deny BestEffort Pods after resource mutation.
    - enforce:
        action: deny
        workloads:
          targets: [pod]
          qosClasses: [BestEffort]

    # Reject control-plane and wildcard tolerations.
    - enforce:
        action: deny
        workloads:
          targets: [pod]
          placement:
            tolerations:
              - key:
                  exact:
                    - node-role.kubernetes.io/control-plane
                    - node-role.kubernetes.io/master
              - key: {exp: '^$'}
                operators: [Exists]

    # Check direct assignment only at creation; allow scheduler-bound updates.
    - enforce:
        action: deny
        conditions:
          - name: direct-node-assignment
            expression: >-
              request.operation == 'CREATE' && has(object.spec.nodeName) && object.spec.nodeName != ''
        workloads:
          targets: [pod]

    # Keep kind-level denials separate from workload property checks.
    - enforce:
        action: deny
        workloads:
          targets: [daemonset]

    # Allow approved images with Always pull policy.
    - enforce:
        action: allow
        workloads:
          targets:
            - pod/containers
            - pod/initcontainers
            - pod/ephemeralcontainers
            - pod/volumes
          registries:
            - exp: '^registry\.example\.com/solar/.+$'
              policy: [Always]

    # Allow only ClusterIP Services.
    - enforce:
        action: allow
        services:
          types: [ClusterIP]

    # Deny all Service external IPs.
    - enforce:
        action: deny
        services:
          externalIPs: {}

    # Apply and reconcile Pod Security labels on the Namespace itself.
    - enforce:
        action: allow
        metadata:
          - apiGroups: [v1]
            kinds: [Namespace]
            labels:
              pod-security.kubernetes.io/enforce:
                managed: restricted
                required: true
                values:
                  - exact: [restricted]
              pod-security.kubernetes.io/enforce-version:
                managed: v1.36
                required: true
                values:
                  - exact: [v1.36]
              pod-security.kubernetes.io/warn:
                managed: restricted
                required: true
                values:
                  - exact: [restricted]
              pod-security.kubernetes.io/warn-version:
                managed: v1.36
                required: true
                values:
                  - exact: [v1.36]
              pod-security.kubernetes.io/audit:
                managed: restricted
                required: true
                values:
                  - exact: [restricted]
              pod-security.kubernetes.io/audit-version:
                managed: v1.36
                required: true
                values:
                  - exact: [v1.36]

    # Reserve this trusted-platform label for administrator-managed namespaces.
    - enforce:
        action: deny
        metadata:
          - apiGroups: [v1]
            kinds: [Namespace]
            labels:
              company.com/system:
                values:
                  - exp: ".*"
Namespace rulesIn declaration order
spec.rules[0]

Shared resource budget

Quota

One shared budget across all namespaces in this Tenant.

- quota:
    - name: application-budget
      hard:
        requests.cpu: "20"
        requests.memory: 40Gi
        limits.memory: 40Gi
        requests.ephemeral-storage: 100Gi
        limits.ephemeral-storage: 200Gi
        pods: "100"
        services: "100"
spec.rules[1]

Placement and user namespaces

MutateEnforce · allow

Apply placement and user-namespace settings on Pod creation.

- mutate:
    - action: merge
      workloads:
        security:
          hostUsers: false
        placement:
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                  - matchExpressions:
                      - key: node-role.kubernetes.io/control-plane
                        operator: DoesNotExist
                      - key: node-role.kubernetes.io/master
                        operator: DoesNotExist
  enforce:
    action: allow
    workloads:
      targets: [pod]
      placement:
        schedulers:
          - exact: [default-scheduler]
spec.rules[2]

Container resource defaults

Enforce · deny

Defaults for application containers, sidecars, and init containers.

- enforce:
    action: deny
    workloads:
      targets: [pod/containers, pod/initcontainers]
      resources:
        requests:
          cpu:
            policy: Default
            value: 250m
          memory:
            policy: Default
            value: 512Mi
          ephemeral-storage:
            policy: Default
            value: 1Gi
        limits:
          cpu:
            policy: Remove
          memory:
            policy: MatchRequest
          ephemeral-storage:
            policy: Default
            value: 2Gi
spec.rules[3]

Pod-level resource limits

Enforce · deny

Normalize limits when a workload supplies Pod-level resources.

- enforce:
    action: deny
    workloads:
      targets: [pod]
      resources:
        limits:
          cpu:
            policy: Remove
          memory:
            policy: MatchRequest
spec.rules[4]

Reject BestEffort Pods

Enforce · deny

Deny BestEffort Pods after resource mutation.

- enforce:
    action: deny
    workloads:
      targets: [pod]
      qosClasses: [BestEffort]
spec.rules[5]

Control-plane tolerations

Enforce · deny

Reject control-plane and wildcard tolerations.

- enforce:
    action: deny
    workloads:
      targets: [pod]
      placement:
        tolerations:
          - key:
              exact:
                - node-role.kubernetes.io/control-plane
                - node-role.kubernetes.io/master
          - key: {exp: '^$'}
            operators: [Exists]
spec.rules[6]

Prevent direct node assignment

Enforce · deny

Check direct assignment only at creation; allow scheduler-bound updates.

- enforce:
    action: deny
    conditions:
      - name: direct-node-assignment
        expression: >-
          request.operation == 'CREATE' && has(object.spec.nodeName) && object.spec.nodeName != ''
    workloads:
      targets: [pod]
spec.rules[7]

Block DaemonSets

Enforce · deny

Keep kind-level denials separate from workload property checks.

- enforce:
    action: deny
    workloads:
      targets: [daemonset]
spec.rules[8]

Approved image registries

Enforce · allow

Allow approved images with Always pull policy.

- enforce:
    action: allow
    workloads:
      targets:
        - pod/containers
        - pod/initcontainers
        - pod/ephemeralcontainers
        - pod/volumes
      registries:
        - exp: '^registry\.example\.com/solar/.+$'
          policy: [Always]
spec.rules[9]

ClusterIP Services only

Enforce · allow

Allow only ClusterIP Services.

- enforce:
    action: allow
    services:
      types: [ClusterIP]
spec.rules[10]

Block external IPs

Enforce · deny

Deny all Service external IPs.

- enforce:
    action: deny
    services:
      externalIPs: {}
spec.rules[11]

Restricted Pod Security labels

Enforce · allow

Apply and reconcile Pod Security labels on the Namespace itself.

- enforce:
    action: allow
    metadata:
      - apiGroups: [v1]
        kinds: [Namespace]
        labels:
          pod-security.kubernetes.io/enforce:
            managed: restricted
            required: true
            values:
              - exact: [restricted]
          pod-security.kubernetes.io/enforce-version:
            managed: v1.36
            required: true
            values:
              - exact: [v1.36]
          pod-security.kubernetes.io/warn:
            managed: restricted
            required: true
            values:
              - exact: [restricted]
          pod-security.kubernetes.io/warn-version:
            managed: v1.36
            required: true
            values:
              - exact: [v1.36]
          pod-security.kubernetes.io/audit:
            managed: restricted
            required: true
            values:
              - exact: [restricted]
          pod-security.kubernetes.io/audit-version:
            managed: v1.36
            required: true
            values:
              - exact: [v1.36]
spec.rules[12]

Protect platform trust labels

Enforce · deny

Reserve this trusted-platform label for administrator-managed namespaces.

- enforce:
    action: deny
    metadata:
      - apiGroups: [v1]
        kinds: [Namespace]
        labels:
          company.com/system:
            values:
              - exp: ".*"

How the Policies Combine

Capsule applies mutations before validation. On Pod creation, the resource rules supply missing requests and storage limits, remove CPU limits, and align memory limits with requests. Explicit requests and storage limits survive the Default policies. Placement mutation adds the control-plane exclusions and sets hostUsers: false; enforcement then checks the resulting Pod.

The workload policies target Pods, including controller-created Pods. The DaemonSet rule separately rejects the controller itself. Add explicit controller targets if you also want resource or image checks on saved controller templates. Keep the DaemonSet denial and conditional direct-assignment denial separate: adding workload properties to a targets-only rule changes its meaning.

The quota rule generates solar-application-budget, a GlobalResourceQuota shared across this Tenant’s namespaces. It bounds aggregate consumption; the resource defaults do not impose maximum requests or reserve node capacity by themselves. Retain capacity for failover and system services as described in capacity planning.

The restricted Pod Security labels are managed values. The platform-label denial checks added or changed metadata; unchanged existing values are skipped on updates. Remove any existing tenant-controlled company.com/system labels before using them as a network trust boundary.

The memory-overcommit and ExternalName examples on the individual pages are deliberate exceptions. Add them only under reviewed namespace selectors, with the selecting labels under platform control. Review rule order and scope when composing further rules so a later decision does not unintentionally relax the baseline.

Complete the Platform Setup

Apply the native NetworkPolicy GlobalTenantResource alongside this Tenant. It distributes default-deny, same-Tenant, DNS, and platform-ingress policies; NetworkPolicies are not embedded in this Tenant manifest. Review its CNI requirements and the permissions needed to prevent tenants from adding policies that widen access.

Use the additional admission policies for requirements such as PDB validation, emptyDir.sizeLimit, debugging access, and certificate issuer restrictions. Those examples require their respective admission mechanisms and are not installed by this Tenant.

Configure authentication, registry mirrors, and secret management at platform level. Review existing workloads and Services before rollout; admission policies do not remove previously admitted resources.