...

/

Implementing a Webhook for Authorization

Implementing a Webhook for Authorization

Learn how to implement a webhook authorization service.

Implement a webhook authorization service

A webhook authorization service is a web server, because the kube-apiserver invokes it through HTTPS POST requests.

Now, let’s implement such a service step by step.

Step 1: Write a simple HTTP server

Let’s write a simple HTTP server that responds with the mock authenticated user mock when requested for the /authorize resource over port 443.

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	authorizationapi "k8s.io/api/authorization/v1beta1"
)

func authZ(sar *authorizationapi.SubjectAccessReview) {
	// now we do some mock for demo
	// Please replace this with your logic
	if sar.Spec.User == "demo-user" {
		sar.Status.Allowed = true
	} else {
		sar.Status.Reason = fmt.Sprintf("User %q is not allowed to access %q",
			sar.Spec.User, sar.Spec.ResourceAttributes.Resource)
	}
}

func helloHandler(w http.ResponseWriter, r *http.Request) {
	log.Printf("Receiving %s", r.Method)

	if r.Method != "POST" {
		http.Error(w, "Only Accept POST requests", http.StatusMethodNotAllowed)
		return
	}

	// Read body of POST request
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	log.Printf("Receiving SubjectAccessReview: %s\n", string(payload))

	// Unmarshal JSON from POST request to SubjectAccessReview object
	sar := &authorizationapi.SubjectAccessReview{}
	err = json.Unmarshal(payload, sar)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	authZ(sar)

	// Marshal the SubjectAccessReview to JSON and send it back
	result, err := json.Marshal(*sar)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(result)
	w.Header().Set("Content-Type", "application/json")
}

func main() {
	// Set up a /authorize resource handler
	http.HandleFunc("/authorize", helloHandler)

	// Listen to port 443 and wait
	log.Println("Listening on port 443 for requests...")
	log.Fatal(http.ListenAndServe(":443", nil))
}
HTTP server

In a real-world scenario, we only need to replace the mock codes in the function authZ() with our actual implementations to determine user privileges. This function should set Status.Allowed to true if the request performed by the user is allowed and false for invalid requests. For the denied reason, it can be set to the field Status.Reason.

The rest of the code is a simple ...

Access this course and 1400+ top-rated courses and projects.