Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gorbe

Gorbe is a Kubernetes admission webhook that enforces per-pod resource constraints using a custom CRD called GorbePolicy. Unlike LimitRange — which applies uniformly to every pod in a namespace — Gorbe uses label selectors so each policy only targets the pods you choose.

Two admission webhooks run in the same server:

Webhook Path What it does
Mutating /mutate Injects default CPU/memory/ephemeralStorage into pods that match a policy and leave those fields unset
Validating /validate Rejects pods whose resources violate the min or max values of any matching policy

Table of contents

  1. How it works
  2. Prerequisites
  3. Running unit tests
  4. Generating CRD manifests
  5. Running integration tests with kind
  6. Deploying to a real cluster
  7. GorbePolicy API reference
  8. Usage example

How it works

Pod CREATE / UPDATE
        │
        ▼
┌───────────────────────┐
│  Mutating webhook     │  /mutate
│  - fetch policies     │  (from informer cache)
│  - match selectors    │
│  - aggregate limits   │  min = max(all mins)
│  - inject defaults    │  max = min(all maxes)
└───────────────────────┘  default = min(all defaults)
        │
        ▼
┌───────────────────────┐
│  Validating webhook   │  /validate
│  - same matching      │
│  - check min / max    │  init containers: each individually
│  - reject if violated │  app containers: sum validated together
└───────────────────────┘

Aggregation rule when multiple selectors match one pod:

Field Rule
min max of all minimums (most restrictive floor)
max min of all maximums (most restrictive ceiling)
default min of all defaults (most conservative default)

Prerequisites

Tool Purpose
Docker + Docker Compose Building, testing, and running everything
kind Local integration testing (creating a Kubernetes cluster in Docker)
kubectl Talking to the kind cluster during integration tests
openssl TLS cert generation for integration test setup

All Go commands (build, test, lint, code generation) run inside a Docker container via docker compose run. You do not need Go installed on your machine.

Install kind: https://kind.sigs.k8s.io/docs/user/quick-start/#installation


Running unit tests

Unit tests cover the policy engine (aggregation, mutation, validation), webhook handlers, and the server lifecycle. No cluster is needed.

make test

This runs go fmt, go vet, and go test -race inside the Docker container. A coverage report is written to cover.out.

You can also run individual steps:

make fmt     # go fmt
make vet     # go vet

Generating CRD manifests

The CRD YAML at config/crd/bases/ is generated from the Go type annotations in pkg/api/v1alpha1/ using controller-gen. The tool is installed automatically inside the container.

# Regenerate the CRD manifest
make manifests

# Regenerate DeepCopy methods
make generate

The generated CRD file will appear at config/crd/bases/.


Running integration tests with kind

Integration tests create a real kind cluster, build and load the Docker image, deploy the webhook with TLS, and assert mutation and rejection behaviour end-to-end.

Prerequisites for integration tests

In addition to Docker, you need kind, kubectl, and openssl installed on your machine.

One-shot (setup + run)

make test-integration

This builds the Docker image, runs kind-setup.sh (creates cluster, deploys gorbe), then runs run-tests.sh.

Step by step

# 1. Build image, create kind cluster, deploy gorbe
make test-integration-setup

# 2. Run only the test assertions (useful when iterating)
make test-integration-run

# 3. Tear down when done
make test-integration-clean

What the tests check

Test Scenario Expected
1a Pod matches test-defaults policy, no CPU set CPU 100m injected
1b Pod matches test-defaults policy, no memory set Memory 64Mi injected
2 Pod matches test-bounded policy, resources within bounds Admitted
3 Pod matches test-bounded policy, CPU 300m > max 200m Rejected
4 Pod matches test-bounded policy, memory 8Mi < min 32Mi Rejected
5 Pod has no label matching any policy Admitted, no resources injected

Test policies and pod fixtures live in test/integration/manifests/.


Deploying to a real cluster

1. Build and push the image

make docker-build IMG=your-registry/gorbe:v1.0.0
make docker-push IMG=your-registry/gorbe:v1.0.0

2. Provision a TLS certificate

The webhook server needs a TLS certificate trusted by kube-apiserver. The recommended approach is cert-manager:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: gorbe-webhook-cert
  namespace: gorbe-system
spec:
  secretName: gorbe-webhook-cert
  dnsNames:
    - gorbe-webhook.gorbe-system.svc
    - gorbe-webhook.gorbe-system.svc.cluster.local
  issuerRef:
    name: your-cluster-issuer
    kind: ClusterIssuer

Alternatively, generate a self-signed cert:

openssl genrsa -out tls.key 2048

cat > san.conf <<EOF
[req]
req_extensions     = v3_req
distinguished_name = req_distinguished_name
prompt             = no
[req_distinguished_name]
CN = gorbe-webhook.gorbe-system.svc
[v3_req]
keyUsage         = keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName   = @alt_names
[alt_names]
DNS.1 = gorbe-webhook.gorbe-system.svc
DNS.2 = gorbe-webhook.gorbe-system.svc.cluster.local
EOF

openssl req -new -key tls.key -out tls.csr -config san.conf
openssl x509 -req -in tls.csr -signkey tls.key -out tls.crt \
  -days 365 -extensions v3_req -extfile san.conf

kubectl create namespace gorbe-system
kubectl create secret tls gorbe-webhook-cert \
  --cert=tls.crt --key=tls.key -n gorbe-system

3. Apply manifests

# Install the CRD
kubectl apply -f config/crd/bases/gorbe.io_gorbepolicies.yaml

# Create namespace and RBAC
kubectl apply -f config/rbac/rbac.yaml

# Deploy the webhook server (update the image reference first)
sed -i 's|gorbe:latest|your-registry/gorbe:v1.0.0|' deploy/deployment.yaml
kubectl apply -f deploy/deployment.yaml

# Wait for the pod to be ready
kubectl rollout status deployment/gorbe-webhook -n gorbe-system --timeout=120s

# Register the webhook configurations (patch caBundle with your CA cert)
CA_BUNDLE=$(base64 < tls.crt | tr -d '\n')

sed "s/caBundle:.*/caBundle: ${CA_BUNDLE}/" config/webhook/mutating.yaml | kubectl apply -f -
sed "s/caBundle:.*/caBundle: ${CA_BUNDLE}/" config/webhook/validating.yaml | kubectl apply -f -

4. Verify

kubectl get pods -n gorbe-system
kubectl get mutatingwebhookconfigurations gorbe-mutating-webhook
kubectl get validatingwebhookconfigurations gorbe-validating-webhook

# Create a test policy and pod
kubectl apply -f - <<EOF
apiVersion: gorbe.io/v1alpha1
kind: GorbePolicy
metadata:
  name: test
  namespace: default
spec:
  podSelectors:
    - selector:
        matchLabels:
          app: myapp
      resources:
        cpu:
          default: "200m"
        memory:
          default: "128Mi"
EOF

kubectl run myapp --image=nginx --labels=app=myapp
kubectl get pod myapp -o jsonpath='{.spec.containers[0].resources}' | python3 -m json.tool

5. Uninstall

kubectl delete mutatingwebhookconfiguration gorbe-mutating-webhook
kubectl delete validatingwebhookconfiguration gorbe-validating-webhook
kubectl delete -f deploy/deployment.yaml
kubectl delete -f config/rbac/rbac.yaml
kubectl delete -f config/crd/bases/gorbe.io_gorbepolicies.yaml
kubectl delete namespace gorbe-system

GorbePolicy API reference

apiVersion: gorbe.io/v1alpha1
kind: GorbePolicy

Scope: Namespaced. A policy only affects pods in the same namespace.

spec.podSelectors[]

Field Type Required Description
selector LabelSelector yes Kubernetes label selector. Supports matchLabels and matchExpressions.
resources ResourceConstraints yes Constraints to apply to matching pods.

spec.podSelectors[].resources

Field Type Description
cpu ResourceSpec CPU constraints
memory ResourceSpec Memory constraints
ephemeralStorage ResourceSpec Ephemeral storage constraints

All three are optional. Omitting a field means no constraint is applied for that resource type.

ResourceSpec

Field Type Description
min quantity Minimum allowed value. Pods with a lower request or limit are rejected.
max quantity Maximum allowed value. Pods with a higher request or limit are rejected.
default quantity Default applied to both requests and limits when the container does not set that resource. Existing values are never overwritten.

Quantities use standard Kubernetes notation: 100m, 500m, "1", "2" for CPU; 128Mi, 1Gi for memory.

Validation semantics:

  • Init containers are validated individually (they run one at a time).
  • Regular containers are validated as a sum (they all run simultaneously).

Usage example

apiVersion: gorbe.io/v1alpha1
kind: GorbePolicy
metadata:
  name: team-a-policy
  namespace: team-a
spec:
  podSelectors:

    # All pods in this namespace get at least a sensible default
    - selector:
        matchLabels:
          team: a
      resources:
        cpu:
          default: "200m"
        memory:
          default: "256Mi"

    # Production pods have tighter bounds
    - selector:
        matchLabels:
          team: a
          env: prod
      resources:
        cpu:
          min: "100m"
          max: "4"
        memory:
          min: "128Mi"
          max: "8Gi"

A pod with labels team: a and env: prod matches both selectors. The aggregated constraints will be:

  • CPU default: 200m, CPU min: 100m, CPU max: 4
  • Memory default: 256Mi, Memory min: 128Mi, Memory max: 8Gi

A pod with only team: a matches the first selector only and gets defaults injected without any min/max enforcement.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages