Skip to content

Commit

Permalink
*: Add docs and examples on token audience reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
brancz committed Feb 7, 2020
1 parent 8d0cbe1 commit 96d3359
Show file tree
Hide file tree
Showing 14 changed files with 816 additions and 2 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,22 @@ All command line flags:
```txt
$ kube-rbac-proxy -h
Usage of _output/linux/amd64/kube-rbac-proxy:
--add_dir_header If true, adds the file directory to the header
--alsologtostderr log to standard error as well as files
--auth-header-fields-enabled When set to true, kube-rbac-proxy adds auth-related fields to the headers of http requests sent to the upstream
--auth-header-groups-field-name string The name of the field inside a http(2) request header to tell the upstream server about the user's groups (default "x-remote-groups")
--auth-header-groups-field-separator string The separator string used for concatenating multiple group names in a groups header field's value (default "|")
--auth-header-user-field-name string The name of the field inside a http(2) request header to tell the upstream server about the user's name (default "x-remote-user")
--auth-token-audiences strings Comma-separated list of token audiences to accept. By default a token does not have to have any specific audience. It is recommended to set a specific audience.
--client-ca-file string If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate.
--config-file string Configuration file to configure kube-rbac-proxy.
--insecure-listen-address string The address the kube-rbac-proxy HTTP server should listen on.
--kubeconfig string Path to a kubeconfig file, specifying how to connect to the API server. If unset, in-cluster configuration will be used
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--log_file string If non-empty, use this log file
--log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--logtostderr log to standard error instead of files (default true)
--oidc-ca-file string If set, the OpenID server's certificate will be verified by one of the authorities in the oidc-ca-file, otherwise the host's root CA set will be used.
--oidc-clientID string The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.
--oidc-groups-claim string Identifier of groups in JWT claim, by default set to 'groups' (default "groups")
Expand All @@ -48,15 +52,18 @@ Usage of _output/linux/amd64/kube-rbac-proxy:
--oidc-sign-alg stringArray Supported signing algorithms, default RS256 (default [RS256])
--oidc-username-claim string Identifier of the user in JWT claim, by default set to 'email' (default "email")
--secure-listen-address string The address the kube-rbac-proxy HTTPs server should listen on.
--skip_headers If true, avoid header prefixes in the log messages
--skip_log_headers If true, avoid headers when opening log files
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
--tls-cert-file string File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert)
--tls-cipher-suites strings Comma-separated list of cipher suites for the server. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If omitted, the default Go cipher suites will be used
--tls-min-version string Minimum TLS version supported. Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants. (default "VersionTLS12")
--tls-private-key-file string File containing the default x509 private key matching --tls-cert-file.
--tls-reload-interval duration The interval at which to watch for TLS certificate changes, by default set to 1 minute. (default 1m0s)
--upstream string The upstream URL to proxy to once requests have successfully been authenticated and authorized.
--upstream-ca-file string The CA the upstream uses for TLS connection. This is required when the upstream uses TLS and its own CA certificate
--upstream-force-h2c Force h2c to communiate with the upstream. This is required when the upstream speaks h2c(http/2 cleartext - insecure variant of http/2) only. For example, go-grpc server in the insecure mode, such as helm's tiller w/o TLS, speaks h2c only
-v, --v Level log level for V logs
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```

Expand Down
292 changes: 292 additions & 0 deletions examples/non-resource-url-token-request/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
# non-resource-url-token-request example

> Token audience reviews can be combined with any of the other features of kube-rbac-proxy, such as reviewing permission for specific resources, this example merely chooses to show the functionality using a non-resource-url permission.
This examples is in essence similar to the [non-resource-url](../non-resource-url/) example, with the key difference, that this example requires the ServiceAccount token sent by a client must be scoped to the `kube-rbac-proxy.default.svc` audience. In this example the scoped ServiceAccount token is obtained via a projected volume and mounted into the client container from where it can be consumed. The reasoning here is that scoped tokens cannot be used to impersonate an entity by re-using the token to perform a request against the Kubernetes API itself.

The audience a token must be scoped to is configured within the kube-rbac-proxy using the `--auth-token-audiences` flag.
```bash
$ kubectl create -f deployment.yaml
```

The content of this manifest is:

[embedmd]:# (./deployment.yaml)
```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: kube-rbac-proxy
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kube-rbac-proxy
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: kube-rbac-proxy
subjects:
- kind: ServiceAccount
name: kube-rbac-proxy
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kube-rbac-proxy
rules:
- apiGroups: ["authentication.k8s.io"]
resources:
- tokenreviews
verbs: ["create"]
- apiGroups: ["authorization.k8s.io"]
resources:
- subjectaccessreviews
verbs: ["create"]
---
apiVersion: v1
kind: Service
metadata:
labels:
app: kube-rbac-proxy
name: kube-rbac-proxy
spec:
ports:
- name: https
port: 8443
targetPort: https
selector:
app: kube-rbac-proxy
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kube-rbac-proxy
spec:
replicas: 1
selector:
matchLabels:
app: kube-rbac-proxy
template:
metadata:
labels:
app: kube-rbac-proxy
spec:
serviceAccountName: kube-rbac-proxy
containers:
- name: kube-rbac-proxy
image: quay.io/brancz/kube-rbac-proxy:v0.4.1
args:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8081/"
- "--auth-token-audiences=kube-rbac-proxy.default.svc"
- "--logtostderr=true"
- "--v=10"
ports:
- containerPort: 8443
name: https
- name: prometheus-example-app
image: quay.io/brancz/prometheus-example-app:v0.1.0
args:
- "--bind=127.0.0.1:8081"
```
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 `/metrics` path in its `nonResourceURLs` it is allowed to access the endpoint.

The Dockerfile of this container can be found [here](../example-client/Dockerfile).

```bash
$ kubectl create -f client-rbac.yaml client.yaml
```

The content of this manifest is:

[embedmd]:# (./client-rbac.yaml)
```yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: metrics
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: metrics
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics
subjects:
- kind: ServiceAccount
name: default
namespace: default
```

[embedmd]:# (./client.yaml)
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: krp-curl
spec:
template:
metadata:
name: krp-curl
spec:
restartPolicy: Never
containers:
- name: krp-curl
image: quay.io/brancz/krp-curl:v0.0.1
command:
- /bin/sh
- -c
- 'curl -v -s -k -H "Authorization: Bearer `cat /service-account/token`" https://kube-rbac-proxy.default.svc:8443/metrics'
volumeMounts:
- name: token-vol
mountPath: "/service-account"
readOnly: true
volumes:
- name: token-vol
projected:
sources:
- serviceAccountToken:
audience: kube-rbac-proxy.default.svc
expirationSeconds: 3600
path: token
backoffLimit: 4
```
We can look at the logs and we should get something similar to:
```
* Trying 10.106.147.107...
* TCP_NODELAY set
* Connected to kube-rbac-proxy.default.svc (10.106.147.107) port 8443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [242 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [49 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [1649 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [300 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [37 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=kube-rbac-proxy-695b54f7ff-z54b7@1579943520
* start date: Jan 25 08:12:00 2020 GMT
* expire date: Jan 24 08:12:00 2021 GMT
* issuer: CN=kube-rbac-proxy-695b54f7ff-z54b7-ca@1579943520
* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> GET /metrics HTTP/1.1
> Host: kube-rbac-proxy.default.svc:8443
> User-Agent: curl/7.61.0
> Accept: */*
> Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InBtUmFFQnJIUzJXS1RuR3FmcmRkRDd3TEM2NUx3STZmb29DczRNRGwzLXcifQ.eyJhdWQiOlsia3ViZS1yYmFjLXByb3h5LmRlZmF1bHQuc3ZjIl0sImV4cCI6MTU3OTk0NzYxMiwiaWF0IjoxNTc5OTQ0MDEyLCJpc3MiOiJrdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJrcnAtY3VybC1nMjVweCIsInVpZCI6IjA3MWYxYzM1LWNmZWYtNGRhNy05ZjMxLWJiMmJkNmJmY2VmNyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjRlYzFiOWU4LTdkZmItNDhiNi1hMjU0LWFiYTg4MGJhZGY5ZiJ9fSwibmJmIjoxNTc5OTQ0MDEyLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.fM05SSlLzb5zMpTjYhn_H8Y0KFwX000VYqE8CMA3sP5lMAbXBInGSudbm_r_ppAMUYar6cmyAiSmIAD1bOR-DlzmJdX-LA5kgA3J9GAsrWBxXMlmASo1OfTjtOuQ98Y8tM6P-BCCe5rOAcx-ppmbPE_8Pu_7IkHjABURtClr6VUspsLfqsZ9GcN5pDBSR9iFt2Cl6m8YsbBXIDJ1kp9CknFt36s5Dg7OcTQR-WWkA21iZiOqayWGphW-DqpjEdm16XpjOqqDOf2qyFisjPhxNN-rivPJaCeoRb3GUIQVbvVShEgygzdM_8OqmZT3THeHBCdC_685Ffv3hFC4G6ijAQ
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; version=0.0.4
< Date: Sat, 25 Jan 2020 09:20:12 GMT
< Content-Length: 102
<
{ [102 bytes data]
* Connection #0 to host kube-rbac-proxy.default.svc left intact
# HELP version Version information about this binary
# TYPE version gauge
version{version="v0.1.0"} 0
```

Whereas if we didn't use a token that was created for the correct audience, for example the default ServiceAccount token mounted into containers, then we should not be able to authenticate with that token. This can be verified with:


[embedmd]:# (./wrong-client.yaml)
```yaml
apiVersion: batch/v1
kind: Job
metadata:
name: krp-wrong-token-curl
spec:
template:
metadata:
name: krp-wrong-token-curl
spec:
restartPolicy: Never
containers:
- name: krp-curl
image: quay.io/brancz/krp-curl:v0.0.1
```
Then the log output should look something along the lines of:
```
* Trying 10.106.147.107...
* TCP_NODELAY set
* Connected to kube-rbac-proxy.default.svc (10.106.147.107) port 8443 (#0)
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [242 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [49 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [1649 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [300 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [37 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: CN=kube-rbac-proxy-695b54f7ff-z54b7@1579943520
* start date: Jan 25 08:12:00 2020 GMT
* expire date: Jan 24 08:12:00 2021 GMT
* issuer: CN=kube-rbac-proxy-695b54f7ff-z54b7-ca@1579943520
* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> GET /metrics HTTP/1.1
> Host: kube-rbac-proxy.default.svc:8443
> User-Agent: curl/7.61.0
> Accept: */*
> Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InBtUmFFQnJIUzJXS1RuR3FmcmRkRDd3TEM2NUx3STZmb29DczRNRGwzLXcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbWtienYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRlYzFiOWU4LTdkZmItNDhiNi1hMjU0LWFiYTg4MGJhZGY5ZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.dWmmPOUTpIXve3svadwPd3a1PswkL8YC5JnPvul4EqQjcf-SLNSgp-TT4I2SqUTiNqwrehmdjjZdD925Erpdb8ZnrTTcaicmO6G95IvpwfMz3EvJY7A0anjjS_IOJpwoBN3RpgftGQcuFIaOc10xa5DC9TcS1-HouoyR-FdciqEOr3ZaOhr_em3W3MLqr6IMBTALz__rObKrb7kAUPNiBfy5fUhznbp2VgQeJYQRIxGQDOnn-_5bfFjsWjQAz098SknNAwOKtdy9BpRPwyrVybQ17i15DJcAP92aSIMP7dhYvDpuSvHBg5GhHNT3y5abd_o4ZXpWpSwqSpxAHqGE5g
>
< HTTP/1.1 401 Unauthorized
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Sat, 25 Jan 2020 09:21:16 GMT
< Content-Length: 13
<
{ [13 bytes data]
* Connection #0 to host kube-rbac-proxy.default.svc left intact
Unauthorized
```
20 changes: 20 additions & 0 deletions examples/non-resource-url-token-request/client-rbac.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: metrics
rules:
- nonResourceURLs: ["/metrics"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: metrics
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metrics
subjects:
- kind: ServiceAccount
name: default
namespace: default
30 changes: 30 additions & 0 deletions examples/non-resource-url-token-request/client.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: batch/v1
kind: Job
metadata:
name: krp-curl
spec:
template:
metadata:
name: krp-curl
spec:
restartPolicy: Never
containers:
- name: krp-curl
image: quay.io/brancz/krp-curl:v0.0.1
command:
- /bin/sh
- -c
- 'curl -v -s -k -H "Authorization: Bearer `cat /service-account/token`" https://kube-rbac-proxy.default.svc:8443/metrics'
volumeMounts:
- name: token-vol
mountPath: "/service-account"
readOnly: true
volumes:
- name: token-vol
projected:
sources:
- serviceAccountToken:
audience: kube-rbac-proxy.default.svc
expirationSeconds: 3600
path: token
backoffLimit: 4
Loading

0 comments on commit 96d3359

Please sign in to comment.