enable resource name and service account cases for impersonation

pull/6/head
deads2k 2016-04-26 09:31:43 -04:00
parent 9db45590cf
commit 622932422d
3 changed files with 77 additions and 7 deletions

View File

@ -410,7 +410,7 @@ func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attrib
return &attribs return &attribs
} }
func WithActingAs(handler http.Handler, requestContextMapper api.RequestContextMapper, a authorizer.Authorizer) http.Handler { func WithImpersonation(handler http.Handler, requestContextMapper api.RequestContextMapper, a authorizer.Authorizer) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
requestedSubject := req.Header.Get("Impersonate-User") requestedSubject := req.Header.Get("Impersonate-User")
if len(requestedSubject) == 0 { if len(requestedSubject) == 0 {
@ -434,9 +434,14 @@ func WithActingAs(handler http.Handler, requestContextMapper api.RequestContextM
Verb: "impersonate", Verb: "impersonate",
APIGroup: api.GroupName, APIGroup: api.GroupName,
Resource: "users", Resource: "users",
// ResourceName: requestedSubject, Name: requestedSubject,
ResourceRequest: true, ResourceRequest: true,
} }
if namespace, name, err := serviceaccount.SplitUsername(requestedSubject); err == nil {
actingAsAttributes.Resource = "serviceaccounts"
actingAsAttributes.Namespace = namespace
actingAsAttributes.Name = name
}
err := a.Authorize(actingAsAttributes) err := a.Authorize(actingAsAttributes)
if err != nil { if err != nil {

View File

@ -472,7 +472,7 @@ func (s *GenericAPIServer) init(c *Config) {
attributeGetter := apiserver.NewRequestAttributeGetter(s.RequestContextMapper, s.NewRequestInfoResolver()) attributeGetter := apiserver.NewRequestAttributeGetter(s.RequestContextMapper, s.NewRequestInfoResolver())
handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, s.authorizer) handler = apiserver.WithAuthorizationCheck(handler, attributeGetter, s.authorizer)
handler = apiserver.WithActingAs(handler, s.RequestContextMapper, s.authorizer) handler = apiserver.WithImpersonation(handler, s.RequestContextMapper, s.authorizer)
// Install Authenticator // Install Authenticator
if c.Authenticator != nil { if c.Authenticator != nil {

View File

@ -47,6 +47,7 @@ import (
"k8s.io/kubernetes/pkg/auth/authorizer/abac" "k8s.io/kubernetes/pkg/auth/authorizer/abac"
"k8s.io/kubernetes/pkg/auth/user" "k8s.io/kubernetes/pkg/auth/user"
"k8s.io/kubernetes/pkg/master" "k8s.io/kubernetes/pkg/master"
"k8s.io/kubernetes/pkg/serviceaccount"
"k8s.io/kubernetes/plugin/pkg/admission/admit" "k8s.io/kubernetes/plugin/pkg/admission/admit"
"k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/tokentest" "k8s.io/kubernetes/plugin/pkg/auth/authenticator/token/tokentest"
"k8s.io/kubernetes/test/integration/framework" "k8s.io/kubernetes/test/integration/framework"
@ -729,12 +730,22 @@ type impersonateAuthorizer struct{}
// alice can't act as anyone and bob can't do anything but act-as someone // alice can't act as anyone and bob can't do anything but act-as someone
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) error { func (impersonateAuthorizer) Authorize(a authorizer.Attributes) error {
// alice can impersonate service accounts and do other actions
if a.GetUserName() == "alice" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
return nil
}
if a.GetUserName() == "alice" && a.GetVerb() != "impersonate" { if a.GetUserName() == "alice" && a.GetVerb() != "impersonate" {
return nil return nil
} }
// bob can impersonate anyone, but that it
if a.GetUserName() == "bob" && a.GetVerb() == "impersonate" { if a.GetUserName() == "bob" && a.GetVerb() == "impersonate" {
return nil return nil
} }
// service accounts can do everything
if strings.HasPrefix(a.GetUserName(), serviceaccount.ServiceAccountUsernamePrefix) {
return nil
}
return errors.New("I can't allow that. Go ask alice.") return errors.New("I can't allow that. Go ask alice.")
} }
@ -757,6 +768,7 @@ func TestImpersonateIsForbidden(t *testing.T) {
transport := http.DefaultTransport transport := http.DefaultTransport
// bob can't perform actions himself
for _, r := range getTestRequests() { for _, r := range getTestRequests() {
token := BobToken token := BobToken
bodyBytes := bytes.NewReader([]byte(r.body)) bodyBytes := bytes.NewReader([]byte(r.body))
@ -781,6 +793,7 @@ func TestImpersonateIsForbidden(t *testing.T) {
}() }()
} }
// bob can impersonate alice to do other things
for _, r := range getTestRequests() { for _, r := range getTestRequests() {
token := BobToken token := BobToken
bodyBytes := bytes.NewReader([]byte(r.body)) bodyBytes := bytes.NewReader([]byte(r.body))
@ -804,6 +817,58 @@ func TestImpersonateIsForbidden(t *testing.T) {
} }
}() }()
} }
// alice can't impersonate bob
for _, r := range getTestRequests() {
token := AliceToken
bodyBytes := bytes.NewReader([]byte(r.body))
req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
req.Header.Set("Impersonate-User", "bob")
func() {
resp, err := transport.RoundTrip(req)
defer resp.Body.Close()
if err != nil {
t.Logf("case %v", r)
t.Fatalf("unexpected error: %v", err)
}
// Expect all of bob's actions to return Forbidden
if resp.StatusCode != http.StatusForbidden {
t.Logf("case %v", r)
t.Errorf("Expected not status Forbidden, but got %s", resp.Status)
}
}()
}
// alice can impersonate a service account
for _, r := range getTestRequests() {
token := BobToken
bodyBytes := bytes.NewReader([]byte(r.body))
req, err := http.NewRequest(r.verb, s.URL+r.URL, bodyBytes)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
req.Header.Set("Impersonate-User", serviceaccount.MakeUsername("default", "default"))
func() {
resp, err := transport.RoundTrip(req)
defer resp.Body.Close()
if err != nil {
t.Logf("case %v", r)
t.Fatalf("unexpected error: %v", err)
}
// Expect all the requests to be allowed, don't care what they actually do
if resp.StatusCode == http.StatusForbidden {
t.Logf("case %v", r)
t.Errorf("Expected status not %v, but got %v", http.StatusForbidden, resp.StatusCode)
}
}()
}
} }
func newAuthorizerWithContents(t *testing.T, contents string) authorizer.Authorizer { func newAuthorizerWithContents(t *testing.T, contents string) authorizer.Authorizer {