Skip to content

Commit 8b3976c

Browse files
authored
Merge pull request brancz#125 from s-urbaniak/pr-116
static authorizer: add e2e tests, additional verifications
2 parents 6492d01 + 4a44b61 commit 8b3976c

16 files changed

+865
-4
lines changed

examples/static-auth/README.md

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Static Authorization example
2+
3+
> Note to try this out with minikube, make sure you enable RBAC correctly. Since minikube v0.26.0 the default bootstrapper is kubeadm - which should enable RBAC by default. For older version follow the instructions [here](../minikube-rbac).
4+
5+
RBAC differentiates in two types, that need to be authorized, resources and non-resources. A resource request authorization, could for example be, that a requesting entity needs to be authorized to perform the `get` action on a particular Kubernetes Deployment.
6+
7+
In this example we deploy the [prometheus-example-app](https://github.com/brancz/prometheus-example-app) and want to protect it with kube-rbac-proxy, just as detailed in the [rewrite example](../rewrite/README.md). In this example however we will avoid the recurring SubjectAccessReview requests to the api server by allowing kube-rbac-proxy to authorize these requests statically. This is configured in the file passed to the kube-rbac-proxy with the `--config-file` flag. Additionally the `--upstream` flag has to be set to configure the application that should be proxied to on successful authentication as well as authorization.
8+
9+
The kube-rbac-proxy itself also requires RBAC access, in order to perform TokenReviews as well as SubjectAccessReviews for requests that are not statically athorized. These are the APIs available from the Kubernetes API to authenticate and then validate the authorization of an entity.
10+
11+
```bash
12+
$ kubectl create -f deployment.yaml
13+
```
14+
15+
The content of this manifest is:
16+
17+
[embedmd]:# (./deployment.yaml)
18+
```yaml
19+
apiVersion: v1
20+
kind: ServiceAccount
21+
metadata:
22+
name: kube-rbac-proxy
23+
---
24+
apiVersion: rbac.authorization.k8s.io/v1
25+
kind: ClusterRoleBinding
26+
metadata:
27+
name: kube-rbac-proxy
28+
roleRef:
29+
apiGroup: rbac.authorization.k8s.io
30+
kind: ClusterRole
31+
name: kube-rbac-proxy
32+
subjects:
33+
- kind: ServiceAccount
34+
name: kube-rbac-proxy
35+
namespace: default
36+
---
37+
apiVersion: rbac.authorization.k8s.io/v1
38+
kind: ClusterRole
39+
metadata:
40+
name: kube-rbac-proxy
41+
rules:
42+
- apiGroups: ["authentication.k8s.io"]
43+
resources:
44+
- tokenreviews
45+
verbs: ["create"]
46+
- apiGroups: ["authorization.k8s.io"]
47+
resources:
48+
- subjectaccessreviews
49+
verbs: ["create"]
50+
---
51+
apiVersion: v1
52+
kind: Service
53+
metadata:
54+
labels:
55+
app: kube-rbac-proxy
56+
name: kube-rbac-proxy
57+
spec:
58+
ports:
59+
- name: https
60+
port: 8443
61+
targetPort: https
62+
selector:
63+
app: kube-rbac-proxy
64+
---
65+
apiVersion: v1
66+
kind: ConfigMap
67+
metadata:
68+
name: kube-rbac-proxy
69+
data:
70+
config-file.yaml: |+
71+
authorization:
72+
rewrites:
73+
byQueryParameter:
74+
name: "namespace"
75+
resourceAttributes:
76+
apiVersion: v1
77+
resource: namespace
78+
subresource: metrics
79+
namespace: "{{ .Value }}"
80+
static:
81+
- resourceRequest: true
82+
resource: namespace
83+
subresource: metrics
84+
---
85+
apiVersion: apps/v1
86+
kind: Deployment
87+
metadata:
88+
name: kube-rbac-proxy
89+
spec:
90+
replicas: 1
91+
selector:
92+
matchLabels:
93+
app: kube-rbac-proxy
94+
template:
95+
metadata:
96+
labels:
97+
app: kube-rbac-proxy
98+
spec:
99+
securityContext:
100+
runAsUser: 65532
101+
serviceAccountName: kube-rbac-proxy
102+
containers:
103+
- name: kube-rbac-proxy
104+
image: quay.io/brancz/kube-rbac-proxy:v0.8.0
105+
args:
106+
- "--secure-listen-address=0.0.0.0:8443"
107+
- "--upstream=http://127.0.0.1:8081/"
108+
- "--config-file=/etc/kube-rbac-proxy/config-file.yaml"
109+
- "--logtostderr=true"
110+
- "--v=10"
111+
ports:
112+
- containerPort: 8443
113+
name: https
114+
volumeMounts:
115+
- name: config
116+
mountPath: /etc/kube-rbac-proxy
117+
securityContext:
118+
allowPrivilegeEscalation: false
119+
- name: prometheus-example-app
120+
image: quay.io/brancz/prometheus-example-app:v0.1.0
121+
args:
122+
- "--bind=127.0.0.1:8081"
123+
volumes:
124+
- name: config
125+
configMap:
126+
name: kube-rbac-proxy
127+
```
128+
129+
Once the prometheus-example-app is up and running, we can test it. In order to test it, we deploy a Job, that performs a `curl` against the above deployment. Because it has the correct RBAC roles, the request will succeed.
130+
131+
```bash
132+
$ kubectl create -f client-rbac.yaml
133+
```
134+
135+
The content of this manifest is:
136+
137+
[embedmd]:# (./client-rbac.yaml)
138+
```yaml
139+
apiVersion: rbac.authorization.k8s.io/v1
140+
kind: RoleBinding
141+
metadata:
142+
name: namespace-metrics
143+
roleRef:
144+
apiGroup: rbac.authorization.k8s.io
145+
kind: Role
146+
name: namespace-metrics
147+
subjects:
148+
- kind: ServiceAccount
149+
name: default
150+
namespace: default
151+
---
152+
apiVersion: rbac.authorization.k8s.io/v1
153+
kind: Role
154+
metadata:
155+
name: namespace-metrics
156+
rules:
157+
- apiGroups: [""]
158+
resources:
159+
- namespace/metrics
160+
verbs: ["get"]
161+
```
162+
163+
Now simply run
164+
```
165+
kubectl run -i -t alpine --image=alpine --restart=Never -- sh -c 'apk add curl; curl -v -s -k -H "Authorization: Bearer `cat /var/run/secrets/kubernetes.io/serviceaccount/token`" https://kube-rbac-proxy.default.svc:8443/metrics?namespace=default'
166+
```
167+
168+
A configuration setting for the static authorization feature for resource requests looks like this:
169+
```
170+
config-file.yaml: |+
171+
authorization:
172+
static:
173+
- user:
174+
name: UserName
175+
groups:
176+
- group1
177+
- group2
178+
verb: get
179+
namespace: default
180+
apiGroup: apps
181+
resourceRequest: true
182+
resource: namespace
183+
subresource: metrics
184+
```
185+
186+
A configuration setting for the static authorization feature for non-resource requests looks like this:
187+
```
188+
config-file.yaml: |+
189+
authorization:
190+
static:
191+
- user:
192+
name: UserName
193+
groups:
194+
- group1
195+
- group2
196+
verb: get
197+
resourceRequest: false
198+
path: /metrics
199+
```
200+
201+
The values in the above example are just aimed at illustrating what is possible. An omitted configuration setting is interpreted as a wildcard. E.g. if a static-auth configuration omits the `user` setting, any user can be statically authorized if a request fits the remaining configuration.

examples/static-auth/client-rbac.yaml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: RoleBinding
3+
metadata:
4+
name: namespace-metrics
5+
roleRef:
6+
apiGroup: rbac.authorization.k8s.io
7+
kind: Role
8+
name: namespace-metrics
9+
subjects:
10+
- kind: ServiceAccount
11+
name: default
12+
namespace: default
13+
---
14+
apiVersion: rbac.authorization.k8s.io/v1
15+
kind: Role
16+
metadata:
17+
name: namespace-metrics
18+
rules:
19+
- apiGroups: [""]
20+
resources:
21+
- namespace/metrics
22+
verbs: ["get"]

examples/static-auth/deployment.yaml

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
apiVersion: v1
2+
kind: ServiceAccount
3+
metadata:
4+
name: kube-rbac-proxy
5+
---
6+
apiVersion: rbac.authorization.k8s.io/v1
7+
kind: ClusterRoleBinding
8+
metadata:
9+
name: kube-rbac-proxy
10+
roleRef:
11+
apiGroup: rbac.authorization.k8s.io
12+
kind: ClusterRole
13+
name: kube-rbac-proxy
14+
subjects:
15+
- kind: ServiceAccount
16+
name: kube-rbac-proxy
17+
namespace: default
18+
---
19+
apiVersion: rbac.authorization.k8s.io/v1
20+
kind: ClusterRole
21+
metadata:
22+
name: kube-rbac-proxy
23+
rules:
24+
- apiGroups: ["authentication.k8s.io"]
25+
resources:
26+
- tokenreviews
27+
verbs: ["create"]
28+
- apiGroups: ["authorization.k8s.io"]
29+
resources:
30+
- subjectaccessreviews
31+
verbs: ["create"]
32+
---
33+
apiVersion: v1
34+
kind: Service
35+
metadata:
36+
labels:
37+
app: kube-rbac-proxy
38+
name: kube-rbac-proxy
39+
spec:
40+
ports:
41+
- name: https
42+
port: 8443
43+
targetPort: https
44+
selector:
45+
app: kube-rbac-proxy
46+
---
47+
apiVersion: v1
48+
kind: ConfigMap
49+
metadata:
50+
name: kube-rbac-proxy
51+
data:
52+
config-file.yaml: |+
53+
authorization:
54+
rewrites:
55+
byQueryParameter:
56+
name: "namespace"
57+
resourceAttributes:
58+
apiVersion: v1
59+
resource: namespace
60+
subresource: metrics
61+
namespace: "{{ .Value }}"
62+
static:
63+
- resourceRequest: true
64+
resource: namespace
65+
subresource: metrics
66+
---
67+
apiVersion: apps/v1
68+
kind: Deployment
69+
metadata:
70+
name: kube-rbac-proxy
71+
spec:
72+
replicas: 1
73+
selector:
74+
matchLabels:
75+
app: kube-rbac-proxy
76+
template:
77+
metadata:
78+
labels:
79+
app: kube-rbac-proxy
80+
spec:
81+
securityContext:
82+
runAsUser: 65532
83+
serviceAccountName: kube-rbac-proxy
84+
containers:
85+
- name: kube-rbac-proxy
86+
image: quay.io/brancz/kube-rbac-proxy:v0.8.0
87+
args:
88+
- "--secure-listen-address=0.0.0.0:8443"
89+
- "--upstream=http://127.0.0.1:8081/"
90+
- "--config-file=/etc/kube-rbac-proxy/config-file.yaml"
91+
- "--logtostderr=true"
92+
- "--v=10"
93+
ports:
94+
- containerPort: 8443
95+
name: https
96+
volumeMounts:
97+
- name: config
98+
mountPath: /etc/kube-rbac-proxy
99+
securityContext:
100+
allowPrivilegeEscalation: false
101+
- name: prometheus-example-app
102+
image: quay.io/brancz/prometheus-example-app:v0.1.0
103+
args:
104+
- "--bind=127.0.0.1:8081"
105+
volumes:
106+
- name: config
107+
configMap:
108+
name: kube-rbac-proxy

main.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"golang.org/x/net/http2"
3838
"golang.org/x/net/http2/h2c"
3939
"k8s.io/apiserver/pkg/authentication/authenticator"
40+
"k8s.io/apiserver/pkg/authorization/union"
4041
"k8s.io/client-go/kubernetes"
4142
"k8s.io/client-go/rest"
4243
"k8s.io/client-go/tools/clientcmd"
@@ -184,12 +185,22 @@ func main() {
184185
}
185186

186187
sarClient := kubeClient.AuthorizationV1().SubjectAccessReviews()
187-
authorizer, err := authz.NewAuthorizer(sarClient)
188+
sarAuthorizer, err := authz.NewSarAuthorizer(sarClient)
188189

189190
if err != nil {
190-
klog.Fatalf("Failed to create authorizer: %v", err)
191+
klog.Fatalf("Failed to create sar authorizer: %v", err)
191192
}
192193

194+
staticAuthorizer, err := authz.NewStaticAuthorizer(cfg.auth.Authorization.Static)
195+
if err != nil {
196+
klog.Fatalf("Failed to create static authorizer: %v", err)
197+
}
198+
199+
authorizer := union.New(
200+
staticAuthorizer,
201+
sarAuthorizer,
202+
)
203+
193204
auth, err := proxy.New(kubeClient, cfg.auth, authorizer, authenticator)
194205

195206
if err != nil {

0 commit comments

Comments
 (0)