Skip to content

Commit

Permalink
Add validation bypass to the webhook.
Browse files Browse the repository at this point in the history
Requests made by rancher-webhook's sudo service account will
bypass the webhook's validation.
  • Loading branch information
KevinJoiner committed Jul 13, 2023
1 parent 56151d6 commit e6d16f9
Show file tree
Hide file tree
Showing 4 changed files with 275 additions and 86 deletions.
2 changes: 1 addition & 1 deletion charts/rancher-webhook/templates/rbac.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ roleRef:
subjects:
- kind: ServiceAccount
name: rancher-webhook
namespace: {{.Release.Namespace}}
namespace: {{.Release.Namespace}}
7 changes: 7 additions & 0 deletions charts/rancher-webhook/templates/serviceaccount.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: rancher-webhook
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: rancher-webhook-sudo
annotations:
cattle.io/description: "SA which can be impersonated to bypass rancher-webhook validation"
33 changes: 32 additions & 1 deletion pkg/admission/admission.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import (
)

const (
webhookQualifier = "rancher.cattle.io"
webhookQualifier = "rancher.cattle.io"
bypassServiceAccount = "system:serviceaccount:cattle-system:rancher-webhook-sudo"
systemMasters = "system:masters"
)

var (
Expand Down Expand Up @@ -187,6 +189,13 @@ func NewValidatingHandlerFunc(handler ValidatingAdmissionHandler) http.HandlerFu
sendError(responseWriter, review, err)
return
}

if bypassValidation(review.Request) {
sendResponse(responseWriter, review, ResponseAllowed())
logrus.Debugf("admit bypassed: %s %s %s", webReq.Operation, webReq.Kind.String(), resourceString(webReq.Namespace, webReq.Name))
return
}

// save the response from the loop so we can return on success
var response *admissionv1.AdmissionResponse
for _, admitter := range handler.Admitters() {
Expand All @@ -198,6 +207,7 @@ func NewValidatingHandlerFunc(handler ValidatingAdmissionHandler) http.HandlerFu
response = &admissionv1.AdmissionResponse{}
}
logrus.Debugf("admit result: %s %s %s user=%s allowed=%v err=%v", webReq.Operation, webReq.Kind.String(), resourceString(webReq.Namespace, webReq.Name), webReq.UserInfo.Username, response.Allowed, err)

// if we get an error or are not allowed, short circuit the admits
if err != nil {
review.Response = response
Expand All @@ -223,11 +233,19 @@ func NewMutatingHandlerFunc(handler MutatingAdmissionHandler) http.HandlerFunc {
sendError(responseWriter, review, err)
return
}

if bypassValidation(review.Request) {
sendResponse(responseWriter, review, ResponseAllowed())
logrus.Debugf("admit bypassed: %s %s %s", webReq.Operation, webReq.Kind.String(), resourceString(webReq.Namespace, webReq.Name))
return
}

response, err := handler.Admit(webReq)
if response == nil {
response = &admissionv1.AdmissionResponse{}
}
logrus.Debugf("admit result: %s %s %s user=%s allowed=%v err=%v", webReq.Operation, webReq.Kind.String(), resourceString(webReq.Namespace, webReq.Name), webReq.UserInfo.Username, response.Allowed, err)

if err != nil {
review.Response = response
sendError(responseWriter, review, err)
Expand Down Expand Up @@ -347,3 +365,16 @@ func CreateWebhookName(handler WebhookHandler, suffix string) string {
}
return fmt.Sprintf("%s.%s.%s", webhookQualifier, subPath, suffix)
}

// bypassValidation users can bypass the webhook if they are the sudo account and system:masters group
func bypassValidation(request *admissionv1.AdmissionRequest) bool {
if request.UserInfo.Username != bypassServiceAccount {
return false
}
for _, group := range request.UserInfo.Groups {
if group == systemMasters {
return true
}
}
return false
}
Loading

0 comments on commit e6d16f9

Please sign in to comment.