blob: 4c9f140ca30dfb275076590bffc38feef6e7c2c4 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2016 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package filters
18
19import (
20 "context"
21 "errors"
22 "net/http"
23
24 "github.com/golang/glog"
25
26 "k8s.io/apimachinery/pkg/runtime"
27 "k8s.io/apiserver/pkg/audit"
28 "k8s.io/apiserver/pkg/authorization/authorizer"
29 "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
30 "k8s.io/apiserver/pkg/endpoints/request"
31)
32
33const (
34 // Annotation key names set in advanced audit
35 decisionAnnotationKey = "authorization.k8s.io/decision"
36 reasonAnnotationKey = "authorization.k8s.io/reason"
37
38 // Annotation values set in advanced audit
39 decisionAllow = "allow"
40 decisionForbid = "forbid"
41 reasonError = "internal error"
42)
43
44// WithAuthorizationCheck passes all authorized requests on to handler, and returns a forbidden error otherwise.
45func WithAuthorization(handler http.Handler, a authorizer.Authorizer, s runtime.NegotiatedSerializer) http.Handler {
46 if a == nil {
47 glog.Warningf("Authorization is disabled")
48 return handler
49 }
50 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
51 ctx := req.Context()
52 ae := request.AuditEventFrom(ctx)
53
54 attributes, err := GetAuthorizerAttributes(ctx)
55 if err != nil {
56 responsewriters.InternalError(w, req, err)
57 return
58 }
59 authorized, reason, err := a.Authorize(attributes)
60 // an authorizer like RBAC could encounter evaluation errors and still allow the request, so authorizer decision is checked before error here.
61 if authorized == authorizer.DecisionAllow {
62 audit.LogAnnotation(ae, decisionAnnotationKey, decisionAllow)
63 audit.LogAnnotation(ae, reasonAnnotationKey, reason)
64 handler.ServeHTTP(w, req)
65 return
66 }
67 if err != nil {
68 audit.LogAnnotation(ae, reasonAnnotationKey, reasonError)
69 responsewriters.InternalError(w, req, err)
70 return
71 }
72
73 glog.V(4).Infof("Forbidden: %#v, Reason: %q", req.RequestURI, reason)
74 audit.LogAnnotation(ae, decisionAnnotationKey, decisionForbid)
75 audit.LogAnnotation(ae, reasonAnnotationKey, reason)
76 responsewriters.Forbidden(ctx, attributes, w, req, reason, s)
77 })
78}
79
80func GetAuthorizerAttributes(ctx context.Context) (authorizer.Attributes, error) {
81 attribs := authorizer.AttributesRecord{}
82
83 user, ok := request.UserFrom(ctx)
84 if ok {
85 attribs.User = user
86 }
87
88 requestInfo, found := request.RequestInfoFrom(ctx)
89 if !found {
90 return nil, errors.New("no RequestInfo found in the context")
91 }
92
93 // Start with common attributes that apply to resource and non-resource requests
94 attribs.ResourceRequest = requestInfo.IsResourceRequest
95 attribs.Path = requestInfo.Path
96 attribs.Verb = requestInfo.Verb
97
98 attribs.APIGroup = requestInfo.APIGroup
99 attribs.APIVersion = requestInfo.APIVersion
100 attribs.Resource = requestInfo.Resource
101 attribs.Subresource = requestInfo.Subresource
102 attribs.Namespace = requestInfo.Namespace
103 attribs.Name = requestInfo.Name
104
105 return &attribs, nil
106}