Skip to content

Commit

Permalink
pkg/proxy: make authorization concurrent
Browse files Browse the repository at this point in the history
Now that KRP can take multiple config files, it is possible that it will
need to make multiple outbout SubjectAccessReview requests to the
Kubernetes API. In order to keep authorization fast, this commit
modifies the proxy so that all authorizations are concurrent. As soon as
one authorization fails, the context is cancelled and all other
in-flight calls are stopped.

Signed-off-by: Lucas Servén Marín <[email protected]>
  • Loading branch information
squat committed Apr 1, 2022
1 parent e6e5cc9 commit ce08ac9
Showing 1 changed file with 33 additions and 14 deletions.
47 changes: 33 additions & 14 deletions pkg/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ package proxy

import (
"bytes"
"context"
"fmt"
"net/http"
"strings"
"sync"
"text/template"

"github.com/brancz/kube-rbac-proxy/pkg/authn"
Expand Down Expand Up @@ -88,21 +90,38 @@ func (h *kubeRBACProxy) Handle(w http.ResponseWriter, req *http.Request) bool {
return false
}

var wg sync.WaitGroup
ctx, cancel := context.WithCancel(ctx)
defer cancel()
for _, attrs := range allAttrs {
// Authorize
authorized, reason, err := h.Authorize(ctx, attrs)
if err != nil {
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
klog.Errorf("%s: %s", msg, err)
http.Error(w, msg, http.StatusInternalServerError)
return false
}
if authorized != authorizer.DecisionAllow {
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
klog.V(2).Infof("%s. Reason: %q.", msg, reason)
http.Error(w, msg, http.StatusForbidden)
return false
}
// Authorize concurrently, as there can be many outbound requests to the kube API.
wg.Add(1)
go func(attrs authorizer.Attributes) {
defer wg.Done()
authorized, reason, err := h.Authorize(ctx, attrs)
if err != nil {
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
klog.Errorf("%s: %s", msg, err)
http.Error(w, msg, http.StatusInternalServerError)
cancel()
return
}
if authorized != authorizer.DecisionAllow {
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
klog.V(2).Infof("%s. Reason: %q.", msg, reason)
http.Error(w, msg, http.StatusForbidden)
cancel()
return
}
return
}(attrs)
}
wg.Wait()
select {
case <-ctx.Done():
// If the context was cancelled by any goroutine, then there was an authz failure.
return false
default:
}

if h.Config.Authentication.Header.Enabled {
Expand Down

0 comments on commit ce08ac9

Please sign in to comment.