/k8s-label-rules-webhook

A validating admission webhook to ensure compliant labels in your k8s cluster

Primary LanguageGoMIT LicenseMIT

Enforce standards for labels of resources being created in your k8s cluster

image

Build Status Go Report Card GitHub release (latest by date) Docker Pulls Buy Me A Coffee

Table of Contents

Usage

gif

Start by creating a rules.yaml file containing rules for labels you require for your cluster resources to have along with a regex pattern for the values of the labels.

Any rules specified in the rulseset will be required on resources to which you configure the admission webhook to fire on. View the kubernetes deployment section.

rules:
  - name: require-phone-number
    key: phone-number
    value:
      regex: "[0-9]{3}-[0-9]{3}-[0-9]{4}" # 555-555-5555
  - name: require-owner
    key: owner
    value:
      regex: ".*" # Any pattern matches, Just ensure a label of "owner" is set

IMPORTANT NOTE: Invalid regex for a given rule will make the rule default to .* which will allow any label value, but will still require the label to be present

Once you have your ruleset, you can deploy the webhook several different ways.

Docker

Volume mount your rules.yaml file

docker run -d --name k8s-label-rules-webhook \
  -p 8080: 8080 \
  -v rules.yaml:/rules.yaml \
  circa10a/k8s-label-rules-webhook

Build your own docker image

FROM circa10a/k8s-label-rules-webhook
COPY rules.yaml /

Kubernetes

Deploy webhook application

Kubernetes admission webhooks require https

apiVersion: apps/v1
kind: Deployment
metadata:
  name: label-rules-webhook
  labels:
    app: label-rules-webhook
spec:
  replicas: 1
  selector:
    matchLabels:
      app: label-rules-webhook
  template:
    metadata:
      labels:
        app: label-rules-webhook
    spec:
      containers:
      - name: label-rules-webhook
        image: circa10a/k8s-label-rules-webhook
        volumeMounts:
        - name: label-rules
          mountPath: /rules.yaml
          subPath: rules.yaml
        readinessProbe:
          httpGet:
            path: /rules
            port: gin-port
          initialDelaySeconds: 5
          periodSeconds: 15
        livenessProbe:
          httpGet:
            path: /rules
            port: gin-port
          initialDelaySeconds: 5
          periodSeconds: 15
        ports:
        - name: gin-port
          containerPort: 8080
      volumes:
        - name: label-rules
          configMap:
            name: label-rules
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: label-rules
data:
  rules.yaml: |
    rules:
      - name: require-phone-number
        key: phone-number
        value:
          regex: "[0-9]{3}-[0-9]{3}-[0-9]{4}"
      - name: require-number
        key: number
        value:
          regex: "[0-1]{1}"
---
apiVersion: v1
kind: Service
metadata:
  name: label-rules-webhook-service
spec:
  selector:
    app: label-rules-webhook
  ports:
  - protocol: TCP
    port: 8080
    targetPort: gin-port
  type: NodePort
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: label-rules-webhook-ingress
spec:
  backend:
    serviceName: label-rules-webhook-service
    servicePort: 8080

Deploy webhook application (TLS)

To have the web server listen on https, you need to supply a certificate and a key in conjunction with the appropriate configuration options.

Here's an example deployment which supplies a cert, key and enables TLS in the application.

Note: The TLS example only works in the default namespace. The subject alt name in the certificate is label-rules-webhook-service.default.svc Note: The default https port is 8443

Deploy admission webhook

More info on kubernetes admission webhooks

apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: label-rules-webhook
webhooks:
- name: my.application.domain
  clientConfig:
    clientConfig:
    caBundle: <base64 encoded cert bundle>
    service:
      namespace: "default"
      name: "label-rules-webhook-service"
      port: 8443
  rules:
  - operations:
    - "CREATE"
    - "UPDATE"
    apiGroups:
      - "apps"
    apiVersions:
      - "v1"
      - "v1beta1"
    resources:
      - "deployments"
      - "replicasets"
  failurePolicy: Fail # Ignore, Fail

Features

Checkout the swagger api docs at /swagger/index.html

Hot reloading of ruleset

Update the rules.yaml file used by your deployed instance then send a POST request to /reload to reload the rules into memory without downtime.

Rule validation

The regex supplied to each rule is compiled when the application starts and any problems are logged.

You can access the /validate endpoint via GET request to view any issues with the current ruleset that is loaded.

Easily view loaded ruleset

Access the /rules endpoint via GET request to see the current rules loaded.

Prometheus Metrics

Prometheus metrics are enabled by default and are available at the /metrics endpoint. Simply unset the METRICS environment variable to disable.

Configuration

Name Description Environment Variable Command Line Argument Required Default
GIN MODE Runs web server in production or debug mode GIN_MODE NONE false release
PORT Port for web server to listen on PORT NONE false 8080
METRICS Enables prometheus metrics on /metrics(unset for false) METRICS --metrics false true
RULES File containing user defined ruleset(default looks to ./rules.yaml) NONE --file true ./rules.yaml
TLS Start web server listening on HTTPS TLS_ENABLED --tls false false
TLS CERT TLS Certificate file path TLS_CERT --tls-cert false None
TLS KEY TLS key file path TLS_KEY --tls-key false None
TLS PORT TLS listening port None --tls-port false 8443

Development

Build

make build

Run

make run

Access via http://localhost:8080

Test

make test

Changelog

Changelog.md

Troubleshooting

Debug web server

Try setting the debug environment variable for the gin web server which is GIN_MODE=debug.

Rule validation problems

Ensure there are no regex compilation errors by accessing the /validate endpoint.