forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
node_auth.go
114 lines (96 loc) · 3.34 KB
/
node_auth.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package node
import (
"net/http"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/apiserver/pkg/authentication/user"
"k8s.io/apiserver/pkg/authorization/authorizer"
authorizationapi "github.com/openshift/origin/pkg/authorization/api"
authzcache "github.com/openshift/origin/pkg/authorization/authorizer/cache"
authzremote "github.com/openshift/origin/pkg/authorization/authorizer/remote"
oclient "github.com/openshift/origin/pkg/client"
)
func newAuthorizerAttributesGetter(nodeName string) (authorizer.RequestAttributesGetter, error) {
return NodeAuthorizerAttributesGetter{nodeName}, nil
}
type NodeAuthorizerAttributesGetter struct {
nodeName string
}
func isSubpath(r *http.Request, path string) bool {
path = strings.TrimSuffix(path, "/")
return r.URL.Path == path || strings.HasPrefix(r.URL.Path, path+"/")
}
// GetRequestAttributes populates authorizer attributes for the requests to the kubelet API.
// Default attributes are {apiVersion=v1,verb=proxy,resource=nodes,resourceName=<node name>}
// More specific verb/resource is set for the following request patterns:
// /stats/* => verb=<api verb from request>, resource=nodes/stats
// /metrics/* => verb=<api verb from request>, resource=nodes/metrics
// /logs/* => verb=<api verb from request>, resource=nodes/log
func (n NodeAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *http.Request) authorizer.Attributes {
namespace := ""
apiVerb := ""
switch r.Method {
case "POST":
apiVerb = "create"
case "GET":
apiVerb = "get"
case "PUT":
apiVerb = "update"
case "PATCH":
apiVerb = "patch"
case "DELETE":
apiVerb = "delete"
}
// Default verb/resource is <apiVerb> nodes/proxy, which allows full access to the kubelet API
attrs := authorizer.AttributesRecord{
User: u,
APIVersion: "v1",
APIGroup: "",
Verb: apiVerb,
Namespace: namespace,
Resource: "nodes",
Subresource: "proxy",
Name: n.nodeName,
Path: r.URL.Path,
ResourceRequest: true,
}
// Override verb/resource for specific paths
// Updates to these rules require updating NodeAdminRole and NodeReaderRole in bootstrap policy
switch {
case isSubpath(r, "/spec"):
attrs.Verb = apiVerb
attrs.Subresource = authorizationapi.NodeSpecSubresource
case isSubpath(r, "/stats"):
attrs.Verb = apiVerb
attrs.Subresource = authorizationapi.NodeStatsSubresource
case isSubpath(r, "/metrics"):
attrs.Verb = apiVerb
attrs.Subresource = authorizationapi.NodeMetricsSubresource
case isSubpath(r, "/logs"):
attrs.Verb = apiVerb
attrs.Subresource = authorizationapi.NodeLogSubresource
}
// TODO: handle other things like /healthz/*? not sure if "non-resource" urls on the kubelet make sense to authorize against master non-resource URL policy
glog.V(2).Infof("Node request attributes: namespace=%s, user=%#v, attrs=%#v", namespace, u, attrs)
return attrs
}
func newAuthorizer(c *oclient.Client, cacheTTL time.Duration, cacheSize int) (authorizer.Authorizer, error) {
var (
authz authorizer.Authorizer
err error
)
// Authorize against the remote master
authz, err = authzremote.NewAuthorizer(c)
if err != nil {
return nil, err
}
// Cache results
if cacheTTL > 0 && cacheSize > 0 {
authz, err = authzcache.NewAuthorizer(authz, cacheTTL, cacheSize)
if err != nil {
return nil, err
}
}
return authz, nil
}