Skip to content

Commit

Permalink
Merge pull request #99961 from margocrawf/master
Browse files Browse the repository at this point in the history
Introduce Impersonate-UID header
  • Loading branch information
k8s-ci-robot committed Jul 7, 2021
2 parents ca0c827 + 74f5ed6 commit e1acbbd
Show file tree
Hide file tree
Showing 9 changed files with 423 additions and 70 deletions.
3 changes: 3 additions & 0 deletions staging/src/k8s.io/api/authentication/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ const (
// It can be repeated multiplied times for multiple groups.
ImpersonateGroupHeader = "Impersonate-Group"

// ImpersonateUIDHeader is used to impersonate a particular UID during an API server request
ImpersonateUIDHeader = "Impersonate-Uid"

// ImpersonateUserExtraHeaderPrefix is a prefix for any header used to impersonate an entry in the
// extra map[string][]string for user.Info. The key will be every after the prefix.
// It can be repeated multiplied times for multiple map keys and the same key can be repeated multiple
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime.
username := ""
groups := []string{}
userExtra := map[string][]string{}
uid := ""
for _, impersonationRequest := range impersonationRequests {
gvk := impersonationRequest.GetObjectKind().GroupVersionKind()
actingAsAttributes := &authorizer.AttributesRecord{
Expand Down Expand Up @@ -103,6 +104,10 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime.
actingAsAttributes.Subresource = extraKey
userExtra[extraKey] = append(userExtra[extraKey], extraValue)

case authenticationv1.SchemeGroupVersion.WithKind("UID").GroupKind():
uid = string(impersonationRequest.Name)
actingAsAttributes.Resource = "uids"

default:
klog.V(4).InfoS("unknown impersonation request type", "Request", impersonationRequest)
responsewriters.Forbidden(ctx, actingAsAttributes, w, req, fmt.Sprintf("unknown impersonation request type: %v", impersonationRequest), s)
Expand Down Expand Up @@ -154,6 +159,7 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime.
Name: username,
Groups: groups,
Extra: userExtra,
UID: uid,
}
req = req.WithContext(request.WithUser(ctx, newUser))

Expand All @@ -166,6 +172,7 @@ func WithImpersonation(handler http.Handler, a authorizer.Authorizer, s runtime.
// clear all the impersonation headers from the request
req.Header.Del(authenticationv1.ImpersonateUserHeader)
req.Header.Del(authenticationv1.ImpersonateGroupHeader)
req.Header.Del(authenticationv1.ImpersonateUIDHeader)
for headerName := range req.Header {
if strings.HasPrefix(headerName, authenticationv1.ImpersonateUserExtraHeaderPrefix) {
req.Header.Del(headerName)
Expand Down Expand Up @@ -231,7 +238,17 @@ func buildImpersonationRequests(headers http.Header) ([]v1.ObjectReference, erro
}
}

if (hasGroups || hasUserExtra) && !hasUser {
requestedUID := headers.Get(authenticationv1.ImpersonateUIDHeader)
hasUID := len(requestedUID) > 0
if hasUID {
impersonationRequests = append(impersonationRequests, v1.ObjectReference{
Kind: "UID",
Name: requestedUID,
APIVersion: authenticationv1.SchemeGroupVersion.String(),
})
}

if (hasGroups || hasUserExtra || hasUID) && !hasUser {
return nil, fmt.Errorf("requested %v without impersonating a user", impersonationRequests)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,27 @@ func (impersonateAuthorizer) Authorize(ctx context.Context, a authorizer.Attribu
}

if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-particular-scopes" &&
a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetName() == "scope-a" {
a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetName() == "scope-a" && a.GetAPIGroup() == "authentication.k8s.io" {
return authorizer.DecisionAllow, "", nil
}

if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-project" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "project" {
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-project" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "project" && a.GetAPIGroup() == "authentication.k8s.io" {
return authorizer.DecisionAllow, "", nil
}

if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "everything-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "users" && a.GetAPIGroup() == "" {
return authorizer.DecisionAllow, "", nil
}

if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "everything-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "uids" && a.GetName() == "some-uid" && a.GetAPIGroup() == "authentication.k8s.io" {
return authorizer.DecisionAllow, "", nil
}

if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "everything-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "groups" && a.GetAPIGroup() == "" {
return authorizer.DecisionAllow, "", nil
}

if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "everything-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetAPIGroup() == "authentication.k8s.io" {
return authorizer.DecisionAllow, "", nil
}

Expand All @@ -93,6 +109,7 @@ func TestImpersonationFilter(t *testing.T) {
impersonationUser string
impersonationGroups []string
impersonationUserExtras map[string][]string
impersonationUid string
expectedUser user.Info
expectedCode int
}{
Expand Down Expand Up @@ -139,6 +156,17 @@ func TestImpersonationFilter(t *testing.T) {
},
expectedCode: http.StatusInternalServerError,
},
{
name: "impersonating-uid-without-user",
user: &user.DefaultInfo{
Name: "tester",
},
impersonationUid: "some-uid",
expectedUser: &user.DefaultInfo{
Name: "tester",
},
expectedCode: http.StatusInternalServerError,
},
{
name: "disallowed-group",
user: &user.DefaultInfo{
Expand Down Expand Up @@ -383,6 +411,60 @@ func TestImpersonationFilter(t *testing.T) {
},
expectedCode: http.StatusOK,
},
{
name: "allowed-user-impersonation-with-uid",
user: &user.DefaultInfo{
Name: "dev",
Groups: []string{
"everything-impersonater",
},
},
impersonationUser: "tester",
impersonationUid: "some-uid",
expectedUser: &user.DefaultInfo{
Name: "tester",
Groups: []string{"system:authenticated"},
Extra: map[string][]string{},
UID: "some-uid",
},
expectedCode: http.StatusOK,
},
{
name: "disallowed-user-impersonation-with-uid",
user: &user.DefaultInfo{
Name: "dev",
Groups: []string{
"everything-impersonater",
},
},
impersonationUser: "tester",
impersonationUid: "disallowed-uid",
expectedUser: &user.DefaultInfo{
Name: "dev",
Groups: []string{"everything-impersonater"},
},
expectedCode: http.StatusForbidden,
},
{
name: "allowed-impersonation-with-all-headers",
user: &user.DefaultInfo{
Name: "dev",
Groups: []string{
"everything-impersonater",
},
},
impersonationUser: "tester",
impersonationUid: "some-uid",
impersonationGroups: []string{"system:authenticated"},
impersonationUserExtras: map[string][]string{"scopes": {"scope-a", "scope-b"}},
expectedUser: &user.DefaultInfo{
Name: "tester",
Groups: []string{"system:authenticated"},
UID: "some-uid",
Extra: map[string][]string{"scopes": {"scope-a", "scope-b"}},
},
expectedCode: http.StatusOK,
},
}

var ctx context.Context
Expand Down Expand Up @@ -410,6 +492,9 @@ func TestImpersonationFilter(t *testing.T) {
t.Fatalf("extra header still present: %v", key)
}
}
if _, ok := req.Header[authenticationapi.ImpersonateUIDHeader]; ok {
t.Fatal("uid header still present")
}

})
handler := func(delegate http.Handler) http.Handler {
Expand Down Expand Up @@ -463,6 +548,9 @@ func TestImpersonationFilter(t *testing.T) {
req.Header.Add(authenticationapi.ImpersonateUserExtraHeaderPrefix+extraKey, value)
}
}
if len(tc.impersonationUid) > 0 {
req.Header.Add(authenticationapi.ImpersonateUIDHeader, tc.impersonationUid)
}

resp, err := http.DefaultClient.Do(req)
if err != nil {
Expand Down

0 comments on commit e1acbbd

Please sign in to comment.