• Stars
    star
    170
  • Rank 215,560 (Top 5 %)
  • Language
    Go
  • License
    MIT License
  • Created over 2 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

This project is aimed at illustrating how to build a fully functioning kubernetes admission webhook in the simplest way possible.

simple-kubernetes-webhook

This is a simple Kubernetes admission webhook. It is meant to be used as a validating and mutating admission webhook only and does not support any controller logic. It has been developed as a simple Go web service without using any framework or boilerplate such as kubebuilder.

This project is aimed at illustrating how to build a fully functioning admission webhook in the simplest way possible. Most existing examples found on the web rely on heavy machinery using powerful frameworks, yet fail to illustrate how to implement a lightweight webhook that can do much needed actions such as rejecting a pod for compliance reasons, or inject helpful environment variables.

For readability, this project has been stripped of the usual production items such as: observability instrumentation, release scripts, redundant deployment configurations, etc. As such, it is not meant to use as-is in a production environment. This project is, in fact, a simplified fork of a system used accross all Kubernetes production environments at Slack.

Installation

This project can fully run locally and includes automation to deploy a local Kubernetes cluster (using Kind).

Requirements

  • Docker
  • kubectl
  • Kind
  • Go >=1.16 (optional)

Usage

Create Cluster

First, we need to create a Kubernetes cluster:

❯ make cluster

🔧 Creating Kubernetes cluster...
kind create cluster --config dev/manifests/kind/kind.cluster.yaml
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.21.1) đŸ–ŧ
 ✓ Preparing nodes đŸ“Ļ
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹ī¸
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:

kubectl cluster-info --context kind-kind

Have a nice day! 👋

Make sure that the Kubernetes node is ready:

❯ kubectl get nodes
NAME                 STATUS   ROLES                  AGE     VERSION
kind-control-plane   Ready    control-plane,master   3m25s   v1.21.1

And that system pods are running happily:

❯ kubectl -n kube-system get pods
NAME                                         READY   STATUS    RESTARTS   AGE
coredns-558bd4d5db-thwvj                     1/1     Running   0          3m39s
coredns-558bd4d5db-w85ks                     1/1     Running   0          3m39s
etcd-kind-control-plane                      1/1     Running   0          3m56s
kindnet-84slq                                1/1     Running   0          3m40s
kube-apiserver-kind-control-plane            1/1     Running   0          3m54s
kube-controller-manager-kind-control-plane   1/1     Running   0          3m56s
kube-proxy-4h6sj                             1/1     Running   0          3m40s
kube-scheduler-kind-control-plane            1/1     Running   0          3m54s

Deploy Admission Webhook

To configure the cluster to use the admission webhook and to deploy said webhook, simply run:

❯ make deploy

đŸ“Ļ Building simple-kubernetes-webhook Docker image...
docker build -t simple-kubernetes-webhook:latest .
[+] Building 14.3s (13/13) FINISHED
...

đŸ“Ļ Pushing admission-webhook image into Kind's Docker daemon...
kind load docker-image simple-kubernetes-webhook:latest
Image: "simple-kubernetes-webhook:latest" with ID "sha256:46b8603bcc11a8fa1825190d3ed99c099096395b22a709e13ec6e7ae2f54014d" not yet present on node "kind-control-plane", loading...

⚙ī¸  Applying cluster config...
kubectl apply -f dev/manifests/cluster-config/
namespace/apps created
mutatingwebhookconfiguration.admissionregistration.k8s.io/simple-kubernetes-webhook.acme.com created
validatingwebhookconfiguration.admissionregistration.k8s.io/simple-kubernetes-webhook.acme.com created

🚀 Deploying simple-kubernetes-webhook...
kubectl apply -f dev/manifests/webhook/
deployment.apps/simple-kubernetes-webhook created
service/simple-kubernetes-webhook created
secret/simple-kubernetes-webhook-tls created

Then, make sure the admission webhook pod is running (in the default namespace):

❯ kubectl get pods
NAME                                        READY   STATUS    RESTARTS   AGE
simple-kubernetes-webhook-77444566b7-wzwmx   1/1     Running   0          2m21s

You can stream logs from it:

❯ make logs

🔍 Streaming simple-kubernetes-webhook logs...
kubectl logs -l app=simple-kubernetes-webhook -f
time="2021-09-03T04:59:10Z" level=info msg="Listening on port 443..."
time="2021-09-03T05:02:21Z" level=debug msg=healthy uri=/health

And hit it's health endpoint from your local machine:

❯ curl -k https://localhost:8443/health
OK

Deploying pods

Deploy a valid test pod that gets succesfully created:

❯ make pod

🚀 Deploying test pod...
kubectl apply -f dev/manifests/pods/lifespan-seven.pod.yaml
pod/lifespan-seven created

You should see in the admission webhook logs that the pod got mutated and validated.

Deploy a non valid pod that gets rejected:

❯ make bad-pod

🚀 Deploying "bad" pod...
kubectl apply -f dev/manifests/pods/bad-name.pod.yaml
Error from server: error when creating "dev/manifests/pods/bad-name.pod.yaml": admission webhook "simple-kubernetes-webhook.acme.com" denied the request: pod name contains "offensive"

You should see in the admission webhook logs that the pod validation failed. It's possible you will also see that the pod was mutated, as webhook configurations are not ordered.

Testing

Unit tests can be run with the following command:

$ make test
go test ./...
?   	github.com/slackhq/simple-kubernetes-webhook	[no test files]
ok  	github.com/slackhq/simple-kubernetes-webhook/pkg/admission	0.611s
ok  	github.com/slackhq/simple-kubernetes-webhook/pkg/mutation	1.064s
ok  	github.com/slackhq/simple-kubernetes-webhook/pkg/validation	0.749s

Admission Logic

A set of validations and mutations are implemented in an extensible framework. Those happen on the fly when a pod is deployed and no further resources are tracked and updated (ie. no controller logic).

Validating Webhooks

Implemented

  • name validation: validates that a pod name doesn't contain any offensive string

How to add a new pod validation

To add a new pod mutation, create a file pkg/validation/MUTATION_NAME.go, then create a new struct implementing the validation.podValidator interface.

Mutating Webhooks

Implemented

  • inject env: inject environment variables into the pod such as KUBE: true
  • minimum pod lifespan: inject a set of tolerations used to match pods to nodes of a certain age, the tolerations injected are controlled via the acme.com/lifespan-requested pod label.

How to add a new pod mutation

To add a new pod mutation, create a file pkg/mutation/MUTATION_NAME.go, then create a new struct implementing the mutation.podMutator interface.

More Repositories

1

nebula

A scalable overlay networking tool with a focus on performance, simplicity and security
Go
13,646
star
2

SlackTextViewController

⛔ī¸**DEPRECATED** ⛔ī¸ A drop-in UIViewController subclass with a growing text input view and other useful messaging features
Objective-C
8,332
star
3

PanModal

An elegant and highly customizable presentation API for constructing bottom sheet modals on iOS.
Swift
3,595
star
4

go-audit

go-audit is an alternative to the auditd daemon that ships with many distros
Go
1,541
star
5

circuit

⚡ī¸ A Compose-driven architecture for Kotlin and Android applications.
Kotlin
1,250
star
6

EitherNet

A pluggable sealed API result type for modeling Retrofit responses.
Kotlin
730
star
7

goSDL

goSDL
PHP
516
star
8

slack-api-docs

API Docs for Slack.com
427
star
9

slack-gradle-plugin

Gradle and IntelliJ build tooling used in Slack's Android repo
Kotlin
418
star
10

compose-lints

Lint checks to aid with a healthy adoption of Compose
Kotlin
349
star
11

keeper

A Gradle plugin that infers Proguard/R8 keep rules for androidTest sources.
Kotlin
248
star
12

slack-lints

A collection of custom Android/Kotlin lint checks we use in our Android and Kotlin code bases at Slack.
Kotlin
207
star
13

magic-cli

Ruby
196
star
14

astra

Astra is a cloud-native search and analytics engine for log, trace, and audit data
Java
189
star
15

csp-html-webpack-plugin

A plugin which, when combined with HTMLWebpackPlugin, adds CSP tags to the HTML output.
JavaScript
158
star
16

hack-sql-fake

A library for testing database driven code in Hack
Hack
75
star
17

hakana

Another typechecker for Hack, built by Slack
Rust
70
star
18

vscode-hack

Hack language & HHVM debugger support for Visual Studio Code
TypeScript
70
star
19

gsuite-oauth-third-party-app-report

Start enforcing G Suite third-party apps via OAuth
JavaScript
54
star
20

backend-interview-prep-questions

A few questions & data to help you prepare for the Slack HQ backend interview
PLpgSQL
45
star
21

moshi-gson-interop

An interop tool for safely mixing Moshi and Gson models in JSON serialization.
Kotlin
43
star
22

kotlin-cli-util

Kotlin CLI utilities, mostly intended for use with Clikt
Kotlin
33
star
23

tree-sitter-hack

Hack grammar for tree-sitter
JavaScript
28
star
24

hack-json-schema

Generate Hack JSON Schema validators based on a JSON Schema.
Hack
27
star
25

deanimator

Go package that can detect animated images and "deanimate" them by rendering just the first frame as a static image.
Go
24
star
26

es-query-simple

A tiny command line utility to query elasticsearch. "
Python
23
star
27

auto-value-kotlin

An AutoValue extension that generates binary and source compatible equivalent Kotlin data classes of AutoValue models.
Kotlin
23
star
28

go-rsyslog-pstats

Parses and forwards rsyslog process stats to a local statsite, statsd, or wire protocol compatible service.
Go
21
star
29

tiny-thumb

Novel, efficient, and practical image compression with visually appealing results. 🤏 ✨
Go
14
star
30

backend-interview-prerequisites

A project to ensure that your backend onsite interview at Slack runs smoothly.
Go
11
star
31

sqlite-go-connect

A simple go app that connects to a sqlite3 database
Go
11
star
32

sqlite-python-connect

Short bit of code to connect to a sqlite db and run a query in python
Python
10
star
33

hack-graphql

Playground for a hack graphql server
Hack
8
star
34

protoc-gen-ts

A Typescript Protocol Buffer Implementation from the Future ✨
TypeScript
8
star
35

htmlsanitizer-hack

A port of the PHP HTML Purifier originally developed by Edward Z. Yang into Hacklang
Hack
7
star
36

sqlite-java-connect

This is a minimal repo project that connects to a sqlite3 database and returns a single row.
Java
6
star
37

grpc-hack

A gRPC extension for HHVM
C++
4
star
38

slack-astra-app

Grafana plugin that adds support for Astra
TypeScript
4
star
39

sqlite-ruby-connect

Just a tiny lil something to connect to SQLite using Ruby
PLpgSQL
3
star
40

proto-hack

hacklang generator for protobuf
Hack
3
star
41

snow

Python
2
star
42

.github

1
star
43

go-metrics-prometheus

Go
1
star
44

quota

1
star