├── .github └── workflows │ └── build.yml ├── .gitignore ├── .golangci.yaml ├── CHANGELOG.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── RELEASE.md ├── VERSION ├── cmd └── kube-rbac-proxy │ ├── app │ ├── kube-rbac-proxy.go │ ├── kube-rbac-proxy_test.go │ ├── options │ │ ├── deprecated.go │ │ └── options.go │ ├── sanitazion.go │ ├── transport.go │ └── transport_test.go │ └── main.go ├── examples ├── example-client-http2 │ └── Dockerfile ├── example-client-urlquery │ └── Dockerfile ├── example-client │ └── Dockerfile ├── grpcc │ └── Dockerfile ├── minikube-rbac │ ├── README.md │ └── minikube-rbac-fix.yaml ├── non-resource-url-token-request │ ├── README.md │ ├── client-rbac.yaml │ ├── client.yaml │ ├── deployment.yaml │ ├── kind-config.yaml │ └── wrong-client.yaml ├── non-resource-url │ ├── README.md │ ├── client-rbac.yaml │ ├── client.yaml │ └── deployment.yaml ├── oidc │ ├── .gitignore │ ├── README.md │ ├── client-rbac.yaml │ └── deployment.yaml ├── resource-attributes │ ├── README.md │ ├── client-rbac.yaml │ ├── client.yaml │ └── deployment.yaml ├── rewrites │ ├── README.md │ ├── client-rbac.yaml │ └── deployment.yaml └── static-auth │ ├── README.md │ ├── client-rbac.yaml │ └── deployment.yaml ├── go.mod ├── go.sum ├── pkg ├── authn │ ├── config.go │ ├── delegating.go │ └── oidc.go ├── authz │ ├── auth.go │ └── auth_test.go ├── filters │ ├── auth.go │ ├── auth_test.go │ ├── path.go │ └── path_test.go ├── proxy │ ├── proxy.go │ └── proxy_test.go └── tls │ ├── reloader.go │ └── reloader_test.go ├── scripts ├── check_license.sh ├── generate-examples.sh ├── generate-help-txt.sh ├── go.mod ├── go.sum ├── kind-load-local.sh ├── publish.sh ├── templates │ ├── non-resource-url-deployment.yaml │ ├── non-resource-url-token-request-deployment.yaml │ ├── oidc-deployment.yaml │ ├── resource-attributes-deployment.yaml │ └── rewrites-deployment.yaml └── tools.go └── test ├── ca.pem ├── e2e ├── allowpaths │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── basics.go ├── basics │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── clientcertificates │ ├── certificate.yaml │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment-wrongca.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── flags │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment-logtostderr.yaml │ ├── deployment-other-flags.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── h2c-upstream │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── h2c_upstream.go ├── http2.go ├── http2 │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment-no-http2.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── ignorepaths │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── kind-config │ └── kind-config.yaml ├── main_test.go ├── static-auth │ ├── clusterRole.yaml │ ├── clusterRoleBinding.yaml │ ├── configmap-non-resource.yaml │ ├── configmap-resource.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml ├── static_authorizer.go ├── tls.go ├── tokenmasking.go ├── tokenmasking │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml └── tokenrequest │ ├── clusterRole-client.yaml │ ├── clusterRole.yaml │ ├── clusterRoleBinding-client.yaml │ ├── clusterRoleBinding.yaml │ ├── deployment.yaml │ ├── service.yaml │ └── serviceAccount.yaml └── kubetest ├── client.go ├── kubernetes.go └── kubetest.go /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | QUAY_PATH: quay.io/brancz/kube-rbac-proxy 7 | kind-version: v0.30.0 8 | go-version: 1.25 9 | 10 | defaults: 11 | run: 12 | shell: bash 13 | 14 | concurrency: 15 | group: ${{ github.ref_name }}-${{ github.ref }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | check-license: 20 | name: Check license 21 | runs-on: ubuntu-24.04 22 | timeout-minutes: 3 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 26 | 27 | - name: Check license 28 | run: make check-license 29 | 30 | generate: 31 | name: Generate 32 | runs-on: ubuntu-24.04 33 | timeout-minutes: 5 34 | steps: 35 | - name: Checkout repository 36 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 37 | 38 | - name: Setup Golang Environment 39 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 40 | with: 41 | go-version: ${{ env.go-version }} 42 | 43 | - name: Generate 44 | run: make generate && git diff --exit-code 45 | 46 | lint: 47 | name: Lint 48 | runs-on: ubuntu-24.04 49 | timeout-minutes: 5 50 | steps: 51 | - name: Checkout repository 52 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 53 | 54 | - name: Lint Go 55 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 56 | with: 57 | version: latest 58 | 59 | build: 60 | name: Build 61 | runs-on: ubuntu-24.04 62 | timeout-minutes: 5 63 | steps: 64 | - name: Checkout repository 65 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 66 | 67 | - name: Setup Golang Environment 68 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 69 | with: 70 | go-version: ${{ env.go-version }} 71 | 72 | - name: Build 73 | run: make build 74 | 75 | unit-tests: 76 | name: Unit tests 77 | runs-on: ubuntu-24.04 78 | timeout-minutes: 10 79 | steps: 80 | - name: Checkout repository 81 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 82 | 83 | - name: Setup Golang Environment 84 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 85 | with: 86 | go-version: ${{ env.go-version }} 87 | 88 | - name: Run unit tests 89 | run: make test-unit 90 | 91 | e2e-tests: 92 | name: E2E tests 93 | runs-on: ubuntu-24.04 94 | timeout-minutes: 30 95 | steps: 96 | - name: Checkout repository 97 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 98 | 99 | - name: Setup Golang Environment 100 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 101 | with: 102 | go-version: ${{ env.go-version }} 103 | 104 | - name: Start kind & create cluster 105 | uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0 106 | with: 107 | version: ${{ env.kind-version }} 108 | config: test/e2e/kind-config/kind-config.yaml 109 | cluster_name: kind 110 | wait: 300s 111 | 112 | - name: Wait for cluster to finish bootstraping 113 | run: kubectl wait --for=condition=Ready pods --all --all-namespaces --timeout=300s 114 | 115 | - name: Create container & run tests 116 | run: | 117 | VERSION=local VERSION_SEMVER=$(cat ./VERSION) make container 118 | kind load docker-image ${QUAY_PATH}:local 119 | until docker exec $(kind get nodes) crictl images | grep "${QUAY_PATH}"; do 120 | echo "no kube-rbac-proxy image" 121 | sleep 1 122 | done 123 | make test-e2e 124 | 125 | publish: 126 | name: Publish container image to Quay 127 | runs-on: ubuntu-24.04 128 | timeout-minutes: 20 129 | if: ${{ github.event.repository.fork == false && github.event_name == 'push' }} 130 | needs: 131 | - check-license 132 | - generate 133 | - build 134 | - unit-tests 135 | - e2e-tests 136 | steps: 137 | - name: Checkout repository 138 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # 5.0.0 139 | 140 | - name: Setup Golang Environment 141 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 142 | with: 143 | go-version: ${{ env.go-version }} 144 | 145 | - name: Login to Quay.io 146 | uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0 147 | with: 148 | registry: quay.io 149 | username: ${{ secrets.QUAY_USERNAME }} 150 | password: ${{ secrets.QUAY_PASSWORD }} 151 | 152 | - name: Build images and push 153 | run: ./scripts/publish.sh 154 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _output/ 2 | manifest-tool 3 | .idea/* 4 | .vscode 5 | tmp 6 | -------------------------------------------------------------------------------- /.golangci.yaml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | exclusions: 4 | generated: lax 5 | presets: 6 | - comments 7 | - common-false-positives 8 | - legacy 9 | - std-error-handling 10 | paths: 11 | - test/ 12 | - third_party$ 13 | - builtin$ 14 | - examples$ 15 | formatters: 16 | exclusions: 17 | generated: lax 18 | paths: 19 | - third_party$ 20 | - builtin$ 21 | - examples$ 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.20.0 / 2025-09-18 4 | 5 | - ENHANCEMENT Major Kubernetes bump 6 | - ENHANCEMENT Bump all other dependencies to satisfy corp CVE scanners 7 | 8 | ## 0.19.1 / 2025-04-23 9 | 10 | - [ENHANCEMENT] Bump deps 11 | - [BUGFIX] Fix nil-pointer dereference in OIDC authenticator 12 | 13 | ## 0.19.0 / 2025-02-14 14 | 15 | - [ENHANCEMENT] Bump deps 16 | - [ENHANCEMENT] OIDC authenticator defaults to using host's root CA pool if CA file is not provided 17 | 18 | ## 0.18.2 / 2024-11-29 19 | 20 | - [BUGFIX] Mask tokens even in the high verbosity in logs 21 | - [ENHANCEMENT] Bump deps 22 | 23 | ## 0.18.1 / 2024-06-05 24 | 25 | - [ENHANCEMENT] Bump deps, in particular go-jose and golang (->CVE) and k8s (v1.31) 26 | 27 | ## 0.18.0 / 2024-06-05 28 | 29 | - [ENHANCEMENT] Bump deps, in particular otel (>CVE) and k8s (v1.30) 30 | - [ENHANCEMENT] Add OIDC username prefix, which was missing 31 | 32 | ## 0.17.1 / 2024-05-07 33 | 34 | - [BUGFIX] make deprecated (usptream removed) flags behave like before 35 | 36 | ## 0.17.0 / 2024-02-08 37 | 38 | - [ENHANCEMENT] add command-line args --kube-api-qps/--kube-api-burst 39 | - [ENHANCEMENT] Bump deps 40 | 41 | ## 0.16.0 / 2024-02-08 42 | 43 | - [ENHANCEMENT] Bump dependencies and in particular to kubernetes to v1.28 44 | - [CHANGE] Due to the bump to k8s v1.28 some logging flags are disabled 45 | 46 | ## 0.15.0 / 2023-10-20 47 | 48 | - [ENHANCEMENT] bump opentelemetry to fix CVE 49 | - [ENHANCEMENT] add option to disable HTTP/2: `--http2-disable` (default: `false`) 50 | - [ENHANCEMENT] add option to fine-tune HTTP/2: 51 | - `--http2-max-size` (default: 256kb) 52 | - `--http2-max-concurrent-streams` (default: 100) 53 | 54 | ## 0.14.4 / 2023-10-16 55 | 56 | - [ENHANCEMENT] bump golang and x/net 57 | 58 | ## 0.14.3 / 2023-09-07 59 | 60 | - [BUGFIX] `--version` returns now the proper kube-rbac-proxy version 61 | - [ENHANCEMENT] bump dependencies 62 | 63 | ## 0.14.2 / 2023-06-05 64 | 65 | - [ENHANCEMENT] bump dependencies 66 | - [ENHANCEMENT] Makefile, Dockerfile to work better with different architectures 67 | 68 | ## 0.14.1 / 2023-04-06 69 | 70 | - [ENHANCEMENT] bump dependencies 71 | 72 | ## 0.14.0 / 2022-12-15 73 | 74 | - [ENHANCEMENT] `README.md` now contains information about the future outlook of the project wrt to deprecations, features and K8s Sig-Auth acceptance 75 | - [ENHANCEMENT] bump dependencies 76 | - [FEATURE] health endpoint `/healthz` offered on `--proxy-endpoints-port` 77 | - [FEATURE] `--upstream-client-cert-file` enables the kube-rbac-proxy client connecting to upstream to use TLS 78 | - [CHANGE] use cobra and usptream command machinery, introduces deprecation to some flags 79 | 80 | ## 0.13.1 / 2022-10-04 81 | 82 | - [ENHANCEMENT] bump k8s to 1.25.2 #200 (contains fixes for CVEs) 83 | - [ENHANCEMENT] bump Go to 1.19.1 #178 (contains fixes for CVEs) 84 | - [ENHANCEMENT] bump golang.org/x/crypto due to CVE-2022-27191 #188 85 | - [CHANGE] add warning messages for features that will be removed 86 | 87 | ## 0.13.0 / 2022-06-29 88 | 89 | - [ENHANCEMENT] bump k8s to 1.24.2 #178 90 | - [ENHANCEMENT] bump Go to 1.18.3 #178 91 | - [ENHANCEMENT] update README.md to be more accurate and up to date #178, #173 92 | - [ENHANCEMENT] check all headers for rewrites and create additional authz requests #171 93 | 94 | ## 0.12.0 / 2022-04-08 95 | 96 | - [ENHANCEMENT] bump k8s to 1.23.5. #149, #155, #160 97 | - [ENHANCEMENT] add release documentation, #156 98 | - [ENHANCEMENT] use supported apiVersion for deployment and authorization. #150 99 | - [BUGFIX] ppc64le image build which in turn fixed multi-arch build. #147 100 | - [ENHANCEMENT] Support building on riscv64 architecture. #141 101 | - [ENHANCEMENT] move --upstream-force-h2c out of --insecure-listen-address. #140 102 | 103 | ## 0.11.0 / 2021-08-02 104 | 105 | - [FEATURE] Support for path patterns in --allow-paths and --ignore-paths. #135 106 | - [ENHANCEMENT] Dynamically reload client CA. #127 107 | - [BUGFIX] Fix panics on client-cert authenticated requests. #132 108 | 109 | ## 0.10.0 / 2021-05-07 110 | 111 | - [FEATURE] Support local static authorizer. #125 112 | 113 | ## 0.9.0 / 2021-04-27 114 | 115 | - [FEATURE] Support rewrites using HTTP headers in addition to query parameters. #104 116 | - [FEATURE] Support pass-through of client certificates. #113 117 | - [FEATURE] Support TLS 1.3. #120 118 | 119 | ## 0.8.0 / 2020-11-03 120 | 121 | - [FEATURE] Add ability with the new `--ignore-paths` flag to define paths for which kube-rbac-proxy will proxy without performing authn/authz. This cannot be used with `--allow-paths`. #91 122 | 123 | ## 0.7.0 / 2020-09-15 124 | 125 | - [CHANGE] Make images rootless. #86 126 | - [FEATURE] Add ability to check for allowed request paths with new `--allow-paths` config option. #83 127 | 128 | ## 0.6.0 / 2020-06-11 129 | 130 | - [CHANGE] Use gcr.io/distroless/static as base image instead of alpine. #67 131 | - [ENHANCEMENT] Add multi-arch container images for amd64, arm, arm64, ppc64le and s390x. #67 132 | 133 | ## 0.5.0 / 2020-02-17 134 | 135 | - [CHANGE] Move from glog to klog for logging. #57 136 | - [FEATURE] Support token audience reviews. #56 137 | - [FEATURE] Support custom upstream CAs. #34 138 | - [ENHANCEMENT] Reload TLS certificates at runtime. #47 139 | - [ENHANCEMENT] Add host in self-signed certs. #43 140 | 141 | ## 0.4.1 / 2019-01-23 142 | 143 | - [ENHANCEMENT] Use golang.org/x/net http2 server. #29 144 | - [ENHANCEMENT] Update Kubernetes to 1.13.2 #28 145 | - [ENHANCEMENT] Make multi-arch builds possible. #21 146 | - [BUGFIX] Log when server isn't able to start. #27 147 | - [BUGFIX] Set user specified TLS configuration when explicit TLS certificates are provided. 148 | 149 | ## 0.4.0 / 2018-10-24 150 | 151 | - [CHANGE] The config file flag has been renamed to `--config-file`. 152 | - [CHANGE] There is a breaking change in the configuration. All configuration that was previously valid, is now nested in `.authorization.resourceAttributes`. 153 | - [FEATURE] Add OIDC token authentication provider (note: this is not a client code flow for client authentication). 154 | - [FEATURE] Add ability to rewrite SubjectAccessReviews based on request query parameters. 155 | 156 | ## 0.3.1 / 2018-06-20 157 | 158 | This release is unmodified code from v0.3.0, but built with latest golang. 159 | 160 | - [BUGFIX] Fix `x509: cannot parse dnsName` in intermediate certificates. 161 | 162 | ## 0.3.0 / 2018-03-27 163 | 164 | - [FEATURE] Add HTTP/2 support. 165 | - [ENHANCEMENT] Add ability to choose TLS cipher suites. 166 | - [ENHANCEMENT] Add ability to choose minimum TLS version and default to TLS 1.2. 167 | 168 | ## 0.2.0 / 2018-01-03 169 | 170 | - [CHANGE] `--listen-address` flag renamed to `--insecure-listen-address`. 171 | - [FEATURE] Add TLS support. 172 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG GOARCH=amd64 2 | 3 | ARG BASEIMAGE=gcr.io/distroless/static:nonroot-$GOARCH 4 | FROM $BASEIMAGE 5 | 6 | ARG GOARCH 7 | ARG GOOS=linux 8 | ARG BINARY=kube-rbac-proxy-$GOOS-$GOARCH 9 | COPY _output/$BINARY /usr/local/bin/kube-rbac-proxy 10 | EXPOSE 8080 11 | USER 65532:65532 12 | 13 | ENTRYPOINT ["/usr/local/bin/kube-rbac-proxy"] 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: check-license build generate test 2 | 3 | GO111MODULE=on 4 | export GO111MODULE 5 | 6 | PROGRAM_NAME?=kube-rbac-proxy 7 | GITHUB_URL=github.com/brancz/kube-rbac-proxy 8 | GOOS?=$(shell uname -s | tr A-Z a-z) 9 | GOARCH?=$(shell go env GOARCH) 10 | BASEIMAGE?=gcr.io/distroless/static:nonroot-$(GOARCH) 11 | OUT_DIR=_output 12 | VERSION?=$(shell cat VERSION)-$(shell git rev-parse --short HEAD) 13 | VERSION_SEMVER?=$(shell echo $(VERSION) | grep -o 'v[0-9]\+\.[0-9]\+\.[0-9]\+') 14 | PKGS=$(shell go list ./... | grep -v /test/e2e) 15 | DOCKER_REPO?=quay.io/brancz/kube-rbac-proxy 16 | KUBECONFIG?=$(HOME)/.kube/config 17 | CONTAINER_NAME?=$(DOCKER_REPO):$(VERSION) 18 | 19 | ALL_ARCH=amd64 arm arm64 ppc64le s390x 20 | ALL_PLATFORMS=$(addprefix linux/,$(ALL_ARCH)) 21 | ALL_BINARIES ?= $(addprefix $(OUT_DIR)/$(PROGRAM_NAME)-, \ 22 | $(addprefix linux-,$(ALL_ARCH)) \ 23 | darwin-amd64 \ 24 | windows-amd64.exe) 25 | 26 | TOOLS_BIN_DIR?=$(shell pwd)/tmp/bin 27 | export PATH := $(TOOLS_BIN_DIR):$(PATH) 28 | 29 | EMBEDMD_BINARY=$(TOOLS_BIN_DIR)/embedmd 30 | TOOLING=$(EMBEDMD_BINARY) 31 | 32 | check-license: 33 | @echo ">> checking license headers" 34 | @./scripts/check_license.sh 35 | 36 | crossbuild: $(ALL_BINARIES) 37 | 38 | $(OUT_DIR)/$(PROGRAM_NAME): $(OUT_DIR)/$(PROGRAM_NAME)-$(GOOS)-$(GOARCH) 39 | cp $(OUT_DIR)/$(PROGRAM_NAME)-$(GOOS)-$(GOARCH) $(OUT_DIR)/$(PROGRAM_NAME) 40 | 41 | $(OUT_DIR)/$(PROGRAM_NAME)-%: 42 | @echo ">> building for $(GOOS)/$(GOARCH) to $(OUT_DIR)/$(PROGRAM_NAME)-$*" 43 | GOARCH=$(word 2,$(subst -, ,$(*:.exe=))) \ 44 | GOOS=$(word 1,$(subst -, ,$(*:.exe=))) \ 45 | CGO_ENABLED=0 \ 46 | go build --installsuffix cgo -ldflags="-X k8s.io/component-base/version.gitVersion=$(VERSION_SEMVER) -X k8s.io/component-base/version.gitCommit=$(shell git rev-parse HEAD) -X k8s.io/component-base/version/verflag.programName=$(PROGRAM_NAME)" -o $(OUT_DIR)/$(PROGRAM_NAME)-$* $(GITHUB_URL)/cmd/kube-rbac-proxy 47 | 48 | clean: 49 | -rm -r $(OUT_DIR) 50 | 51 | build: clean $(OUT_DIR)/$(PROGRAM_NAME) 52 | 53 | update-go-deps: 54 | @for m in $$(go list -mod=readonly -m -f '{{ if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all); do \ 55 | go get -u $$m; \ 56 | done 57 | go mod tidy 58 | 59 | container: $(OUT_DIR)/$(PROGRAM_NAME)-$(GOOS)-$(GOARCH) Dockerfile 60 | docker build --build-arg BINARY=$(PROGRAM_NAME)-$(GOOS)-$(GOARCH) --build-arg GOARCH=$(GOARCH) --build-arg BASEIMAGE=$(BASEIMAGE) -t $(CONTAINER_NAME)-$(GOARCH) . 61 | ifeq ($(GOARCH), amd64) 62 | docker tag $(DOCKER_REPO):$(VERSION)-$(GOARCH) $(CONTAINER_NAME) 63 | endif 64 | 65 | manifest-tool: 66 | curl -fsSL https://github.com/estesp/manifest-tool/releases/download/v1.0.2/manifest-tool-linux-amd64 > ./manifest-tool 67 | chmod +x ./manifest-tool 68 | 69 | push-%: 70 | $(MAKE) GOARCH=$* container 71 | docker push $(DOCKER_REPO):$(VERSION)-$* 72 | 73 | comma:= , 74 | empty:= 75 | space:= $(empty) $(empty) 76 | manifest-push: manifest-tool 77 | ./manifest-tool push from-args --platforms $(subst $(space),$(comma),$(ALL_PLATFORMS)) --template $(DOCKER_REPO):$(VERSION)-ARCH --target $(DOCKER_REPO):$(VERSION) 78 | 79 | push: crossbuild manifest-tool $(addprefix push-,$(ALL_ARCH)) manifest-push 80 | 81 | curl-container: 82 | docker build -f ./examples/example-client/Dockerfile -t quay.io/brancz/krp-curl:v0.0.2 . 83 | 84 | run-curl-container: 85 | @echo 'Example: curl -v -s -k -H "Authorization: Bearer `cat /var/run/secrets/kubernetes.io/serviceaccount/token`" https://kube-rbac-proxy.default.svc:8443/metrics' 86 | kubectl run -i -t krp-curl --image=quay.io/brancz/krp-curl:v0.0.2 --restart=Never --command -- /bin/sh 87 | 88 | grpcc-container: 89 | docker build -f ./examples/grpcc/Dockerfile -t mumoshu/grpcc:v0.0.1 . 90 | 91 | test-container: $(OUT_DIR)/$(PROGRAM_NAME)-linux-$(GOARCH) Dockerfile 92 | docker build --build-arg BINARY=$(PROGRAM_NAME)-linux-$(GOARCH) --build-arg BASEIMAGE=$(BASEIMAGE) -t $(CONTAINER_NAME) . 93 | 94 | test: test-unit test-e2e 95 | 96 | test-unit: 97 | go test -v -race -count=1 $(PKGS) 98 | 99 | test-e2e: 100 | go test -timeout 55m -v ./test/e2e/ $(TEST_RUN_ARGS) 101 | 102 | test-local-setup: VERSION = local 103 | test-local-setup: VERSION_SEMVER = $(shell cat VERSION) 104 | test-local-setup: clean test-container kind-create-cluster 105 | test-local: test-local-setup test 106 | 107 | kind-delete-cluster: 108 | kind delete cluster 109 | 110 | kind-create-cluster: kind-delete-cluster 111 | kind create cluster --config ./test/e2e/kind-config/kind-config.yaml 112 | kind load docker-image $(CONTAINER_NAME) 113 | 114 | generate: build $(EMBEDMD_BINARY) 115 | @echo ">> generating examples" 116 | @./scripts/generate-examples.sh 117 | @echo ">> generating docs" 118 | @./scripts/generate-help-txt.sh 119 | @$(EMBEDMD_BINARY) -w `find ./ -name "*.md" -print` 120 | 121 | $(TOOLS_BIN_DIR): 122 | @mkdir -p $(TOOLS_BIN_DIR) 123 | 124 | $(TOOLING): $(TOOLS_BIN_DIR) 125 | @echo Installing tools from scripts/tools.go 126 | @cat scripts/tools.go | grep _ | awk -F'"' '{print $$2}' | GOBIN=$(TOOLS_BIN_DIR) xargs -tI % go install -mod=readonly -modfile=scripts/go.mod % 127 | 128 | .PHONY: all check-license crossbuild build container push push-% manifest-push curl-container test test-unit test-e2e generate update-go-deps clean kind-delete-cluster kind-create-cluster 129 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | v0.20.0 2 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/app/kube-rbac-proxy_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package app 18 | 19 | import ( 20 | "os" 21 | "path/filepath" 22 | "reflect" 23 | "testing" 24 | 25 | "github.com/brancz/kube-rbac-proxy/pkg/authz" 26 | "github.com/google/go-cmp/cmp" 27 | ) 28 | 29 | func Test_parseAuthorizationConfigFile(t *testing.T) { 30 | tmpDir := t.TempDir() 31 | filePath := filepath.Join(tmpDir, "configfile.yaml") 32 | 33 | tests := []struct { 34 | name string 35 | fileContent string 36 | want *authz.Config 37 | wantErr bool 38 | }{ 39 | { 40 | name: "resources", 41 | fileContent: `authorization: 42 | rewrites: 43 | byQueryParameter: 44 | name: "namespace" 45 | resourceAttributes: 46 | resource: namespaces 47 | subresource: metrics 48 | namespace: "{{ .Value }}" 49 | static: 50 | - user: 51 | name: system:serviceaccount:default:default 52 | resourceRequest: true 53 | resource: namespaces 54 | subresource: metrics 55 | namespace: default 56 | verb: get`, 57 | want: &authz.Config{ 58 | Rewrites: &authz.SubjectAccessReviewRewrites{ 59 | ByQueryParameter: &authz.QueryParameterRewriteConfig{ 60 | Name: "namespace", 61 | }, 62 | }, 63 | ResourceAttributes: &authz.ResourceAttributes{ 64 | Resource: "namespaces", 65 | Subresource: "metrics", 66 | Namespace: "{{ .Value }}", 67 | }, 68 | Static: []authz.StaticAuthorizationConfig{ 69 | { 70 | User: authz.UserConfig{ 71 | Name: "system:serviceaccount:default:default", 72 | }, 73 | ResourceRequest: true, 74 | Resource: "namespaces", 75 | Subresource: "metrics", 76 | Namespace: "default", 77 | Verb: "get", 78 | }, 79 | }, 80 | }, 81 | }, 82 | { 83 | name: "non-resources", 84 | fileContent: `authorization: 85 | static: 86 | - user: 87 | name: system:serviceaccount:default:default 88 | resourceRequest: false 89 | verb: get 90 | path: /metrics`, 91 | want: &authz.Config{ 92 | Static: []authz.StaticAuthorizationConfig{ 93 | { 94 | User: authz.UserConfig{ 95 | Name: "system:serviceaccount:default:default", 96 | }, 97 | ResourceRequest: false, 98 | Verb: "get", 99 | Path: "/metrics", 100 | }, 101 | }, 102 | }, 103 | }, 104 | } 105 | for _, tt := range tests { 106 | t.Run(tt.name, func(t *testing.T) { 107 | if err := os.WriteFile(filePath, []byte(tt.fileContent), 0666); err != nil { 108 | t.Fatalf("failed to write file: %v", err) 109 | } 110 | 111 | got, err := parseAuthorizationConfigFile(filePath) 112 | if (err != nil) != tt.wantErr { 113 | t.Errorf("parseAuthorizationConfigFile() error = %v, wantErr %v", err, tt.wantErr) 114 | return 115 | } 116 | if !reflect.DeepEqual(got, tt.want) { 117 | t.Errorf("parseAuthorizationConfigFile(): %s", cmp.Diff(got, tt.want)) 118 | } 119 | }) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/app/options/deprecated.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package options 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/spf13/pflag" 23 | "k8s.io/klog/v2" 24 | ) 25 | 26 | var disabledFlagsType = map[string]string{ 27 | "logtostderr": "bool", 28 | "add-dir-header": "bool", 29 | "alsologtostderr": "bool", 30 | "log-backtrace-at": "string", 31 | "log-dir": "string", 32 | "log-file": "string", 33 | "log-file-max-size": "uint64", 34 | "one-output": "bool", 35 | "skip-headers": "bool", 36 | "skip-log-headers": "bool", 37 | "stderrthreshold": "string", 38 | } 39 | 40 | func (o *ProxyRunOptions) addDisabledFlags(flagset *pflag.FlagSet) { 41 | // disabled flags 42 | o.flagSet = flagset // reference used for validation 43 | 44 | for name, typeStr := range disabledFlagsType { 45 | switch typeStr { 46 | case "bool": 47 | _ = flagset.Bool(name, false, "[DISABLED]") 48 | case "string": 49 | _ = flagset.String(name, "", "[DISABLED]") 50 | case "uint64": 51 | _ = flagset.Uint64(name, 0, "[DISABLED]") 52 | default: 53 | panic(fmt.Sprintf("unknown type %q", typeStr)) 54 | } 55 | 56 | if err := flagset.MarkHidden(name); err != nil { 57 | panic(err) 58 | } 59 | } 60 | } 61 | 62 | func (o *ProxyRunOptions) validateDisabledFlags() error { 63 | // Removed upstream flags shouldn't be use 64 | for disabledOpt := range disabledFlagsType { 65 | if flag := o.flagSet.Lookup(disabledOpt); flag.Changed { 66 | klog.Warningf(` 67 | ==== Removed Flag Warning ====================== 68 | 69 | %s is removed in the k8s upstream and has no effect any more. 70 | 71 | =============================================== 72 | `, disabledOpt) 73 | } 74 | } 75 | 76 | return nil 77 | } 78 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/app/sanitazion.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package app 18 | 19 | import ( 20 | "bytes" 21 | "encoding/json" 22 | v1 "k8s.io/api/authentication/v1" 23 | "strings" 24 | ) 25 | 26 | // SanitizingFilter implements the LogFilter interface from klog with custom functions to detect and mask tokens. 27 | type SanitizingFilter struct{} 28 | 29 | // Filter is the filter function for non-formatting logging functions of klog. 30 | func (sf *SanitizingFilter) Filter(args []interface{}) []interface{} { 31 | for i, v := range args { 32 | if strValue, ok := v.(string); ok { 33 | if strings.Contains(strValue, `"kind":"TokenReview"`) { 34 | args[i] = maskTokenInLog(strValue) 35 | } 36 | } 37 | } 38 | return args 39 | } 40 | 41 | // FilterF is the filter function for formatting logging functions of klog. 42 | func (sf *SanitizingFilter) FilterF(format string, args []interface{}) (string, []interface{}) { 43 | for i, v := range args { 44 | if strValue, ok := v.(string); ok { 45 | if strings.Contains(strValue, `"kind":"TokenReview"`) { 46 | args[i] = maskTokenInLog(strValue) 47 | } 48 | } 49 | } 50 | return format, args 51 | } 52 | 53 | // FilterS is the filter function for structured logging functions of klog. 54 | func (sf *SanitizingFilter) FilterS(msg string, keysAndValues []interface{}) (string, []interface{}) { 55 | for i, v := range keysAndValues { 56 | if strValue, ok := v.(string); ok { 57 | if strings.Contains(strValue, `"kind":"TokenReview"`) { 58 | keysAndValues[i] = maskTokenInLog(strValue) 59 | } 60 | } 61 | } 62 | return msg, keysAndValues 63 | } 64 | 65 | func maskTokenInLog(logStr string) string { 66 | var tokenReview v1.TokenReview 67 | if err := json.Unmarshal([]byte(logStr), &tokenReview); err != nil { 68 | return "" 69 | } 70 | 71 | if tokenReview.Spec.Token != "" { 72 | tokenReview.Spec.Token = "" 73 | } 74 | 75 | var buf bytes.Buffer 76 | encoder := json.NewEncoder(&buf) 77 | encoder.SetEscapeHTML(false) 78 | if err := encoder.Encode(tokenReview); err != nil { 79 | return "" 80 | } 81 | return buf.String() 82 | } 83 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/app/transport.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package app 18 | 19 | import ( 20 | "crypto/tls" 21 | "crypto/x509" 22 | "fmt" 23 | "net" 24 | "net/http" 25 | "time" 26 | ) 27 | 28 | func initTransport(upstreamCAPool *x509.CertPool, upstreamClientCertPath, upstreamClientKeyPath string) (http.RoundTripper, error) { 29 | if upstreamCAPool == nil { 30 | return http.DefaultTransport, nil 31 | } 32 | 33 | var certKeyPair tls.Certificate 34 | if len(upstreamClientCertPath) > 0 { 35 | var err error 36 | certKeyPair, err = tls.LoadX509KeyPair(upstreamClientCertPath, upstreamClientKeyPath) 37 | if err != nil { 38 | return nil, fmt.Errorf("failed to read upstream client cert/key: %w", err) 39 | } 40 | } 41 | 42 | // http.Transport sourced from go 1.10.7 43 | transport := &http.Transport{ 44 | Proxy: http.ProxyFromEnvironment, 45 | DialContext: (&net.Dialer{ 46 | Timeout: 30 * time.Second, 47 | KeepAlive: 30 * time.Second, 48 | DualStack: true, 49 | }).DialContext, 50 | MaxIdleConns: 100, 51 | IdleConnTimeout: 90 * time.Second, 52 | TLSHandshakeTimeout: 10 * time.Second, 53 | ExpectContinueTimeout: 1 * time.Second, 54 | TLSClientConfig: &tls.Config{ 55 | RootCAs: upstreamCAPool, 56 | }, 57 | } 58 | 59 | if certKeyPair.Certificate != nil { 60 | transport.TLSClientConfig.Certificates = []tls.Certificate{certKeyPair} 61 | } 62 | 63 | return transport, nil 64 | } 65 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/app/transport_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package app 17 | 18 | import ( 19 | "crypto/rand" 20 | "crypto/rsa" 21 | "crypto/tls" 22 | "crypto/x509" 23 | "crypto/x509/pkix" 24 | "encoding/pem" 25 | "fmt" 26 | "io" 27 | "math/big" 28 | "net" 29 | "net/http" 30 | "net/http/httputil" 31 | "os" 32 | "path/filepath" 33 | "testing" 34 | "time" 35 | 36 | certutil "k8s.io/client-go/util/cert" 37 | "k8s.io/client-go/util/keyutil" 38 | ) 39 | 40 | func TestInitTransportWithDefault(t *testing.T) { 41 | roundTripper, err := initTransport(nil, "", "") 42 | if err != nil { 43 | t.Errorf("want err to be nil, but got %v", err) 44 | return 45 | } 46 | if roundTripper == nil { 47 | t.Error("expected roundtripper, got nil") 48 | } 49 | } 50 | 51 | func TestInitTransportWithCustomCA(t *testing.T) { 52 | upstreamCAPEM, err := os.ReadFile("../../../test/ca.pem") 53 | if err != nil { 54 | t.Fatalf("failed to read '../../../test/ca.pem': %v", err) 55 | } 56 | 57 | upstreamCAPool := x509.NewCertPool() 58 | upstreamCAPool.AppendCertsFromPEM(upstreamCAPEM) 59 | 60 | roundTripper, err := initTransport(upstreamCAPool, "", "") 61 | if err != nil { 62 | t.Fatalf("want err to be nil, but got %v", err) 63 | } 64 | transport := roundTripper.(*http.Transport) 65 | if transport.TLSClientConfig.RootCAs == nil { 66 | t.Error("expected root CA to be set, got nil") 67 | } 68 | } 69 | 70 | func testHTTPHandler(w http.ResponseWriter, req *http.Request) { 71 | if len(req.TLS.PeerCertificates) > 0 { 72 | _, _ = w.Write([]byte("ok")) 73 | return 74 | } else { 75 | reqDump, _ := httputil.DumpRequest(req, false) 76 | resp := fmt.Sprintf("got request without client certificates:\n%s\n", reqDump) 77 | resp += fmt.Sprintf("TLS config: %#v\n", req.TLS) 78 | http.Error(w, resp, http.StatusBadRequest) 79 | } 80 | } 81 | 82 | func TestInitTransportWithClientCertAuth(t *testing.T) { 83 | tlsServer := http.Server{ 84 | Handler: http.HandlerFunc(testHTTPHandler), 85 | } 86 | 87 | cert, key, err := certutil.GenerateSelfSignedCertKey("127.0.0.1", nil, nil) 88 | if err != nil { 89 | t.Fatalf("failed to create a new serving cert: %v", err) 90 | } 91 | 92 | tlsCert, err := tls.X509KeyPair(cert, key) 93 | if err != nil { 94 | t.Fatalf("failed to load a new serving cert: %v", err) 95 | } 96 | 97 | clientCert, clientKey, clientCA, err := generateClientCert(t) 98 | if err != nil { 99 | t.Fatalf("failed to generate client cert: %v", err) 100 | } 101 | 102 | l, err := net.Listen("tcp", "127.0.0.1:0") 103 | if err != nil { 104 | t.Fatalf("failed to listen on secure address: %v", err) 105 | } 106 | defer l.Close() 107 | tlsListener := tls.NewListener(l, &tls.Config{ 108 | Certificates: []tls.Certificate{tlsCert}, 109 | ClientCAs: clientCA, 110 | ClientAuth: tls.RequireAndVerifyClientCert, 111 | }) 112 | defer tlsListener.Close() 113 | 114 | go func() { 115 | if err := tlsServer.Serve(tlsListener); err != nil { 116 | t.Logf("failed to run the test server: %v", err) 117 | } 118 | }() 119 | defer tlsServer.Close() 120 | 121 | tmpDir := t.TempDir() 122 | clientCertPath := filepath.Join(tmpDir, "client.crt") 123 | clientKeyPath := filepath.Join(tmpDir, "client.key") 124 | 125 | if err := certutil.WriteCert(clientCertPath, clientCert); err != nil { 126 | t.Fatalf("failed to write client cert: %v", err) 127 | } 128 | if err := keyutil.WriteKey(clientKeyPath, clientKey); err != nil { 129 | t.Fatalf("failed to write client key: %v", err) 130 | } 131 | 132 | serverCA := x509.NewCertPool() 133 | serverCA.AppendCertsFromPEM(cert) 134 | roundTripper, err := initTransport(serverCA, clientCertPath, clientKeyPath) 135 | if err != nil { 136 | t.Errorf("want err to be nil, but got %v", err) 137 | return 138 | } 139 | 140 | httpReq, err := http.NewRequest(http.MethodPost, fmt.Sprintf("https://127.0.0.1:%d", l.Addr().(*net.TCPAddr).Port), nil) 141 | if err != nil { 142 | t.Fatalf("failed to create an HTTP request: %v", err) 143 | } 144 | 145 | resp, err := roundTripper.RoundTrip(httpReq) 146 | if err != nil { 147 | t.Fatalf("request failed: %v", err) 148 | } 149 | defer resp.Body.Close() 150 | 151 | if resp.StatusCode != http.StatusOK { 152 | respBody, err := io.ReadAll(resp.Body) 153 | if err != nil { 154 | t.Logf("failed to read response body: %v", err) 155 | } 156 | t.Logf("response with failure logs:\n%s", respBody) 157 | t.Errorf("expected the response code to be '%d', but it is '%d'", http.StatusOK, resp.StatusCode) 158 | } 159 | } 160 | 161 | func generateClientCert(t *testing.T) ([]byte, []byte, *x509.CertPool, error) { 162 | t.Helper() 163 | 164 | privKey, err := rsa.GenerateKey(rand.Reader, 2048) 165 | if err != nil { 166 | return nil, nil, nil, fmt.Errorf("failed to generate private key: %v", err) 167 | } 168 | ca, err := certutil.NewSelfSignedCACert(certutil.Config{CommonName: "testing-ca"}, privKey) 169 | if err != nil { 170 | return nil, nil, nil, fmt.Errorf("failed to generate CA cert: %v", err) 171 | } 172 | 173 | privKeyClient, err := rsa.GenerateKey(rand.Reader, 2048) 174 | if err != nil { 175 | return nil, nil, nil, fmt.Errorf("failed to generate private key: %v", err) 176 | } 177 | 178 | certDER, err := x509.CreateCertificate(rand.Reader, 179 | &x509.Certificate{ 180 | Subject: pkix.Name{CommonName: "testing-client"}, 181 | SerialNumber: big.NewInt(15233), 182 | NotBefore: time.Now().Add(-5 * time.Second), 183 | NotAfter: time.Now().Add(1 * time.Minute), 184 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 185 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 186 | }, 187 | ca, privKeyClient.Public(), privKey, 188 | ) 189 | if err != nil { 190 | return nil, nil, nil, fmt.Errorf("failed to create a client cert: %v", err) 191 | } 192 | 193 | certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) 194 | 195 | caPool := x509.NewCertPool() 196 | caPool.AddCert(ca) 197 | 198 | privKeyPEM, err := keyutil.MarshalPrivateKeyToPEM(privKeyClient) 199 | if err != nil { 200 | return nil, nil, nil, fmt.Errorf("failed to encode private key to pem: %v", err) 201 | } 202 | 203 | return certPEM, privKeyPEM, caPool, nil 204 | } 205 | -------------------------------------------------------------------------------- /cmd/kube-rbac-proxy/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "os" 21 | 22 | "k8s.io/component-base/cli" 23 | 24 | "github.com/brancz/kube-rbac-proxy/cmd/kube-rbac-proxy/app" 25 | ) 26 | 27 | func main() { 28 | command := app.NewKubeRBACProxyCommand() 29 | code := cli.Run(command) 30 | os.Exit(code) 31 | } 32 | -------------------------------------------------------------------------------- /examples/example-client-http2/Dockerfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brancz/kube-rbac-proxy/b09fd1628faf7d33ee09b34bac2c404ec4e2856f/examples/example-client-http2/Dockerfile -------------------------------------------------------------------------------- /examples/example-client-urlquery/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.7 2 | 3 | RUN apk add --no-cache curl 4 | 5 | CMD 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 6 | -------------------------------------------------------------------------------- /examples/example-client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.12 2 | 3 | RUN apk add --no-cache curl 4 | 5 | CMD curl -v -s -k -H "Authorization: Bearer `cat /var/run/secrets/kubernetes.io/serviceaccount/token`" https://kube-rbac-proxy.default.svc:8443/metrics 6 | -------------------------------------------------------------------------------- /examples/grpcc/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.9.4-alpine 2 | 3 | RUN apk add --update --no-cache python 4 | 5 | # `yarn global add` is easier than `npm install -g` in this case due to the npm bug: 6 | # https://github.com/nodejs/docker-node/issues/423#issuecomment-306470507 7 | # To work-around the npm bug, we need to upgrade it like this: 8 | # https://github.com/me-ventures/angular-cli-docker/commit/3d40e583e865817831e93c55fab01cb6857a24c7 9 | # However, isn't it too much boiler-plate just for installing a single module? :) 10 | 11 | # RUN yarn global add grpcc 12 | 13 | # see https://github.com/njpatel/grpcc/pull/48 14 | RUN yarn global add https://github.com/njpatel/grpcc/archive/d82c570.tar.gz 15 | 16 | ADD https://raw.githubusercontent.com/njpatel/grpcc/master/test/test.proto /test.proto 17 | 18 | RUN apk add --update --no-cache nghttp2 19 | 20 | ENTRYPOINT ["grpcc"] 21 | -------------------------------------------------------------------------------- /examples/minikube-rbac/README.md: -------------------------------------------------------------------------------- 1 | # Minikube + RBAC 2 | 3 | To start [minikube](https://github.com/kubernetes/minikube) with RBAC enabled run it with the `--extra-config=apiserver.Authorization.Mode=RBAC` flag: 4 | 5 | ```bash 6 | $ minikube start --extra-config=apiserver.Authorization.Mode=RBAC 7 | Starting local Kubernetes v1.8.0 cluster... 8 | Starting VM... 9 | Getting VM IP address... 10 | Moving files into cluster... 11 | Setting up certs... 12 | Connecting to cluster... 13 | Setting up kubeconfig... 14 | Starting cluster components... 15 | Kubectl is now configured to use the cluster. 16 | Loading cached images from config file. 17 | ``` 18 | 19 | When minikube is started with this flag it does not handle RBAC for addons, so that needs to be fixed. 20 | 21 | ```bash 22 | $ kubectl apply -f minikube-rbac-fix.yaml 23 | clusterrole "cluster-writer" created 24 | clusterrole "cluster-reader" created 25 | clusterrolebinding "cluster-write" created 26 | clusterrolebinding "cluster-read" created 27 | rolebinding "sd-build-write" created 28 | ``` 29 | 30 | Ensure that everything is running as expected: 31 | 32 | ```bash 33 | $ kubectl get pods --namespace=kube-system 34 | NAME READY STATUS RESTARTS AGE 35 | kube-addon-manager-minikube 1/1 Running 0 8m 36 | kube-dns-86f6f55dd5-lncvt 3/3 Running 0 51s 37 | storage-provisioner 1/1 Running 0 8m 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /examples/minikube-rbac/minikube-rbac-fix.yaml: -------------------------------------------------------------------------------- 1 | # Wide open access to the cluster (mostly for kubelet) 2 | kind: ClusterRole 3 | apiVersion: rbac.authorization.k8s.io/v1 4 | metadata: 5 | name: cluster-writer 6 | rules: 7 | - apiGroups: ["*"] 8 | resources: ["*"] 9 | verbs: ["*"] 10 | - nonResourceURLs: ["*"] 11 | verbs: ["*"] 12 | 13 | --- 14 | 15 | # Full read access to the api and resources 16 | kind: ClusterRole 17 | apiVersion: rbac.authorization.k8s.io/v1 18 | metadata: 19 | name: cluster-reader 20 | rules: 21 | - apiGroups: ["*"] 22 | resources: ["*"] 23 | verbs: ["get", "list", "watch"] 24 | - nonResourceURLs: ["*"] 25 | verbs: ["*"] 26 | --- 27 | # Give admin, kubelet, kube-system, kube-proxy god access 28 | kind: ClusterRoleBinding 29 | apiVersion: rbac.authorization.k8s.io/v1 30 | metadata: 31 | name: cluster-write 32 | subjects: 33 | - kind: User 34 | name: admin 35 | - kind: User 36 | name: kubelet 37 | - kind: ServiceAccount 38 | name: default 39 | namespace: kube-system 40 | - kind: User 41 | name: kube-proxy 42 | roleRef: 43 | kind: ClusterRole 44 | name: cluster-writer 45 | apiGroup: rbac.authorization.k8s.io 46 | 47 | --- 48 | 49 | # Setup sd-build as a reader. This has to be a 50 | # ClusterRoleBinding to get access to non-resource URLs 51 | kind: ClusterRoleBinding 52 | apiVersion: rbac.authorization.k8s.io/v1 53 | metadata: 54 | name: cluster-read 55 | subjects: 56 | - kind: ServiceAccount 57 | name: sd-build 58 | namespace: default 59 | roleRef: 60 | kind: ClusterRole 61 | name: cluster-reader 62 | apiGroup: rbac.authorization.k8s.io 63 | 64 | --- 65 | 66 | # Setup sd-build as a writer in its namespace 67 | kind: RoleBinding 68 | apiVersion: rbac.authorization.k8s.io/v1 69 | metadata: 70 | name: sd-build-write 71 | subjects: 72 | - kind: ServiceAccount 73 | name: sd-build 74 | namespace: default 75 | roleRef: 76 | kind: ClusterRole 77 | name: cluster-writer 78 | apiGroup: rbac.authorization.k8s.io 79 | -------------------------------------------------------------------------------- /examples/non-resource-url-token-request/client-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: metrics 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: ClusterRole 16 | name: metrics 17 | subjects: 18 | - kind: ServiceAccount 19 | name: default 20 | namespace: default 21 | -------------------------------------------------------------------------------- /examples/non-resource-url-token-request/client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: krp-curl 5 | spec: 6 | template: 7 | metadata: 8 | name: krp-curl 9 | spec: 10 | restartPolicy: Never 11 | containers: 12 | - name: krp-curl 13 | image: quay.io/brancz/krp-curl:v0.0.2 14 | command: 15 | - /bin/sh 16 | - -c 17 | - 'curl -v -s -k -H "Authorization: Bearer `cat /service-account/token`" https://kube-rbac-proxy.default.svc:8443/metrics' 18 | volumeMounts: 19 | - name: token-vol 20 | mountPath: "/service-account" 21 | readOnly: true 22 | volumes: 23 | - name: token-vol 24 | projected: 25 | sources: 26 | - serviceAccountToken: 27 | audience: kube-rbac-proxy.default.svc 28 | expirationSeconds: 3600 29 | path: token 30 | backoffLimit: 4 31 | -------------------------------------------------------------------------------- /examples/non-resource-url-token-request/deployment.yaml: -------------------------------------------------------------------------------- 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: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: kube-rbac-proxy 51 | spec: 52 | replicas: 1 53 | selector: 54 | matchLabels: 55 | app: kube-rbac-proxy 56 | template: 57 | metadata: 58 | labels: 59 | app: kube-rbac-proxy 60 | spec: 61 | securityContext: 62 | runAsUser: 65532 63 | serviceAccountName: kube-rbac-proxy 64 | containers: 65 | - name: kube-rbac-proxy 66 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 67 | args: 68 | - "--secure-listen-address=0.0.0.0:8443" 69 | - "--upstream=http://127.0.0.1:8081/" 70 | - "--auth-token-audiences=kube-rbac-proxy.default.svc" 71 | - "--logtostderr=true" 72 | - "--v=10" 73 | ports: 74 | - containerPort: 8443 75 | name: https 76 | securityContext: 77 | allowPrivilegeEscalation: false 78 | - name: prometheus-example-app 79 | image: quay.io/brancz/prometheus-example-app:v0.5.0 80 | args: 81 | - "--bind=127.0.0.1:8081" 82 | -------------------------------------------------------------------------------- /examples/non-resource-url-token-request/kind-config.yaml: -------------------------------------------------------------------------------- 1 | # this config file contains all config fields with comments 2 | kind: Cluster 3 | apiVersion: kind.x-k8s.io/v1alpha4 4 | # patch the generated kubeadm config with some extra settings 5 | kubeadmConfigPatches: 6 | - | 7 | apiVersion: kubeadm.k8s.io/v1beta2 8 | kind: ClusterConfiguration 9 | metadata: 10 | name: config 11 | apiServer: 12 | extraArgs: 13 | service-account-signing-key-file: /etc/kubernetes/pki/sa.key 14 | service-account-issuer: kubernetes.default.svc 15 | v: "10" 16 | -------------------------------------------------------------------------------- /examples/non-resource-url-token-request/wrong-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: krp-wrong-token-curl 5 | spec: 6 | template: 7 | metadata: 8 | name: krp-wrong-token-curl 9 | spec: 10 | restartPolicy: Never 11 | containers: 12 | - name: krp-curl 13 | image: quay.io/brancz/krp-curl:v0.0.2 14 | -------------------------------------------------------------------------------- /examples/non-resource-url/README.md: -------------------------------------------------------------------------------- 1 | # non-resource-url example 2 | 3 | > Note to try this out with minikube, make sure you enable RBAC correctly as explained [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. A non-resource authorization validates, that an entity is authorized to request a bare URL. 6 | 7 | Take the following example. We want to deploy a [prometheus-example-app](https://github.com/brancz/prometheus-example-app), and protect its `/metrics` endpoint. This endpoint does not correspond to a resource, and is therefore treated as a non-resource-url in RBAC. For non-resource-url authorizations there are no extra arguments required to be passed to the kube-rbac-proxy besides the `--upstream` flag in order for it to perform the authorization. 8 | 9 | The kube-rbac-proxy itself also requires RBAC access, in order to perform TokenReviews as well as SubjectAccessReviews. 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: apps/v1 66 | kind: Deployment 67 | metadata: 68 | name: kube-rbac-proxy 69 | spec: 70 | replicas: 1 71 | selector: 72 | matchLabels: 73 | app: kube-rbac-proxy 74 | template: 75 | metadata: 76 | labels: 77 | app: kube-rbac-proxy 78 | spec: 79 | securityContext: 80 | runAsUser: 65532 81 | serviceAccountName: kube-rbac-proxy 82 | containers: 83 | - name: kube-rbac-proxy 84 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 85 | args: 86 | - "--secure-listen-address=0.0.0.0:8443" 87 | - "--upstream=http://127.0.0.1:8081/" 88 | - "--logtostderr=true" 89 | - "--v=10" 90 | ports: 91 | - containerPort: 8443 92 | name: https 93 | securityContext: 94 | allowPrivilegeEscalation: false 95 | - name: prometheus-example-app 96 | image: quay.io/brancz/prometheus-example-app:v0.5.0 97 | args: 98 | - "--bind=127.0.0.1:8081" 99 | ``` 100 | 101 | 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. 102 | 103 | The Dockerfile of this container can be found [here](../example-client/Dockerfile). 104 | 105 | ```bash 106 | $ kubectl create -f client-rbac.yaml client.yaml 107 | ``` 108 | 109 | The content of this manifest is: 110 | 111 | [embedmd]:# (./client-rbac.yaml) 112 | ```yaml 113 | apiVersion: rbac.authorization.k8s.io/v1 114 | kind: ClusterRole 115 | metadata: 116 | name: metrics 117 | rules: 118 | - nonResourceURLs: ["/metrics"] 119 | verbs: ["get"] 120 | --- 121 | apiVersion: rbac.authorization.k8s.io/v1 122 | kind: ClusterRoleBinding 123 | metadata: 124 | name: metrics 125 | roleRef: 126 | apiGroup: rbac.authorization.k8s.io 127 | kind: ClusterRole 128 | name: metrics 129 | subjects: 130 | - kind: ServiceAccount 131 | name: default 132 | namespace: default 133 | ``` 134 | 135 | [embedmd]:# (./client.yaml) 136 | ```yaml 137 | apiVersion: batch/v1 138 | kind: Job 139 | metadata: 140 | name: krp-curl 141 | spec: 142 | template: 143 | metadata: 144 | name: krp-curl 145 | spec: 146 | containers: 147 | - name: krp-curl 148 | image: quay.io/brancz/krp-curl:v0.0.2 149 | restartPolicy: Never 150 | backoffLimit: 4 151 | ``` 152 | 153 | We can look at the logs and we should get something similar to: 154 | 155 | ``` 156 | $ kubectl logs job/krp-curl 157 | * Trying 10.99.141.73... 158 | * TCP_NODELAY set 159 | * Connected to kube-rbac-proxy.default.svc (10.99.141.73) port 8080 (#0) 160 | > GET /metrics HTTP/1.1 161 | > Host: kube-rbac-proxy.default.svc:8080 162 | > User-Agent: curl/7.57.0 163 | > Accept: */* 164 | > Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNHBzeHYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjY2YTAzNTdiLWUzMmYtMTFlNy04YjIzLTA4MDAyNzhkNDA5OSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.egkmiNUcs8gB9I1EHPwdzr-xYjVK5dpd8OihPkMiM1DjRN7PoVVTWiM9IWBo2gZRGxV8ItpwCFDALs2Y85nfZk8l82YE6qHdQHG3-igqbiNNwRUIkVcpNpKmA-859LdC3C2ia0cnvll_ge1FlVOWMGH8rvSwD4-We2xbEwJ6djmBMF3iN6zHmeiom8WGKxoF3ddKoCKhLEN9pTiOVeXitWm6U2xEj_WyrMSpaIlfoT-BxNSOxTTPo5Nk71yM1bEzGb6jQdixOPsgHZP0nNxf9tmWnyb9qjBOPzObze9GHAoJUx9a94rURR8Zpf6DgPtKMJxcNq2buI05RdBwCkfjug 165 | > 166 | < HTTP/1.1 200 OK 167 | < Content-Type: text/plain; version=0.0.4 168 | < Date: Sun, 17 Dec 2017 13:40:00 GMT 169 | < Content-Length: 102 170 | < 171 | { [102 bytes data] 172 | * Connection #0 to host kube-rbac-proxy.default.svc left intact 173 | # HELP version Version information about this binary 174 | # TYPE version gauge 175 | version{version="v0.1.0"} 0 176 | ``` 177 | 178 | -------------------------------------------------------------------------------- /examples/non-resource-url/client-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: metrics 13 | roleRef: 14 | apiGroup: rbac.authorization.k8s.io 15 | kind: ClusterRole 16 | name: metrics 17 | subjects: 18 | - kind: ServiceAccount 19 | name: default 20 | namespace: default 21 | -------------------------------------------------------------------------------- /examples/non-resource-url/client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: krp-curl 5 | spec: 6 | template: 7 | metadata: 8 | name: krp-curl 9 | spec: 10 | containers: 11 | - name: krp-curl 12 | image: quay.io/brancz/krp-curl:v0.0.2 13 | restartPolicy: Never 14 | backoffLimit: 4 15 | -------------------------------------------------------------------------------- /examples/non-resource-url/deployment.yaml: -------------------------------------------------------------------------------- 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: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: kube-rbac-proxy 51 | spec: 52 | replicas: 1 53 | selector: 54 | matchLabels: 55 | app: kube-rbac-proxy 56 | template: 57 | metadata: 58 | labels: 59 | app: kube-rbac-proxy 60 | spec: 61 | securityContext: 62 | runAsUser: 65532 63 | serviceAccountName: kube-rbac-proxy 64 | containers: 65 | - name: kube-rbac-proxy 66 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 67 | args: 68 | - "--secure-listen-address=0.0.0.0:8443" 69 | - "--upstream=http://127.0.0.1:8081/" 70 | - "--logtostderr=true" 71 | - "--v=10" 72 | ports: 73 | - containerPort: 8443 74 | name: https 75 | securityContext: 76 | allowPrivilegeEscalation: false 77 | - name: prometheus-example-app 78 | image: quay.io/brancz/prometheus-example-app:v0.5.0 79 | args: 80 | - "--bind=127.0.0.1:8081" 81 | -------------------------------------------------------------------------------- /examples/oidc/.gitignore: -------------------------------------------------------------------------------- 1 | ssl 2 | dex-tls-ca-secret.yaml 3 | dex-tls-secret.yaml 4 | -------------------------------------------------------------------------------- /examples/oidc/README.md: -------------------------------------------------------------------------------- 1 | # OIDC authentication 2 | 3 | Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac/README.md) 4 | 5 | Kubernetes supports OIDC authentication natively, configured via API server flags. In this case, a request contains the OIDC ID token in its bearer header. The token is then used for token review by the Kubernetes API. This already works with the existing kube-rbac-proxy functionality. The resulting metadata (user and/or group information) is then passed to the subject review Kubernetes API for authorization. 6 | 7 | If Kubernetes is not configured to use OIDC and changes to the API server are not possible (i.e. in 3rd party or restricted environments), kube-rbac-proxy can be configured to authenticate the request against OIDC itself. In this case, the token review functionality of Kubernetes is omitted. As above the resulting metadata is still passed to the subject review Kubernetes API for authorization. 8 | 9 | Like in other examples, `kube-rbac-proxy` also requires RBAC access to perform SubjectAccessReviews. 10 | 11 | ```bash 12 | $ kubectl create -f deployment.yaml 13 | ``` 14 | ```bash 15 | $ kubectl create -f configmap.yaml 16 | ``` 17 | 18 | ```bash 19 | $ kubectl create -f client-rbac.yaml 20 | ``` 21 | 22 | Note: The {ISSUER} and {CLIENT_ID} in the deployment have to be replaced with the issuer and client in the OIDC provider configuration. 23 | -------------------------------------------------------------------------------- /examples/oidc/client-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get", "list"] 8 | --- 9 | apiVersion: rbac.authorization.k8s.io/v1 10 | kind: ClusterRoleBinding 11 | metadata: 12 | name: metrics 13 | namespace: default 14 | roleRef: 15 | apiGroup: rbac.authorization.k8s.io 16 | kind: ClusterRole 17 | name: metrics 18 | subjects: 19 | - kind: User 20 | name: admin 21 | apiGroup: rbac.authorization.k8s.io 22 | -------------------------------------------------------------------------------- /examples/oidc/deployment.yaml: -------------------------------------------------------------------------------- 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 | namespace: default 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: kube-rbac-proxy 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kube-rbac-proxy 18 | namespace: default 19 | --- 20 | apiVersion: rbac.authorization.k8s.io/v1 21 | kind: ClusterRole 22 | metadata: 23 | name: kube-rbac-proxy 24 | rules: 25 | - apiGroups: ["authentication.k8s.io"] 26 | resources: 27 | - tokenreviews 28 | verbs: ["create"] 29 | - apiGroups: ["authorization.k8s.io"] 30 | resources: 31 | - subjectaccessreviews 32 | verbs: ["create"] 33 | --- 34 | apiVersion: v1 35 | kind: Service 36 | metadata: 37 | labels: 38 | app: kube-rbac-proxy 39 | name: kube-rbac-proxy 40 | spec: 41 | ports: 42 | - name: https 43 | port: 8444 44 | targetPort: https 45 | selector: 46 | app: kube-rbac-proxy 47 | --- 48 | apiVersion: apps/v1 49 | kind: Deployment 50 | metadata: 51 | name: kube-rbac-proxy 52 | spec: 53 | replicas: 1 54 | selector: 55 | matchLabels: 56 | app: kube-rbac-proxy 57 | template: 58 | metadata: 59 | labels: 60 | app: kube-rbac-proxy 61 | spec: 62 | # {BEGIN} for minikube development only if OIDC provider is deployed in minikube itself ie. dex 63 | hostNetwork: true 64 | dnsPolicy: ClusterFirstWithHostNet 65 | # {END} 66 | serviceAccountName: kube-rbac-proxy 67 | containers: 68 | - name: kube-rbac-proxy 69 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 70 | args: 71 | - "--insecure-listen-address=0.0.0.0:8444" 72 | - "--upstream=http://127.0.0.1:8081/" 73 | - "--logtostderr=true" 74 | - "--v=10" 75 | - "--oidc-issuer={ISSUER}" 76 | - "--oidc-clientID={CLIENT_ID}" 77 | ports: 78 | - containerPort: 8444 79 | name: https 80 | securityContext: 81 | allowPrivilegeEscalation: false 82 | - name: prometheus-example-app 83 | image: quay.io/brancz/prometheus-example-app:v0.5.0 84 | args: 85 | - "--bind=127.0.0.1:8081" 86 | -------------------------------------------------------------------------------- /examples/resource-attributes/README.md: -------------------------------------------------------------------------------- 1 | # resource-attributes example 2 | 3 | > Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac). 4 | 5 | RBAC differentiates in two types, that need to be authorized, resources and non-resoruces. 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 | Take the following example. We want to deploy a [prometheus-example-app](https://github.com/brancz/prometheus-example-app), and protect it with the kube-rbac-proxy. In this example we require a requesting entity to be allowed to call the `proxy` subresource on a Kubernetes Service called `kube-rbac-proxy`. 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. 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 | resourceAttributes: 73 | namespace: default 74 | apiVersion: v1 75 | resource: services 76 | subresource: proxy 77 | name: kube-rbac-proxy 78 | --- 79 | apiVersion: apps/v1 80 | kind: Deployment 81 | metadata: 82 | name: kube-rbac-proxy 83 | spec: 84 | replicas: 1 85 | selector: 86 | matchLabels: 87 | app: kube-rbac-proxy 88 | template: 89 | metadata: 90 | labels: 91 | app: kube-rbac-proxy 92 | spec: 93 | securityContext: 94 | runAsUser: 65532 95 | serviceAccountName: kube-rbac-proxy 96 | containers: 97 | - name: kube-rbac-proxy 98 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 99 | args: 100 | - "--secure-listen-address=0.0.0.0:8443" 101 | - "--upstream=http://127.0.0.1:8081/" 102 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 103 | - "--logtostderr=true" 104 | - "--v=10" 105 | ports: 106 | - containerPort: 8443 107 | name: https 108 | volumeMounts: 109 | - name: config 110 | mountPath: /etc/kube-rbac-proxy 111 | securityContext: 112 | allowPrivilegeEscalation: false 113 | - name: prometheus-example-app 114 | image: quay.io/brancz/prometheus-example-app:v0.5.0 115 | args: 116 | - "--bind=127.0.0.1:8081" 117 | volumes: 118 | - name: config 119 | configMap: 120 | name: kube-rbac-proxy 121 | ``` 122 | 123 | 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. 124 | 125 | The Dockerfile of this container can be found [here](../example-client/Dockerfile). 126 | 127 | ```bash 128 | $ kubectl create -f client-rbac.yaml client.yaml 129 | ``` 130 | 131 | The content of this manifest is: 132 | 133 | [embedmd]:# (./client-rbac.yaml) 134 | ```yaml 135 | apiVersion: rbac.authorization.k8s.io/v1 136 | kind: ClusterRole 137 | metadata: 138 | name: kube-rbac-proxy-client 139 | rules: 140 | - apiGroups: [""] 141 | resources: ["services/proxy"] 142 | verbs: ["get"] 143 | --- 144 | apiVersion: rbac.authorization.k8s.io/v1 145 | kind: ClusterRoleBinding 146 | metadata: 147 | name: kube-rbac-proxy-client 148 | roleRef: 149 | apiGroup: rbac.authorization.k8s.io 150 | kind: ClusterRole 151 | name: kube-rbac-proxy-client 152 | subjects: 153 | - kind: ServiceAccount 154 | name: default 155 | namespace: default 156 | ``` 157 | 158 | [embedmd]:# (./client.yaml) 159 | ```yaml 160 | apiVersion: batch/v1 161 | kind: Job 162 | metadata: 163 | name: krp-curl 164 | spec: 165 | template: 166 | metadata: 167 | name: krp-curl 168 | spec: 169 | containers: 170 | - name: krp-curl 171 | image: quay.io/brancz/krp-curl:v0.0.2 172 | restartPolicy: Never 173 | backoffLimit: 4 174 | ``` 175 | 176 | We can look at the logs and we should get something similar to: 177 | 178 | ``` 179 | $ kubectl logs job/krp-curl 180 | * Trying 10.111.34.206... 181 | * TCP_NODELAY set 182 | * Connected to kube-rbac-proxy.default.svc (10.111.34.206) port 8080 (#0) 183 | > GET /metrics HTTP/1.1 184 | > Host: kube-rbac-proxy.default.svc:8080 185 | > User-Agent: curl/7.57.0 186 | > Accept: */* 187 | > Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNHZxZGIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQwNzU4NDE3LWUzMmUtMTFlNy1hOTQ1LTA4MDAyNzg2NjgwMCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.eftzPb2rthIcW8Md4URFYpDhyEKuqepP7WKsWO25uBdWlN85TcPkeGSaRf7-dRp7ie5ADp-UgTZtI2lu6ssntmxsATeH_jE0zye6UlTqM-_2iLNLexgE29bYD8cqH5WMc7tE-y_Y0u0F3hjvURNvQycxfrGWICd1gNrk2jpxC6mAYVt3ldT5rylw0FWot7t8uDvorW6QScfvPPNmwh0hHsdvMuJ2e8lc9KDnTS-yRuQ1SmMNyc7L2JyZ7bphahNZNa8K7D3C1NOAmAQrDfBAr97peGbQ02yCc4hG_YQDyO2xMaQs_AFf38ZIiM-z7OnSQO4_D8FmkY2CG2jnd6ZXlw 188 | > 189 | < HTTP/1.1 200 OK 190 | < Content-Type: text/plain; version=0.0.4 191 | < Date: Sun, 17 Dec 2017 13:34:26 GMT 192 | < Content-Length: 102 193 | < 194 | { [102 bytes data] 195 | * Connection #0 to host kube-rbac-proxy.default.svc left intact 196 | # HELP version Version information about this binary 197 | # TYPE version gauge 198 | version{version="v0.1.0"} 0 199 | ``` 200 | 201 | -------------------------------------------------------------------------------- /examples/resource-attributes/client-rbac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy-client 5 | rules: 6 | - apiGroups: [""] 7 | resources: ["services/proxy"] 8 | verbs: ["get"] 9 | --- 10 | apiVersion: rbac.authorization.k8s.io/v1 11 | kind: ClusterRoleBinding 12 | metadata: 13 | name: kube-rbac-proxy-client 14 | roleRef: 15 | apiGroup: rbac.authorization.k8s.io 16 | kind: ClusterRole 17 | name: kube-rbac-proxy-client 18 | subjects: 19 | - kind: ServiceAccount 20 | name: default 21 | namespace: default 22 | -------------------------------------------------------------------------------- /examples/resource-attributes/client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: krp-curl 5 | spec: 6 | template: 7 | metadata: 8 | name: krp-curl 9 | spec: 10 | containers: 11 | - name: krp-curl 12 | image: quay.io/brancz/krp-curl:v0.0.2 13 | restartPolicy: Never 14 | backoffLimit: 4 15 | -------------------------------------------------------------------------------- /examples/resource-attributes/deployment.yaml: -------------------------------------------------------------------------------- 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 | resourceAttributes: 55 | namespace: default 56 | apiVersion: v1 57 | resource: services 58 | subresource: proxy 59 | name: kube-rbac-proxy 60 | --- 61 | apiVersion: apps/v1 62 | kind: Deployment 63 | metadata: 64 | name: kube-rbac-proxy 65 | spec: 66 | replicas: 1 67 | selector: 68 | matchLabels: 69 | app: kube-rbac-proxy 70 | template: 71 | metadata: 72 | labels: 73 | app: kube-rbac-proxy 74 | spec: 75 | securityContext: 76 | runAsUser: 65532 77 | serviceAccountName: kube-rbac-proxy 78 | containers: 79 | - name: kube-rbac-proxy 80 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 81 | args: 82 | - "--secure-listen-address=0.0.0.0:8443" 83 | - "--upstream=http://127.0.0.1:8081/" 84 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 85 | - "--logtostderr=true" 86 | - "--v=10" 87 | ports: 88 | - containerPort: 8443 89 | name: https 90 | volumeMounts: 91 | - name: config 92 | mountPath: /etc/kube-rbac-proxy 93 | securityContext: 94 | allowPrivilegeEscalation: false 95 | - name: prometheus-example-app 96 | image: quay.io/brancz/prometheus-example-app:v0.5.0 97 | args: 98 | - "--bind=127.0.0.1:8081" 99 | volumes: 100 | - name: config 101 | configMap: 102 | name: kube-rbac-proxy 103 | -------------------------------------------------------------------------------- /examples/rewrites/README.md: -------------------------------------------------------------------------------- 1 | # rewriting SubjectAccessReviews example 2 | 3 | > Note to try this out with minikube, make sure you enable RBAC correctly as explained [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 | Take the following example. We want to deploy a [prometheus-example-app](https://github.com/brancz/prometheus-example-app), and protect it with the kube-rbac-proxy. In this example we require a requesting entity to be allowed to call the `metrics` subresource on a Kubernetes Namespace, the name of which is passed by the HTTP URL query parameter `namespace`. 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. 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 | --- 81 | apiVersion: apps/v1 82 | kind: Deployment 83 | metadata: 84 | name: kube-rbac-proxy 85 | spec: 86 | replicas: 1 87 | selector: 88 | matchLabels: 89 | app: kube-rbac-proxy 90 | template: 91 | metadata: 92 | labels: 93 | app: kube-rbac-proxy 94 | spec: 95 | securityContext: 96 | runAsUser: 65532 97 | serviceAccountName: kube-rbac-proxy 98 | containers: 99 | - name: kube-rbac-proxy 100 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 101 | args: 102 | - "--secure-listen-address=0.0.0.0:8443" 103 | - "--upstream=http://127.0.0.1:8081/" 104 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 105 | - "--logtostderr=true" 106 | - "--v=10" 107 | ports: 108 | - containerPort: 8443 109 | name: https 110 | volumeMounts: 111 | - name: config 112 | mountPath: /etc/kube-rbac-proxy 113 | securityContext: 114 | allowPrivilegeEscalation: false 115 | - name: prometheus-example-app 116 | image: quay.io/brancz/prometheus-example-app:v0.5.0 117 | args: 118 | - "--bind=127.0.0.1:8081" 119 | volumes: 120 | - name: config 121 | configMap: 122 | name: kube-rbac-proxy 123 | ``` 124 | 125 | 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. 126 | 127 | The Dockerfile of this container can be found [here](../example-client-urlquery/Dockerfile). 128 | 129 | ```bash 130 | $ kubectl create -f client-rbac.yaml 131 | ``` 132 | 133 | The content of this manifest is: 134 | 135 | [embedmd]:# (./client-rbac.yaml) 136 | ```yaml 137 | apiVersion: rbac.authorization.k8s.io/v1 138 | kind: RoleBinding 139 | metadata: 140 | name: namespace-metrics 141 | roleRef: 142 | apiGroup: rbac.authorization.k8s.io 143 | kind: Role 144 | name: namespace-metrics 145 | subjects: 146 | - kind: ServiceAccount 147 | name: default 148 | namespace: default 149 | --- 150 | apiVersion: rbac.authorization.k8s.io/v1 151 | kind: Role 152 | metadata: 153 | name: namespace-metrics 154 | rules: 155 | - apiGroups: [""] 156 | resources: 157 | - namespace/metrics 158 | verbs: ["get"] 159 | ``` 160 | -------------------------------------------------------------------------------- /examples/rewrites/client-rbac.yaml: -------------------------------------------------------------------------------- 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"] 23 | -------------------------------------------------------------------------------- /examples/rewrites/deployment.yaml: -------------------------------------------------------------------------------- 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 | --- 63 | apiVersion: apps/v1 64 | kind: Deployment 65 | metadata: 66 | name: kube-rbac-proxy 67 | spec: 68 | replicas: 1 69 | selector: 70 | matchLabels: 71 | app: kube-rbac-proxy 72 | template: 73 | metadata: 74 | labels: 75 | app: kube-rbac-proxy 76 | spec: 77 | securityContext: 78 | runAsUser: 65532 79 | serviceAccountName: kube-rbac-proxy 80 | containers: 81 | - name: kube-rbac-proxy 82 | image: quay.io/brancz/kube-rbac-proxy:v0.20.0 83 | args: 84 | - "--secure-listen-address=0.0.0.0:8443" 85 | - "--upstream=http://127.0.0.1:8081/" 86 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 87 | - "--logtostderr=true" 88 | - "--v=10" 89 | ports: 90 | - containerPort: 8443 91 | name: https 92 | volumeMounts: 93 | - name: config 94 | mountPath: /etc/kube-rbac-proxy 95 | securityContext: 96 | allowPrivilegeEscalation: false 97 | - name: prometheus-example-app 98 | image: quay.io/brancz/prometheus-example-app:v0.5.0 99 | args: 100 | - "--bind=127.0.0.1:8081" 101 | volumes: 102 | - name: config 103 | configMap: 104 | name: kube-rbac-proxy 105 | -------------------------------------------------------------------------------- /examples/static-auth/README.md: -------------------------------------------------------------------------------- 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.5.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. 202 | -------------------------------------------------------------------------------- /examples/static-auth/client-rbac.yaml: -------------------------------------------------------------------------------- 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"] 23 | -------------------------------------------------------------------------------- /examples/static-auth/deployment.yaml: -------------------------------------------------------------------------------- 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.5.0 103 | args: 104 | - "--bind=127.0.0.1:8081" 105 | volumes: 106 | - name: config 107 | configMap: 108 | name: kube-rbac-proxy 109 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/brancz/kube-rbac-proxy 2 | 3 | go 1.24.6 4 | 5 | require ( 6 | github.com/ghodss/yaml v1.0.0 7 | github.com/google/go-cmp v0.7.0 8 | github.com/oklog/run v1.2.0 9 | github.com/spf13/cobra v1.10.1 10 | github.com/spf13/pflag v1.0.10 11 | golang.org/x/net v0.44.0 12 | gopkg.in/yaml.v2 v2.4.0 13 | k8s.io/api v0.34.1 14 | k8s.io/apimachinery v0.34.1 15 | k8s.io/apiserver v0.34.1 16 | k8s.io/client-go v0.34.1 17 | k8s.io/component-base v0.34.1 18 | k8s.io/klog/v2 v2.130.1 19 | ) 20 | 21 | require ( 22 | cel.dev/expr v0.24.0 // indirect 23 | github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect 24 | github.com/NYTimes/gziphandler v1.1.1 // indirect 25 | github.com/antlr4-go/antlr/v4 v4.13.0 // indirect 26 | github.com/beorn7/perks v1.0.1 // indirect 27 | github.com/blang/semver/v4 v4.0.0 // indirect 28 | github.com/cenkalti/backoff/v4 v4.3.0 // indirect 29 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 30 | github.com/coreos/go-oidc v2.3.0+incompatible // indirect 31 | github.com/coreos/go-semver v0.3.1 // indirect 32 | github.com/coreos/go-systemd/v22 v22.5.0 // indirect 33 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 34 | github.com/emicklei/go-restful/v3 v3.12.2 // indirect 35 | github.com/felixge/httpsnoop v1.0.4 // indirect 36 | github.com/fsnotify/fsnotify v1.9.0 // indirect 37 | github.com/fxamacker/cbor/v2 v2.9.0 // indirect 38 | github.com/go-logr/logr v1.4.3 // indirect 39 | github.com/go-logr/stdr v1.2.2 // indirect 40 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 41 | github.com/go-openapi/jsonreference v0.20.2 // indirect 42 | github.com/go-openapi/swag v0.23.0 // indirect 43 | github.com/gogo/protobuf v1.3.2 // indirect 44 | github.com/golang/protobuf v1.5.4 // indirect 45 | github.com/google/btree v1.1.3 // indirect 46 | github.com/google/cel-go v0.26.0 // indirect 47 | github.com/google/gnostic-models v0.7.0 // indirect 48 | github.com/google/uuid v1.6.0 // indirect 49 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect 50 | github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect 51 | github.com/inconshreveable/mousetrap v1.1.0 // indirect 52 | github.com/josharian/intern v1.0.0 // indirect 53 | github.com/json-iterator/go v1.1.12 // indirect 54 | github.com/kylelemons/godebug v1.1.0 // indirect 55 | github.com/mailru/easyjson v0.7.7 // indirect 56 | github.com/moby/term v0.5.0 // indirect 57 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 58 | github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect 59 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 60 | github.com/pkg/errors v0.9.1 // indirect 61 | github.com/pmezard/go-difflib v1.0.0 // indirect 62 | github.com/pquerna/cachecontrol v0.1.0 // indirect 63 | github.com/prometheus/client_golang v1.22.0 // indirect 64 | github.com/prometheus/client_model v0.6.1 // indirect 65 | github.com/prometheus/common v0.62.0 // indirect 66 | github.com/prometheus/procfs v0.15.1 // indirect 67 | github.com/stoewer/go-strcase v1.3.0 // indirect 68 | github.com/x448/float16 v0.8.4 // indirect 69 | go.etcd.io/etcd/api/v3 v3.6.4 // indirect 70 | go.etcd.io/etcd/client/pkg/v3 v3.6.4 // indirect 71 | go.etcd.io/etcd/client/v3 v3.6.4 // indirect 72 | go.opentelemetry.io/auto/sdk v1.1.0 // indirect 73 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect 74 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect 75 | go.opentelemetry.io/otel v1.35.0 // indirect 76 | go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect 77 | go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect 78 | go.opentelemetry.io/otel/metric v1.35.0 // indirect 79 | go.opentelemetry.io/otel/sdk v1.34.0 // indirect 80 | go.opentelemetry.io/otel/trace v1.35.0 // indirect 81 | go.opentelemetry.io/proto/otlp v1.5.0 // indirect 82 | go.uber.org/multierr v1.11.0 // indirect 83 | go.uber.org/zap v1.27.0 // indirect 84 | go.yaml.in/yaml/v2 v2.4.2 // indirect 85 | go.yaml.in/yaml/v3 v3.0.4 // indirect 86 | golang.org/x/crypto v0.42.0 // indirect 87 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect 88 | golang.org/x/oauth2 v0.27.0 // indirect 89 | golang.org/x/sync v0.17.0 // indirect 90 | golang.org/x/sys v0.36.0 // indirect 91 | golang.org/x/term v0.35.0 // indirect 92 | golang.org/x/text v0.29.0 // indirect 93 | golang.org/x/time v0.9.0 // indirect 94 | google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect 95 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect 96 | google.golang.org/grpc v1.72.1 // indirect 97 | google.golang.org/protobuf v1.36.5 // indirect 98 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 99 | gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect 100 | gopkg.in/inf.v0 v0.9.1 // indirect 101 | gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect 102 | gopkg.in/yaml.v3 v3.0.1 // indirect 103 | k8s.io/kms v0.34.1 // indirect 104 | k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect 105 | k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 // indirect 106 | sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect 107 | sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect 108 | sigs.k8s.io/randfill v1.0.0 // indirect 109 | sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect 110 | sigs.k8s.io/yaml v1.6.0 // indirect 111 | ) 112 | -------------------------------------------------------------------------------- /pkg/authn/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package authn 18 | 19 | // AuthnHeaderConfig contains authentication header settings which enable more information about the user identity to be sent to the upstream 20 | type AuthnHeaderConfig struct { 21 | // When set to true, kube-rbac-proxy adds auth-related fields to the headers of http requests sent to the upstream 22 | Enabled bool 23 | // Corresponds to the name of the field inside a http(2) request header 24 | // to tell the upstream server about the user's name 25 | UserFieldName string 26 | // Corresponds to the name of the field inside a http(2) request header 27 | // to tell the upstream server about the user's groups 28 | GroupsFieldName string 29 | // The separator string used for concatenating multiple group names in a groups header field's value 30 | GroupSeparator string 31 | } 32 | 33 | // AuthnConfig holds all configurations related to authentication options 34 | type AuthnConfig struct { 35 | X509 *X509Config 36 | Header *AuthnHeaderConfig 37 | OIDC *OIDCConfig 38 | Token *TokenConfig 39 | } 40 | 41 | // X509Config holds public client certificate used for authentication requests if specified 42 | type X509Config struct { 43 | ClientCAFile string 44 | UpstreamClientCertificate string 45 | UpstreamClientKey string 46 | } 47 | 48 | // TokenConfig holds configuration as to how token authentication is to be done 49 | type TokenConfig struct { 50 | Audiences []string 51 | } 52 | 53 | // OIDCConfig represents configuration used for JWT request authentication 54 | type OIDCConfig struct { 55 | IssuerURL string 56 | ClientID string 57 | CAFile string 58 | UsernameClaim string 59 | UsernamePrefix string 60 | GroupsClaim string 61 | GroupsPrefix string 62 | SupportedSigningAlgs []string 63 | } 64 | -------------------------------------------------------------------------------- /pkg/authn/delegating.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package authn 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "net/http" 23 | "time" 24 | 25 | "k8s.io/apiserver/pkg/apis/apiserver" 26 | "k8s.io/apiserver/pkg/authentication/authenticator" 27 | "k8s.io/apiserver/pkg/authentication/authenticatorfactory" 28 | "k8s.io/apiserver/pkg/server/dynamiccertificates" 29 | "k8s.io/apiserver/pkg/server/options" 30 | authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1" 31 | ) 32 | 33 | type DelegatingAuthenticator struct { 34 | dynamicClientCA *dynamiccertificates.DynamicFileCAContent 35 | requestAuthenticator authenticator.Request 36 | } 37 | 38 | var ( 39 | _ (authenticator.Request) = (*DelegatingAuthenticator)(nil) 40 | ) 41 | 42 | // NewDelegatingAuthenticator creates an authenticator compatible with the kubelet's needs 43 | func NewDelegatingAuthenticator(client authenticationclient.AuthenticationV1Interface, authn *AuthnConfig) (*DelegatingAuthenticator, error) { 44 | if client == nil { 45 | return nil, errors.New("tokenAccessReview client not provided, cannot use webhook authentication") 46 | } 47 | 48 | var ( 49 | p *dynamiccertificates.DynamicFileCAContent 50 | err error 51 | ) 52 | 53 | authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig{ 54 | Anonymous: &apiserver.AnonymousAuthConfig{ 55 | Enabled: false, // always require authentication 56 | }, 57 | // Better defaults would be here: apiserver/pkg/server/options/authentication.go. 58 | CacheTTL: 2 * time.Minute, 59 | TokenAccessReviewClient: client, 60 | APIAudiences: authenticator.Audiences(authn.Token.Audiences), 61 | WebhookRetryBackoff: options.DefaultAuthWebhookRetryBackoff(), 62 | } 63 | 64 | if len(authn.X509.ClientCAFile) > 0 { 65 | p, err = dynamiccertificates.NewDynamicCAContentFromFile("client-ca", authn.X509.ClientCAFile) 66 | if err != nil { 67 | return nil, err 68 | } 69 | authenticatorConfig.ClientCertificateCAContentProvider = p 70 | } 71 | 72 | authenticator, _, err := authenticatorConfig.New() 73 | if err != nil { 74 | return nil, err 75 | } 76 | 77 | return &DelegatingAuthenticator{requestAuthenticator: authenticator, dynamicClientCA: p}, nil 78 | } 79 | 80 | func (a *DelegatingAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { 81 | return a.requestAuthenticator.AuthenticateRequest(req) 82 | } 83 | 84 | func (a *DelegatingAuthenticator) Run(ctx context.Context) { 85 | if a.dynamicClientCA != nil { 86 | a.dynamicClientCA.Run(ctx, 1) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /pkg/authn/oidc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package authn 18 | 19 | import ( 20 | "context" 21 | "net/http" 22 | 23 | "k8s.io/apiserver/pkg/apis/apiserver" 24 | "k8s.io/apiserver/pkg/authentication/authenticator" 25 | "k8s.io/apiserver/pkg/authentication/request/bearertoken" 26 | "k8s.io/apiserver/pkg/server/dynamiccertificates" 27 | "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" 28 | ) 29 | 30 | type OIDCAuthenticator struct { 31 | dynamicClientCA *dynamiccertificates.DynamicFileCAContent 32 | requestAuthenticator authenticator.Request 33 | } 34 | 35 | var ( 36 | _ (authenticator.Request) = (*OIDCAuthenticator)(nil) 37 | ) 38 | 39 | // NewOIDCAuthenticator returns OIDC authenticator 40 | func NewOIDCAuthenticator(ctx context.Context, config *OIDCConfig) (*OIDCAuthenticator, error) { 41 | var ( 42 | // Assign the [dynamiccertificates.CAContentProvider] interface only if the underlying concrete type is not nil. 43 | // Otherwise, the interface will get a type associated with it and will fail a nil check later on. 44 | // See https://github.com/brancz/kube-rbac-proxy/pull/361 for more details. 45 | dynamicCA *dynamiccertificates.DynamicFileCAContent 46 | caContentProvider dynamiccertificates.CAContentProvider 47 | ) 48 | 49 | if len(config.CAFile) > 0 { // if unset, the OIDC authenticator defaults to host's trust store 50 | var err error 51 | dynamicCA, err = dynamiccertificates.NewDynamicCAContentFromFile("oidc-ca", config.CAFile) 52 | if err != nil { 53 | return nil, err 54 | } 55 | caContentProvider = dynamicCA 56 | } 57 | 58 | tokenAuthenticator, err := oidc.New(ctx, oidc.Options{ 59 | JWTAuthenticator: apiserver.JWTAuthenticator{ 60 | Issuer: apiserver.Issuer{ 61 | URL: config.IssuerURL, 62 | Audiences: []string{config.ClientID}, 63 | }, 64 | ClaimMappings: apiserver.ClaimMappings{ 65 | Username: apiserver.PrefixedClaimOrExpression{ 66 | Prefix: &config.UsernamePrefix, 67 | Claim: config.UsernameClaim, 68 | }, 69 | Groups: apiserver.PrefixedClaimOrExpression{ 70 | Prefix: &config.GroupsPrefix, 71 | Claim: config.GroupsClaim, 72 | }, 73 | }, 74 | }, 75 | CAContentProvider: caContentProvider, 76 | SupportedSigningAlgs: config.SupportedSigningAlgs, 77 | }) 78 | if err != nil { 79 | return nil, err 80 | } 81 | 82 | return &OIDCAuthenticator{ 83 | dynamicClientCA: dynamicCA, 84 | requestAuthenticator: bearertoken.New(tokenAuthenticator), 85 | }, nil 86 | } 87 | 88 | func (o *OIDCAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { 89 | return o.requestAuthenticator.AuthenticateRequest(req) 90 | } 91 | 92 | func (o *OIDCAuthenticator) Run(ctx context.Context) { 93 | if o.dynamicClientCA != nil { 94 | o.dynamicClientCA.Run(ctx, 1) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /pkg/authz/auth.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk Authors. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package authz 18 | 19 | import ( 20 | "context" 21 | "errors" 22 | "fmt" 23 | "time" 24 | 25 | "k8s.io/apiserver/pkg/authorization/authorizer" 26 | "k8s.io/apiserver/pkg/authorization/authorizerfactory" 27 | "k8s.io/apiserver/pkg/server/options" 28 | authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" 29 | ) 30 | 31 | // Config holds configuration enabling request authorization 32 | type Config struct { 33 | Rewrites *SubjectAccessReviewRewrites `json:"rewrites,omitempty"` 34 | ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty"` 35 | ResourceAttributesFile string `json:"-"` 36 | Static []StaticAuthorizationConfig `json:"static,omitempty"` 37 | } 38 | 39 | // SubjectAccessReviewRewrites describes how SubjectAccessReview may be 40 | // rewritten on a given request. 41 | type SubjectAccessReviewRewrites struct { 42 | ByQueryParameter *QueryParameterRewriteConfig `json:"byQueryParameter,omitempty"` 43 | ByHTTPHeader *HTTPHeaderRewriteConfig `json:"byHttpHeader,omitempty"` 44 | } 45 | 46 | // QueryParameterRewriteConfig describes which HTTP URL query parameter is to 47 | // be used to rewrite a SubjectAccessReview on a given request. 48 | type QueryParameterRewriteConfig struct { 49 | Name string `json:"name,omitempty"` 50 | } 51 | 52 | // HTTPHeaderRewriteConfig describes which HTTP header is to 53 | // be used to rewrite a SubjectAccessReview on a given request. 54 | type HTTPHeaderRewriteConfig struct { 55 | Name string `json:"name,omitempty"` 56 | } 57 | 58 | // ResourceAttributes describes attributes available for resource request authorization 59 | type ResourceAttributes struct { 60 | Namespace string `json:"namespace,omitempty"` 61 | APIGroup string `json:"apiGroup,omitempty"` 62 | APIVersion string `json:"apiVersion,omitempty"` 63 | Resource string `json:"resource,omitempty"` 64 | Subresource string `json:"subresource,omitempty"` 65 | Name string `json:"name,omitempty"` 66 | } 67 | 68 | // StaticAuthorizationConfig describes what is needed to specify a static 69 | // authorization. 70 | type StaticAuthorizationConfig struct { 71 | User UserConfig 72 | Verb string `json:"verb,omitempty"` 73 | Namespace string `json:"namespace,omitempty"` 74 | APIGroup string `json:"apiGroup,omitempty"` 75 | Resource string `json:"resource,omitempty"` 76 | Subresource string `json:"subresource,omitempty"` 77 | Name string `json:"name,omitempty"` 78 | ResourceRequest bool `json:"resourceRequest,omitempty"` 79 | Path string `json:"path,omitempty"` 80 | } 81 | 82 | type UserConfig struct { 83 | Name string `json:"name,omitempty"` 84 | Groups []string `json:"groups,omitempty"` 85 | } 86 | 87 | // NewSarAuthorizer creates an authorizer compatible with the kubelet's needs 88 | func NewSarAuthorizer(client authorizationclient.AuthorizationV1Interface) (authorizer.Authorizer, error) { 89 | if client == nil { 90 | return nil, errors.New("no client provided, cannot use webhook authorization") 91 | } 92 | authorizerConfig := authorizerfactory.DelegatingAuthorizerConfig{ 93 | SubjectAccessReviewClient: client, 94 | // Defaults are most probably taken from: kubernetes/pkg/kubelet/apis/config/v1beta1/defaults.go 95 | // Defaults that are more reasonable: apiserver/pkg/server/options/authorization.go 96 | AllowCacheTTL: 5 * time.Minute, 97 | DenyCacheTTL: 30 * time.Second, 98 | WebhookRetryBackoff: options.DefaultAuthWebhookRetryBackoff(), 99 | } 100 | return authorizerConfig.New() 101 | } 102 | 103 | type staticAuthorizer struct { 104 | config []StaticAuthorizationConfig 105 | } 106 | 107 | func (saConfig StaticAuthorizationConfig) Matches(a authorizer.Attributes) bool { 108 | isAllowed := func(staticConf string, requestVal string) bool { 109 | if staticConf == "" { 110 | return true 111 | } else { 112 | return staticConf == requestVal 113 | } 114 | } 115 | 116 | userName := "" 117 | if a.GetUser() != nil { 118 | userName = a.GetUser().GetName() 119 | } 120 | 121 | if isAllowed(saConfig.User.Name, userName) && 122 | isAllowed(saConfig.Verb, a.GetVerb()) && 123 | isAllowed(saConfig.Namespace, a.GetNamespace()) && 124 | isAllowed(saConfig.APIGroup, a.GetAPIGroup()) && 125 | isAllowed(saConfig.Resource, a.GetResource()) && 126 | isAllowed(saConfig.Subresource, a.GetSubresource()) && 127 | isAllowed(saConfig.Name, a.GetName()) && 128 | isAllowed(saConfig.Path, a.GetPath()) && 129 | saConfig.ResourceRequest == a.IsResourceRequest() { 130 | return true 131 | } 132 | return false 133 | } 134 | 135 | func (sa staticAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { 136 | // compare a against the configured static auths 137 | for _, saConfig := range sa.config { 138 | if saConfig.Matches(a) { 139 | return authorizer.DecisionAllow, "found corresponding static auth config", nil 140 | } 141 | } 142 | 143 | return authorizer.DecisionNoOpinion, "", nil 144 | } 145 | 146 | func NewStaticAuthorizer(config []StaticAuthorizationConfig) (*staticAuthorizer, error) { 147 | for _, c := range config { 148 | if c.ResourceRequest != (c.Path == "") { 149 | return nil, fmt.Errorf("invalid configuration: resource requests must not include a path: %v", config) 150 | } 151 | } 152 | return &staticAuthorizer{config}, nil 153 | } 154 | -------------------------------------------------------------------------------- /pkg/authz/auth_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Kube RBAC Proxy Authors rights reserved. 3 |  4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 |  8 |  http://www.apache.org/licenses/LICENSE-2.0 9 |  10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package authz 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | 23 | "k8s.io/apiserver/pkg/authentication/user" 24 | "k8s.io/apiserver/pkg/authorization/authorizer" 25 | ) 26 | 27 | func TestStaticAuthorizer(t *testing.T) { 28 | tests := []struct { 29 | name string 30 | config []StaticAuthorizationConfig 31 | 32 | shouldFail bool 33 | shouldPass []authorizer.Attributes 34 | shouldNoOpinion []authorizer.Attributes 35 | }{ 36 | { 37 | name: "pathOnly", 38 | config: []StaticAuthorizationConfig{ 39 | {Path: "/metrics", ResourceRequest: false}, 40 | }, 41 | shouldPass: []authorizer.Attributes{ 42 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics"}, 43 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics"}, 44 | }, 45 | shouldNoOpinion: []authorizer.Attributes{ 46 | // wrong path 47 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api"}, 48 | }, 49 | }, 50 | { 51 | name: "pathAndVerb", 52 | config: []StaticAuthorizationConfig{ 53 | {Path: "/metrics", Verb: "get"}, 54 | }, 55 | shouldPass: []authorizer.Attributes{ 56 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics"}, 57 | }, 58 | shouldNoOpinion: []authorizer.Attributes{ 59 | // wrong path 60 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api"}, 61 | // wrong path 62 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics"}, 63 | }, 64 | }, 65 | { 66 | name: "nonResourceRequestSpecifiedTrue", 67 | config: []StaticAuthorizationConfig{ 68 | {Path: "/metrics", Verb: "get", ResourceRequest: true}, 69 | }, 70 | shouldFail: true, 71 | }, 72 | { 73 | name: "resourceRequestSpecifiedFalse", 74 | config: []StaticAuthorizationConfig{ 75 | {Resource: "namespaces", Verb: "get", ResourceRequest: false}, 76 | }, 77 | shouldFail: true, 78 | }, 79 | { 80 | name: "resourceRequestSpecifiedFalse", 81 | config: []StaticAuthorizationConfig{ 82 | {Path: "/metrics", Verb: "get", ResourceRequest: false}, 83 | }, 84 | shouldPass: []authorizer.Attributes{ 85 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: false}, 86 | }, 87 | shouldNoOpinion: []authorizer.Attributes{ 88 | // wrong resourceRequest 89 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: true}, 90 | }, 91 | }, 92 | { 93 | name: "resourceRequestUnspecified", 94 | config: []StaticAuthorizationConfig{ 95 | {Path: "/metrics", Verb: "get"}, 96 | }, 97 | shouldPass: []authorizer.Attributes{ 98 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: false}, 99 | }, 100 | shouldNoOpinion: []authorizer.Attributes{ 101 | // Verb: get and ResourceRequest: true should be 102 | // mutually exclusive 103 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: true}, 104 | // wrong path 105 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api", ResourceRequest: true}, 106 | // wrong path 107 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics", ResourceRequest: false}, 108 | }, 109 | }, 110 | { 111 | name: "resourceRequest", 112 | config: []StaticAuthorizationConfig{ 113 | {Resource: "namespaces", Verb: "get", ResourceRequest: true}, 114 | }, 115 | shouldPass: []authorizer.Attributes{ 116 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, 117 | authorizer.AttributesRecord{Verb: "get", Resource: "namespaces", ResourceRequest: true}, 118 | }, 119 | shouldNoOpinion: []authorizer.Attributes{ 120 | authorizer.AttributesRecord{Verb: "get", Resource: "services", ResourceRequest: true}, 121 | }, 122 | }, 123 | { 124 | name: "resourceRequestSpecificUser", 125 | config: []StaticAuthorizationConfig{ 126 | {User: UserConfig{Name: "system:foo"}, Resource: "namespaces", Verb: "get", ResourceRequest: true}, 127 | }, 128 | shouldPass: []authorizer.Attributes{ 129 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, 130 | }, 131 | shouldNoOpinion: []authorizer.Attributes{ 132 | authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:bar"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, 133 | authorizer.AttributesRecord{Verb: "get", Resource: "namespaces", ResourceRequest: true}, 134 | authorizer.AttributesRecord{Verb: "get", Resource: "services", ResourceRequest: true}, 135 | }, 136 | }, 137 | } 138 | for _, tt := range tests { 139 | t.Run(tt.name, func(t *testing.T) { 140 | auth, err := NewStaticAuthorizer(tt.config) 141 | if failed := err != nil; tt.shouldFail != failed { 142 | t.Errorf("static authorizer creation expected to fail: %v, got %v, err: %v", tt.shouldFail, failed, err) 143 | return 144 | } 145 | 146 | for _, attr := range tt.shouldPass { 147 | if decision, _, _ := auth.Authorize(context.Background(), attr); decision != authorizer.DecisionAllow { 148 | t.Errorf("incorrectly restricted %v", attr) 149 | } 150 | } 151 | 152 | for _, attr := range tt.shouldNoOpinion { 153 | if decision, _, _ := auth.Authorize(context.Background(), attr); decision != authorizer.DecisionNoOpinion { 154 | t.Errorf("incorrectly opinionated %v", attr) 155 | } 156 | } 157 | }) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /pkg/filters/auth.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 the kube-rbac-proxy maintainers All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package filters 17 | 18 | import ( 19 | "fmt" 20 | "net/http" 21 | "strings" 22 | 23 | "github.com/brancz/kube-rbac-proxy/pkg/authn" 24 | "github.com/brancz/kube-rbac-proxy/pkg/authz" 25 | "github.com/brancz/kube-rbac-proxy/pkg/proxy" 26 | 27 | "k8s.io/apiserver/pkg/authentication/authenticator" 28 | "k8s.io/apiserver/pkg/authorization/authorizer" 29 | "k8s.io/apiserver/pkg/endpoints/request" 30 | "k8s.io/klog/v2" 31 | ) 32 | 33 | func WithAuthentication( 34 | authReq authenticator.Request, 35 | audiences []string, 36 | handler http.HandlerFunc, 37 | ) http.HandlerFunc { 38 | return func(w http.ResponseWriter, req *http.Request) { 39 | ctx := req.Context() 40 | if len(audiences) > 0 { 41 | ctx = authenticator.WithAudiences(ctx, audiences) 42 | req = req.WithContext(ctx) 43 | } 44 | 45 | res, ok, err := authReq.AuthenticateRequest(req) 46 | if err != nil { 47 | klog.Errorf("Unable to authenticate the request due to an error: %v", err) 48 | http.Error(w, "Unauthorized", http.StatusUnauthorized) 49 | return 50 | } 51 | if !ok { 52 | http.Error(w, "Unauthorized", http.StatusUnauthorized) 53 | return 54 | } 55 | 56 | req = req.WithContext(request.WithUser(req.Context(), res.User)) 57 | handler.ServeHTTP(w, req) 58 | } 59 | } 60 | 61 | func WithAuthorization( 62 | authz authorizer.Authorizer, 63 | cfg *authz.Config, 64 | handler http.HandlerFunc, 65 | ) http.HandlerFunc { 66 | getRequestAttributes := proxy. 67 | NewKubeRBACProxyAuthorizerAttributesGetter(cfg). 68 | GetRequestAttributes 69 | 70 | return func(w http.ResponseWriter, req *http.Request) { 71 | u, ok := request.UserFrom(req.Context()) 72 | if !ok { 73 | http.Error(w, "user not in context", http.StatusBadRequest) 74 | return 75 | } 76 | 77 | // Get authorization attributes 78 | allAttrs := getRequestAttributes(u, req) 79 | if len(allAttrs) == 0 { 80 | msg := "Bad Request. The request or configuration is malformed." 81 | klog.V(2).Info(msg) 82 | http.Error(w, msg, http.StatusBadRequest) 83 | return 84 | } 85 | 86 | for _, attrs := range allAttrs { 87 | // Authorize 88 | authorized, reason, err := authz.Authorize(req.Context(), attrs) 89 | if err != nil { 90 | msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource()) 91 | klog.Errorf("%s: %s", msg, err) 92 | http.Error(w, msg, http.StatusInternalServerError) 93 | return 94 | } 95 | if authorized != authorizer.DecisionAllow { 96 | msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource()) 97 | klog.V(2).Infof("%s. Reason: %q.", msg, reason) 98 | http.Error(w, msg, http.StatusForbidden) 99 | return 100 | } 101 | } 102 | 103 | handler.ServeHTTP(w, req) 104 | } 105 | } 106 | 107 | // WithAuthHeaders adds identity information to the headers. 108 | // Must not be used, if connection is not encrypted with TLS. 109 | func WithAuthHeaders(cfg *authn.AuthnHeaderConfig, handler http.HandlerFunc) http.HandlerFunc { 110 | if !cfg.Enabled { 111 | return handler 112 | } 113 | 114 | return func(w http.ResponseWriter, req *http.Request) { 115 | u, ok := request.UserFrom(req.Context()) 116 | if ok { 117 | // Seemingly well-known headers to tell the upstream about user's identity 118 | // so that the upstream can achieve the original goal of delegating RBAC authn/authz to kube-rbac-proxy 119 | req.Header.Set(cfg.UserFieldName, u.GetName()) 120 | req.Header.Set(cfg.GroupsFieldName, strings.Join(u.GetGroups(), cfg.GroupSeparator)) 121 | } 122 | 123 | handler.ServeHTTP(w, req) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /pkg/filters/path.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 the kube-rbac-proxy maintainers All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package filters 17 | 18 | import ( 19 | "net/http" 20 | "path" 21 | ) 22 | 23 | func WithAllowPaths(allowPaths []string, handler http.HandlerFunc) http.HandlerFunc { 24 | if len(allowPaths) == 0 { 25 | return handler 26 | } 27 | 28 | return func(w http.ResponseWriter, req *http.Request) { 29 | for _, pathAllowed := range allowPaths { 30 | found, err := path.Match(pathAllowed, req.URL.Path) 31 | if err != nil { 32 | http.Error( 33 | w, 34 | http.StatusText(http.StatusInternalServerError), 35 | http.StatusInternalServerError, 36 | ) 37 | return 38 | } 39 | 40 | if found { 41 | handler.ServeHTTP(w, req) 42 | return 43 | } 44 | } 45 | 46 | http.NotFound(w, req) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pkg/filters/path_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 the kube-rbac-proxy maintainers All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package filters_test 17 | 18 | import ( 19 | "net/http" 20 | "net/http/httptest" 21 | "testing" 22 | 23 | "github.com/brancz/kube-rbac-proxy/pkg/filters" 24 | ) 25 | 26 | func emptyHandler(w http.ResponseWriter, r *http.Request) {} 27 | 28 | func TestAllowPath(t *testing.T) { 29 | validPath := "/allowed" 30 | 31 | for _, tt := range []struct { 32 | name string 33 | paths []string 34 | status int 35 | }{ 36 | { 37 | name: "should let request through if path allowed", 38 | paths: []string{validPath}, 39 | status: http.StatusOK, 40 | }, 41 | { 42 | name: "should not let request through if path not allowed", 43 | paths: []string{"/denied"}, 44 | status: http.StatusNotFound, 45 | }, 46 | { 47 | name: "should let request through if no path specified", 48 | paths: []string{}, 49 | status: http.StatusOK, 50 | }, 51 | { 52 | name: "should not let request through if path is non-sense", 53 | paths: []string{"[]a]"}, 54 | status: http.StatusInternalServerError, 55 | }, 56 | } { 57 | tt := tt 58 | t.Run(tt.name, func(t *testing.T) { 59 | rec := httptest.NewRecorder() 60 | req, err := http.NewRequest(http.MethodGet, validPath, nil) 61 | if err != nil { 62 | t.Fatal(err) 63 | } 64 | 65 | filters.WithAllowPaths(tt.paths, emptyHandler).ServeHTTP(rec, req) 66 | res := rec.Result() 67 | 68 | if res.StatusCode != tt.status { 69 | t.Errorf("want: %d\nhave: %d\n", tt.status, res.StatusCode) 70 | } 71 | }) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /pkg/proxy/proxy.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package proxy 18 | 19 | import ( 20 | "bytes" 21 | "net/http" 22 | "net/textproto" 23 | "text/template" 24 | 25 | "github.com/brancz/kube-rbac-proxy/pkg/authn" 26 | "github.com/brancz/kube-rbac-proxy/pkg/authz" 27 | "k8s.io/apiserver/pkg/authentication/user" 28 | "k8s.io/apiserver/pkg/authorization/authorizer" 29 | "k8s.io/klog/v2" 30 | ) 31 | 32 | // Config holds proxy authorization and authentication settings 33 | type Config struct { 34 | Authentication *authn.AuthnConfig 35 | Authorization *authz.Config 36 | } 37 | 38 | func NewKubeRBACProxyAuthorizerAttributesGetter(authzConfig *authz.Config) *krpAuthorizerAttributesGetter { 39 | return &krpAuthorizerAttributesGetter{authzConfig} 40 | } 41 | 42 | type krpAuthorizerAttributesGetter struct { 43 | authzConfig *authz.Config 44 | } 45 | 46 | // GetRequestAttributes populates authorizer attributes for the requests to kube-rbac-proxy. 47 | func (n krpAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *http.Request) []authorizer.Attributes { 48 | apiVerb := "*" 49 | switch r.Method { 50 | case "POST": 51 | apiVerb = "create" 52 | case "GET": 53 | apiVerb = "get" 54 | case "PUT": 55 | apiVerb = "update" 56 | case "PATCH": 57 | apiVerb = "patch" 58 | case "DELETE": 59 | apiVerb = "delete" 60 | } 61 | 62 | var allAttrs []authorizer.Attributes 63 | 64 | defer func() { 65 | for attrs := range allAttrs { 66 | klog.V(5).Infof("kube-rbac-proxy request attributes: attrs=%#+v", attrs) 67 | } 68 | }() 69 | 70 | if n.authzConfig.ResourceAttributes == nil { 71 | // Default attributes mirror the API attributes that would allow this access to kube-rbac-proxy 72 | allAttrs := append(allAttrs, authorizer.AttributesRecord{ 73 | User: u, 74 | Verb: apiVerb, 75 | Namespace: "", 76 | APIGroup: "", 77 | APIVersion: "", 78 | Resource: "", 79 | Subresource: "", 80 | Name: "", 81 | ResourceRequest: false, 82 | Path: r.URL.Path, 83 | }) 84 | return allAttrs 85 | } 86 | 87 | if n.authzConfig.Rewrites == nil { 88 | allAttrs := append(allAttrs, authorizer.AttributesRecord{ 89 | User: u, 90 | Verb: apiVerb, 91 | Namespace: n.authzConfig.ResourceAttributes.Namespace, 92 | APIGroup: n.authzConfig.ResourceAttributes.APIGroup, 93 | APIVersion: n.authzConfig.ResourceAttributes.APIVersion, 94 | Resource: n.authzConfig.ResourceAttributes.Resource, 95 | Subresource: n.authzConfig.ResourceAttributes.Subresource, 96 | Name: n.authzConfig.ResourceAttributes.Name, 97 | ResourceRequest: true, 98 | }) 99 | return allAttrs 100 | } 101 | 102 | params := []string{} 103 | if n.authzConfig.Rewrites.ByQueryParameter != nil && n.authzConfig.Rewrites.ByQueryParameter.Name != "" { 104 | if ps, ok := r.URL.Query()[n.authzConfig.Rewrites.ByQueryParameter.Name]; ok { 105 | params = append(params, ps...) 106 | } 107 | } 108 | if n.authzConfig.Rewrites.ByHTTPHeader != nil && n.authzConfig.Rewrites.ByHTTPHeader.Name != "" { 109 | mimeHeader := textproto.MIMEHeader(r.Header) 110 | mimeKey := textproto.CanonicalMIMEHeaderKey(n.authzConfig.Rewrites.ByHTTPHeader.Name) 111 | if ps, ok := mimeHeader[mimeKey]; ok { 112 | params = append(params, ps...) 113 | } 114 | } 115 | 116 | if len(params) == 0 { 117 | return allAttrs 118 | } 119 | 120 | for _, param := range params { 121 | attrs := authorizer.AttributesRecord{ 122 | User: u, 123 | Verb: apiVerb, 124 | Namespace: templateWithValue(n.authzConfig.ResourceAttributes.Namespace, param), 125 | APIGroup: templateWithValue(n.authzConfig.ResourceAttributes.APIGroup, param), 126 | APIVersion: templateWithValue(n.authzConfig.ResourceAttributes.APIVersion, param), 127 | Resource: templateWithValue(n.authzConfig.ResourceAttributes.Resource, param), 128 | Subresource: templateWithValue(n.authzConfig.ResourceAttributes.Subresource, param), 129 | Name: templateWithValue(n.authzConfig.ResourceAttributes.Name, param), 130 | ResourceRequest: true, 131 | } 132 | allAttrs = append(allAttrs, attrs) 133 | } 134 | return allAttrs 135 | } 136 | 137 | func templateWithValue(templateString, value string) string { 138 | tmpl, _ := template.New("valueTemplate").Parse(templateString) 139 | out := bytes.NewBuffer(nil) 140 | err := tmpl.Execute(out, struct{ Value string }{Value: value}) 141 | if err != nil { 142 | return "" 143 | } 144 | return out.String() 145 | } 146 | -------------------------------------------------------------------------------- /pkg/tls/reloader.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package tls 18 | 19 | import ( 20 | "bytes" 21 | "context" 22 | "crypto/tls" 23 | "fmt" 24 | "os" 25 | "sync" 26 | "time" 27 | 28 | "k8s.io/klog/v2" 29 | ) 30 | 31 | // CertReloader is the struct that parses a certificate/key pair, 32 | // providing a goroutine safe GetCertificate method to retrieve the parsed content. 33 | // 34 | // The GetCertificate signature is compatible with https://golang.org/pkg/crypto/tls/#Config.GetCertificate 35 | // and can be used to hot-reload a certificate/key pair. 36 | // 37 | // For hot-reloading the Watch method must be started explicitly. 38 | type CertReloader struct { 39 | certPath, keyPath string 40 | interval time.Duration 41 | 42 | mu sync.RWMutex // protects the fields below 43 | cert *tls.Certificate 44 | certRaw, keyRaw []byte 45 | } 46 | 47 | // NewCertReloader creates a new CertReloader that loads certs in an interval. 48 | func NewCertReloader(certPath, keyPath string, interval time.Duration) (*CertReloader, error) { 49 | r := &CertReloader{ 50 | certPath: certPath, 51 | keyPath: keyPath, 52 | interval: interval, 53 | } 54 | 55 | if err := r.reload(); err != nil { 56 | return nil, fmt.Errorf("error loading certificates: %v", err) 57 | } 58 | 59 | return r, nil 60 | } 61 | 62 | // Watch watches the configured certificate and key path and blocks the current goroutine 63 | // until the scenario context is done or an error occurred during reloading. 64 | func (r *CertReloader) Watch(ctx context.Context) error { 65 | t := time.NewTicker(r.interval) 66 | 67 | for { 68 | select { 69 | case <-t.C: 70 | case <-ctx.Done(): 71 | return nil 72 | } 73 | 74 | if err := r.reload(); err != nil { 75 | return fmt.Errorf("reloading failed: %v", err) 76 | } 77 | } 78 | } 79 | 80 | func (r *CertReloader) reload() error { 81 | certRaw, err := os.ReadFile(r.certPath) 82 | if err != nil { 83 | return fmt.Errorf("error loading certificate: %v", err) 84 | } 85 | 86 | keyRaw, err := os.ReadFile(r.keyPath) 87 | if err != nil { 88 | return fmt.Errorf("error loading key: %v", err) 89 | } 90 | 91 | r.mu.RLock() 92 | equal := bytes.Equal(keyRaw, r.keyRaw) && bytes.Equal(certRaw, r.certRaw) 93 | r.mu.RUnlock() 94 | 95 | if equal { 96 | return nil 97 | } 98 | 99 | klog.V(4).Info("reloading key ", r.keyPath, " certificate ", r.certPath) 100 | 101 | cert, err := tls.X509KeyPair(certRaw, keyRaw) 102 | if err != nil { 103 | return fmt.Errorf("error parsing certificate: %v", err) 104 | } 105 | 106 | r.mu.Lock() 107 | r.cert = &cert 108 | r.certRaw = certRaw 109 | r.keyRaw = keyRaw 110 | r.mu.Unlock() 111 | 112 | return nil 113 | } 114 | 115 | // GetCertificate returns the current valid certificate. 116 | // The ClientHello message is ignored 117 | // and is just there to be compatible with https://golang.org/pkg/crypto/tls/#Config.GetCertificate. 118 | func (r *CertReloader) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { 119 | r.mu.RLock() 120 | defer r.mu.RUnlock() 121 | 122 | return r.cert, nil 123 | } 124 | -------------------------------------------------------------------------------- /scripts/check_license.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | licRes=$( 4 | for file in $(find . -type f -iname '*.go' ! -path '*/vendor/*'); do 5 | head -n5 "${file}" | grep -Eq "(Copyright|generated|GENERATED)" || printf " %s\n" "${file}" 6 | done 7 | ) 8 | if [ -n "${licRes}" ]; then 9 | printf "license header checking failed:\n%s\n" "${licRes}" 10 | exit 255 11 | fi 12 | -------------------------------------------------------------------------------- /scripts/generate-examples.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/non-resource-url-deployment.yaml > examples/non-resource-url/deployment.yaml 4 | sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/non-resource-url-token-request-deployment.yaml > examples/non-resource-url-token-request/deployment.yaml 5 | sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/resource-attributes-deployment.yaml > examples/resource-attributes/deployment.yaml 6 | sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/rewrites-deployment.yaml > examples/rewrites/deployment.yaml 7 | sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/oidc-deployment.yaml > examples/oidc/deployment.yaml 8 | -------------------------------------------------------------------------------- /scripts/generate-help-txt.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "$ kube-rbac-proxy -h" > _output/help.txt 4 | _output/kube-rbac-proxy -h >> _output/help.txt 5 | exit 0 6 | -------------------------------------------------------------------------------- /scripts/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/brancz/kube-rbac-proxy/tooling 2 | 3 | go 1.14 4 | 5 | require github.com/campoy/embedmd v1.0.0 6 | -------------------------------------------------------------------------------- /scripts/go.sum: -------------------------------------------------------------------------------- 1 | github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= 2 | github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | -------------------------------------------------------------------------------- /scripts/kind-load-local.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | kind load docker-image quay.io/brancz/kube-rbac-proxy:local 4 | kind load docker-image quay.io/brancz/prometheus-example-app:v0.5.0 5 | kind load docker-image quay.io/brancz/prometheus-example-app:v0.4.0 6 | kind load docker-image quay.io/brancz/krp-curl:v0.0.2 7 | -------------------------------------------------------------------------------- /scripts/publish.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # exit immediately when a command fails 3 | set -e 4 | # only exit with zero if all commands of the pipeline exit successfully 5 | set -o pipefail 6 | # error on unset variables 7 | set -u 8 | # for debugging 9 | set -x 10 | 11 | # github actions, by default, fetches using `--no-tags`. 12 | # we need tags though to create a release version string. 13 | git fetch --tags --force 14 | 15 | QUAY_PATH="${QUAY_PATH:-quay.io/brancz/kube-rbac-proxy}" 16 | CPU_ARCHS="amd64 arm64 arm ppc64le s390x" 17 | TAG_COMMIT=$(git rev-list --abbrev-commit --tags --max-count=1) 18 | COMMIT=$(git rev-parse --short HEAD) 19 | TAG=$(git describe --abbrev=0 --tags ${TAG_COMMIT}) 20 | VERSION="${TAG}" 21 | 22 | # if the current commit, does not correspond to a tag, create a verbose version string. 23 | if [ "${TAG_COMMIT}" != "${COMMIT}" ]; then 24 | VERSION=$(git rev-parse --abbrev-ref HEAD | tr / -)-$(date +%Y-%m-%d)-$(git rev-parse --short HEAD) 25 | fi 26 | 27 | # build and push arch specific images 28 | for arch in ${CPU_ARCHS}; do 29 | VERSION="${VERSION}" DOCKER_REPO="${QUAY_PATH}" GOARCH="${arch}" make container 30 | docker push "${QUAY_PATH}:${VERSION}-${arch}" 31 | done 32 | 33 | # Create manifest to join all images under one virtual tag 34 | MANIFEST="docker manifest create -a ${QUAY_PATH}:${VERSION}" 35 | for arch in ${CPU_ARCHS}; do 36 | MANIFEST="${MANIFEST} ${QUAY_PATH}:${VERSION}-${arch}" 37 | done 38 | eval "${MANIFEST}" 39 | 40 | # Annotate to set which image is build for which CPU architecture 41 | for arch in ${CPU_ARCHS}; do 42 | docker manifest annotate --arch "${arch}" "${QUAY_PATH}:${VERSION}" "${QUAY_PATH}:${VERSION}-${arch}" 43 | done 44 | docker manifest push "${QUAY_PATH}:${VERSION}" 45 | -------------------------------------------------------------------------------- /scripts/templates/non-resource-url-deployment.yaml: -------------------------------------------------------------------------------- 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: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: kube-rbac-proxy 51 | spec: 52 | replicas: 1 53 | selector: 54 | matchLabels: 55 | app: kube-rbac-proxy 56 | template: 57 | metadata: 58 | labels: 59 | app: kube-rbac-proxy 60 | spec: 61 | securityContext: 62 | runAsUser: 65532 63 | serviceAccountName: kube-rbac-proxy 64 | containers: 65 | - name: kube-rbac-proxy 66 | image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION 67 | args: 68 | - "--secure-listen-address=0.0.0.0:8443" 69 | - "--upstream=http://127.0.0.1:8081/" 70 | - "--logtostderr=true" 71 | - "--v=10" 72 | ports: 73 | - containerPort: 8443 74 | name: https 75 | securityContext: 76 | allowPrivilegeEscalation: false 77 | - name: prometheus-example-app 78 | image: quay.io/brancz/prometheus-example-app:v0.5.0 79 | args: 80 | - "--bind=127.0.0.1:8081" 81 | -------------------------------------------------------------------------------- /scripts/templates/non-resource-url-token-request-deployment.yaml: -------------------------------------------------------------------------------- 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: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: kube-rbac-proxy 51 | spec: 52 | replicas: 1 53 | selector: 54 | matchLabels: 55 | app: kube-rbac-proxy 56 | template: 57 | metadata: 58 | labels: 59 | app: kube-rbac-proxy 60 | spec: 61 | securityContext: 62 | runAsUser: 65532 63 | serviceAccountName: kube-rbac-proxy 64 | containers: 65 | - name: kube-rbac-proxy 66 | image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION 67 | args: 68 | - "--secure-listen-address=0.0.0.0:8443" 69 | - "--upstream=http://127.0.0.1:8081/" 70 | - "--auth-token-audiences=kube-rbac-proxy.default.svc" 71 | - "--logtostderr=true" 72 | - "--v=10" 73 | ports: 74 | - containerPort: 8443 75 | name: https 76 | securityContext: 77 | allowPrivilegeEscalation: false 78 | - name: prometheus-example-app 79 | image: quay.io/brancz/prometheus-example-app:v0.5.0 80 | args: 81 | - "--bind=127.0.0.1:8081" 82 | -------------------------------------------------------------------------------- /scripts/templates/oidc-deployment.yaml: -------------------------------------------------------------------------------- 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 | namespace: default 11 | roleRef: 12 | apiGroup: rbac.authorization.k8s.io 13 | kind: ClusterRole 14 | name: kube-rbac-proxy 15 | subjects: 16 | - kind: ServiceAccount 17 | name: kube-rbac-proxy 18 | namespace: default 19 | --- 20 | apiVersion: rbac.authorization.k8s.io/v1 21 | kind: ClusterRole 22 | metadata: 23 | name: kube-rbac-proxy 24 | rules: 25 | - apiGroups: ["authentication.k8s.io"] 26 | resources: 27 | - tokenreviews 28 | verbs: ["create"] 29 | - apiGroups: ["authorization.k8s.io"] 30 | resources: 31 | - subjectaccessreviews 32 | verbs: ["create"] 33 | --- 34 | apiVersion: v1 35 | kind: Service 36 | metadata: 37 | labels: 38 | app: kube-rbac-proxy 39 | name: kube-rbac-proxy 40 | spec: 41 | ports: 42 | - name: https 43 | port: 8444 44 | targetPort: https 45 | selector: 46 | app: kube-rbac-proxy 47 | --- 48 | apiVersion: apps/v1 49 | kind: Deployment 50 | metadata: 51 | name: kube-rbac-proxy 52 | spec: 53 | replicas: 1 54 | selector: 55 | matchLabels: 56 | app: kube-rbac-proxy 57 | template: 58 | metadata: 59 | labels: 60 | app: kube-rbac-proxy 61 | spec: 62 | # {BEGIN} for minikube development only if OIDC provider is deployed in minikube itself ie. dex 63 | hostNetwork: true 64 | dnsPolicy: ClusterFirstWithHostNet 65 | # {END} 66 | serviceAccountName: kube-rbac-proxy 67 | containers: 68 | - name: kube-rbac-proxy 69 | image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION 70 | args: 71 | - "--insecure-listen-address=0.0.0.0:8444" 72 | - "--upstream=http://127.0.0.1:8081/" 73 | - "--logtostderr=true" 74 | - "--v=10" 75 | - "--oidc-issuer={ISSUER}" 76 | - "--oidc-clientID={CLIENT_ID}" 77 | ports: 78 | - containerPort: 8444 79 | name: https 80 | securityContext: 81 | allowPrivilegeEscalation: false 82 | - name: prometheus-example-app 83 | image: quay.io/brancz/prometheus-example-app:v0.5.0 84 | args: 85 | - "--bind=127.0.0.1:8081" 86 | -------------------------------------------------------------------------------- /scripts/templates/resource-attributes-deployment.yaml: -------------------------------------------------------------------------------- 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 | resourceAttributes: 55 | namespace: default 56 | apiVersion: v1 57 | resource: services 58 | subresource: proxy 59 | name: kube-rbac-proxy 60 | --- 61 | apiVersion: apps/v1 62 | kind: Deployment 63 | metadata: 64 | name: kube-rbac-proxy 65 | spec: 66 | replicas: 1 67 | selector: 68 | matchLabels: 69 | app: kube-rbac-proxy 70 | template: 71 | metadata: 72 | labels: 73 | app: kube-rbac-proxy 74 | spec: 75 | securityContext: 76 | runAsUser: 65532 77 | serviceAccountName: kube-rbac-proxy 78 | containers: 79 | - name: kube-rbac-proxy 80 | image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION 81 | args: 82 | - "--secure-listen-address=0.0.0.0:8443" 83 | - "--upstream=http://127.0.0.1:8081/" 84 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 85 | - "--logtostderr=true" 86 | - "--v=10" 87 | ports: 88 | - containerPort: 8443 89 | name: https 90 | volumeMounts: 91 | - name: config 92 | mountPath: /etc/kube-rbac-proxy 93 | securityContext: 94 | allowPrivilegeEscalation: false 95 | - name: prometheus-example-app 96 | image: quay.io/brancz/prometheus-example-app:v0.5.0 97 | args: 98 | - "--bind=127.0.0.1:8081" 99 | volumes: 100 | - name: config 101 | configMap: 102 | name: kube-rbac-proxy 103 | -------------------------------------------------------------------------------- /scripts/templates/rewrites-deployment.yaml: -------------------------------------------------------------------------------- 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 | --- 63 | apiVersion: apps/v1 64 | kind: Deployment 65 | metadata: 66 | name: kube-rbac-proxy 67 | spec: 68 | replicas: 1 69 | selector: 70 | matchLabels: 71 | app: kube-rbac-proxy 72 | template: 73 | metadata: 74 | labels: 75 | app: kube-rbac-proxy 76 | spec: 77 | securityContext: 78 | runAsUser: 65532 79 | serviceAccountName: kube-rbac-proxy 80 | containers: 81 | - name: kube-rbac-proxy 82 | image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION 83 | args: 84 | - "--secure-listen-address=0.0.0.0:8443" 85 | - "--upstream=http://127.0.0.1:8081/" 86 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 87 | - "--logtostderr=true" 88 | - "--v=10" 89 | ports: 90 | - containerPort: 8443 91 | name: https 92 | volumeMounts: 93 | - name: config 94 | mountPath: /etc/kube-rbac-proxy 95 | securityContext: 96 | allowPrivilegeEscalation: false 97 | - name: prometheus-example-app 98 | image: quay.io/brancz/prometheus-example-app:v0.5.0 99 | args: 100 | - "--bind=127.0.0.1:8081" 101 | volumes: 102 | - name: config 103 | configMap: 104 | name: kube-rbac-proxy 105 | -------------------------------------------------------------------------------- /scripts/tools.go: -------------------------------------------------------------------------------- 1 | //go:build tools 2 | // +build tools 3 | 4 | /* 5 | Copyright 2020 Frederic Branczyk All rights reserved. 6 | 7 | Licensed under the Apache License, Version 2.0 (the "License"); 8 | you may not use this file except in compliance with the License. 9 | You may obtain a copy of the License at 10 | 11 | http://www.apache.org/licenses/LICENSE-2.0 12 | 13 | Unless required by applicable law or agreed to in writing, software 14 | distributed under the License is distributed on an "AS IS" BASIS, 15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | See the License for the specific language governing permissions and 17 | limitations under the License. 18 | */ 19 | 20 | package tools 21 | 22 | import ( 23 | _ "github.com/campoy/embedmd" 24 | ) 25 | -------------------------------------------------------------------------------- /test/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu 3 | c2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUwHhcNMTgxMDI1MTQwNzM1WhcNMjMxMDI0 4 | MTQwNzM2WjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUw 5 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ1+8Z00Ovc93IpUjOsWs2 6 | ueNfcaDpDYW7P2y50jqy4XGdRRdHiLQKQv7S3Zqy/wTlnaDpk8TLMp6YSZ41p1Qy 7 | 5HhIbXMviR9Bqg1JziSx9HaFvo5w79gn7YbICpftKpsi1L2KBk2ekgnTnt+pw+Ml 8 | L8N/ELtWtK8pu5cNZJIkJptxTWJzPyeUSVfDDPbEXP0VSDw2MOSoIxqcH1C4mR42 9 | Wr/6Crxtr2oyvAzLZvAtWCtUEY9fkmJVTGMjzfwRnrvxsfMguwSHKyyrRdDLoQMp 10 | sFn8cRBu0omTIbyMQlHo+QVgdQ+P6LnV9Dbjn5fX7+5ithyu4iTrJFqjDsd47vBN 11 | AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG 12 | SIb3DQEBCwUAA4IBAQBIzSylEYbVIl/KzelTWz0FZznczPMJnBlJAa4OGUHt8VuY 13 | viUcItOdjrGhzwCzJn+IfbLtuv7d5YHYKEZZFNbUIPyvRByAM+iNKXXFSSnGBelz 14 | J3onnrM4kMD8TwNZA4AJGpWy7Ntmtw/ie2BZ1AgBR9AhpxLC1Md7zxly59QGmahT 15 | ym2aYUfblwQRm0AgRlccRgyVZdf3fCU5/BxLZkRT/hOKMQbAPPlxIGnpk/uJJcD4 16 | ZxKXypiQ2tzsKId8VybBYmgdG482bKrd6q/bsJGZx4B1++hHrvIPDaJYrmJG3UMP 17 | x8z5unyK1BzrXFcyID1Dw998m4dhspjJeYPVNd2a 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--proxy-endpoints-port=8643" 23 | - "--upstream=http://127.0.0.1:8081/" 24 | - "--allow-paths=/metrics,/api/v1/label/*/values" 25 | - "--v=10" 26 | ports: 27 | - containerPort: 8443 28 | name: https 29 | - containerPort: 8643 30 | name: proxy 31 | readinessProbe: 32 | httpGet: 33 | scheme: HTTPS 34 | port: 8643 35 | path: healthz 36 | - name: prometheus-example-app 37 | image: quay.io/brancz/prometheus-example-app:v0.5.0 38 | args: 39 | - "--bind=127.0.0.1:8081" 40 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/allowpaths/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/basics/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/basics/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/basics/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/basics/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/basics/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--v=10" 24 | ports: 25 | - containerPort: 8443 26 | name: https 27 | - name: prometheus-example-app 28 | image: quay.io/brancz/prometheus-example-app:v0.5.0 29 | args: 30 | - "--bind=127.0.0.1:8081" 31 | -------------------------------------------------------------------------------- /test/e2e/basics/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/basics/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/certificate.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: kube-rbac-proxy-client-certificates 5 | type: kubernetes.io/tls 6 | data: 7 | tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURhakNDQWxLZ0F3SUJBZ0lVYzlWWlg2dDNqVHRwZWZycjQzcGQzVW8vNGFBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xERXFNQ2dHQTFVRUF4TWhhM1ZpWlMxeVltRmpMWEJ5YjNoNUxXTmxjblJwWm1sallYUmxjeTEwWlhOMApNQjRYRFRJeE1ETXhOakUzTWpVd01Gb1hEVE14TURNeE5ERTNNalV3TUZvd0xERXFNQ2dHQTFVRUF4TWhhM1ZpClpTMXlZbUZqTFhCeWIzaDVMV05sY25ScFptbGpZWFJsY3kxMFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUEvVjdzelZNdXl5ZFk1bHMwdkxyVWh0cE1kWmtVV2ZWQTIyQW5tbGhtNk5oeQowVjlMK1dKc3VZbTlicjl4VUJLV1JPaGVkNk5SaGYxRkczL1JBRWROM1l0MUM0eEw4TUxOTzUwbVYvTGdTL3lFCnlXaUlPdEhaRk9SM1NzcWVCVlJWd2N2ekhmdnFKQTl2Ujh4MVR4NVAyd1ZlRHpOWHVQSGJCSW1KREcwZXNSWjkKWTBZeGZCK3M2eTJaeUxRK3JXSDRheDRjVHlaWGVSSGZoZmhMdStkOTJScDIvSmx2aDRaUXJzcFIyQ0YxZE5CQgpxNnE3LzdreWd3TmVsTmZkeU9sbDlCT1hOVHBKQmdYa3FCQUE4RWllWkhuUGZ5TGJuYVdVSzFQS2REV2hwOTNWCnRiSU9IZklXamc0OTdSZ2RsazhGTlptTkxJbjI1dzB0VHVSWktOQzM2UUlEQVFBQm80R0RNSUdBTUE0R0ExVWQKRHdFQi93UUVBd0lGb0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQU1CZ05WSFJNQkFmOEVBakFBTUIwRwpBMVVkRGdRV0JCUjdyTjFscFB2Qlk3YjdqUjMxbDF5aStaSDVRREFzQmdOVkhSRUVKVEFqZ2lGcmRXSmxMWEppCllXTXRjSEp2ZUhrdFkyVnlkR2xtYVdOaGRHVnpMWFJsYzNRd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFFZnQKUFkxc3RQSk1IeEE4UjVOQk01TTVwV0lDK3hENVZHc3RhV0M3a0RTWit5TjdMS1lSQjdVV0d5c2dCbkZsK2hqOApHWVBOQUgrbkNDOWJEODhSQi9aWkhBZ3dtREJPbG01OVUvSjUzL0pLQlhFS0l3cjg2WmI0SU9pYlVPbG94RDJBCnUwVTJteGRQb3ZBSjZ1akplN3k5YTh0QUFTV1BVck9xUElVWHNkbFR6RmJ2UktxN3hScTZXaWtKQndqRzhYd0oKd0NNc2Jja2pES2Q1T2tMWTk4WkJWWmlFcGoyaXFJdDNCSk95cnV0eEh1N05Pcm5UdEdCVmlSZlVrRlltcEVoTApDYkp3bnNCbitCTWFSd3FxNWRtZXJzV0RnREtYK1ZGYXZzUVZvN1VubGRFcmlvVzZlaTFxZnV1M1NsZDF5a3NPCkx2QW9ISDRxZXIwS2loTGMwZms9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 8 | tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBL1Y3c3pWTXV5eWRZNWxzMHZMclVodHBNZFprVVdmVkEyMkFubWxobTZOaHkwVjlMCitXSnN1WW05YnI5eFVCS1dST2hlZDZOUmhmMUZHMy9SQUVkTjNZdDFDNHhMOE1MTk81MG1WL0xnUy95RXlXaUkKT3RIWkZPUjNTc3FlQlZSVndjdnpIZnZxSkE5dlI4eDFUeDVQMndWZUR6Tlh1UEhiQkltSkRHMGVzUlo5WTBZeApmQitzNnkyWnlMUStyV0g0YXg0Y1R5WlhlUkhmaGZoTHUrZDkyUnAyL0psdmg0WlFyc3BSMkNGMWROQkJxNnE3Ci83a3lnd05lbE5mZHlPbGw5Qk9YTlRwSkJnWGtxQkFBOEVpZVpIblBmeUxibmFXVUsxUEtkRFdocDkzVnRiSU8KSGZJV2pnNDk3UmdkbGs4Rk5abU5MSW4yNXcwdFR1UlpLTkMzNlFJREFRQUJBb0lCQUNnMUNCOE5ORC9JM3JLdgpobzdzbHcxUFZ4TFNXQWh1Z3Z4TkpmdTRTNXhudk5DODdyR0VqUHhrZjBzejFpZCt5NW5qeGhuMk1ObXlkMlVGCnc0VG55OU44YmZhSExRWG40K214NW9QT1p3bW42T3FOVEJFSmZBbDB0L21HYmMwcXRQRXNERWlWMFhJbmdPRkQKOE5tOVZhN01DMEVlUksxMHMremtabnN5VmN5RUZFemRibzFHQnQ3Sjg2c3JkR3JGekV1Yk1wSHRvcHdLYkpCUApQVkE1eEo4dXJ5T0t0Rm9PZUM5M0NMaWozL1k3dE9iWTkzNGVVRFlmek5mbnNFajlSWjJlVkt5bnZSMjMvMDh4Cm1kZVdnVDIzMEFGai95U0JZT0c1bXRObHBVaVlySmZhRHpzbmViOUFuTElXVmU1WitlcnF2ZTB6MGkrb2lCK0EKWFIrVjVJRUNnWUVBL2xDQ3orbXc5Z25Rc1ZlZFRZMm5vSVkxSWNKcmttYnIwZ3dWNS9YVmg3QUpyZjJkUVpmcQpyUDIvWVNwNUY0Qkh3WXBzU0ZuZER4ZEMyQ24yUThzSWhZWm5MUC81eFd2UmlaVFpQcGdFamRYdksvUXBOdmorCk41MnZHUHBJLzN1TTRoTldtQytEUnhTOCtjOTUwbU5Jakt3R1AyTGQwc09BelJKb3RTS3lJMThDZ1lFQS93elEKR05jK0sxY2FTWmgrN1cwUWEvSWR6SXBjaDJTSkZ3N2NpbUpBdGI1QWUxcUNTV05VVEU3K2g0ZUoxRUVMeFdKSAo4ZVhwOXM2YmJqUUdhK1VnVWZ0Y2FGeTVsQUp5cUJlR0Yvb2d5NGVma1pmZm90dkhoamwrK0F4c2EzakZ5OWZCCnI3TE1DQVdxWUFNbjhVbDZEdDIrYU1TQ2FKVWJKb2wzeVF2ejhiY0NnWUFaMkF5ekhFaURlRlBnOGNwbWl6S3gKdVhIRTBJRW1DNWVEYlA3ODU1cWZnMkE0Y2tGODNQZFlSU0VodXJNN2xDbTJuVjZMcTdZdlJtbmdsY01VK0prUgpHS3Q3Z3pmYXZDNDdFUWxTdHhnZllkSkFZVHVlL29hM0dDc25HcWc0YmxITzE3QkJIdkwwVWtNeUQ4ZU5mZEZ0Cm1qMjRTMC9IajE2VGVIOXppT2NaZVFLQmdRQ1pMVmpOa25nRUQ0djZKMXdUdkN6Z3A4aTl6MXRDOVY1Z09zeTUKVDhrTlhmWGNINytmMDhnTkRHUlJnVldGNUlydFFObDBybUNWbWdBL2IzOXJ6WEJiekZyelVyMGg1MVoxSGF1cgpPczMzYnJ5bTlFK2J2K05VK2JNSHhtNVhIWEd0dXliWUhzbnJCM3dMcmRtUFVGRytHKzcvZlFYVlNiZkVyVXNECnMrb09nUUtCZ1FESDJrR2NsZkdqZWpPUThpZTFIeTViQUg4M2RpdzVzRWJHdUlabDRjRGc3VlpUY08zR3dPWG4KbGFyL1RVTVR0S0ROWHVWSU02ZWtKTVlZZ2V4V1VGaFRCTlN4VGc0cjUxR2w4a09UZ0tsMUFWemgzZHRYVzRhaAorWHp6QkJMOUsxZXpEajQzT2JaY3FVeEtraStSTzN5Y2RuaFFtMzZGVWVyVUlXRGNZVVV3SGc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= 9 | ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLRENDQWhDZ0F3SUJBZ0lVZkUvWU1TT2NzZkVIOGN2TWxvRFkvS1prUnA4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xERXFNQ2dHQTFVRUF4TWhhM1ZpWlMxeVltRmpMWEJ5YjNoNUxXTmxjblJwWm1sallYUmxjeTEwWlhOMApNQjRYRFRJeE1ETXhOakUzTWpVd01Gb1hEVEkyTURNeE5URTNNalV3TUZvd0xERXFNQ2dHQTFVRUF4TWhhM1ZpClpTMXlZbUZqTFhCeWIzaDVMV05sY25ScFptbGpZWFJsY3kxMFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyeFJ4bGZOOFl5aG0rY0RheW0wNENLSmkzSlJ6d0FVQ1hPZkZidzd6VDBuZwo3SnNNQ0hONDVDZmFLSElTV0diL1AwWkRrSDBCUVpGcEczcmx2T2NDS2szbDFieHFCMGcwL0p4ekhvSWVTVW1wCndrRG1HSm5rcHQ5dVVaZFpKbGFCZkZNZ2RjUlNkaFZZdlZMYXRGdUNsTENlbmVvek9RcDkya3dPRStpUTBreWUKNTd6QXpWN0d0ZWd0UHVnQ2V3bmpvOFg5amg4bXlaRlZBbGFnRmVpUjJjNWZRbGJZLzMwS1VieTNkeTNodTRNWApmMlN6a3l0dFpSUkxhaHo4eWdieXptMExMOHBuZ1RPcFNNRGkrcDNnRFg3QmRUUnQ2QUgvUkp0aVVPdTJjS0hzCkdUZG51SEdScldLZFZJQ20zWUFhRVBXN3hwSG92Y3dzaGdrOTFpbXByUUlEQVFBQm8wSXdRREFPQmdOVkhROEIKQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVQkRIcGEvNXlFSUh3VVF4aQoxS1loakJZQnQ0a3dEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQlZKQzIya2lrQXhlV0MycGVPQ2ZHQW96ZUtBCksvUTBpSDRWeXYzRnpCaExZMDRHcmEwYWpNbGZXU3hERVRXU2xYVHp5cnIwR1NMNEdJMWZlUHN5MTcwcVpBTnYKaTRCZGRWVHEvY0p6NittVythekNaeHFid2o3RDkvNDFUa3BhOW5xZ3ZBSVJwN3laQXcrSnY1T2ZuUXQ5VFkrcgphNDlqMEdVZ1VKUGlxZGc1M25NWUhmQWw0QThTN0U5VytrZWJpMXRBL1RYcVVhMGtGNjNMbUpWSGcybGVDUllRCjRmK1ZDd3g0TVZDOHhRdE9NZVp2T1YzQVNLRmxvV1Rab1drUFlwcURSaEdVaGdxMjhLMDdUZ2RYck0rYUhFdWUKK3hFN24rd3JJSUhxZTJZbkVwT010ajJpZThnUDJ6cmdTRVk5ZytVbjV0SzJlUFVBSGtmVm9mVE9ZZDA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K 10 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | rules: 6 | - apiGroups: ["authentication.k8s.io"] 7 | resources: 8 | - tokenreviews 9 | verbs: ["create"] 10 | - apiGroups: ["authorization.k8s.io"] 11 | resources: 12 | - subjectaccessreviews 13 | verbs: ["create"] 14 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: User 11 | name: kube-rbac-proxy-certificates-test 12 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: kube-rbac-proxy 9 | subjects: 10 | - kind: ServiceAccount 11 | name: kube-rbac-proxy 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/deployment-wrongca.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--client-ca-file=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | volumeMounts: 29 | - mountPath: /certs 30 | name: certs 31 | - name: prometheus-example-app 32 | image: quay.io/brancz/prometheus-example-app:v0.5.0 33 | args: 34 | - "--bind=127.0.0.1:8081" 35 | volumes: 36 | - name: certs 37 | secret: 38 | secretName: kube-rbac-proxy-client-certificates 39 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--client-ca-file=/certs/ca.crt" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | volumeMounts: 29 | - mountPath: /certs 30 | name: certs 31 | - name: prometheus-example-app 32 | image: quay.io/brancz/prometheus-example-app:v0.5.0 33 | args: 34 | - "--bind=127.0.0.1:8081" 35 | volumes: 36 | - name: certs 37 | secret: 38 | secretName: kube-rbac-proxy-client-certificates 39 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/clientcertificates/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/flags/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/flags/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/flags/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/flags/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/flags/deployment-logtostderr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--logtostderr" 23 | - "--upstream=http://127.0.0.1:8081/" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | - name: prometheus-example-app 29 | image: quay.io/brancz/prometheus-example-app:v0.5.0 30 | args: 31 | - "--bind=127.0.0.1:8081" 32 | -------------------------------------------------------------------------------- /test/e2e/flags/deployment-other-flags.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--add-dir-header=true" 24 | - "--alsologtostderr=true" 25 | - "--log-backtrace-at=0" 26 | - "--log-dir=mustnotexist" 27 | - "--log-file=mustnotexist" 28 | - "--log-file-max-size=1800" 29 | - "--one-output=true" 30 | - "--skip-headers=true" 31 | - "--skip-log-headers=true" 32 | - "--stderrthreshold=2" 33 | - "--v=10" 34 | ports: 35 | - containerPort: 8443 36 | name: https 37 | - name: prometheus-example-app 38 | image: quay.io/brancz/prometheus-example-app:v0.5.0 39 | args: 40 | - "--bind=127.0.0.1:8081" 41 | -------------------------------------------------------------------------------- /test/e2e/flags/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/flags/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--upstream-force-h2c=true" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | - name: prometheus-example-app 29 | image: quay.io/brancz/prometheus-example-app:v0.4.0 30 | args: 31 | - "--bind=127.0.0.1:8081" 32 | - "--h2c=true" 33 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/h2c-upstream/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/h2c_upstream.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | "testing" 21 | 22 | "k8s.io/client-go/kubernetes" 23 | 24 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 25 | ) 26 | 27 | func testH2CUpstream(client kubernetes.Interface) kubetest.TestSuite { 28 | return func(t *testing.T) { 29 | command := `curl --connect-timeout 5 -v -s -k --fail -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics` 30 | 31 | kubetest.Scenario{ 32 | Name: "With H2C Upstream", 33 | 34 | Given: kubetest.Actions( 35 | kubetest.CreatedManifests( 36 | client, 37 | "h2c-upstream/clusterRole.yaml", 38 | "h2c-upstream/clusterRoleBinding.yaml", 39 | "h2c-upstream/deployment.yaml", 40 | "h2c-upstream/service.yaml", 41 | "h2c-upstream/serviceAccount.yaml", 42 | "h2c-upstream/clusterRole-client.yaml", 43 | "h2c-upstream/clusterRoleBinding-client.yaml", 44 | ), 45 | ), 46 | When: kubetest.Actions( 47 | kubetest.PodsAreReady( 48 | client, 49 | 1, 50 | "app=kube-rbac-proxy", 51 | ), 52 | kubetest.ServiceIsReady( 53 | client, 54 | "kube-rbac-proxy", 55 | ), 56 | ), 57 | Then: kubetest.Actions( 58 | kubetest.ClientSucceeds( 59 | client, 60 | command, 61 | nil, 62 | ), 63 | ), 64 | }.Run(t) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/e2e/http2.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2023 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package e2e 17 | 18 | import ( 19 | "testing" 20 | 21 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 22 | "k8s.io/client-go/kubernetes" 23 | ) 24 | 25 | func testHTTP2(client kubernetes.Interface) kubetest.TestSuite { 26 | return func(t *testing.T) { 27 | command := `HTTP_VERSION=$(curl -sI --http2 --connect-timeout 5 -k --fail -w "%{http_version}\n" -o /dev/null https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics); if [[ "$HTTP_VERSION" != "2" ]]; then echo "Did expect HTTP/2. Actual protocol: $HTTP_VERSION" > /proc/self/fd/2; exit 1; fi` 28 | 29 | kubetest.Scenario{ 30 | Name: "With succeeding HTTP2-client", 31 | Description: ` 32 | Expecting http/2 capable client to succeed to connect with http/2. 33 | `, 34 | 35 | Given: kubetest.Actions( 36 | kubetest.CreatedManifests( 37 | client, 38 | "http2/clusterRole.yaml", 39 | "http2/clusterRoleBinding.yaml", 40 | "http2/deployment.yaml", 41 | "http2/service.yaml", 42 | "http2/serviceAccount.yaml", 43 | "http2/clusterRole-client.yaml", 44 | "http2/clusterRoleBinding-client.yaml", 45 | ), 46 | ), 47 | When: kubetest.Actions( 48 | kubetest.PodsAreReady( 49 | client, 50 | 1, 51 | "app=kube-rbac-proxy", 52 | ), 53 | kubetest.ServiceIsReady( 54 | client, 55 | "kube-rbac-proxy", 56 | ), 57 | ), 58 | Then: kubetest.Actions( 59 | kubetest.ClientSucceeds( 60 | client, 61 | command, 62 | nil, 63 | ), 64 | ), 65 | }.Run(t) 66 | 67 | kubetest.Scenario{ 68 | Name: "With failing HTTP2-client", 69 | Description: ` 70 | Expecting http/2 capable client to fail to connect with http/2. 71 | `, 72 | 73 | Given: kubetest.Actions( 74 | kubetest.CreatedManifests( 75 | client, 76 | "http2/clusterRole.yaml", 77 | "http2/clusterRoleBinding.yaml", 78 | "http2/deployment-no-http2.yaml", 79 | "http2/service.yaml", 80 | "http2/serviceAccount.yaml", 81 | "http2/clusterRole-client.yaml", 82 | "http2/clusterRoleBinding-client.yaml", 83 | ), 84 | ), 85 | When: kubetest.Actions( 86 | kubetest.PodsAreReady( 87 | client, 88 | 1, 89 | "app=kube-rbac-proxy", 90 | ), 91 | kubetest.ServiceIsReady( 92 | client, 93 | "kube-rbac-proxy", 94 | ), 95 | ), 96 | Then: kubetest.Actions( 97 | kubetest.ClientFails( 98 | client, 99 | command, 100 | nil, 101 | ), 102 | ), 103 | }.Run(t) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /test/e2e/http2/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/http2/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/http2/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/http2/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/http2/deployment-no-http2.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--ignore-paths=/metrics,/api/v1/*" 24 | - "--http2-disable=true" 25 | - "--v=10" 26 | ports: 27 | - containerPort: 8443 28 | name: https 29 | - name: prometheus-example-app 30 | image: quay.io/brancz/prometheus-example-app:v0.5.0 31 | args: 32 | - "--bind=127.0.0.1:8081" 33 | -------------------------------------------------------------------------------- /test/e2e/http2/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--ignore-paths=/metrics,/api/v1/*" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | - name: prometheus-example-app 29 | image: quay.io/brancz/prometheus-example-app:v0.5.0 30 | args: 31 | - "--bind=127.0.0.1:8081" 32 | -------------------------------------------------------------------------------- /test/e2e/http2/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/http2/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--ignore-paths=/metrics,/api/v1/*" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | - name: prometheus-example-app 29 | image: quay.io/brancz/prometheus-example-app:v0.5.0 30 | args: 31 | - "--bind=127.0.0.1:8081" 32 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/ignorepaths/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/kind-config/kind-config.yaml: -------------------------------------------------------------------------------- 1 | # this config file contains all config fields with comments 2 | kind: Cluster 3 | apiVersion: kind.x-k8s.io/v1alpha4 4 | # patch the generated kubeadm config with some extra settings 5 | kubeadmConfigPatches: 6 | - | 7 | apiVersion: kubeadm.k8s.io/v1beta2 8 | kind: ClusterConfiguration 9 | metadata: 10 | name: config 11 | apiServer: 12 | extraArgs: 13 | service-account-signing-key-file: /etc/kubernetes/pki/sa.key 14 | service-account-issuer: kubernetes.default.svc 15 | v: "10" 16 | -------------------------------------------------------------------------------- /test/e2e/main_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "k8s.io/client-go/kubernetes" 24 | "k8s.io/client-go/rest" 25 | "k8s.io/client-go/tools/clientcmd" 26 | 27 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 28 | ) 29 | 30 | func Test(t *testing.T) { 31 | clientConfig, err := newClientConfigForTest() 32 | if err != nil { 33 | t.Fatalf("failed retrieving kubernetes client config: %v", err) 34 | } 35 | client, err := kubernetes.NewForConfig(clientConfig) 36 | if err != nil { 37 | t.Fatalf("failed to setup a client for the tests: %v", err) 38 | } 39 | 40 | tests := map[string]kubetest.TestSuite{ 41 | "Basics": testBasics(client), 42 | "H2CUpstream": testH2CUpstream(client), 43 | "ClientCertificates": testClientCertificates(client), 44 | "TokenAudience": testTokenAudience(client), 45 | "AllowPath": testAllowPathsRegexp(client), 46 | "IgnorePath": testIgnorePaths(client), 47 | "TLS": testTLS(client), 48 | "StaticAuthorizer": testStaticAuthorizer(client), 49 | "HTTP2": testHTTP2(client), 50 | "Flags": testFlags(client), 51 | "TokenMasking": testTokenMasking(client), 52 | } 53 | 54 | for name, tc := range tests { 55 | t.Run(name, tc) 56 | } 57 | } 58 | 59 | // NewClientConfigForTest returns a config configured to connect to the api server 60 | func newClientConfigForTest() (*rest.Config, error) { 61 | loader := clientcmd.NewDefaultClientConfigLoadingRules() 62 | clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loader, &clientcmd.ConfigOverrides{}) 63 | config, err := clientConfig.ClientConfig() 64 | if err == nil { 65 | fmt.Printf("Found configuration for host %v.\n", config.Host) 66 | } 67 | 68 | return config, err 69 | } 70 | -------------------------------------------------------------------------------- /test/e2e/static-auth/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/static-auth/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/static-auth/configmap-non-resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kube-rbac-proxy 5 | data: 6 | config-file.yaml: |+ 7 | authorization: 8 | static: 9 | - user: 10 | name: system:serviceaccount:default:default 11 | resourceRequest: false 12 | verb: get 13 | path: /metrics 14 | -------------------------------------------------------------------------------- /test/e2e/static-auth/configmap-resource.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: kube-rbac-proxy 5 | data: 6 | config-file.yaml: |+ 7 | authorization: 8 | rewrites: 9 | byQueryParameter: 10 | name: "namespace" 11 | resourceAttributes: 12 | resource: namespaces 13 | subresource: metrics 14 | namespace: "{{ .Value }}" 15 | static: 16 | - user: 17 | name: system:serviceaccount:default:default 18 | resourceRequest: true 19 | resource: namespaces 20 | subresource: metrics 21 | namespace: default 22 | verb: get 23 | -------------------------------------------------------------------------------- /test/e2e/static-auth/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | securityContext: 17 | runAsUser: 65532 18 | serviceAccountName: kube-rbac-proxy 19 | containers: 20 | - name: kube-rbac-proxy 21 | image: quay.io/brancz/kube-rbac-proxy:local 22 | args: 23 | - "--secure-listen-address=0.0.0.0:8443" 24 | - "--upstream=http://127.0.0.1:8081/" 25 | - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" 26 | - "--v=10" 27 | ports: 28 | - containerPort: 8443 29 | name: https 30 | volumeMounts: 31 | - name: config 32 | mountPath: /etc/kube-rbac-proxy 33 | securityContext: 34 | allowPrivilegeEscalation: false 35 | - name: prometheus-example-app 36 | image: quay.io/brancz/prometheus-example-app:v0.5.0 37 | args: 38 | - "--bind=127.0.0.1:8081" 39 | volumes: 40 | - name: config 41 | configMap: 42 | name: kube-rbac-proxy 43 | -------------------------------------------------------------------------------- /test/e2e/static-auth/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/static-auth/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/static_authorizer.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "k8s.io/client-go/kubernetes" 24 | 25 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 26 | ) 27 | 28 | func testStaticAuthorizer(client kubernetes.Interface) kubetest.TestSuite { 29 | return func(t *testing.T) { 30 | command := `curl --connect-timeout 5 -v -s -k --fail -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kube-rbac-proxy.default.svc.cluster.local:8443%v` 31 | 32 | for _, tc := range []struct { 33 | name string 34 | given kubetest.Action 35 | check kubetest.Action 36 | }{ 37 | { 38 | name: "resource/namespace/metrics/query rewrite/granted", 39 | given: kubetest.Actions( 40 | kubetest.CreatedManifests( 41 | client, 42 | "static-auth/configmap-resource.yaml", 43 | "static-auth/clusterRole.yaml", 44 | "static-auth/clusterRoleBinding.yaml", 45 | "static-auth/deployment.yaml", 46 | "static-auth/service.yaml", 47 | "static-auth/serviceAccount.yaml", 48 | ), 49 | ), 50 | check: kubetest.Actions( 51 | kubetest.ClientSucceeds( 52 | client, 53 | fmt.Sprintf(command, "/metrics?namespace=default"), 54 | nil, 55 | ), 56 | ), 57 | }, 58 | { 59 | name: "resource/namespace/metrics/query rewrite/forbidden", 60 | given: kubetest.Actions( 61 | kubetest.CreatedManifests( 62 | client, 63 | "static-auth/configmap-resource.yaml", 64 | "static-auth/clusterRole.yaml", 65 | "static-auth/clusterRoleBinding.yaml", 66 | "static-auth/deployment.yaml", 67 | "static-auth/service.yaml", 68 | "static-auth/serviceAccount.yaml", 69 | ), 70 | ), 71 | check: kubetest.Actions( 72 | kubetest.ClientFails( 73 | client, 74 | fmt.Sprintf(command, "/metrics?namespace=forbidden"), 75 | nil, 76 | ), 77 | ), 78 | }, 79 | { 80 | name: "non-resource/get/metrics/granted", 81 | given: kubetest.Actions( 82 | kubetest.CreatedManifests( 83 | client, 84 | "static-auth/configmap-non-resource.yaml", 85 | "static-auth/clusterRole.yaml", 86 | "static-auth/clusterRoleBinding.yaml", 87 | "static-auth/deployment.yaml", 88 | "static-auth/service.yaml", 89 | "static-auth/serviceAccount.yaml", 90 | ), 91 | ), 92 | check: kubetest.Actions( 93 | kubetest.ClientSucceeds( 94 | client, 95 | fmt.Sprintf(command, "/metrics"), 96 | nil, 97 | ), 98 | ), 99 | }, 100 | { 101 | name: "non-resource/get/metrics/forbidden", 102 | given: kubetest.Actions( 103 | kubetest.CreatedManifests( 104 | client, 105 | "static-auth/configmap-non-resource.yaml", 106 | "static-auth/clusterRole.yaml", 107 | "static-auth/clusterRoleBinding.yaml", 108 | "static-auth/deployment.yaml", 109 | "static-auth/service.yaml", 110 | "static-auth/serviceAccount.yaml", 111 | ), 112 | ), 113 | check: kubetest.Actions( 114 | kubetest.ClientFails( 115 | client, 116 | fmt.Sprintf(command, "/forbidden"), 117 | nil, 118 | ), 119 | ), 120 | }, 121 | } { 122 | kubetest.Scenario{ 123 | Name: tc.name, 124 | Given: kubetest.Actions(tc.given), 125 | When: kubetest.Actions( 126 | kubetest.PodsAreReady( 127 | client, 128 | 1, 129 | "app=kube-rbac-proxy", 130 | ), 131 | kubetest.ServiceIsReady( 132 | client, 133 | "kube-rbac-proxy", 134 | ), 135 | ), 136 | Then: kubetest.Actions(tc.check), 137 | }.Run(t) 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /test/e2e/tls.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2021 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "k8s.io/client-go/kubernetes" 24 | 25 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 26 | ) 27 | 28 | func testTLS(client kubernetes.Interface) kubetest.TestSuite { 29 | return func(t *testing.T) { 30 | command := `curl %v --connect-timeout 5 -v -s -k --fail -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics` 31 | 32 | for _, tc := range []struct { 33 | name string 34 | tlsFlag string 35 | }{ 36 | { 37 | name: "1.0", 38 | tlsFlag: "--tlsv1.0", 39 | }, 40 | { 41 | name: "1.1", 42 | tlsFlag: "--tlsv1.1", 43 | }, 44 | { 45 | name: "1.2", 46 | tlsFlag: "--tlsv1.2", 47 | }, 48 | { 49 | name: "1.3", 50 | tlsFlag: "--tlsv1.3", 51 | }, 52 | } { 53 | kubetest.Scenario{ 54 | Name: tc.name, 55 | 56 | Given: kubetest.Actions( 57 | kubetest.CreatedManifests( 58 | client, 59 | "basics/clusterRole.yaml", 60 | "basics/clusterRoleBinding.yaml", 61 | "basics/deployment.yaml", 62 | "basics/service.yaml", 63 | "basics/serviceAccount.yaml", 64 | // This adds the clients cluster role to succeed 65 | "basics/clusterRole-client.yaml", 66 | "basics/clusterRoleBinding-client.yaml", 67 | ), 68 | ), 69 | When: kubetest.Actions( 70 | kubetest.PodsAreReady( 71 | client, 72 | 1, 73 | "app=kube-rbac-proxy", 74 | ), 75 | kubetest.ServiceIsReady( 76 | client, 77 | "kube-rbac-proxy", 78 | ), 79 | ), 80 | Then: kubetest.Actions( 81 | kubetest.ClientSucceeds( 82 | client, 83 | fmt.Sprintf(command, tc.tlsFlag), 84 | nil, 85 | ), 86 | ), 87 | }.Run(t) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2024 the kube-rbac-proxy maintainers. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package e2e 18 | 19 | import ( 20 | "bufio" 21 | "context" 22 | "fmt" 23 | "github.com/brancz/kube-rbac-proxy/test/kubetest" 24 | corev1 "k8s.io/api/core/v1" 25 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 | "k8s.io/client-go/kubernetes" 27 | "strings" 28 | "testing" 29 | ) 30 | 31 | func testTokenMasking(client kubernetes.Interface) kubetest.TestSuite { 32 | return func(t *testing.T) { 33 | command := `curl --connect-timeout 5 -v -s -k --fail -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics` 34 | 35 | kubetest.Scenario{ 36 | Name: "TokenMasking", 37 | Description: ` 38 | As a client making a request through kube-rbac-proxy, 39 | I expect the logs to have tokens masked. 40 | `, 41 | 42 | Given: kubetest.Actions( 43 | kubetest.CreatedManifests( 44 | client, 45 | "tokenmasking/clusterRole.yaml", 46 | "tokenmasking/clusterRoleBinding.yaml", 47 | "tokenmasking/deployment.yaml", 48 | "tokenmasking/service.yaml", 49 | "tokenmasking/serviceAccount.yaml", 50 | "tokenmasking/clusterRole-client.yaml", 51 | "tokenmasking/clusterRoleBinding-client.yaml", 52 | ), 53 | ), 54 | When: kubetest.Actions( 55 | kubetest.PodsAreReady( 56 | client, 57 | 1, 58 | "app=kube-rbac-proxy", 59 | ), 60 | kubetest.ServiceIsReady( 61 | client, 62 | "kube-rbac-proxy", 63 | ), 64 | ), 65 | Then: kubetest.Actions( 66 | kubetest.ClientSucceeds( 67 | client, 68 | command, 69 | nil, 70 | ), 71 | checkLogsForMaskedToken(client), 72 | ), 73 | }.Run(t) 74 | } 75 | } 76 | 77 | func checkLogsForMaskedToken(client kubernetes.Interface) kubetest.Action { 78 | return func(ctx *kubetest.ScenarioContext) error { 79 | pods, err := client.CoreV1().Pods(ctx.Namespace).List(context.TODO(), v1.ListOptions{ 80 | LabelSelector: "app=kube-rbac-proxy", 81 | }) 82 | if err != nil { 83 | return fmt.Errorf("failed to list pods: %v", err) 84 | } 85 | 86 | if len(pods.Items) == 0 { 87 | return fmt.Errorf("no pods found with label app=kube-rbac-proxy") 88 | } 89 | 90 | podName := pods.Items[0].Name 91 | 92 | logsReq := client.CoreV1().Pods(ctx.Namespace).GetLogs(podName, &corev1.PodLogOptions{ 93 | Container: "kube-rbac-proxy", 94 | }) 95 | logsStream, err := logsReq.Stream(context.TODO()) 96 | if err != nil { 97 | return fmt.Errorf("failed to get logs: %v", err) 98 | } 99 | defer func() { 100 | closeErr := logsStream.Close() 101 | if closeErr != nil && err == nil { 102 | err = fmt.Errorf("failed to close logs stream: %v", closeErr) 103 | } 104 | }() 105 | 106 | scanner := bufio.NewScanner(logsStream) 107 | foundMaskedToken := false 108 | for scanner.Scan() { 109 | line := scanner.Text() 110 | if strings.Contains(line, `"kind":"TokenReview"`) { 111 | if strings.Contains(line, `"token":""`) { 112 | foundMaskedToken = true 113 | break 114 | } else { 115 | return fmt.Errorf("found TokenReview in logs but token is not masked") 116 | } 117 | } 118 | } 119 | if err := scanner.Err(); err != nil { 120 | return fmt.Errorf("error reading logs: %v", err) 121 | } 122 | 123 | if !foundMaskedToken { 124 | return fmt.Errorf("no TokenReview log found with masked token") 125 | } 126 | 127 | return nil 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | rules: 7 | - apiGroups: ["authentication.k8s.io"] 8 | resources: 9 | - tokenreviews 10 | verbs: ["create"] 11 | - apiGroups: ["authorization.k8s.io"] 12 | resources: 13 | - subjectaccessreviews 14 | verbs: ["create"] 15 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | roleRef: 7 | apiGroup: rbac.authorization.k8s.io 8 | kind: ClusterRole 9 | name: kube-rbac-proxy 10 | subjects: 11 | - kind: ServiceAccount 12 | name: kube-rbac-proxy 13 | namespace: default 14 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | securityContext: 17 | runAsUser: 65532 18 | serviceAccountName: kube-rbac-proxy 19 | containers: 20 | - name: kube-rbac-proxy 21 | image: quay.io/brancz/kube-rbac-proxy:local 22 | args: 23 | - "--secure-listen-address=0.0.0.0:8443" 24 | - "--upstream=http://127.0.0.1:8081/" 25 | - "--logtostderr=true" 26 | - "--v=10" 27 | ports: 28 | - containerPort: 8443 29 | name: https 30 | securityContext: 31 | allowPrivilegeEscalation: false 32 | - name: prometheus-example-app 33 | image: quay.io/brancz/prometheus-example-app:v0.5.0 34 | args: 35 | - "--bind=127.0.0.1:8081" 36 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/tokenmasking/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/clusterRole-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: metrics 5 | rules: 6 | - nonResourceURLs: ["/metrics"] 7 | verbs: ["get"] 8 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/clusterRole.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: kube-rbac-proxy 5 | rules: 6 | - apiGroups: ["authentication.k8s.io"] 7 | resources: 8 | - tokenreviews 9 | verbs: ["create"] 10 | - apiGroups: ["authorization.k8s.io"] 11 | resources: 12 | - subjectaccessreviews 13 | verbs: ["create"] 14 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/clusterRoleBinding-client.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: metrics 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: metrics 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/clusterRoleBinding.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: kube-rbac-proxy 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: kube-rbac-proxy 9 | subjects: 10 | - kind: ServiceAccount 11 | name: kube-rbac-proxy 12 | namespace: default 13 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kube-rbac-proxy 11 | template: 12 | metadata: 13 | labels: 14 | app: kube-rbac-proxy 15 | spec: 16 | serviceAccountName: kube-rbac-proxy 17 | containers: 18 | - name: kube-rbac-proxy 19 | image: quay.io/brancz/kube-rbac-proxy:local 20 | args: 21 | - "--secure-listen-address=0.0.0.0:8443" 22 | - "--upstream=http://127.0.0.1:8081/" 23 | - "--auth-token-audiences=kube-rbac-proxy" 24 | - "--v=10" 25 | ports: 26 | - containerPort: 8443 27 | name: https 28 | - name: prometheus-example-app 29 | image: quay.io/brancz/prometheus-example-app:v0.5.0 30 | args: 31 | - "--bind=127.0.0.1:8081" 32 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | app: kube-rbac-proxy 6 | name: kube-rbac-proxy 7 | namespace: default 8 | spec: 9 | ports: 10 | - name: https 11 | port: 8443 12 | targetPort: https 13 | selector: 14 | app: kube-rbac-proxy 15 | -------------------------------------------------------------------------------- /test/e2e/tokenrequest/serviceAccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: kube-rbac-proxy 5 | namespace: default 6 | -------------------------------------------------------------------------------- /test/kubetest/client.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2022 kube-rbac-proxy authors. All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kubetest 18 | 19 | import "k8s.io/client-go/kubernetes" 20 | 21 | func ClientSucceeds(client kubernetes.Interface, command string, opts *RunOptions) Action { 22 | return func(ctx *ScenarioContext) error { 23 | return RunSucceeds( 24 | client, 25 | "quay.io/brancz/krp-curl:v0.0.2", 26 | "kube-rbac-proxy-client", 27 | []string{"/bin/sh", "-c", command}, 28 | opts, 29 | )(ctx) 30 | } 31 | } 32 | 33 | func ClientFails(client kubernetes.Interface, command string, opts *RunOptions) Action { 34 | return func(ctx *ScenarioContext) error { 35 | return RunFails( 36 | client, 37 | "quay.io/brancz/krp-curl:v0.0.2", 38 | "kube-rbac-proxy-client", 39 | []string{"/bin/sh", "-c", command}, 40 | opts, 41 | )(ctx) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/kubetest/kubetest.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2017 Frederic Branczyk All rights reserved. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package kubetest 18 | 19 | import ( 20 | "testing" 21 | 22 | "k8s.io/client-go/kubernetes" 23 | "k8s.io/client-go/tools/clientcmd" 24 | ) 25 | 26 | func NewClientFromKubeconfig(path string) (kubernetes.Interface, error) { 27 | config, err := clientcmd.BuildConfigFromFlags("", path) 28 | if err != nil { 29 | return nil, err 30 | } 31 | 32 | client, err := kubernetes.NewForConfig(config) 33 | if err != nil { 34 | return nil, err 35 | } 36 | 37 | return client, nil 38 | } 39 | 40 | type TestSuite func(t *testing.T) 41 | 42 | type Scenario struct { 43 | KubeClient kubernetes.Interface 44 | 45 | Name string 46 | Description string 47 | 48 | Given Action 49 | When Action 50 | Then Action 51 | } 52 | 53 | func (s Scenario) Run(t *testing.T) bool { 54 | ctx := &ScenarioContext{ 55 | Namespace: "default", 56 | } 57 | 58 | defer func(ctx *ScenarioContext) { 59 | for _, f := range ctx.CleanUp { 60 | if err := f(); err != nil { 61 | panic(err) 62 | } 63 | } 64 | }(ctx) 65 | 66 | return t.Run(s.Name, func(t *testing.T) { 67 | if s.Given != nil { 68 | if err := s.Given(ctx); err != nil { 69 | t.Fatalf("failed to create given setup: %v", err) 70 | } 71 | } 72 | 73 | if s.When != nil { 74 | if err := s.When(ctx); err != nil { 75 | t.Errorf("failed to evaluate state: %v", err) 76 | } 77 | } 78 | 79 | if s.Then != nil { 80 | if err := s.Then(ctx); err != nil { 81 | t.Errorf("checks failed: %v", err) 82 | } 83 | } 84 | }) 85 | } 86 | 87 | type ScenarioContext struct { 88 | Namespace string 89 | CleanUp []CleanUp 90 | } 91 | 92 | func (ctx *ScenarioContext) AddCleanUp(f CleanUp) { 93 | ctx.CleanUp = append(ctx.CleanUp, f) 94 | } 95 | 96 | type CleanUp func() error 97 | 98 | type Action func(ctx *ScenarioContext) error 99 | 100 | func Actions(ss ...Action) Action { 101 | return func(ctx *ScenarioContext) error { 102 | for _, s := range ss { 103 | if err := s(ctx); err != nil { 104 | return err 105 | } 106 | } 107 | return nil 108 | } 109 | } 110 | --------------------------------------------------------------------------------