Skip to content

Commit 7b41c4b

Browse files
committed
add webhook source file.
1 parent b9c7294 commit 7b41c4b

File tree

2 files changed

+92
-1
lines changed

2 files changed

+92
-1
lines changed

content/en/blog/_posts/2024-04-24-validating-admission-policy-ga/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ func verifyDeployment(deploy *appsv1.Deployment) error {
4848
}
4949
```
5050

51-
Check out [What are admission webhooks?](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks) Or, see the [full code](https://gist.github.com/jiahuif/2653f2ce41fe6a2e5739ea7cd76b182b) of this webhook to follow along with this walkthrough.
51+
Check out [What are admission webhooks?](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks)
52+
Or, see the [full code](webhook.go) of this webhook to follow along with this walkthrough.
5253

5354
## The policy
5455
Now let's try to recreate the validation faithfully with a ValidatingAdmissionPolicy.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"flag"
6+
"fmt"
7+
"log"
8+
"net/http"
9+
10+
admissionv1 "k8s.io/api/admission/v1"
11+
appsv1 "k8s.io/api/apps/v1"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/util/errors"
14+
)
15+
16+
func verifyDeployment(deploy *appsv1.Deployment) error {
17+
var errs []error
18+
for i, c := range deploy.Spec.Template.Spec.Containers {
19+
if c.Name == "" {
20+
return fmt.Errorf("container %d has no name", i)
21+
}
22+
if c.SecurityContext == nil {
23+
errs = append(errs, fmt.Errorf("container %q does not have SecurityContext", c.Name))
24+
}
25+
if c.SecurityContext.RunAsNonRoot == nil || !*c.SecurityContext.RunAsNonRoot {
26+
errs = append(errs, fmt.Errorf("container %q must set RunAsNonRoot to true in its SecurityContext", c.Name))
27+
}
28+
if c.SecurityContext.ReadOnlyRootFilesystem == nil || !*c.SecurityContext.ReadOnlyRootFilesystem {
29+
errs = append(errs, fmt.Errorf("container %q must set ReadOnlyRootFilesystem to true in its SecurityContext", c.Name))
30+
}
31+
if c.SecurityContext.AllowPrivilegeEscalation != nil && *c.SecurityContext.AllowPrivilegeEscalation {
32+
errs = append(errs, fmt.Errorf("container %q must NOT set AllowPrivilegeEscalation to true in its SecurityContext", c.Name))
33+
}
34+
if c.SecurityContext.Privileged != nil && *c.SecurityContext.Privileged {
35+
errs = append(errs, fmt.Errorf("container %q must NOT set Privileged to true in its SecurityContext", c.Name))
36+
}
37+
}
38+
return errors.NewAggregate(errs)
39+
}
40+
41+
func WebhookEnforceSecurePodConfiguration(rw http.ResponseWriter, req *http.Request) {
42+
result := &admissionv1.AdmissionReview{Response: &admissionv1.AdmissionResponse{}}
43+
err := func() error {
44+
ar := new(admissionv1.AdmissionReview)
45+
err := json.NewDecoder(req.Body).Decode(ar)
46+
if err != nil {
47+
return err
48+
}
49+
if ar.Request == nil {
50+
return nil
51+
}
52+
result.TypeMeta = ar.TypeMeta
53+
result.Response.UID = ar.Request.UID
54+
if len(ar.Request.Object.Raw) == 0 {
55+
return nil
56+
}
57+
deploy := new(appsv1.Deployment)
58+
err = json.Unmarshal(ar.Request.Object.Raw, deploy)
59+
if err != nil {
60+
return err
61+
}
62+
return verifyDeployment(deploy)
63+
}()
64+
if err == nil {
65+
result.Response.Allowed = true
66+
} else {
67+
result.Response.Allowed = false
68+
result.Response.Result = &metav1.Status{
69+
Code: http.StatusForbidden,
70+
Message: err.Error(),
71+
}
72+
}
73+
err = json.NewEncoder(rw).Encode(result)
74+
if err != nil {
75+
log.Println(err)
76+
}
77+
}
78+
79+
var _ http.HandlerFunc = WebhookEnforceSecurePodConfiguration
80+
81+
func main() {
82+
http.HandleFunc("/", WebhookEnforceSecurePodConfiguration)
83+
84+
addr := flag.String("addr", ":8443", "address to listen on")
85+
certFile := flag.String("cert", "cert.pem", "path to TLS certificate")
86+
keyFile := flag.String("key", "key.pem", "path to TLS key")
87+
flag.Parse()
88+
89+
log.Fatalln(http.ListenAndServeTLS(*addr, *certFile, *keyFile, nil))
90+
}

0 commit comments

Comments
 (0)