diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index c14025b2e..000000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: Go - -on: [push, pull_request] - -env: - QUAY_PATH: quay.io/brancz/kube-rbac-proxy - go-version: '1.17.3' - kind-version: 'v0.11.0' - -jobs: - check-license: - runs-on: ubuntu-latest - name: Check license - steps: - - uses: actions/checkout@v2 - - run: make check-license - generate: - runs-on: ubuntu-latest - name: Generate - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.go-version }} - - run: make generate && git diff --exit-code - lint: - runs-on: ubuntu-latest - name: Lint - steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: latest - args: --timeout=5m - build: - runs-on: ubuntu-latest - name: Build - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.go-version }} - - run: make build - unit-tests: - runs-on: ubuntu-latest - name: Unit tests - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 - with: - go-version: ${{ env.go-version }} - - run: make test-unit - e2e-tests: - runs-on: ubuntu-latest - name: E2E tests - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Start kind & create cluster - uses: engineerd/setup-kind@v0.5.0 - with: - version: ${{ env.kind-version }} - config: test/e2e/kind-config/kind-config.yaml - wait: 300s - - name: Wait for cluster to finish bootstraping - run: kubectl wait --for=condition=Ready pods --all --all-namespaces --timeout=300s - - name: Create container & run tests - run: | - VERSION=local make container - kind load docker-image ${QUAY_PATH}:local - until docker exec $(kind get nodes) crictl images | grep "${QUAY_PATH}"; do - echo "no kube-rbac-proxy image" - sleep 1 - done - make test-e2e - publish: - runs-on: ubuntu-latest - name: Publish container image to Quay - if: github.event_name == 'push' - needs: - - check-license - - generate - - build - - unit-tests - - e2e-tests - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Login to Quay.io - uses: docker/login-action@v1 - with: - registry: quay.io - username: ${{ secrets.QUAY_USERNAME }} - password: ${{ secrets.QUAY_PASSWORD }} - - name: Build images and push - run: ./scripts/publish.sh diff --git a/.golangci.yaml b/.golangci.yaml deleted file mode 100644 index 472842c5b..000000000 --- a/.golangci.yaml +++ /dev/null @@ -1,3 +0,0 @@ -run: - skip-dirs: - - test/ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 738828d51..000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,69 +0,0 @@ -## 0.11.0 / 2021-08-02 - -* [FEATURE] Support for path patterns in --allow-paths and --ignore-paths. #135 -* [ENHANCEMENT] Dynamically reload client CA. #127 -* [BUGFIX] Fix panics on client-cert authenticated requests. #132 - -## 0.10.0 / 2021-05-07 - -* [FEATURE] Support local static authorizer. #125 - -## 0.9.0 / 2021-04-27 - -* [FEATURE] Support rewrites using HTTP headers in addition to query parameters. #104 -* [FEATURE] Support pass-through of client certificates. #113 -* [FEATURE] Support TLS 1.3. #120 - -## 0.8.0 / 2020-11-03 - -* [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 - -## 0.7.0 / 2020-09-15 - -* [CHANGE] Make images rootless. #86 -* [FEATURE] Add ability to check for allowed request paths with new `--allow-paths` config option. #83 - -## 0.6.0 / 2020-06-11 - -* [CHANGE] Use gcr.io/distroless/static as base image instead of alpine. #67 -* [ENHANCEMENT] Add multi-arch container images for amd64, arm, arm64, ppc64le and s390x. #67 - -## 0.5.0 / 2020-02-17 - -* [CHANGE] Move from glog to klog for logging. #57 -* [FEATURE] Support token audience reviews. #56 -* [FEATURE] Support custom upstream CAs. #34 -* [ENHANCEMENT] Reload TLS certificates at runtime. #47 -* [ENHANCEMENT] Add host in self-signed certs. #43 - -## 0.4.1 / 2019-01-23 - -* [ENHANCEMENT] Use golang.org/x/net http2 server. #29 -* [ENHANCEMENT] Update Kubernetes to 1.13.2 #28 -* [ENHANCEMENT] Make multi-arch builds possible. #21 -* [BUGFIX] Log when server isn't able to start. #27 -* [BUGFIX] Set user specified TLS configuration when explicit TLS certificates are provided. - -## 0.4.0 / 2018-10-24 - -* [CHANGE] The config file flag has been renamed to `--config-file`. -* [CHANGE] There is a breaking change in the configuration. All configuration that was previously valid, is now nested in `.authorization.resourceAttributes`. -* [FEATURE] Add OIDC token authentication provider (note: this is not a client code flow for client authentication). -* [FEATURE] Add ability to rewrite SubjectAccessReviews based on request query parameters. - -## 0.3.1 / 2018-06-20 - -This release is unmodified code from v0.3.0, but built with latest golang. - -* [BUGFIX] Fix `x509: cannot parse dnsName` in intermediate certificates. - -## 0.3.0 / 2018-03-27 - -* [FEATURE] Add HTTP/2 support. -* [ENHANCEMENT] Add ability to choose TLS cipher suites. -* [ENHANCEMENT] Add ability to choose minimum TLS version and default to TLS 1.2. - -## 0.2.0 / 2018-01-03 - -* [CHANGE] `--listen-address` flag renamed to `--insecure-listen-address`. -* [FEATURE] Add TLS support. diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index a937b7857..000000000 --- a/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -ARG GOARCH=amd64 -FROM gcr.io/distroless/static:nonroot-$GOARCH - -ARG BINARY=kube-rbac-proxy-linux-amd64 -COPY _output/$BINARY /usr/local/bin/kube-rbac-proxy -EXPOSE 8080 -USER 65532:65532 - -ENTRYPOINT ["/usr/local/bin/kube-rbac-proxy"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 63b459896..000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2017 Frederic Branczyk - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/Makefile b/Makefile deleted file mode 100644 index bb6c7d902..000000000 --- a/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -all: check-license build generate test - -GO111MODULE=on -export GO111MODULE - -GITHUB_URL=github.com/brancz/kube-rbac-proxy -GOOS?=$(shell uname -s | tr A-Z a-z) -GOARCH?=$(shell go env GOARCH) -OUT_DIR=_output -BIN?=kube-rbac-proxy -VERSION?=$(shell cat VERSION)-$(shell git rev-parse --short HEAD) -PKGS=$(shell go list ./... | grep -v /test/e2e) -DOCKER_REPO?=quay.io/brancz/kube-rbac-proxy -KUBECONFIG?=$(HOME)/.kube/config - -ALL_ARCH=amd64 arm arm64 ppc64le s390x -ALL_PLATFORMS=$(addprefix linux/,$(ALL_ARCH)) -ALL_BINARIES ?= $(addprefix $(OUT_DIR)/$(BIN)-, \ - $(addprefix linux-,$(ALL_ARCH)) \ - darwin-amd64 \ - windows-amd64.exe) - -TOOLS_BIN_DIR?=$(shell pwd)/tmp/bin -export PATH := $(TOOLS_BIN_DIR):$(PATH) - -EMBEDMD_BINARY=$(TOOLS_BIN_DIR)/embedmd -TOOLING=$(EMBEDMD_BINARY) - -check-license: - @echo ">> checking license headers" - @./scripts/check_license.sh - -crossbuild: $(ALL_BINARIES) - -$(OUT_DIR)/$(BIN): $(OUT_DIR)/$(BIN)-$(GOOS)-$(GOARCH) - cp $(OUT_DIR)/$(BIN)-$(GOOS)-$(GOARCH) $(OUT_DIR)/$(BIN) - -$(OUT_DIR)/$(BIN)-%: - @echo ">> building for $(GOOS)/$(GOARCH) to $(OUT_DIR)/$(BIN)-$*" - GOARCH=$(word 2,$(subst -, ,$(*:.exe=))) \ - GOOS=$(word 1,$(subst -, ,$(*:.exe=))) \ - CGO_ENABLED=0 \ - go build --installsuffix cgo -o $(OUT_DIR)/$(BIN)-$* $(GITHUB_URL) - -build: $(OUT_DIR)/$(BIN) - -container: $(OUT_DIR)/$(BIN)-$(GOOS)-$(GOARCH) Dockerfile - docker build --build-arg BINARY=$(BIN)-$(GOOS)-$(GOARCH) --build-arg GOARCH=$(GOARCH) -t $(DOCKER_REPO):$(VERSION)-$(GOARCH) . -ifeq ($(GOARCH), amd64) - docker tag $(DOCKER_REPO):$(VERSION)-$(GOARCH) $(DOCKER_REPO):$(VERSION) -endif - - -manifest-tool: - curl -fsSL https://github.com/estesp/manifest-tool/releases/download/v1.0.2/manifest-tool-linux-amd64 > ./manifest-tool - chmod +x ./manifest-tool - -push-%: - $(MAKE) GOARCH=$* container - docker push $(DOCKER_REPO):$(VERSION)-$* - -comma:= , -empty:= -space:= $(empty) $(empty) -manifest-push: manifest-tool - ./manifest-tool push from-args --platforms $(subst $(space),$(comma),$(ALL_PLATFORMS)) --template $(DOCKER_REPO):$(VERSION)-ARCH --target $(DOCKER_REPO):$(VERSION) - -push: crossbuild manifest-tool $(addprefix push-,$(ALL_ARCH)) manifest-push - -curl-container: - docker build -f ./examples/example-client/Dockerfile -t quay.io/brancz/krp-curl:v0.0.2 . - -run-curl-container: - @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' - kubectl run -i -t krp-curl --image=quay.io/brancz/krp-curl:v0.0.2 --restart=Never --command -- /bin/sh - -grpcc-container: - docker build -f ./examples/grpcc/Dockerfile -t mumoshu/grpcc:v0.0.1 . - -test: test-unit test-e2e - -test-unit: - go test -v -race -count=1 $(PKGS) - -test-e2e: - go test -timeout 55m -v ./test/e2e/ $(TEST_RUN_ARGS) --kubeconfig=$(KUBECONFIG) - -generate: build $(EMBEDMD_BINARY) - @echo ">> generating examples" - @./scripts/generate-examples.sh - @echo ">> generating docs" - @./scripts/generate-help-txt.sh - @$(EMBEDMD_BINARY) -w `find ./ -name "*.md" -print` - -$(TOOLS_BIN_DIR): - @mkdir -p $(TOOLS_BIN_DIR) - -$(TOOLING): $(TOOLS_BIN_DIR) - @echo Installing tools from scripts/tools.go - @cat scripts/tools.go | grep _ | awk -F'"' '{print $$2}' | GOBIN=$(TOOLS_BIN_DIR) xargs -tI % go install -mod=readonly -modfile=scripts/go.mod % - -.PHONY: all check-license crossbuild build container push push-% manifest-push curl-container test test-unit test-e2e generate diff --git a/README.md b/README.md deleted file mode 100644 index ce09dca7f..000000000 --- a/README.md +++ /dev/null @@ -1,114 +0,0 @@ -# kube-rbac-proxy - -[![Docker Repository on Quay](https://quay.io/repository/brancz/kube-rbac-proxy/status "Docker Repository on Quay")](https://quay.io/repository/brancz/kube-rbac-proxy) - -> NOTE: This project is *alpha* stage. Flags, configuration, behavior and design may change significantly in following releases. - -The kube-rbac-proxy is a small HTTP proxy for a single upstream, that can perform RBAC authorization against the Kubernetes API using [SubjectAccessReview](https://kubernetes.io/docs/reference/access-authn-authz/authorization/). - -In Kubernetes clusters without NetworkPolicies any Pod can perform requests to every other Pod in the cluster. This proxy was developed in order to restrict requests to only those Pods, that present a valid and RBAC authorized token or client TLS certificate. - -## Usage - -The kube-rbac-proxy has all [`glog`](https://github.com/golang/glog) flags for logging purposes. To use the kube-rbac-proxy there are a few flags you may want to set: - -* `--upstream`: This is the upstream you want to proxy to. -* `--config-file`: This file specifies details on the SubjectAccessReview you want to be performed on a request. For example, this could contain that an entity performing a request has to be allowed to perform a `get` on the Deployment called `my-frontend-app`, as well as the ability to configure whether SubjectAccessReviews are rewritten based on requests. - -See the [`examples/`](examples/) directory for the following examples: - -* [non-resource-url example](examples/non-resource-url) -* [resource-attributes example](examples/resource-attributes) -* [oidc example](examples/oidc) -* [rewriting SubjectAccessReviews based on request query parameters](examples/rewrites) - -All command line flags: - -[embedmd]:# (_output/help.txt) -```txt -$ kube-rbac-proxy -h -Usage of _output/kube-rbac-proxy: - --add_dir_header If true, adds the file directory to the header of the log messages - --allow-paths strings Comma-separated list of paths against which kube-rbac-proxy matches the incoming request. If the request doesn't match, kube-rbac-proxy responds with a 404 status code. If omitted, the incoming request path isn't checked. Cannot be used with --ignore-paths. - --alsologtostderr log to standard error as well as files - --auth-header-fields-enabled When set to true, kube-rbac-proxy adds auth-related fields to the headers of http requests sent to the upstream - --auth-header-groups-field-name string The name of the field inside a http(2) request header to tell the upstream server about the user's groups (default "x-remote-groups") - --auth-header-groups-field-separator string The separator string used for concatenating multiple group names in a groups header field's value (default "|") - --auth-header-user-field-name string The name of the field inside a http(2) request header to tell the upstream server about the user's name (default "x-remote-user") - --auth-token-audiences strings Comma-separated list of token audiences to accept. By default a token does not have to have any specific audience. It is recommended to set a specific audience. - --client-ca-file string If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate. - --config-file string Configuration file to configure kube-rbac-proxy. - --ignore-paths strings Comma-separated list of paths against which kube-rbac-proxy will proxy without performing an authentication or authorization check. Cannot be used with --allow-paths. - --insecure-listen-address string The address the kube-rbac-proxy HTTP server should listen on. - --kubeconfig string Path to a kubeconfig file, specifying how to connect to the API server. If unset, in-cluster configuration will be used - --log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0) - --log_dir string If non-empty, write log files in this directory - --log_file string If non-empty, use this log file - --log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800) - --logtostderr log to standard error instead of files (default true) - --oidc-ca-file string If set, the OpenID server's certificate will be verified by one of the authorities in the oidc-ca-file, otherwise the host's root CA set will be used. - --oidc-clientID string The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set. - --oidc-groups-claim string Identifier of groups in JWT claim, by default set to 'groups' (default "groups") - --oidc-groups-prefix string If provided, all groups will be prefixed with this value to prevent conflicts with other authentication strategies. - --oidc-issuer string The URL of the OpenID issuer, only HTTPS scheme will be accepted. If set, it will be used to verify the OIDC JSON Web Token (JWT). - --oidc-sign-alg stringArray Supported signing algorithms, default RS256 (default [RS256]) - --oidc-username-claim string Identifier of the user in JWT claim, by default set to 'email' (default "email") - --secure-listen-address string The address the kube-rbac-proxy HTTPs server should listen on. - --skip_headers If true, avoid header prefixes in the log messages - --skip_log_headers If true, avoid headers when opening log files - --stderrthreshold severity logs at or above this threshold go to stderr (default 2) - --tls-cert-file string File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert) - --tls-cipher-suites strings Comma-separated list of cipher suites for the server. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If omitted, the default Go cipher suites will be used - --tls-min-version string Minimum TLS version supported. Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants. (default "VersionTLS12") - --tls-private-key-file string File containing the default x509 private key matching --tls-cert-file. - --tls-reload-interval duration The interval at which to watch for TLS certificate changes, by default set to 1 minute. (default 1m0s) - --upstream string The upstream URL to proxy to once requests have successfully been authenticated and authorized. - --upstream-ca-file string The CA the upstream uses for TLS connection. This is required when the upstream uses TLS and its own CA certificate - --upstream-force-h2c Force h2c to communiate with the upstream. This is required when the upstream speaks h2c(http/2 cleartext - insecure variant of http/2) only. For example, go-grpc server in the insecure mode, such as helm's tiller w/o TLS, speaks h2c only - -v, --v Level number for the log level verbosity - --vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging -``` - -## Why? - -You may ask yourself, why not just use the Kubernetes apiserver proxy functionality? There are two reasons why this makes sense, the first is to take load off of the Kubernetes API, so it can be used for actual requests serving the cluster components, rather than in order to serve client requests. The second and more important reason is, this proxy is intended to be a sidecar that accepts incoming HTTP requests. This way, one can ensure that a request is truly authorized, instead of being able to access an application simply because an entity has network access to it. - -## Motivation - -I developed this proxy in order to be able to protect [Prometheus](https://prometheus.io/) metrics endpoints. In a scenario, where an attacker might obtain full control over a Pod, that attacker would have the ability to discover a lot of information about the workload as well as the current load of the respective workload. This information could originate for example from the [node-exporter](https://github.com/prometheus/node_exporter) and [kube-state-metrics](https://github.com/kubernetes/kube-state-metrics). Both of those metric sources can commonly be found in Prometheus monitoring stacks on [Kubernetes](https://kubernetes.io/). - -This project was created to specifically solve the above problem, however, I felt there is a larger need for such a proxy in general. - -## How does it work? - -On an incoming request, kube-rbac-proxy first figures out which user is performing the request. The kube-rbac-proxy supports using client TLS certificates, as well as tokens. In case of a client certificates, the certificate is simply validated against the configured CA. In case of a bearer token being presented, the `authentication.k8s.io` is used to perform a `TokenReview`. - -Once a user has been authenticated, again the `authentication.k8s.io` is used to perform a `SubjectAccessReview`, in order to authorize the respective request, to ensure the authenticated user has the required RBAC roles. - -## Notes on ServiceAccount token security - -Note that when using tokens for authentication, the receiving side can use the token to impersonate the client. Only use token authentication, when the receiving side is already higher privileged or the token itself is super low privileged, such as when the only roles bound to it are for authorization purposes with this project. Passing around highly privileged tokens is a security risk, and is not recommended. - -This project was built to be used to protect metrics of cluster components. These cluster components are much higher privileged than the Prometheus Pod, so if those Pods were to use the token provided by Prometheus it would actually be lower privileged. It is not recommended to use this method for non infrastructure components. - -For better security properties use mTLS for authentication instead, and for user authentication, other methods have yet to be added. - -## Why are NetworkPolicies not enough? - -There are a couple of reasons why the existence of NetworkPolicies may not cover the same use case(s): - -* NetworkPolicies are not available in all providers, installers and distros. -* NetworkPolicies do not apply to Pods with HostNetworking enabled, the use case I created this project with the Prometheus node-exporter requires this. -* Once TLS/OIDC is supported, the kube-rbac-proxy can be used to perform AuthN/AuthZ on users. - -## Differentiation to [Envoy](https://www.envoyproxy.io/)/[Istio](https://istio.io/) - -This projects is not intended to compete with Envoy or IstioMesh. Although on the surface they seem similar, the goals and usage complement each other. It's perfectly ok to use Envoy as the ingress point of traffic of a Pod, which then forwards traffic to the kube-rbac-proxy, which in turn then proxies to the actually serving application. - -Additionally, to my knowledge Envoy neither has nor plans Kubernetes specific RBAC/AuthZ support (maybe it shouldn’t even). My knowledge may very well be incomplete, please point out if it is. After all I'm happy if I don't have to maintain more code, but as long as this serves a purpose to me and no other project can provide it, I'll maintain this. - -## Roadmap - -PRs are more than welcome! - -* Tests diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 36fe1e630..000000000 --- a/RELEASE.md +++ /dev/null @@ -1,131 +0,0 @@ -# Releases - -This page describes the release process and the respective release shepherd. -Release shepherds are chosen on a voluntary basis. - -## Release schedule - -| release series | date of release (year-month-day) | release shepherd | -|----------------|----------------------------------|---------------------------------------------| -| v0.12.0 | TBD | Krzysztof Ostrowski (GitHub: @ibihim) -| v0.11.0 | 2021-08-02 | Sergiusz Urbaniak (GitHub: @s-urbaniak) | -| v0.10.0 | 2021-05-07 | Sergiusz Urbaniak (GitHub: @s-urbaniak) | -| v0.9.0 | 2021-04-27 | Sergiusz Urbaniak (GitHub: @s-urbaniak) | -| v0.8.0 | 2020-11-03 | Paweł Krupa (GitHub: @paulfantom) | -| v0.7.0 | 2020-09-15 | Paweł Krupa (GitHub: @paulfantom) | -| v0.6.0 | 2020-06-11 | Frederic Branczyk (GitHub: @brancz) | -| v0.5.0 | 2020-02-17 | Frederic Branczyk (GitHub: @brancz) | -| v0.4.1 | 2019-01-23 | Frederic Branczyk (GitHub: @brancz) | -| v0.4.0 | 2018-10-24 | Frederic Branczyk (GitHub: @brancz) | -| v0.3.1 | 2018-06-20 | Frederic Branczyk (GitHub: @brancz) | - -## How to cut a new release - -> This guide is strongly based on the [Prometheus release instructions](https://github.com/prometheus/prometheus/blob/main/RELEASE.md). - -We maintain a separate branch for each minor release, named release-., e.g. release-1.1, release-2.0. - -### Branch management and versioning strategy - -We use [Semantic Versioning](https://semver.org/). - -We maintain a separate branch for each minor release, named `release-.`, e.g. `release-1.1`, `release-2.0`. - -Note that branch protection kicks in automatically for any branches whose name starts with `release-`. Never use names starting with `release-` for branches that are not release branches. - -The usual flow is to merge new features and changes into the master branch and -to merge bug fixes into the latest release branch. Bug fixes are then merged -into main from the latest release branch. The main branch should always contain -all commits from the latest release branch. As long as main hasn't deviated from -the release branch, new commits can also go to main, followed by merging main -back into the release branch. - -If a bug fix got accidentally merged into main after non-bug-fix changes in -main, the bug-fix commits have to be cherry-picked into the release branch, -which then have to be merged back into main. Try to avoid that situation. - -### 1. Updating dependencies - -Before publishing a new release, consider updating the dependencies. Then create -a pull request against the main branch. - -Note that after a dependency update, you should look out for any weirdness that -might have happened. Such weirdnesses include but are not limited to: flaky -tests, differences in resource usage, panic. - -In case of doubt or issues that can't be solved in a reasonable amount of time, -you can skip the dependency update or only update select dependencies. In such a -case, you have to create an issue or pull request in the GitHub project for -later follow-up. - -#### Updating Go dependencies - -``` -make update-go-deps -git add go.mod go.sum -git commit -m "Update dependencies" -``` - -### 2. Prepare your release - -At the start of a new major or minor release cycle create the corresponding -release branch based on the main branch. For example if we're releasing `2.17.0` -and the previous stable release is `2.16.0` we need to create a `release-2.17` -branch. Note that all releases are handled in protected release branches, see -the above `Branch management and versioning` section. - -Bump the version in the `VERSION` file and update `CHANGELOG.md`. Do this in a -proper PR pointing to the release branch as this gives others the opportunity to -chime in on the release in general and on the addition to the changelog in -particular. - -Note that `CHANGELOG.md` should only document changes relevant to users of -kube-rbac-proxy, including external API changes, performance improvements, and -new features. Do not document changes of internal interfaces, code refactorings -and clean-ups, changes to the build process, etc. People interested in these are -asked to refer to the git history. - -Entries in the `CHANGELOG.md` are meant to be in this order: - -* `[CHANGE]` -* `[FEATURE]` -* `[ENHANCEMENT]` -* `[BUGFIX]` - -### 3. Draft the new release - -Tag the new release via the following commands: - -```bash -$ tag="v$(< VERSION)" -$ git tag -s "${tag}" -m "${tag}" -$ git push origin "${tag}" -``` - -Optionally, you can use this handy `.gitconfig` alias. - -```ini -[alias] - tag-release = "!f() { tag=v${1:-$(cat VERSION)} ; git tag -s ${tag} -m ${tag} && git push origin ${tag}; }; f" -``` - -Then release with `git tag-release`. - -Signing a tag with a GPG key is appreciated, but in case you can't add a GPG key -to your Github account using the following -[procedure](https://help.github.com/articles/generating-a-gpg-key/), you can -replace the `-s` flag by `-a` flag of the `git tag` command to only annotate the -tag without signing. - -Once a tag is created, the release process through GitHub Actions will be -triggered for this tag. - -Finally, wait for the build step for the tag to finish. The point here is to -wait for tarballs to be uploaded to the Github release and the container images -to be pushed to Quay.io. - -### 4. Wrapping up - -If the release has happened in the latest release branch, merge the changes into -main. - diff --git a/VERSION b/VERSION deleted file mode 100644 index fd2726c91..000000000 --- a/VERSION +++ /dev/null @@ -1 +0,0 @@ -v0.11.0 diff --git a/examples/example-client-http2/Dockerfile b/examples/example-client-http2/Dockerfile deleted file mode 100644 index e69de29bb..000000000 diff --git a/examples/example-client-urlquery/Dockerfile b/examples/example-client-urlquery/Dockerfile deleted file mode 100644 index 61b34a86b..000000000 --- a/examples/example-client-urlquery/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM alpine:3.7 - -RUN apk add --no-cache curl - -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 diff --git a/examples/example-client/Dockerfile b/examples/example-client/Dockerfile deleted file mode 100644 index 1635c783a..000000000 --- a/examples/example-client/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM alpine:3.12 - -RUN apk add --no-cache curl - -CMD curl -v -s -k -H "Authorization: Bearer `cat /var/run/secrets/kubernetes.io/serviceaccount/token`" https://kube-rbac-proxy.default.svc:8443/metrics diff --git a/examples/grpcc/Dockerfile b/examples/grpcc/Dockerfile deleted file mode 100644 index 487161c1b..000000000 --- a/examples/grpcc/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -FROM node:8.9.4-alpine - -RUN apk add --update --no-cache python - -# `yarn global add` is easier than `npm install -g` in this case due to the npm bug: -# https://github.com/nodejs/docker-node/issues/423#issuecomment-306470507 -# To work-around the npm bug, we need to upgrade it like this: -# https://github.com/me-ventures/angular-cli-docker/commit/3d40e583e865817831e93c55fab01cb6857a24c7 -# However, isn't it too much boiler-plate just for installing a single module? :) - -# RUN yarn global add grpcc - -# see https://github.com/njpatel/grpcc/pull/48 -RUN yarn global add https://github.com/njpatel/grpcc/archive/d82c570.tar.gz - -ADD https://raw.githubusercontent.com/njpatel/grpcc/master/test/test.proto /test.proto - -RUN apk add --update --no-cache nghttp2 - -ENTRYPOINT ["grpcc"] diff --git a/examples/minikube-rbac/README.md b/examples/minikube-rbac/README.md deleted file mode 100644 index bf42477e9..000000000 --- a/examples/minikube-rbac/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Minikube + RBAC - -To start [minikube](https://github.com/kubernetes/minikube) with RBAC enabled run it with the `--extra-config=apiserver.Authorization.Mode=RBAC` flag: - -```bash -$ minikube start --extra-config=apiserver.Authorization.Mode=RBAC -Starting local Kubernetes v1.8.0 cluster... -Starting VM... -Getting VM IP address... -Moving files into cluster... -Setting up certs... -Connecting to cluster... -Setting up kubeconfig... -Starting cluster components... -Kubectl is now configured to use the cluster. -Loading cached images from config file. -``` - -When minikube is started with this flag it does not handle RBAC for addons, so that needs to be fixed. - -```bash -$ kubectl apply -f minikube-rbac-fix.yaml -clusterrole "cluster-writer" created -clusterrole "cluster-reader" created -clusterrolebinding "cluster-write" created -clusterrolebinding "cluster-read" created -rolebinding "sd-build-write" created -``` - -Ensure that everything is running as expected: - -```bash -$ kubectl get pods --namespace=kube-system -NAME READY STATUS RESTARTS AGE -kube-addon-manager-minikube 1/1 Running 0 8m -kube-dns-86f6f55dd5-lncvt 3/3 Running 0 51s -storage-provisioner 1/1 Running 0 8m -``` - diff --git a/examples/minikube-rbac/minikube-rbac-fix.yaml b/examples/minikube-rbac/minikube-rbac-fix.yaml deleted file mode 100644 index 93d9d0bb5..000000000 --- a/examples/minikube-rbac/minikube-rbac-fix.yaml +++ /dev/null @@ -1,78 +0,0 @@ -# Wide open access to the cluster (mostly for kubelet) -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: cluster-writer -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["*"] - - nonResourceURLs: ["*"] - verbs: ["*"] - ---- - -# Full read access to the api and resources -kind: ClusterRole -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: cluster-reader -rules: - - apiGroups: ["*"] - resources: ["*"] - verbs: ["get", "list", "watch"] - - nonResourceURLs: ["*"] - verbs: ["*"] ---- -# Give admin, kubelet, kube-system, kube-proxy god access -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: cluster-write -subjects: - - kind: User - name: admin - - kind: User - name: kubelet - - kind: ServiceAccount - name: default - namespace: kube-system - - kind: User - name: kube-proxy -roleRef: - kind: ClusterRole - name: cluster-writer - apiGroup: rbac.authorization.k8s.io - ---- - -# Setup sd-build as a reader. This has to be a -# ClusterRoleBinding to get access to non-resource URLs -kind: ClusterRoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: cluster-read -subjects: - - kind: ServiceAccount - name: sd-build - namespace: default -roleRef: - kind: ClusterRole - name: cluster-reader - apiGroup: rbac.authorization.k8s.io - ---- - -# Setup sd-build as a writer in its namespace -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - name: sd-build-write -subjects: - - kind: ServiceAccount - name: sd-build - namespace: default -roleRef: - kind: ClusterRole - name: cluster-writer - apiGroup: rbac.authorization.k8s.io diff --git a/examples/non-resource-url-token-request/README.md b/examples/non-resource-url-token-request/README.md deleted file mode 100644 index 78474b7d7..000000000 --- a/examples/non-resource-url-token-request/README.md +++ /dev/null @@ -1,296 +0,0 @@ -# non-resource-url-token-request example - -> Token audience reviews can be combined with any of the other features of kube-rbac-proxy, such as reviewing permission for specific resources, this example merely chooses to show the functionality using a non-resource-url permission. - -This examples is in essence similar to the [non-resource-url](../non-resource-url/) example, with the key difference, that this example requires the ServiceAccount token sent by a client must be scoped to the `kube-rbac-proxy.default.svc` audience. In this example the scoped ServiceAccount token is obtained via a projected volume and mounted into the client container from where it can be consumed. The reasoning here is that scoped tokens cannot be used to impersonate an entity by re-using the token to perform a request against the Kubernetes API itself. - -The audience a token must be scoped to is configured within the kube-rbac-proxy using the `--auth-token-audiences` flag. -```bash -$ kubectl create -f deployment.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./deployment.yaml) -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--auth-token-audiences=kube-rbac-proxy.default.svc" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" -``` - -Once the prometheus-example-app is up and running, we can test it. In order to test it, we deploy a Job, that performs a `curl` against the above deployment. Because it has the `/metrics` path in its `nonResourceURLs` it is allowed to access the endpoint. - -The Dockerfile of this container can be found [here](../example-client/Dockerfile). - -```bash -$ kubectl create -f client-rbac.yaml client.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./client-rbac.yaml) -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default -``` - -[embedmd]:# (./client.yaml) -```yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - restartPolicy: Never - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - command: - - /bin/sh - - -c - - 'curl -v -s -k -H "Authorization: Bearer `cat /service-account/token`" https://kube-rbac-proxy.default.svc:8443/metrics' - volumeMounts: - - name: token-vol - mountPath: "/service-account" - readOnly: true - volumes: - - name: token-vol - projected: - sources: - - serviceAccountToken: - audience: kube-rbac-proxy.default.svc - expirationSeconds: 3600 - path: token - backoffLimit: 4 -``` - -We can look at the logs and we should get something similar to: - -``` -* Trying 10.106.147.107... -* TCP_NODELAY set -* Connected to kube-rbac-proxy.default.svc (10.106.147.107) port 8443 (#0) -* ALPN, offering http/1.1 -* successfully set certificate verify locations: -* CAfile: /etc/ssl/certs/ca-certificates.crt - CApath: none -* TLSv1.2 (OUT), TLS handshake, Client hello (1): -} [242 bytes data] -* TLSv1.2 (IN), TLS handshake, Server hello (2): -{ [49 bytes data] -* TLSv1.2 (IN), TLS handshake, Certificate (11): -{ [1649 bytes data] -* TLSv1.2 (IN), TLS handshake, Server key exchange (12): -{ [300 bytes data] -* TLSv1.2 (IN), TLS handshake, Server finished (14): -{ [4 bytes data] -* TLSv1.2 (OUT), TLS handshake, Client key exchange (16): -} [37 bytes data] -* TLSv1.2 (OUT), TLS change cipher, Client hello (1): -} [1 bytes data] -* TLSv1.2 (OUT), TLS handshake, Finished (20): -} [16 bytes data] -* TLSv1.2 (IN), TLS change cipher, Client hello (1): -{ [1 bytes data] -* TLSv1.2 (IN), TLS handshake, Finished (20): -{ [16 bytes data] -* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 -* ALPN, server did not agree to a protocol -* Server certificate: -* subject: CN=kube-rbac-proxy-695b54f7ff-z54b7@1579943520 -* start date: Jan 25 08:12:00 2020 GMT -* expire date: Jan 24 08:12:00 2021 GMT -* issuer: CN=kube-rbac-proxy-695b54f7ff-z54b7-ca@1579943520 -* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway. -> GET /metrics HTTP/1.1 -> Host: kube-rbac-proxy.default.svc:8443 -> User-Agent: curl/7.61.0 -> Accept: */* -> Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InBtUmFFQnJIUzJXS1RuR3FmcmRkRDd3TEM2NUx3STZmb29DczRNRGwzLXcifQ.eyJhdWQiOlsia3ViZS1yYmFjLXByb3h5LmRlZmF1bHQuc3ZjIl0sImV4cCI6MTU3OTk0NzYxMiwiaWF0IjoxNTc5OTQ0MDEyLCJpc3MiOiJrdWJlcm5ldGVzLmRlZmF1bHQuc3ZjIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJkZWZhdWx0IiwicG9kIjp7Im5hbWUiOiJrcnAtY3VybC1nMjVweCIsInVpZCI6IjA3MWYxYzM1LWNmZWYtNGRhNy05ZjMxLWJiMmJkNmJmY2VmNyJ9LCJzZXJ2aWNlYWNjb3VudCI6eyJuYW1lIjoiZGVmYXVsdCIsInVpZCI6IjRlYzFiOWU4LTdkZmItNDhiNi1hMjU0LWFiYTg4MGJhZGY5ZiJ9fSwibmJmIjoxNTc5OTQ0MDEyLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDpkZWZhdWx0In0.fM05SSlLzb5zMpTjYhn_H8Y0KFwX000VYqE8CMA3sP5lMAbXBInGSudbm_r_ppAMUYar6cmyAiSmIAD1bOR-DlzmJdX-LA5kgA3J9GAsrWBxXMlmASo1OfTjtOuQ98Y8tM6P-BCCe5rOAcx-ppmbPE_8Pu_7IkHjABURtClr6VUspsLfqsZ9GcN5pDBSR9iFt2Cl6m8YsbBXIDJ1kp9CknFt36s5Dg7OcTQR-WWkA21iZiOqayWGphW-DqpjEdm16XpjOqqDOf2qyFisjPhxNN-rivPJaCeoRb3GUIQVbvVShEgygzdM_8OqmZT3THeHBCdC_685Ffv3hFC4G6ijAQ -> -< HTTP/1.1 200 OK -< Content-Type: text/plain; version=0.0.4 -< Date: Sat, 25 Jan 2020 09:20:12 GMT -< Content-Length: 102 -< -{ [102 bytes data] -* Connection #0 to host kube-rbac-proxy.default.svc left intact -# HELP version Version information about this binary -# TYPE version gauge -version{version="v0.1.0"} 0 -``` - -Whereas if we didn't use a token that was created for the correct audience, for example the default ServiceAccount token mounted into containers, then we should not be able to authenticate with that token. This can be verified with: - - -[embedmd]:# (./wrong-client.yaml) -```yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-wrong-token-curl -spec: - template: - metadata: - name: krp-wrong-token-curl - spec: - restartPolicy: Never - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 -``` - -Then the log output should look something along the lines of: - -``` -* Trying 10.106.147.107... -* TCP_NODELAY set -* Connected to kube-rbac-proxy.default.svc (10.106.147.107) port 8443 (#0) -* ALPN, offering http/1.1 -* successfully set certificate verify locations: -* CAfile: /etc/ssl/certs/ca-certificates.crt - CApath: none -* TLSv1.2 (OUT), TLS handshake, Client hello (1): -} [242 bytes data] -* TLSv1.2 (IN), TLS handshake, Server hello (2): -{ [49 bytes data] -* TLSv1.2 (IN), TLS handshake, Certificate (11): -{ [1649 bytes data] -* TLSv1.2 (IN), TLS handshake, Server key exchange (12): -{ [300 bytes data] -* TLSv1.2 (IN), TLS handshake, Server finished (14): -{ [4 bytes data] -* TLSv1.2 (OUT), TLS handshake, Client key exchange (16): -} [37 bytes data] -* TLSv1.2 (OUT), TLS change cipher, Client hello (1): -} [1 bytes data] -* TLSv1.2 (OUT), TLS handshake, Finished (20): -} [16 bytes data] -* TLSv1.2 (IN), TLS change cipher, Client hello (1): -{ [1 bytes data] -* TLSv1.2 (IN), TLS handshake, Finished (20): -{ [16 bytes data] -* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256 -* ALPN, server did not agree to a protocol -* Server certificate: -* subject: CN=kube-rbac-proxy-695b54f7ff-z54b7@1579943520 -* start date: Jan 25 08:12:00 2020 GMT -* expire date: Jan 24 08:12:00 2021 GMT -* issuer: CN=kube-rbac-proxy-695b54f7ff-z54b7-ca@1579943520 -* SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway. -> GET /metrics HTTP/1.1 -> Host: kube-rbac-proxy.default.svc:8443 -> User-Agent: curl/7.61.0 -> Accept: */* -> Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InBtUmFFQnJIUzJXS1RuR3FmcmRkRDd3TEM2NUx3STZmb29DczRNRGwzLXcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tbWtienYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjRlYzFiOWU4LTdkZmItNDhiNi1hMjU0LWFiYTg4MGJhZGY5ZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.dWmmPOUTpIXve3svadwPd3a1PswkL8YC5JnPvul4EqQjcf-SLNSgp-TT4I2SqUTiNqwrehmdjjZdD925Erpdb8ZnrTTcaicmO6G95IvpwfMz3EvJY7A0anjjS_IOJpwoBN3RpgftGQcuFIaOc10xa5DC9TcS1-HouoyR-FdciqEOr3ZaOhr_em3W3MLqr6IMBTALz__rObKrb7kAUPNiBfy5fUhznbp2VgQeJYQRIxGQDOnn-_5bfFjsWjQAz098SknNAwOKtdy9BpRPwyrVybQ17i15DJcAP92aSIMP7dhYvDpuSvHBg5GhHNT3y5abd_o4ZXpWpSwqSpxAHqGE5g -> -< HTTP/1.1 401 Unauthorized -< Content-Type: text/plain; charset=utf-8 -< X-Content-Type-Options: nosniff -< Date: Sat, 25 Jan 2020 09:21:16 GMT -< Content-Length: 13 -< -{ [13 bytes data] -* Connection #0 to host kube-rbac-proxy.default.svc left intact -Unauthorized -``` diff --git a/examples/non-resource-url-token-request/client-rbac.yaml b/examples/non-resource-url-token-request/client-rbac.yaml deleted file mode 100644 index b13c24e13..000000000 --- a/examples/non-resource-url-token-request/client-rbac.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default diff --git a/examples/non-resource-url-token-request/client.yaml b/examples/non-resource-url-token-request/client.yaml deleted file mode 100644 index 1bc82e31f..000000000 --- a/examples/non-resource-url-token-request/client.yaml +++ /dev/null @@ -1,30 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - restartPolicy: Never - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - command: - - /bin/sh - - -c - - 'curl -v -s -k -H "Authorization: Bearer `cat /service-account/token`" https://kube-rbac-proxy.default.svc:8443/metrics' - volumeMounts: - - name: token-vol - mountPath: "/service-account" - readOnly: true - volumes: - - name: token-vol - projected: - sources: - - serviceAccountToken: - audience: kube-rbac-proxy.default.svc - expirationSeconds: 3600 - path: token - backoffLimit: 4 diff --git a/examples/non-resource-url-token-request/deployment.yaml b/examples/non-resource-url-token-request/deployment.yaml deleted file mode 100644 index 66f4d632d..000000000 --- a/examples/non-resource-url-token-request/deployment.yaml +++ /dev/null @@ -1,81 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--auth-token-audiences=kube-rbac-proxy.default.svc" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/examples/non-resource-url-token-request/kind-config.yaml b/examples/non-resource-url-token-request/kind-config.yaml deleted file mode 100644 index 419147f0a..000000000 --- a/examples/non-resource-url-token-request/kind-config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# this config file contains all config fields with comments -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -# patch the generated kubeadm config with some extra settings -kubeadmConfigPatches: -- | - apiVersion: kubeadm.k8s.io/v1beta2 - kind: ClusterConfiguration - metadata: - name: config - apiServer: - extraArgs: - service-account-signing-key-file: /etc/kubernetes/pki/sa.key - service-account-issuer: kubernetes.default.svc - v: "10" diff --git a/examples/non-resource-url-token-request/wrong-client.yaml b/examples/non-resource-url-token-request/wrong-client.yaml deleted file mode 100644 index c5f087a93..000000000 --- a/examples/non-resource-url-token-request/wrong-client.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-wrong-token-curl -spec: - template: - metadata: - name: krp-wrong-token-curl - spec: - restartPolicy: Never - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 diff --git a/examples/non-resource-url/README.md b/examples/non-resource-url/README.md deleted file mode 100644 index fe4ffb590..000000000 --- a/examples/non-resource-url/README.md +++ /dev/null @@ -1,177 +0,0 @@ -# non-resource-url example - -> Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac). - -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. - -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. - -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. - -```bash -$ kubectl create -f deployment.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./deployment.yaml) -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" -``` - -Once the prometheus-example-app is up and running, we can test it. In order to test it, we deploy a Job, that performs a `curl` against the above deployment. Because it has the `/metrics` path in its `nonResourceURLs` it is allowed to access the endpoint. - -The Dockerfile of this container can be found [here](../example-client/Dockerfile). - -```bash -$ kubectl create -f client-rbac.yaml client.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./client-rbac.yaml) -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default -``` - -[embedmd]:# (./client.yaml) -```yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - restartPolicy: Never - backoffLimit: 4 -``` - -We can look at the logs and we should get something similar to: - -``` -$ kubectl logs job/krp-curl -* Trying 10.99.141.73... -* TCP_NODELAY set -* Connected to kube-rbac-proxy.default.svc (10.99.141.73) port 8080 (#0) -> GET /metrics HTTP/1.1 -> Host: kube-rbac-proxy.default.svc:8080 -> User-Agent: curl/7.57.0 -> Accept: */* -> Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNHBzeHYiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjY2YTAzNTdiLWUzMmYtMTFlNy04YjIzLTA4MDAyNzhkNDA5OSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.egkmiNUcs8gB9I1EHPwdzr-xYjVK5dpd8OihPkMiM1DjRN7PoVVTWiM9IWBo2gZRGxV8ItpwCFDALs2Y85nfZk8l82YE6qHdQHG3-igqbiNNwRUIkVcpNpKmA-859LdC3C2ia0cnvll_ge1FlVOWMGH8rvSwD4-We2xbEwJ6djmBMF3iN6zHmeiom8WGKxoF3ddKoCKhLEN9pTiOVeXitWm6U2xEj_WyrMSpaIlfoT-BxNSOxTTPo5Nk71yM1bEzGb6jQdixOPsgHZP0nNxf9tmWnyb9qjBOPzObze9GHAoJUx9a94rURR8Zpf6DgPtKMJxcNq2buI05RdBwCkfjug -> -< HTTP/1.1 200 OK -< Content-Type: text/plain; version=0.0.4 -< Date: Sun, 17 Dec 2017 13:40:00 GMT -< Content-Length: 102 -< -{ [102 bytes data] -* Connection #0 to host kube-rbac-proxy.default.svc left intact -# HELP version Version information about this binary -# TYPE version gauge -version{version="v0.1.0"} 0 -``` - diff --git a/examples/non-resource-url/client-rbac.yaml b/examples/non-resource-url/client-rbac.yaml deleted file mode 100644 index b13c24e13..000000000 --- a/examples/non-resource-url/client-rbac.yaml +++ /dev/null @@ -1,20 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default diff --git a/examples/non-resource-url/client.yaml b/examples/non-resource-url/client.yaml deleted file mode 100644 index fe9f0b435..000000000 --- a/examples/non-resource-url/client.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - restartPolicy: Never - backoffLimit: 4 diff --git a/examples/non-resource-url/deployment.yaml b/examples/non-resource-url/deployment.yaml deleted file mode 100644 index ef9959bb7..000000000 --- a/examples/non-resource-url/deployment.yaml +++ /dev/null @@ -1,80 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/examples/oidc/.gitignore b/examples/oidc/.gitignore deleted file mode 100644 index 8ec3e81be..000000000 --- a/examples/oidc/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -ssl -dex-tls-ca-secret.yaml -dex-tls-secret.yaml diff --git a/examples/oidc/README.md b/examples/oidc/README.md deleted file mode 100644 index a2893ee83..000000000 --- a/examples/oidc/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# OIDC authentication - -Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac/README.md) - -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. - -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. - -Like in other examples, `kube-rbac-proxy` also requires RBAC access to perform SubjectAccessReviews. - -```bash -$ kubectl create -f deployment.yaml -``` -```bash -$ kubectl create -f configmap.yaml -``` - -```bash -$ kubectl create -f client-rbac.yaml -``` - -Note: The {ISSUER} and {CLIENT_ID} in the deployment have to be replaced with the issuer and client in the OIDC provider configuration. diff --git a/examples/oidc/client-rbac.yaml b/examples/oidc/client-rbac.yaml deleted file mode 100644 index 3d326adc5..000000000 --- a/examples/oidc/client-rbac.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get", "list"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: User - name: admin - apiGroup: rbac.authorization.k8s.io diff --git a/examples/oidc/deployment.yaml b/examples/oidc/deployment.yaml deleted file mode 100644 index 834a0e778..000000000 --- a/examples/oidc/deployment.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8444 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - # {BEGIN} for minikube development only if OIDC provider is deployed in minikube itself ie. dex - hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - # {END} - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--insecure-listen-address=0.0.0.0:8444" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - - "--oidc-issuer={ISSUER}" - - "--oidc-clientID={CLIENT_ID}" - ports: - - containerPort: 8444 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/examples/resource-attributes/README.md b/examples/resource-attributes/README.md deleted file mode 100644 index 0b91bc696..000000000 --- a/examples/resource-attributes/README.md +++ /dev/null @@ -1,200 +0,0 @@ -# resource-attributes example - -> Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac). - -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. - -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. - -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. - -```bash -$ kubectl create -f deployment.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./deployment.yaml) -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - resourceAttributes: - namespace: default - apiVersion: v1 - resource: services - subresource: proxy - name: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy -``` - -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. - -The Dockerfile of this container can be found [here](../example-client/Dockerfile). - -```bash -$ kubectl create -f client-rbac.yaml client.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./client-rbac.yaml) -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy-client -rules: -- apiGroups: [""] - resources: ["services/proxy"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy-client -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy-client -subjects: -- kind: ServiceAccount - name: default - namespace: default -``` - -[embedmd]:# (./client.yaml) -```yaml -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - restartPolicy: Never - backoffLimit: 4 -``` - -We can look at the logs and we should get something similar to: - -``` -$ kubectl logs job/krp-curl -* Trying 10.111.34.206... -* TCP_NODELAY set -* Connected to kube-rbac-proxy.default.svc (10.111.34.206) port 8080 (#0) -> GET /metrics HTTP/1.1 -> Host: kube-rbac-proxy.default.svc:8080 -> User-Agent: curl/7.57.0 -> Accept: */* -> Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tNHZxZGIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImQwNzU4NDE3LWUzMmUtMTFlNy1hOTQ1LTA4MDAyNzg2NjgwMCIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.eftzPb2rthIcW8Md4URFYpDhyEKuqepP7WKsWO25uBdWlN85TcPkeGSaRf7-dRp7ie5ADp-UgTZtI2lu6ssntmxsATeH_jE0zye6UlTqM-_2iLNLexgE29bYD8cqH5WMc7tE-y_Y0u0F3hjvURNvQycxfrGWICd1gNrk2jpxC6mAYVt3ldT5rylw0FWot7t8uDvorW6QScfvPPNmwh0hHsdvMuJ2e8lc9KDnTS-yRuQ1SmMNyc7L2JyZ7bphahNZNa8K7D3C1NOAmAQrDfBAr97peGbQ02yCc4hG_YQDyO2xMaQs_AFf38ZIiM-z7OnSQO4_D8FmkY2CG2jnd6ZXlw -> -< HTTP/1.1 200 OK -< Content-Type: text/plain; version=0.0.4 -< Date: Sun, 17 Dec 2017 13:34:26 GMT -< Content-Length: 102 -< -{ [102 bytes data] -* Connection #0 to host kube-rbac-proxy.default.svc left intact -# HELP version Version information about this binary -# TYPE version gauge -version{version="v0.1.0"} 0 -``` - diff --git a/examples/resource-attributes/client-rbac.yaml b/examples/resource-attributes/client-rbac.yaml deleted file mode 100644 index 062cba7a4..000000000 --- a/examples/resource-attributes/client-rbac.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy-client -rules: -- apiGroups: [""] - resources: ["services/proxy"] - verbs: ["get"] ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy-client -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy-client -subjects: -- kind: ServiceAccount - name: default - namespace: default diff --git a/examples/resource-attributes/client.yaml b/examples/resource-attributes/client.yaml deleted file mode 100644 index fe9f0b435..000000000 --- a/examples/resource-attributes/client.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: batch/v1 -kind: Job -metadata: - name: krp-curl -spec: - template: - metadata: - name: krp-curl - spec: - containers: - - name: krp-curl - image: quay.io/brancz/krp-curl:v0.0.2 - restartPolicy: Never - backoffLimit: 4 diff --git a/examples/resource-attributes/deployment.yaml b/examples/resource-attributes/deployment.yaml deleted file mode 100644 index f15ccc131..000000000 --- a/examples/resource-attributes/deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - resourceAttributes: - namespace: default - apiVersion: v1 - resource: services - subresource: proxy - name: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/examples/rewrites/README.md b/examples/rewrites/README.md deleted file mode 100644 index 785e44c3f..000000000 --- a/examples/rewrites/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# rewriting SubjectAccessReviews example - -> Note to try this out with minikube, make sure you enable RBAC correctly as explained [here](../minikube-rbac). - -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. - -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. - -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. - -```bash -$ kubectl create -f deployment.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./deployment.yaml) -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - apiVersion: v1 - resource: namespace - subresource: metrics - namespace: "{{ .Value }}" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy -``` - -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. - -The Dockerfile of this container can be found [here](../example-client-urlquery/Dockerfile). - -```bash -$ kubectl create -f client-rbac.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./client-rbac.yaml) -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: namespace-metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: namespace-metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: namespace-metrics -rules: -- apiGroups: [""] - resources: - - namespace/metrics - verbs: ["get"] -``` diff --git a/examples/rewrites/client-rbac.yaml b/examples/rewrites/client-rbac.yaml deleted file mode 100644 index 2ad696d09..000000000 --- a/examples/rewrites/client-rbac.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: namespace-metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: namespace-metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: namespace-metrics -rules: -- apiGroups: [""] - resources: - - namespace/metrics - verbs: ["get"] diff --git a/examples/rewrites/deployment.yaml b/examples/rewrites/deployment.yaml deleted file mode 100644 index acd5a5199..000000000 --- a/examples/rewrites/deployment.yaml +++ /dev/null @@ -1,104 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - apiVersion: v1 - resource: namespace - subresource: metrics - namespace: "{{ .Value }}" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.11.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/examples/static-auth/README.md b/examples/static-auth/README.md deleted file mode 100644 index 220e6d537..000000000 --- a/examples/static-auth/README.md +++ /dev/null @@ -1,201 +0,0 @@ -# Static Authorization example - -> 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). - -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. - -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. - -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. - -```bash -$ kubectl create -f deployment.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./deployment.yaml) -```yaml -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - apiVersion: v1 - resource: namespace - subresource: metrics - namespace: "{{ .Value }}" - static: - - resourceRequest: true - resource: namespace - subresource: metrics ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.8.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy -``` - -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. - -```bash -$ kubectl create -f client-rbac.yaml -``` - -The content of this manifest is: - -[embedmd]:# (./client-rbac.yaml) -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: namespace-metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: namespace-metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: namespace-metrics -rules: -- apiGroups: [""] - resources: - - namespace/metrics - verbs: ["get"] -``` - -Now simply run -``` -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' -``` - -A configuration setting for the static authorization feature for resource requests looks like this: -``` - config-file.yaml: |+ - authorization: - static: - - user: - name: UserName - groups: - - group1 - - group2 - verb: get - namespace: default - apiGroup: apps - resourceRequest: true - resource: namespace - subresource: metrics -``` - -A configuration setting for the static authorization feature for non-resource requests looks like this: -``` - config-file.yaml: |+ - authorization: - static: - - user: - name: UserName - groups: - - group1 - - group2 - verb: get - resourceRequest: false - path: /metrics -``` - -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. diff --git a/examples/static-auth/client-rbac.yaml b/examples/static-auth/client-rbac.yaml deleted file mode 100644 index 2ad696d09..000000000 --- a/examples/static-auth/client-rbac.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: namespace-metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: namespace-metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: namespace-metrics -rules: -- apiGroups: [""] - resources: - - namespace/metrics - verbs: ["get"] diff --git a/examples/static-auth/deployment.yaml b/examples/static-auth/deployment.yaml deleted file mode 100644 index 08382c3a2..000000000 --- a/examples/static-auth/deployment.yaml +++ /dev/null @@ -1,108 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - apiVersion: v1 - resource: namespace - subresource: metrics - namespace: "{{ .Value }}" - static: - - resourceRequest: true - resource: namespace - subresource: metrics ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:v0.8.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/go.mod b/go.mod deleted file mode 100644 index b9d3c344c..000000000 --- a/go.mod +++ /dev/null @@ -1,71 +0,0 @@ -module github.com/brancz/kube-rbac-proxy - -go 1.17 - -require ( - github.com/ghodss/yaml v1.0.0 - github.com/google/go-cmp v0.5.4 - github.com/oklog/run v1.0.0 - github.com/spf13/pflag v1.0.5 - golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 - gopkg.in/yaml.v2 v2.2.8 - k8s.io/api v0.19.16 - k8s.io/apimachinery v0.19.16 - k8s.io/apiserver v0.19.16 - k8s.io/client-go v0.19.16 - k8s.io/component-base v0.19.16 - k8s.io/klog/v2 v2.3.0 -) - -require ( - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver v3.5.0+incompatible // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect - github.com/coreos/go-oidc v2.1.0+incompatible // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/evanphx/json-patch v4.9.0+incompatible // indirect - github.com/go-logr/logr v0.2.0 // indirect - github.com/go-openapi/jsonpointer v0.19.3 // indirect - github.com/go-openapi/jsonreference v0.19.3 // indirect - github.com/go-openapi/spec v0.19.3 // indirect - github.com/go-openapi/swag v0.19.5 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7 // indirect - github.com/golang/protobuf v1.4.2 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.1 // indirect - github.com/googleapis/gnostic v0.4.1 // indirect - github.com/hashicorp/golang-lru v0.5.1 // indirect - github.com/imdario/mergo v0.3.5 // indirect - github.com/json-iterator/go v1.1.10 // indirect - github.com/mailru/easyjson v0.7.0 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect - github.com/prometheus/client_golang v1.7.1 // indirect - github.com/prometheus/client_model v0.2.0 // indirect - github.com/prometheus/common v0.10.0 // indirect - github.com/prometheus/procfs v0.7.3 // indirect - golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8 // indirect - golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6 // indirect - golang.org/x/sync v0.0.0-20201207232520-09787c993a3a // indirect - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect - golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect - golang.org/x/text v0.3.7 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - google.golang.org/appengine v1.6.5 // indirect - google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect - google.golang.org/grpc v1.27.0 // indirect - google.golang.org/protobuf v1.24.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/square/go-jose.v2 v2.2.2 // indirect - k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6 // indirect - k8s.io/utils v0.0.0-20200729134348-d5654de09c73 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect - sigs.k8s.io/yaml v1.2.0 // indirect -) diff --git a/main.go b/main.go deleted file mode 100644 index 6e523db1c..000000000 --- a/main.go +++ /dev/null @@ -1,426 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "context" - "crypto/tls" - "flag" - "io/ioutil" - "net" - "net/http" - "net/http/httputil" - "net/url" - "os" - "os/signal" - "path" - "strings" - "syscall" - "time" - - "github.com/ghodss/yaml" - "github.com/oklog/run" - "github.com/spf13/pflag" - "golang.org/x/net/http2" - "golang.org/x/net/http2/h2c" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authorization/union" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - certutil "k8s.io/client-go/util/cert" - k8sapiflag "k8s.io/component-base/cli/flag" - "k8s.io/klog/v2" - - "github.com/brancz/kube-rbac-proxy/pkg/authn" - "github.com/brancz/kube-rbac-proxy/pkg/authz" - "github.com/brancz/kube-rbac-proxy/pkg/proxy" - rbac_proxy_tls "github.com/brancz/kube-rbac-proxy/pkg/tls" -) - -type config struct { - insecureListenAddress string - secureListenAddress string - upstream string - upstreamForceH2C bool - upstreamCAFile string - auth proxy.Config - tls tlsConfig - kubeconfigLocation string - allowPaths []string - ignorePaths []string -} - -type tlsConfig struct { - certFile string - keyFile string - minVersion string - cipherSuites []string - reloadInterval time.Duration -} - -type configfile struct { - AuthorizationConfig *authz.Config `json:"authorization,omitempty"` -} - -func main() { - cfg := config{ - auth: proxy.Config{ - Authentication: &authn.AuthnConfig{ - X509: &authn.X509Config{}, - Header: &authn.AuthnHeaderConfig{}, - OIDC: &authn.OIDCConfig{}, - Token: &authn.TokenConfig{}, - }, - Authorization: &authz.Config{}, - }, - } - configFileName := "" - - // Add klog flags - klogFlags := flag.NewFlagSet(os.Args[0], flag.ExitOnError) - klog.InitFlags(klogFlags) - - flagset := pflag.NewFlagSet(os.Args[0], pflag.ExitOnError) - flagset.AddGoFlagSet(klogFlags) - - // kube-rbac-proxy flags - flagset.StringVar(&cfg.insecureListenAddress, "insecure-listen-address", "", "The address the kube-rbac-proxy HTTP server should listen on.") - flagset.StringVar(&cfg.secureListenAddress, "secure-listen-address", "", "The address the kube-rbac-proxy HTTPs server should listen on.") - flagset.StringVar(&cfg.upstream, "upstream", "", "The upstream URL to proxy to once requests have successfully been authenticated and authorized.") - flagset.BoolVar(&cfg.upstreamForceH2C, "upstream-force-h2c", false, "Force h2c to communiate with the upstream. This is required when the upstream speaks h2c(http/2 cleartext - insecure variant of http/2) only. For example, go-grpc server in the insecure mode, such as helm's tiller w/o TLS, speaks h2c only") - flagset.StringVar(&cfg.upstreamCAFile, "upstream-ca-file", "", "The CA the upstream uses for TLS connection. This is required when the upstream uses TLS and its own CA certificate") - flagset.StringVar(&configFileName, "config-file", "", "Configuration file to configure kube-rbac-proxy.") - flagset.StringSliceVar(&cfg.allowPaths, "allow-paths", nil, "Comma-separated list of paths against which kube-rbac-proxy matches the incoming request. If the request doesn't match, kube-rbac-proxy responds with a 404 status code. If omitted, the incoming request path isn't checked. Cannot be used with --ignore-paths.") - flagset.StringSliceVar(&cfg.ignorePaths, "ignore-paths", nil, "Comma-separated list of paths against which kube-rbac-proxy will proxy without performing an authentication or authorization check. Cannot be used with --allow-paths.") - - // TLS flags - flagset.StringVar(&cfg.tls.certFile, "tls-cert-file", "", "File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert)") - flagset.StringVar(&cfg.tls.keyFile, "tls-private-key-file", "", "File containing the default x509 private key matching --tls-cert-file.") - flagset.StringVar(&cfg.tls.minVersion, "tls-min-version", "VersionTLS12", "Minimum TLS version supported. Value must match version names from https://golang.org/pkg/crypto/tls/#pkg-constants.") - flagset.StringSliceVar(&cfg.tls.cipherSuites, "tls-cipher-suites", nil, "Comma-separated list of cipher suites for the server. Values are from tls package constants (https://golang.org/pkg/crypto/tls/#pkg-constants). If omitted, the default Go cipher suites will be used") - flagset.DurationVar(&cfg.tls.reloadInterval, "tls-reload-interval", time.Minute, "The interval at which to watch for TLS certificate changes, by default set to 1 minute.") - - // Auth flags - flagset.StringVar(&cfg.auth.Authentication.X509.ClientCAFile, "client-ca-file", "", "If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate.") - flagset.BoolVar(&cfg.auth.Authentication.Header.Enabled, "auth-header-fields-enabled", false, "When set to true, kube-rbac-proxy adds auth-related fields to the headers of http requests sent to the upstream") - flagset.StringVar(&cfg.auth.Authentication.Header.UserFieldName, "auth-header-user-field-name", "x-remote-user", "The name of the field inside a http(2) request header to tell the upstream server about the user's name") - flagset.StringVar(&cfg.auth.Authentication.Header.GroupsFieldName, "auth-header-groups-field-name", "x-remote-groups", "The name of the field inside a http(2) request header to tell the upstream server about the user's groups") - flagset.StringVar(&cfg.auth.Authentication.Header.GroupSeparator, "auth-header-groups-field-separator", "|", "The separator string used for concatenating multiple group names in a groups header field's value") - flagset.StringSliceVar(&cfg.auth.Authentication.Token.Audiences, "auth-token-audiences", []string{}, "Comma-separated list of token audiences to accept. By default a token does not have to have any specific audience. It is recommended to set a specific audience.") - - //Authn OIDC flags - flagset.StringVar(&cfg.auth.Authentication.OIDC.IssuerURL, "oidc-issuer", "", "The URL of the OpenID issuer, only HTTPS scheme will be accepted. If set, it will be used to verify the OIDC JSON Web Token (JWT).") - flagset.StringVar(&cfg.auth.Authentication.OIDC.ClientID, "oidc-clientID", "", "The client ID for the OpenID Connect client, must be set if oidc-issuer-url is set.") - flagset.StringVar(&cfg.auth.Authentication.OIDC.GroupsClaim, "oidc-groups-claim", "groups", "Identifier of groups in JWT claim, by default set to 'groups'") - flagset.StringVar(&cfg.auth.Authentication.OIDC.UsernameClaim, "oidc-username-claim", "email", "Identifier of the user in JWT claim, by default set to 'email'") - flagset.StringVar(&cfg.auth.Authentication.OIDC.GroupsPrefix, "oidc-groups-prefix", "", "If provided, all groups will be prefixed with this value to prevent conflicts with other authentication strategies.") - flagset.StringArrayVar(&cfg.auth.Authentication.OIDC.SupportedSigningAlgs, "oidc-sign-alg", []string{"RS256"}, "Supported signing algorithms, default RS256") - flagset.StringVar(&cfg.auth.Authentication.OIDC.CAFile, "oidc-ca-file", "", "If set, the OpenID server's certificate will be verified by one of the authorities in the oidc-ca-file, otherwise the host's root CA set will be used.") - - //Kubeconfig flag - flagset.StringVar(&cfg.kubeconfigLocation, "kubeconfig", "", "Path to a kubeconfig file, specifying how to connect to the API server. If unset, in-cluster configuration will be used") - - err := flagset.Parse(os.Args[1:]) - if err != nil { - klog.Fatalf("Failed to parse CLI flags: %v", err) - } - kcfg := initKubeConfig(cfg.kubeconfigLocation) - - upstreamURL, err := url.Parse(cfg.upstream) - if err != nil { - klog.Fatalf("Failed to parse upstream URL: %v", err) - } - - if configFileName != "" { - klog.Infof("Reading config file: %s", configFileName) - b, err := ioutil.ReadFile(configFileName) - if err != nil { - klog.Fatalf("Failed to read resource-attribute file: %v", err) - } - - configfile := configfile{} - - err = yaml.Unmarshal(b, &configfile) - if err != nil { - klog.Fatalf("Failed to parse config file content: %v", err) - } - - cfg.auth.Authorization = configfile.AuthorizationConfig - } - - kubeClient, err := kubernetes.NewForConfig(kcfg) - if err != nil { - klog.Fatalf("Failed to instantiate Kubernetes client: %v", err) - } - - var authenticator authenticator.Request - // If OIDC configuration provided, use oidc authenticator - if cfg.auth.Authentication.OIDC.IssuerURL != "" { - authenticator, err = authn.NewOIDCAuthenticator(cfg.auth.Authentication.OIDC) - if err != nil { - klog.Fatalf("Failed to instantiate OIDC authenticator: %v", err) - } - } else { - //Use Delegating authenticator - klog.Infof("Valid token audiences: %s", strings.Join(cfg.auth.Authentication.Token.Audiences, ", ")) - - tokenClient := kubeClient.AuthenticationV1().TokenReviews() - delegatingAuthenticator, err := authn.NewDelegatingAuthenticator(tokenClient, cfg.auth.Authentication) - if err != nil { - klog.Fatalf("Failed to instantiate delegating authenticator: %v", err) - } - - go delegatingAuthenticator.Run(1, context.Background().Done()) - authenticator = delegatingAuthenticator - } - - sarClient := kubeClient.AuthorizationV1().SubjectAccessReviews() - sarAuthorizer, err := authz.NewSarAuthorizer(sarClient) - - if err != nil { - klog.Fatalf("Failed to create sar authorizer: %v", err) - } - - staticAuthorizer, err := authz.NewStaticAuthorizer(cfg.auth.Authorization.Static) - if err != nil { - klog.Fatalf("Failed to create static authorizer: %v", err) - } - - authorizer := union.New( - staticAuthorizer, - sarAuthorizer, - ) - - auth, err := proxy.New(kubeClient, cfg.auth, authorizer, authenticator) - - if err != nil { - klog.Fatalf("Failed to create rbac-proxy: %v", err) - } - - upstreamTransport, err := initTransport(cfg.upstreamCAFile) - if err != nil { - klog.Fatalf("Failed to set up upstream TLS connection: %v", err) - } - - if len(cfg.allowPaths) > 0 && len(cfg.ignorePaths) > 0 { - klog.Fatal("Cannot use --allow-paths and --ignore-paths together.") - } - - for _, pathAllowed := range cfg.allowPaths { - _, err := path.Match(pathAllowed, "") - if err != nil { - klog.Fatalf("Failed to verify allow path: %s", pathAllowed) - } - } - - for _, pathIgnored := range cfg.ignorePaths { - _, err := path.Match(pathIgnored, "") - if err != nil { - klog.Fatalf("Failed to verify ignored path: %s", pathIgnored) - } - } - - proxy := httputil.NewSingleHostReverseProxy(upstreamURL) - proxy.Transport = upstreamTransport - - if cfg.upstreamForceH2C { - // Force http/2 for connections to the upstream i.e. do not start with HTTP1.1 UPGRADE req to - // initialize http/2 session. - // See https://github.com/golang/go/issues/14141#issuecomment-219212895 for more context - proxy.Transport = &http2.Transport{ - // Allow http schema. This doesn't automatically disable TLS - AllowHTTP: true, - // Do disable TLS. - // In combination with the schema check above. We could enforce h2c against the upstream server - DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) { - return net.Dial(netw, addr) - }, - } - } - - mux := http.NewServeMux() - mux.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - found := len(cfg.allowPaths) == 0 - for _, pathAllowed := range cfg.allowPaths { - found, err = path.Match(pathAllowed, req.URL.Path) - if err != nil { - return - } - if found { - break - } - } - if !found { - http.NotFound(w, req) - return - } - - ignorePathFound := false - for _, pathIgnored := range cfg.ignorePaths { - ignorePathFound, err = path.Match(pathIgnored, req.URL.Path) - if err != nil { - return - } - if ignorePathFound { - break - } - } - - if !ignorePathFound { - ok := auth.Handle(w, req) - if !ok { - return - } - } - - proxy.ServeHTTP(w, req) - })) - - var gr run.Group - { - if cfg.secureListenAddress != "" { - srv := &http.Server{Handler: mux, TLSConfig: &tls.Config{}} - - if cfg.tls.certFile == "" && cfg.tls.keyFile == "" { - klog.Info("Generating self signed cert as no cert is provided") - host, err := os.Hostname() - if err != nil { - klog.Fatalf("Failed to retrieve hostname for self-signed cert: %v", err) - } - certBytes, keyBytes, err := certutil.GenerateSelfSignedCertKey(host, nil, nil) - if err != nil { - klog.Fatalf("Failed to generate self signed cert and key: %v", err) - } - cert, err := tls.X509KeyPair(certBytes, keyBytes) - if err != nil { - klog.Fatalf("Failed to load generated self signed cert and key: %v", err) - } - - srv.TLSConfig.Certificates = []tls.Certificate{cert} - } else { - klog.Info("Reading certificate files") - ctx, cancel := context.WithCancel(context.Background()) - r, err := rbac_proxy_tls.NewCertReloader(cfg.tls.certFile, cfg.tls.keyFile, cfg.tls.reloadInterval) - if err != nil { - klog.Fatalf("Failed to initialize certificate reloader: %v", err) - } - - srv.TLSConfig.GetCertificate = r.GetCertificate - - gr.Add(func() error { - return r.Watch(ctx) - }, func(error) { - cancel() - }) - } - - version, err := k8sapiflag.TLSVersion(cfg.tls.minVersion) - if err != nil { - klog.Fatalf("TLS version invalid: %v", err) - } - - cipherSuiteIDs, err := k8sapiflag.TLSCipherSuites(cfg.tls.cipherSuites) - if err != nil { - klog.Fatalf("Failed to convert TLS cipher suite name to ID: %v", err) - } - - srv.TLSConfig.CipherSuites = cipherSuiteIDs - srv.TLSConfig.MinVersion = version - srv.TLSConfig.ClientAuth = tls.RequestClientCert - - if err := http2.ConfigureServer(srv, nil); err != nil { - klog.Fatalf("failed to configure http2 server: %v", err) - } - - klog.Infof("Starting TCP socket on %v", cfg.secureListenAddress) - l, err := net.Listen("tcp", cfg.secureListenAddress) - if err != nil { - klog.Fatalf("failed to listen on secure address: %v", err) - } - - gr.Add(func() error { - klog.Infof("Listening securely on %v", cfg.secureListenAddress) - tlsListener := tls.NewListener(l, srv.TLSConfig) - return srv.Serve(tlsListener) - }, func(err error) { - if err := srv.Shutdown(context.Background()); err != nil { - klog.Errorf("failed to gracefully shutdown server: %v", err) - } - if err := l.Close(); err != nil { - klog.Errorf("failed to gracefully close secure listener: %v", err) - } - }) - } - } - { - if cfg.insecureListenAddress != "" { - srv := &http.Server{Handler: h2c.NewHandler(mux, &http2.Server{})} - - l, err := net.Listen("tcp", cfg.insecureListenAddress) - if err != nil { - klog.Fatalf("Failed to listen on insecure address: %v", err) - } - - gr.Add(func() error { - klog.Infof("Listening insecurely on %v", cfg.insecureListenAddress) - return srv.Serve(l) - }, func(err error) { - if err := srv.Shutdown(context.Background()); err != nil { - klog.Errorf("failed to gracefully shutdown server: %v", err) - } - if err := l.Close(); err != nil { - klog.Errorf("failed to gracefully close listener: %v", err) - } - }) - } - } - { - sig := make(chan os.Signal, 1) - gr.Add(func() error { - signal.Notify(sig, os.Interrupt, syscall.SIGTERM) - <-sig - klog.Info("received interrupt, shutting down") - return nil - }, func(err error) { - close(sig) - }) - } - - if err := gr.Run(); err != nil { - klog.Fatalf("failed to run groups: %v", err) - } -} - -// Returns intiliazed config, allows local usage (outside cluster) based on provided kubeconfig or in-cluter -func initKubeConfig(kcLocation string) *rest.Config { - - if kcLocation != "" { - kubeConfig, err := clientcmd.BuildConfigFromFlags("", kcLocation) - if err != nil { - klog.Fatalf("unable to build rest config based on provided path to kubeconfig file: %v", err) - } - return kubeConfig - } - - kubeConfig, err := rest.InClusterConfig() - if err != nil { - klog.Fatalf("cannot find Service Account in pod to build in-cluster rest config: %v", err) - } - - return kubeConfig -} diff --git a/pkg/authn/config.go b/pkg/authn/config.go deleted file mode 100644 index 76ea6be2d..000000000 --- a/pkg/authn/config.go +++ /dev/null @@ -1,49 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authn - -// AuthnHeaderConfig contains authentication header settings which enable more information about the user identity to be sent to the upstream -type AuthnHeaderConfig struct { - // When set to true, kube-rbac-proxy adds auth-related fields to the headers of http requests sent to the upstream - Enabled bool - // Corresponds to the name of the field inside a http(2) request header - // to tell the upstream server about the user's name - UserFieldName string - // Corresponds to the name of the field inside a http(2) request header - // to tell the upstream server about the user's groups - GroupsFieldName string - // The separator string used for concatenating multiple group names in a groups header field's value - GroupSeparator string -} - -// AuthnConfig holds all configurations related to authentication options -type AuthnConfig struct { - X509 *X509Config - Header *AuthnHeaderConfig - OIDC *OIDCConfig - Token *TokenConfig -} - -// X509Config holds public client certificate used for authentication requests if specified -type X509Config struct { - ClientCAFile string -} - -// TokenConfig holds configuration as to how token authentication is to be done -type TokenConfig struct { - Audiences []string -} diff --git a/pkg/authn/delegating.go b/pkg/authn/delegating.go deleted file mode 100644 index ac2594625..000000000 --- a/pkg/authn/delegating.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authn - -import ( - "errors" - "net/http" - "time" - - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/authenticatorfactory" - "k8s.io/apiserver/pkg/server/dynamiccertificates" - authenticationclient "k8s.io/client-go/kubernetes/typed/authentication/v1" -) - -type DelegatingAuthenticator struct { - dynamicClientCA *dynamiccertificates.DynamicFileCAContent - requestAuthenticator authenticator.Request -} - -// NewDelegatingAuthenticator creates an authenticator compatible with the kubelet's needs -func NewDelegatingAuthenticator(client authenticationclient.TokenReviewInterface, authn *AuthnConfig) (*DelegatingAuthenticator, error) { - if client == nil { - return nil, errors.New("tokenAccessReview client not provided, cannot use webhook authentication") - } - - var ( - p *dynamiccertificates.DynamicFileCAContent - err error - ) - - authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig{ - Anonymous: false, // always require authentication - CacheTTL: 2 * time.Minute, - TokenAccessReviewClient: client, - APIAudiences: authenticator.Audiences(authn.Token.Audiences), - } - - if len(authn.X509.ClientCAFile) > 0 { - p, err = dynamiccertificates.NewDynamicCAContentFromFile("client-ca", authn.X509.ClientCAFile) - if err != nil { - return nil, err - } - authenticatorConfig.ClientCertificateCAContentProvider = p - } - - authenticator, _, err := authenticatorConfig.New() - if err != nil { - return nil, err - } - - return &DelegatingAuthenticator{requestAuthenticator: authenticator, dynamicClientCA: p}, nil -} - -func (a *DelegatingAuthenticator) AuthenticateRequest(req *http.Request) (*authenticator.Response, bool, error) { - return a.requestAuthenticator.AuthenticateRequest(req) -} - -func (a *DelegatingAuthenticator) RunOnce() error { - if a.dynamicClientCA != nil { - return a.dynamicClientCA.RunOnce() - } - return nil -} - -func (a *DelegatingAuthenticator) Run(workers int, stopCh <-chan struct{}) { - if a.dynamicClientCA != nil { - a.dynamicClientCA.Run(workers, stopCh) - } -} diff --git a/pkg/authn/oidc.go b/pkg/authn/oidc.go deleted file mode 100644 index 146f1e91f..000000000 --- a/pkg/authn/oidc.go +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authn - -import ( - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/request/bearertoken" - "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" -) - -// OIDCConfig represents configuration used for JWT request authentication -type OIDCConfig struct { - IssuerURL string - ClientID string - CAFile string - UsernameClaim string - UsernamePrefix string - GroupsClaim string - GroupsPrefix string - SupportedSigningAlgs []string -} - -// NewOIDCAuthenticator returns OIDC authenticator -func NewOIDCAuthenticator(config *OIDCConfig) (authenticator.Request, error) { - tokenAuthenticator, err := oidc.New(oidc.Options{ - IssuerURL: config.IssuerURL, - ClientID: config.ClientID, - CAFile: config.CAFile, - UsernameClaim: config.UsernameClaim, - UsernamePrefix: config.UsernamePrefix, - GroupsClaim: config.GroupsClaim, - GroupsPrefix: config.GroupsPrefix, - SupportedSigningAlgs: config.SupportedSigningAlgs, - }) - if err != nil { - return nil, err - } - - return bearertoken.New(tokenAuthenticator), nil -} diff --git a/pkg/authz/auth.go b/pkg/authz/auth.go deleted file mode 100644 index 94b297d40..000000000 --- a/pkg/authz/auth.go +++ /dev/null @@ -1,149 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authz - -import ( - "context" - "errors" - "fmt" - "time" - - "k8s.io/apiserver/pkg/authorization/authorizer" - "k8s.io/apiserver/pkg/authorization/authorizerfactory" - authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1" -) - -// Config holds configuration enabling request authorization -type Config struct { - Rewrites *SubjectAccessReviewRewrites `json:"rewrites,omitempty"` - ResourceAttributes *ResourceAttributes `json:"resourceAttributes,omitempty"` - ResourceAttributesFile string `json:"-"` - Static []StaticAuthorizationConfig `json:"static,omitempty"` -} - -// SubjectAccessReviewRewrites describes how SubjectAccessReview may be -// rewritten on a given request. -type SubjectAccessReviewRewrites struct { - ByQueryParameter *QueryParameterRewriteConfig `json:"byQueryParameter,omitempty"` - ByHTTPHeader *HTTPHeaderRewriteConfig `json:"byHttpHeader,omitempty"` -} - -// QueryParameterRewriteConfig describes which HTTP URL query parameter is to -// be used to rewrite a SubjectAccessReview on a given request. -type QueryParameterRewriteConfig struct { - Name string `json:"name,omitempty"` -} - -// HTTPHeaderRewriteConfig describes which HTTP header is to -// be used to rewrite a SubjectAccessReview on a given request. -type HTTPHeaderRewriteConfig struct { - Name string `json:"name,omitempty"` -} - -// ResourceAttributes describes attributes available for resource request authorization -type ResourceAttributes struct { - Namespace string `json:"namespace,omitempty"` - APIGroup string `json:"apiGroup,omitempty"` - APIVersion string `json:"apiVersion,omitempty"` - Resource string `json:"resource,omitempty"` - Subresource string `json:"subresource,omitempty"` - Name string `json:"name,omitempty"` -} - -// StaticAuthorizationConfig describes what is needed to specify a static -// authorization. -type StaticAuthorizationConfig struct { - User UserConfig - Verb string `json:"verb,omitempty"` - Namespace string `json:"namespace,omitempty"` - APIGroup string `json:"apiGroup,omitempty"` - Resource string `json:"resource,omitempty"` - Subresource string `json:"subresource,omitempty"` - Name string `json:"name,omitempty"` - ResourceRequest bool `json:"resourceRequest,omitempty"` - Path string `json:"path,omitempty"` -} - -type UserConfig struct { - Name string `json:"name,omitempty"` - Groups []string `json:"groups,omitempty"` -} - -// NewSarAuthorizer creates an authorizer compatible with the kubelet's needs -func NewSarAuthorizer(client authorizationclient.SubjectAccessReviewInterface) (authorizer.Authorizer, error) { - if client == nil { - return nil, errors.New("no client provided, cannot use webhook authorization") - } - authorizerConfig := authorizerfactory.DelegatingAuthorizerConfig{ - SubjectAccessReviewClient: client, - AllowCacheTTL: 5 * time.Minute, - DenyCacheTTL: 30 * time.Second, - } - return authorizerConfig.New() -} - -type staticAuthorizer struct { - config []StaticAuthorizationConfig -} - -func (saConfig StaticAuthorizationConfig) Equal(a authorizer.Attributes) bool { - isAllowed := func(staticConf string, requestVal string) bool { - if staticConf == "" { - return true - } else { - return staticConf == requestVal - } - } - - userName := "" - if a.GetUser() != nil { - userName = a.GetUser().GetName() - } - - if isAllowed(saConfig.User.Name, userName) && - isAllowed(saConfig.Verb, a.GetVerb()) && - isAllowed(saConfig.Namespace, a.GetNamespace()) && - isAllowed(saConfig.APIGroup, a.GetAPIGroup()) && - isAllowed(saConfig.Resource, a.GetResource()) && - isAllowed(saConfig.Subresource, a.GetSubresource()) && - isAllowed(saConfig.Name, a.GetName()) && - isAllowed(saConfig.Path, a.GetPath()) && - saConfig.ResourceRequest == a.IsResourceRequest() { - return true - } - return false -} - -func (sa staticAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { - // compare a against the configured static auths - for _, saConfig := range sa.config { - if saConfig.Equal(a) { - return authorizer.DecisionAllow, "found corresponding static auth config", nil - } - } - - return authorizer.DecisionNoOpinion, "", nil -} - -func NewStaticAuthorizer(config []StaticAuthorizationConfig) (*staticAuthorizer, error) { - for _, c := range config { - if c.ResourceRequest != (c.Path == "") { - return nil, fmt.Errorf("invalid configuration: resource requests must not include a path: %v", config) - } - } - return &staticAuthorizer{config}, nil -} diff --git a/pkg/authz/auth_test.go b/pkg/authz/auth_test.go deleted file mode 100644 index 608ecb294..000000000 --- a/pkg/authz/auth_test.go +++ /dev/null @@ -1,159 +0,0 @@ -/* -Copyright 2021 Kube RBAC Proxy Authors rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package authz - -import ( - "context" - "testing" - - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/authorization/authorizer" -) - -func TestStaticAuthorizer(t *testing.T) { - tests := []struct { - name string - config []StaticAuthorizationConfig - - shouldFail bool - shouldPass []authorizer.Attributes - shouldNoOpinion []authorizer.Attributes - }{ - { - name: "pathOnly", - config: []StaticAuthorizationConfig{ - {Path: "/metrics", ResourceRequest: false}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics"}, - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics"}, - }, - shouldNoOpinion: []authorizer.Attributes{ - // wrong path - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api"}, - }, - }, - { - name: "pathAndVerb", - config: []StaticAuthorizationConfig{ - {Path: "/metrics", Verb: "get"}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics"}, - }, - shouldNoOpinion: []authorizer.Attributes{ - // wrong path - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api"}, - // wrong path - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics"}, - }, - }, - { - name: "nonResourceRequestSpecifiedTrue", - config: []StaticAuthorizationConfig{ - {Path: "/metrics", Verb: "get", ResourceRequest: true}, - }, - shouldFail: true, - }, - { - name: "resourceRequestSpecifiedFalse", - config: []StaticAuthorizationConfig{ - {Resource: "namespaces", Verb: "get", ResourceRequest: false}, - }, - shouldFail: true, - }, - { - name: "resourceRequestSpecifiedFalse", - config: []StaticAuthorizationConfig{ - {Path: "/metrics", Verb: "get", ResourceRequest: false}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: false}, - }, - shouldNoOpinion: []authorizer.Attributes{ - // wrong resourceRequest - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: true}, - }, - }, - { - name: "resourceRequestUnspecified", - config: []StaticAuthorizationConfig{ - {Path: "/metrics", Verb: "get"}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: false}, - }, - shouldNoOpinion: []authorizer.Attributes{ - // Verb: get and ResourceRequest: true should be - // mutually exclusive - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/metrics", ResourceRequest: true}, - // wrong path - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Path: "/api", ResourceRequest: true}, - // wrong path - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "update", Path: "/metrics", ResourceRequest: false}, - }, - }, - { - name: "resourceRequest", - config: []StaticAuthorizationConfig{ - {Resource: "namespaces", Verb: "get", ResourceRequest: true}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, - authorizer.AttributesRecord{Verb: "get", Resource: "namespaces", ResourceRequest: true}, - }, - shouldNoOpinion: []authorizer.Attributes{ - authorizer.AttributesRecord{Verb: "get", Resource: "services", ResourceRequest: true}, - }, - }, - { - name: "resourceRequestSpecificUser", - config: []StaticAuthorizationConfig{ - {User: UserConfig{Name: "system:foo"}, Resource: "namespaces", Verb: "get", ResourceRequest: true}, - }, - shouldPass: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:foo"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, - }, - shouldNoOpinion: []authorizer.Attributes{ - authorizer.AttributesRecord{User: &user.DefaultInfo{Name: "system:bar"}, Verb: "get", Resource: "namespaces", ResourceRequest: true}, - authorizer.AttributesRecord{Verb: "get", Resource: "namespaces", ResourceRequest: true}, - authorizer.AttributesRecord{Verb: "get", Resource: "services", ResourceRequest: true}, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - auth, err := NewStaticAuthorizer(tt.config) - if failed := err != nil; tt.shouldFail != failed { - t.Errorf("static authorizer creation expected to fail: %v, got %v, err: %v", tt.shouldFail, failed, err) - return - } - - for _, attr := range tt.shouldPass { - if decision, _, _ := auth.Authorize(context.Background(), attr); decision != authorizer.DecisionAllow { - t.Errorf("incorrectly restricted %v", attr) - } - } - - for _, attr := range tt.shouldNoOpinion { - if decision, _, _ := auth.Authorize(context.Background(), attr); decision != authorizer.DecisionNoOpinion { - t.Errorf("incorrectly opinionated %v", attr) - } - } - }) - } -} diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go deleted file mode 100644 index aaac103cc..000000000 --- a/pkg/proxy/proxy.go +++ /dev/null @@ -1,267 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package proxy - -import ( - "bytes" - "fmt" - "net/http" - "strings" - "text/template" - - "github.com/brancz/kube-rbac-proxy/pkg/authn" - "github.com/brancz/kube-rbac-proxy/pkg/authz" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/authorization/authorizer" - clientset "k8s.io/client-go/kubernetes" - "k8s.io/klog/v2" -) - -// Config holds proxy authorization and authentication settings -type Config struct { - Authentication *authn.AuthnConfig - Authorization *authz.Config -} - -type kubeRBACProxy struct { - // authenticator identifies the user for requests to kube-rbac-proxy - authenticator.Request - // authorizer determines whether a given authorization.Attributes is allowed - authorizer.Authorizer - // authorizerAttributesGetter implements retrieving authorization attributes for a respective request. - authorizerAttributesGetter *krpAuthorizerAttributesGetter - // config for kube-rbac-proxy - Config Config -} - -func new(authenticator authenticator.Request, authorizer authorizer.Authorizer, config Config) *kubeRBACProxy { - return &kubeRBACProxy{authenticator, authorizer, newKubeRBACProxyAuthorizerAttributesGetter(config.Authorization), config} -} - -// New creates an authenticator, an authorizer, and a matching authorizer attributes getter compatible with the kube-rbac-proxy -func New(client clientset.Interface, config Config, authorizer authorizer.Authorizer, authenticator authenticator.Request) (*kubeRBACProxy, error) { - return new(authenticator, authorizer, config), nil -} - -// Handle authenticates the client and authorizes the request. -// If the authn fails, a 401 error is returned. If the authz fails, a 403 error is returned -func (h *kubeRBACProxy) Handle(w http.ResponseWriter, req *http.Request) bool { - ctx := req.Context() - if len(h.Config.Authentication.Token.Audiences) > 0 { - ctx = authenticator.WithAudiences(ctx, h.Config.Authentication.Token.Audiences) - req = req.WithContext(ctx) - } - - // Authenticate - u, ok, err := h.AuthenticateRequest(req) - if err != nil { - klog.Errorf("Unable to authenticate the request due to an error: %v", err) - http.Error(w, "Unauthorized", http.StatusUnauthorized) - return false - } - if !ok { - http.Error(w, "Unauthorized", http.StatusUnauthorized) - return false - } - - // Get authorization attributes - allAttrs := h.authorizerAttributesGetter.GetRequestAttributes(u.User, req) - if len(allAttrs) == 0 { - msg := "Bad Request. The request or configuration is malformed." - klog.V(2).Info(msg) - http.Error(w, msg, http.StatusBadRequest) - return false - } - - for _, attrs := range allAttrs { - // Authorize - authorized, reason, err := h.Authorize(ctx, attrs) - if err != nil { - msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource()) - klog.Errorf("%s: %s", msg, err) - http.Error(w, msg, http.StatusInternalServerError) - return false - } - if authorized != authorizer.DecisionAllow { - msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.User.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource()) - klog.V(2).Infof("%s. Reason: %q.", msg, reason) - http.Error(w, msg, http.StatusForbidden) - return false - } - } - - if h.Config.Authentication.Header.Enabled { - // Seemingly well-known headers to tell the upstream about user's identity - // so that the upstream can achieve the original goal of delegating RBAC authn/authz to kube-rbac-proxy - headerCfg := h.Config.Authentication.Header - req.Header.Set(headerCfg.UserFieldName, u.User.GetName()) - req.Header.Set(headerCfg.GroupsFieldName, strings.Join(u.User.GetGroups(), headerCfg.GroupSeparator)) - } - - return true -} - -func newKubeRBACProxyAuthorizerAttributesGetter(authzConfig *authz.Config) *krpAuthorizerAttributesGetter { - return &krpAuthorizerAttributesGetter{authzConfig} -} - -type krpAuthorizerAttributesGetter struct { - authzConfig *authz.Config -} - -// GetRequestAttributes populates authorizer attributes for the requests to kube-rbac-proxy. -func (n krpAuthorizerAttributesGetter) GetRequestAttributes(u user.Info, r *http.Request) []authorizer.Attributes { - apiVerb := "" - switch r.Method { - case "POST": - apiVerb = "create" - case "GET": - apiVerb = "get" - case "PUT": - apiVerb = "update" - case "PATCH": - apiVerb = "patch" - case "DELETE": - apiVerb = "delete" - } - - var allAttrs []authorizer.Attributes - - defer func() { - for attrs := range allAttrs { - klog.V(5).Infof("kube-rbac-proxy request attributes: attrs=%#+v", attrs) - } - }() - - if n.authzConfig.ResourceAttributes == nil { - // Default attributes mirror the API attributes that would allow this access to kube-rbac-proxy - allAttrs := append(allAttrs, authorizer.AttributesRecord{ - User: u, - Verb: apiVerb, - Namespace: "", - APIGroup: "", - APIVersion: "", - Resource: "", - Subresource: "", - Name: "", - ResourceRequest: false, - Path: r.URL.Path, - }) - return allAttrs - } - - if n.authzConfig.Rewrites == nil { - allAttrs := append(allAttrs, authorizer.AttributesRecord{ - User: u, - Verb: apiVerb, - Namespace: n.authzConfig.ResourceAttributes.Namespace, - APIGroup: n.authzConfig.ResourceAttributes.APIGroup, - APIVersion: n.authzConfig.ResourceAttributes.APIVersion, - Resource: n.authzConfig.ResourceAttributes.Resource, - Subresource: n.authzConfig.ResourceAttributes.Subresource, - Name: n.authzConfig.ResourceAttributes.Name, - ResourceRequest: true, - }) - return allAttrs - } - - params := []string{} - if n.authzConfig.Rewrites.ByQueryParameter != nil && n.authzConfig.Rewrites.ByQueryParameter.Name != "" { - if ps, ok := r.URL.Query()[n.authzConfig.Rewrites.ByQueryParameter.Name]; ok { - params = append(params, ps...) - } - } - if n.authzConfig.Rewrites.ByHTTPHeader != nil && n.authzConfig.Rewrites.ByHTTPHeader.Name != "" { - if p := r.Header.Get(n.authzConfig.Rewrites.ByHTTPHeader.Name); p != "" { - params = append(params, p) - } - } - - if len(params) == 0 { - return allAttrs - } - - for _, param := range params { - attrs := authorizer.AttributesRecord{ - User: u, - Verb: apiVerb, - Namespace: templateWithValue(n.authzConfig.ResourceAttributes.Namespace, param), - APIGroup: templateWithValue(n.authzConfig.ResourceAttributes.APIGroup, param), - APIVersion: templateWithValue(n.authzConfig.ResourceAttributes.APIVersion, param), - Resource: templateWithValue(n.authzConfig.ResourceAttributes.Resource, param), - Subresource: templateWithValue(n.authzConfig.ResourceAttributes.Subresource, param), - Name: templateWithValue(n.authzConfig.ResourceAttributes.Name, param), - ResourceRequest: true, - } - allAttrs = append(allAttrs, attrs) - } - return allAttrs -} - -// DeepCopy of Proxy Configuration -func (c *Config) DeepCopy() *Config { - res := &Config{ - Authentication: &authn.AuthnConfig{}, - } - - if c.Authentication != nil { - res.Authentication = &authn.AuthnConfig{} - - if c.Authentication.X509 != nil { - res.Authentication.X509 = &authn.X509Config{ - ClientCAFile: c.Authentication.X509.ClientCAFile, - } - } - - if c.Authentication.Header != nil { - res.Authentication.Header = &authn.AuthnHeaderConfig{ - Enabled: c.Authentication.Header.Enabled, - UserFieldName: c.Authentication.Header.UserFieldName, - GroupsFieldName: c.Authentication.Header.GroupsFieldName, - GroupSeparator: c.Authentication.Header.GroupSeparator, - } - } - } - - if c.Authorization != nil { - if c.Authorization.ResourceAttributes != nil { - res.Authorization = &authz.Config{ - ResourceAttributes: &authz.ResourceAttributes{ - Namespace: c.Authorization.ResourceAttributes.Namespace, - APIGroup: c.Authorization.ResourceAttributes.APIGroup, - APIVersion: c.Authorization.ResourceAttributes.APIVersion, - Resource: c.Authorization.ResourceAttributes.Resource, - Subresource: c.Authorization.ResourceAttributes.Subresource, - Name: c.Authorization.ResourceAttributes.Name, - }, - } - } - } - - return res -} - -func templateWithValue(templateString, value string) string { - tmpl, _ := template.New("valueTemplate").Parse(templateString) - out := bytes.NewBuffer(nil) - err := tmpl.Execute(out, struct{ Value string }{Value: value}) - if err != nil { - return "" - } - return out.String() -} diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go deleted file mode 100644 index d5afc3622..000000000 --- a/pkg/proxy/proxy_test.go +++ /dev/null @@ -1,336 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package proxy - -import ( - "context" - "net/http" - "net/http/httptest" - "strings" - "testing" - - "github.com/brancz/kube-rbac-proxy/pkg/authn" - "github.com/brancz/kube-rbac-proxy/pkg/authz" - "github.com/google/go-cmp/cmp" - "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/apiserver/pkg/authentication/request/bearertoken" - "k8s.io/apiserver/pkg/authentication/user" - "k8s.io/apiserver/pkg/authorization/authorizer" - testclient "k8s.io/client-go/kubernetes/fake" -) - -func TestProxyWithOIDCSupport(t *testing.T) { - kc := testclient.NewSimpleClientset() - cfg := Config{ - Authentication: &authn.AuthnConfig{ - OIDC: &authn.OIDCConfig{}, - Header: &authn.AuthnHeaderConfig{ - Enabled: true, - UserFieldName: "user", - GroupsFieldName: "groups", - }, - Token: &authn.TokenConfig{}, - }, - Authorization: &authz.Config{}, - } - - fakeUser := user.DefaultInfo{Name: "Foo Bar", Groups: []string{"foo-bars"}} - authenticator := fakeOIDCAuthenticator(t, &fakeUser) - - scenario := setupTestScenario() - for _, v := range scenario { - - t.Run(v.description, func(t *testing.T) { - - w := httptest.NewRecorder() - proxy, err := New(kc, cfg, v.authorizer, authenticator) - - if err != nil { - t.Fatalf("Failed to instantiate test proxy. Details : %s", err.Error()) - } - proxy.Handle(w, v.req) - - resp := w.Result() - - if resp.StatusCode != v.status { - t.Errorf("Expected response: %d received : %d", v.status, resp.StatusCode) - } - - if v.verifyUser { - user := v.req.Header.Get(cfg.Authentication.Header.UserFieldName) - groups := v.req.Header.Get(cfg.Authentication.Header.GroupsFieldName) - if user != fakeUser.GetName() { - t.Errorf("User in the response header does not match authenticated user. Expected : %s, received : %s ", fakeUser.GetName(), user) - } - if groups != strings.Join(fakeUser.GetGroups(), cfg.Authentication.Header.GroupSeparator) { - t.Errorf("Groupsr in the response header does not match authenticated user groups. Expected : %s, received : %s ", fakeUser.GetName(), groups) - } - } - }) - } -} - -func TestGeneratingAuthorizerAttributes(t *testing.T) { - cases := []struct { - desc string - authzCfg *authz.Config - req *http.Request - expected []authorizer.Attributes - }{ - { - "without resource attributes and rewrites", - &authz.Config{}, - createRequest(nil, nil), - []authorizer.Attributes{ - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "", - APIGroup: "", - APIVersion: "", - Resource: "", - Subresource: "", - Name: "", - ResourceRequest: false, - Path: "/accounts", - }, - }, - }, - { - "without rewrites config", - &authz.Config{ResourceAttributes: &authz.ResourceAttributes{Namespace: "tenant1", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}}, - createRequest(nil, nil), - []authorizer.Attributes{ - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "tenant1", - APIGroup: "", - APIVersion: "v1", - Resource: "namespace", - Subresource: "metrics", - Name: "", - ResourceRequest: true, - }, - }, - }, - { - "with query param rewrites config", - &authz.Config{ - Rewrites: &authz.SubjectAccessReviewRewrites{ByQueryParameter: &authz.QueryParameterRewriteConfig{Name: "namespace"}}, - ResourceAttributes: &authz.ResourceAttributes{Namespace: "{{ .Value }}", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}, - }, - createRequest(map[string]string{"namespace": "tenant1"}, nil), - []authorizer.Attributes{ - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "tenant1", - APIGroup: "", - APIVersion: "v1", - Resource: "namespace", - Subresource: "metrics", - Name: "", - ResourceRequest: true, - }, - }, - }, - { - "with query param rewrites config but missing URL query", - &authz.Config{ - Rewrites: &authz.SubjectAccessReviewRewrites{ByQueryParameter: &authz.QueryParameterRewriteConfig{Name: "namespace"}}, - ResourceAttributes: &authz.ResourceAttributes{Namespace: "{{ .Value }}", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}, - }, - createRequest(nil, nil), - nil, - }, - { - "with http header rewrites config", - &authz.Config{ - Rewrites: &authz.SubjectAccessReviewRewrites{ByHTTPHeader: &authz.HTTPHeaderRewriteConfig{Name: "namespace"}}, - ResourceAttributes: &authz.ResourceAttributes{Namespace: "{{ .Value }}", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}, - }, - createRequest(nil, map[string]string{"namespace": "tenant1"}), - []authorizer.Attributes{ - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "tenant1", - APIGroup: "", - APIVersion: "v1", - Resource: "namespace", - Subresource: "metrics", - Name: "", - ResourceRequest: true, - }, - }, - }, - { - "with http header rewrites config but missing header", - &authz.Config{ - Rewrites: &authz.SubjectAccessReviewRewrites{ByQueryParameter: &authz.QueryParameterRewriteConfig{Name: "namespace"}}, - ResourceAttributes: &authz.ResourceAttributes{Namespace: "{{ .Value }}", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}, - }, - createRequest(nil, nil), - nil, - }, - { - "with http header and query param rewrites config", - &authz.Config{ - Rewrites: &authz.SubjectAccessReviewRewrites{ - ByHTTPHeader: &authz.HTTPHeaderRewriteConfig{Name: "namespace"}, - ByQueryParameter: &authz.QueryParameterRewriteConfig{Name: "namespace"}, - }, - ResourceAttributes: &authz.ResourceAttributes{Namespace: "{{ .Value }}", APIVersion: "v1", Resource: "namespace", Subresource: "metrics"}, - }, - createRequest(map[string]string{"namespace": "tenant1"}, map[string]string{"namespace": "tenant2"}), - []authorizer.Attributes{ - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "tenant1", - APIGroup: "", - APIVersion: "v1", - Resource: "namespace", - Subresource: "metrics", - Name: "", - ResourceRequest: true, - }, - authorizer.AttributesRecord{ - User: nil, - Verb: "get", - Namespace: "tenant2", - APIGroup: "", - APIVersion: "v1", - Resource: "namespace", - Subresource: "metrics", - Name: "", - ResourceRequest: true, - }, - }, - }, - } - - for _, c := range cases { - t.Run(c.desc, func(t *testing.T) { - t.Log(c.req.URL.Query()) - n := krpAuthorizerAttributesGetter{authzConfig: c.authzCfg} - res := n.GetRequestAttributes(nil, c.req) - if !cmp.Equal(res, c.expected) { - t.Errorf("Generated authorizer attributes are not correct. Expected %v, recieved %v", c.expected, res) - } - }) - } -} - -func createRequest(queryParams, headers map[string]string) *http.Request { - r := httptest.NewRequest("GET", "/accounts", nil) - if queryParams != nil { - q := r.URL.Query() - for k, v := range queryParams { - q.Add(k, v) - } - r.URL.RawQuery = q.Encode() - } - for k, v := range headers { - r.Header.Set(k, v) - } - return r -} - -func setupTestScenario() []testCase { - testScenario := []testCase{ - { - description: "Request with invalid Token should be authenticated and rejected with 401", - given: given{ - req: fakeJWTRequest("GET", "/accounts", "Bearer INVALID"), - authorizer: denier{}, - }, - expected: expected{ - status: http.StatusUnauthorized, - }, - }, - { - description: "Request with valid token should return 403 due to lack of permissions", - given: given{ - req: fakeJWTRequest("GET", "/accounts", "Bearer VALID"), - authorizer: denier{}, - }, - expected: expected{ - status: http.StatusForbidden, - }, - }, - { - description: "Request with valid token, should return 200 due to lack of permissions", - given: given{ - req: fakeJWTRequest("GET", "/accounts", "Bearer VALID"), - authorizer: approver{}, - }, - expected: expected{ - status: http.StatusOK, - verifyUser: true, - }, - }, - } - return testScenario -} - -func fakeJWTRequest(method, path, token string) *http.Request { - req := httptest.NewRequest(method, path, nil) - req.Header.Add("Authorization", token) - - return req -} - -func fakeOIDCAuthenticator(t *testing.T, fakeUser *user.DefaultInfo) authenticator.Request { - - auth := bearertoken.New(authenticator.TokenFunc(func(ctx context.Context, token string) (*authenticator.Response, bool, error) { - if token != "VALID" { - return nil, false, nil - } - return &authenticator.Response{User: fakeUser}, true, nil - })) - return auth -} - -type denier struct{} - -func (d denier) Authorize(ctx context.Context, auth authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { - return authorizer.DecisionDeny, "user not allowed", nil -} - -type approver struct{} - -func (a approver) Authorize(ctx context.Context, auth authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) { - return authorizer.DecisionAllow, "user allowed", nil -} - -type given struct { - req *http.Request - authorizer authorizer.Authorizer -} - -type expected struct { - status int - verifyUser bool -} - -type testCase struct { - given - expected - description string -} diff --git a/pkg/tls/reloader.go b/pkg/tls/reloader.go deleted file mode 100644 index 6702fdfd7..000000000 --- a/pkg/tls/reloader.go +++ /dev/null @@ -1,122 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tls - -import ( - "bytes" - "context" - "crypto/tls" - "fmt" - "io/ioutil" - "sync" - "time" - - "k8s.io/klog/v2" -) - -// CertReloader is the struct that parses a certificate/key pair, -// providing a goroutine safe GetCertificate method to retrieve the parsed content. -// -// The GetCertificate signature is compatible with https://golang.org/pkg/crypto/tls/#Config.GetCertificate -// and can be used to hot-reload a certificate/key pair. -// -// For hot-reloading the Watch method must be started explicitly. -type CertReloader struct { - certPath, keyPath string - interval time.Duration - - mu sync.RWMutex // protects the fields below - cert *tls.Certificate - certRaw, keyRaw []byte -} - -func NewCertReloader(certPath, keyPath string, interval time.Duration) (*CertReloader, error) { - r := &CertReloader{ - certPath: certPath, - keyPath: keyPath, - interval: interval, - } - - if err := r.reload(); err != nil { - return nil, fmt.Errorf("error loading certificates: %v", err) - } - - return r, nil -} - -// Watch watches the configured certificate and key path and blocks the current goroutine -// until the scenario context is done or an error occurred during reloading. -func (r *CertReloader) Watch(ctx context.Context) error { - t := time.NewTicker(r.interval) - - for { - select { - case <-t.C: - case <-ctx.Done(): - return nil - } - - if err := r.reload(); err != nil { - return fmt.Errorf("reloading failed: %v", err) - } - } -} - -func (r *CertReloader) reload() error { - certRaw, err := ioutil.ReadFile(r.certPath) - if err != nil { - return fmt.Errorf("error loading certificate: %v", err) - } - - keyRaw, err := ioutil.ReadFile(r.keyPath) - if err != nil { - return fmt.Errorf("error loading key: %v", err) - } - - r.mu.RLock() - equal := bytes.Equal(keyRaw, r.keyRaw) && bytes.Equal(certRaw, r.certRaw) - r.mu.RUnlock() - - if equal { - return nil - } - - klog.V(4).Info("reloading key ", r.keyPath, " certificate ", r.certPath) - - cert, err := tls.X509KeyPair(certRaw, keyRaw) - if err != nil { - return fmt.Errorf("error parsing certificate: %v", err) - } - - r.mu.Lock() - r.cert = &cert - r.certRaw = certRaw - r.keyRaw = keyRaw - r.mu.Unlock() - - return nil -} - -// GetCertificate returns the current valid certificate. -// The ClientHello message is ignored -// and is just there to be compatible with https://golang.org/pkg/crypto/tls/#Config.GetCertificate. -func (r *CertReloader) GetCertificate(_ *tls.ClientHelloInfo) (*tls.Certificate, error) { - r.mu.RLock() - defer r.mu.RUnlock() - - return r.cert, nil -} diff --git a/pkg/tls/reloader_test.go b/pkg/tls/reloader_test.go deleted file mode 100644 index 726d3827a..000000000 --- a/pkg/tls/reloader_test.go +++ /dev/null @@ -1,355 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package tls - -import ( - "context" - "crypto/x509" - "flag" - "fmt" - "io" - "io/ioutil" - "log" - "os" - "path" - "strings" - "testing" - "time" - - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/klog/v2" - - certutil "k8s.io/client-go/util/cert" -) - -func TestReloader(t *testing.T) { - cases := []struct { - name string - given stepFunc - check checkFunc - }{ - { - name: "match cn", - given: steps( - newSelfSignedCert("foo"), - newCertReloader, - ), - check: commonNameIs("foo"), - }, - { - name: "change", - given: steps( - newSelfSignedCert("foo"), - newCertReloader, - startWatching, - newSelfSignedCert("baz"), - swapCert, - ), - check: commonNameIs("baz"), - }, - { - name: "double symlink", - given: steps( - newSelfSignedCert("foo"), - doubleSymlinkCert, - newCertReloader, - startWatching, - newSelfSignedCert("bar"), - swapSymlink, - ), - check: commonNameIs("bar"), - }, - { - name: "swap double symlink twice", - given: steps( - newSelfSignedCert("foo"), - doubleSymlinkCert, - newCertReloader, - startWatching, - newSelfSignedCert("bar"), - swapSymlink, - newSelfSignedCert("baz"), - swapSymlink, - ), - check: commonNameIs("baz"), - }, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - s := &scenario{} - - tc.given(t, s) - - if err := tc.check(s); err != nil { - t.Error(err) - } - - for _, cleanup := range s.cleanups { - cleanup() - } - }) - } -} - -func TestMain(m *testing.M) { - // add klog flags - klog.InitFlags(flag.CommandLine) - - var err error - err = flag.Set("alsologtostderr", "true") - if err != nil { - log.Fatal(err) - } - - err = flag.Set("v", "5") - if err != nil { - log.Fatal(err) - } - - flag.Parse() - os.Exit(m.Run()) -} - -type scenario struct { - certPath, keyPath string - reloader *CertReloader - cleanups []func() -} - -type stepFunc func(*testing.T, *scenario) - -type checkFunc func(*scenario) error - -func commonNameIs(want string) checkFunc { - return func(g *scenario) error { - return poll(10*time.Millisecond, 100*time.Millisecond, func() (err error) { - cert, err := g.reloader.GetCertificate(nil) - if err != nil { - return fmt.Errorf("error getting certificate: %v", err) - } - - first, err := x509.ParseCertificate(cert.Certificate[0]) - if err != nil { - return fmt.Errorf("error parsing certificate: %v", err) - } - - if !strings.HasPrefix(first.Subject.CommonName, want) { - return fmt.Errorf("want subject common name to start with %q, got %q", want, first.Subject.CommonName) - } - - return nil - }) - } -} - -func newCertReloader(t *testing.T, s *scenario) { - r, err := NewCertReloader(s.certPath, s.keyPath, 10*time.Millisecond) - if err != nil { - t.Fatalf("error creating cert reloader: %v", err) - } - s.reloader = r -} - -func startWatching(t *testing.T, s *scenario) { - ctx, cancel := context.WithCancel(context.Background()) - done := make(chan error) - - go func() { - done <- s.reloader.Watch(ctx) - }() - - cleanup := func() { - cancel() - - if err := <-done; err != nil { - t.Fatal(err) - } - } - - s.cleanups = append([]func(){cleanup}, s.cleanups...) -} - -func newSelfSignedCert(hostname string) stepFunc { - return func(t *testing.T, s *scenario) { - var err error - certBytes, keyBytes, err := certutil.GenerateSelfSignedCertKey(hostname, nil, nil) - if err != nil { - t.Fatalf("generation of self signed cert and key failed: %v", err) - } - - certPath, err := writeTempFile("cert", certBytes) - if err != nil { - t.Fatalf("error writing cert data: %v", err) - } - keyPath, err := writeTempFile("key", keyBytes) - if err != nil { - t.Fatalf("error writing key data: %v", err) - } - - s.certPath = certPath - s.keyPath = keyPath - - s.cleanups = append(s.cleanups, func() { - _ = os.Remove(certPath) - _ = os.Remove(keyPath) - }) - } -} - -func doubleSymlinkCert(t *testing.T, s *scenario) { - name, err := ioutil.TempDir("", "keys") - if err != nil { - t.Fatal(err) - } - - keyPath := path.Join(name, "key") - if err := os.Rename(s.keyPath, keyPath); err != nil { - t.Fatal(err) - } - - certPath := path.Join(name, "cert") - if err := os.Rename(s.certPath, certPath); err != nil { - t.Fatal(err) - } - - keysdir := path.Join(os.TempDir(), "keys") - if err := os.Symlink(name, keysdir); err != nil { - t.Fatal(err) - } - - keyLink := path.Join(os.TempDir(), "key") - _ = os.Symlink(path.Join(keysdir, "key"), keyLink) - - certLink := path.Join(os.TempDir(), "cert") - _ = os.Symlink(path.Join(keysdir, "cert"), certLink) - - s.keyPath = keyLink - s.certPath = certLink - - s.cleanups = append(s.cleanups, func() { - _ = os.Remove(keyPath) - _ = os.Remove(certPath) - _ = os.Remove(keyLink) - _ = os.Remove(certLink) - _ = os.Remove(keysdir) - _ = os.RemoveAll(name) - }) -} - -func swapCert(t *testing.T, s *scenario) { - t.Log("renaming", s.keyPath, "to", s.reloader.keyPath) - if err := os.Rename(s.certPath, s.reloader.certPath); err != nil { - t.Fatal(err) - } - - if err := os.Rename(s.keyPath, s.reloader.keyPath); err != nil { - t.Fatal(err) - } - - s.certPath = s.reloader.certPath - s.keyPath = s.reloader.keyPath -} - -func swapSymlink(t *testing.T, s *scenario) { - name, err := ioutil.TempDir("", "keys") - if err != nil { - t.Fatal(err) - } - - keyPath := path.Join(name, "key") - if err := os.Rename(s.keyPath, keyPath); err != nil { - t.Fatal(err) - } - - certPath := path.Join(name, "cert") - if err := os.Rename(s.certPath, certPath); err != nil { - t.Fatal(err) - } - - tmp := path.Join(os.TempDir(), "keys.tmp") - if err := os.Symlink(name, tmp); err != nil { - t.Fatal(err) - } - - keysdir := path.Join(os.TempDir(), "keys") - if err := os.Rename(tmp, keysdir); err != nil { - t.Fatal(err) - } - - s.keyPath = path.Join(os.TempDir(), "key") - s.certPath = path.Join(os.TempDir(), "cert") - - s.cleanups = append(s.cleanups, func() { - _ = os.Remove(keyPath) - _ = os.Remove(certPath) - _ = os.Remove(keysdir) - _ = os.RemoveAll(name) - }) -} - -func steps(gs ...stepFunc) stepFunc { - return func(t *testing.T, g *scenario) { - for _, gf := range gs { - gf(t, g) - } - } -} - -func writeTempFile(pattern string, data []byte) (string, error) { - f, err := ioutil.TempFile("", pattern) - if err != nil { - return "", fmt.Errorf("error creating temp file: %v", err) - } - defer f.Close() - - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } - - if err != nil { - return "", fmt.Errorf("error writing temporary file: %v", err) - } - - return f.Name(), nil -} - -// poll calls the scenario function f every scenario interval -// until it returns no error or the scenario timeout occurs. -// If a timeout occurs, the last observed error is returned -// or wait.ErrWaitTimeout if no error occurred. -func poll(interval, timeout time.Duration, f func() error) error { - var lastErr error - - err := wait.Poll(interval, timeout, func() (bool, error) { - lastErr = f() - - if lastErr != nil { - klog.V(4).Infof("error loading certificate: %v, retrying ...", lastErr) - return false, nil - } - - return true, nil - }) - - if err != nil && err == wait.ErrWaitTimeout && lastErr != nil { - err = fmt.Errorf("%v: %v", err, lastErr) - } - - return err -} diff --git a/scripts/check_license.sh b/scripts/check_license.sh deleted file mode 100755 index 07b14db8e..000000000 --- a/scripts/check_license.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh - -licRes=$( -for file in $(find . -type f -iname '*.go' ! -path '*/vendor/*'); do - head -n3 "${file}" | grep -Eq "(Copyright|generated|GENERATED)" || echo -e " ${file}" -done;) -if [ -n "${licRes}" ]; then - echo -e "license header checking failed:\n${licRes}" - exit 255 -fi diff --git a/scripts/generate-examples.sh b/scripts/generate-examples.sh deleted file mode 100755 index b509ac5c8..000000000 --- a/scripts/generate-examples.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/non-resource-url-deployment.yaml > examples/non-resource-url/deployment.yaml -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 -sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/resource-attributes-deployment.yaml > examples/resource-attributes/deployment.yaml -sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/rewrites-deployment.yaml > examples/rewrites/deployment.yaml -sed -e "s/KUBE_RBAC_PROXY_VERSION/`cat VERSION`/g" scripts/templates/oidc-deployment.yaml > examples/oidc/deployment.yaml diff --git a/scripts/generate-help-txt.sh b/scripts/generate-help-txt.sh deleted file mode 100755 index 1c7200afd..000000000 --- a/scripts/generate-help-txt.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -echo "$ kube-rbac-proxy -h" > _output/help.txt -_output/kube-rbac-proxy -h 2>> _output/help.txt -exit 0 diff --git a/scripts/go.mod b/scripts/go.mod deleted file mode 100644 index 6895fb466..000000000 --- a/scripts/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/brancz/kube-rbac-proxy/tooling - -go 1.14 - -require github.com/campoy/embedmd v1.0.0 diff --git a/scripts/go.sum b/scripts/go.sum deleted file mode 100644 index 74a5597d6..000000000 --- a/scripts/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -github.com/campoy/embedmd v1.0.0 h1:V4kI2qTJJLf4J29RzI/MAt2c3Bl4dQSYPuflzwFH2hY= -github.com/campoy/embedmd v1.0.0/go.mod h1:oxyr9RCiSXg0M3VJ3ks0UGfp98BpSSGr0kpiX3MzVl8= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/scripts/kind-load-local.sh b/scripts/kind-load-local.sh deleted file mode 100755 index 9af1eacd9..000000000 --- a/scripts/kind-load-local.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -kind load docker-image quay.io/brancz/kube-rbac-proxy:local -kind load docker-image quay.io/brancz/prometheus-example-app:v0.1.0 -kind load docker-image quay.io/brancz/prometheus-example-app:v0.4.0 -kind load docker-image quay.io/brancz/krp-curl:v0.0.2 diff --git a/scripts/publish.sh b/scripts/publish.sh deleted file mode 100755 index 8808d0a60..000000000 --- a/scripts/publish.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash -# exit immediately when a command fails -set -e -# only exit with zero if all commands of the pipeline exit successfully -set -o pipefail -# error on unset variables -set -u -# for debugging -set -x - -# github actions, by default, fetches using `--no-tags`. -# we need tags though to create a release version string. -git fetch --tags - -QUAY_PATH="${QUAY_PATH:-quay.io/brancz/kube-rbac-proxy}" -CPU_ARCHS="amd64 arm64 arm ppc64le s390x" -TAG_COMMIT=$(git rev-list --abbrev-commit --tags --max-count=1) -COMMIT=$(git rev-parse --short HEAD) -TAG=$(git describe --abbrev=0 --tags ${TAG_COMMIT}) -VERSION="${TAG}" - -# if the current commit, does not correspond to a tag, create a verbose version string. -if [ "${TAG_COMMIT}" != "${COMMIT}" ]; then - VERSION=$(git rev-parse --abbrev-ref HEAD | tr / -)-$(date +%Y-%m-%d)-$(git rev-parse --short HEAD) -fi - -# build and push arch specific images -for arch in ${CPU_ARCHS}; do - VERSION="${VERSION}" DOCKER_REPO="${QUAY_PATH}" GOARCH="${arch}" make container - docker push "${QUAY_PATH}:${VERSION}-${arch}" -done - -# Create manifest to join all images under one virtual tag -MANIFEST="docker manifest create -a ${QUAY_PATH}:${VERSION}" -for arch in ${CPU_ARCHS}; do - MANIFEST="${MANIFEST} ${QUAY_PATH}:${VERSION}-${arch}" -done -eval "${MANIFEST}" - -# Annotate to set which image is build for which CPU architecture -for arch in ${CPU_ARCHS}; do - docker manifest annotate --arch "${arch}" "${QUAY_PATH}:${VERSION}" "${QUAY_PATH}:${VERSION}-${arch}" -done -docker manifest push "${QUAY_PATH}:${VERSION}" diff --git a/scripts/templates/non-resource-url-deployment.yaml b/scripts/templates/non-resource-url-deployment.yaml deleted file mode 100644 index 063f96971..000000000 --- a/scripts/templates/non-resource-url-deployment.yaml +++ /dev/null @@ -1,80 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/scripts/templates/non-resource-url-token-request-deployment.yaml b/scripts/templates/non-resource-url-token-request-deployment.yaml deleted file mode 100644 index ea65c2b15..000000000 --- a/scripts/templates/non-resource-url-token-request-deployment.yaml +++ /dev/null @@ -1,81 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--auth-token-audiences=kube-rbac-proxy.default.svc" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/scripts/templates/oidc-deployment.yaml b/scripts/templates/oidc-deployment.yaml deleted file mode 100644 index 9f9147da2..000000000 --- a/scripts/templates/oidc-deployment.yaml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8444 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - # {BEGIN} for minikube development only if OIDC provider is deployed in minikube itself ie. dex - hostNetwork: true - dnsPolicy: ClusterFirstWithHostNet - # {END} - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION - args: - - "--insecure-listen-address=0.0.0.0:8444" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - - "--oidc-issuer={ISSUER}" - - "--oidc-clientID={CLIENT_ID}" - ports: - - containerPort: 8444 - name: https - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/scripts/templates/resource-attributes-deployment.yaml b/scripts/templates/resource-attributes-deployment.yaml deleted file mode 100644 index ee4e22ffd..000000000 --- a/scripts/templates/resource-attributes-deployment.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - resourceAttributes: - namespace: default - apiVersion: v1 - resource: services - subresource: proxy - name: kube-rbac-proxy ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/scripts/templates/rewrites-deployment.yaml b/scripts/templates/rewrites-deployment.yaml deleted file mode 100644 index 988dc2a9e..000000000 --- a/scripts/templates/rewrites-deployment.yaml +++ /dev/null @@ -1,104 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - apiVersion: v1 - resource: namespace - subresource: metrics - namespace: "{{ .Value }}" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:KUBE_RBAC_PROXY_VERSION - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/scripts/tools.go b/scripts/tools.go deleted file mode 100644 index 132565426..000000000 --- a/scripts/tools.go +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2020 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -//+build tools - -package tools - -import ( - _ "github.com/campoy/embedmd" -) diff --git a/test/ca.pem b/test/ca.pem deleted file mode 100644 index dad127f54..000000000 --- a/test/ca.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC6jCCAdKgAwIBAgIBATANBgkqhkiG9w0BAQsFADAmMSQwIgYDVQQDDBtvcGVu -c2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUwHhcNMTgxMDI1MTQwNzM1WhcNMjMxMDI0 -MTQwNzM2WjAmMSQwIgYDVQQDDBtvcGVuc2hpZnQtc2lnbmVyQDE1NDA0NzY0NTUw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ1+8Z00Ovc93IpUjOsWs2 -ueNfcaDpDYW7P2y50jqy4XGdRRdHiLQKQv7S3Zqy/wTlnaDpk8TLMp6YSZ41p1Qy -5HhIbXMviR9Bqg1JziSx9HaFvo5w79gn7YbICpftKpsi1L2KBk2ekgnTnt+pw+Ml -L8N/ELtWtK8pu5cNZJIkJptxTWJzPyeUSVfDDPbEXP0VSDw2MOSoIxqcH1C4mR42 -Wr/6Crxtr2oyvAzLZvAtWCtUEY9fkmJVTGMjzfwRnrvxsfMguwSHKyyrRdDLoQMp -sFn8cRBu0omTIbyMQlHo+QVgdQ+P6LnV9Dbjn5fX7+5ithyu4iTrJFqjDsd47vBN -AgMBAAGjIzAhMA4GA1UdDwEB/wQEAwICpDAPBgNVHRMBAf8EBTADAQH/MA0GCSqG -SIb3DQEBCwUAA4IBAQBIzSylEYbVIl/KzelTWz0FZznczPMJnBlJAa4OGUHt8VuY -viUcItOdjrGhzwCzJn+IfbLtuv7d5YHYKEZZFNbUIPyvRByAM+iNKXXFSSnGBelz -J3onnrM4kMD8TwNZA4AJGpWy7Ntmtw/ie2BZ1AgBR9AhpxLC1Md7zxly59QGmahT -ym2aYUfblwQRm0AgRlccRgyVZdf3fCU5/BxLZkRT/hOKMQbAPPlxIGnpk/uJJcD4 -ZxKXypiQ2tzsKId8VybBYmgdG482bKrd6q/bsJGZx4B1++hHrvIPDaJYrmJG3UMP -x8z5unyK1BzrXFcyID1Dw998m4dhspjJeYPVNd2a ------END CERTIFICATE----- diff --git a/test/e2e/allowpaths/clusterRole-client.yaml b/test/e2e/allowpaths/clusterRole-client.yaml deleted file mode 100644 index 421a9d947..000000000 --- a/test/e2e/allowpaths/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: - - nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/allowpaths/clusterRole.yaml b/test/e2e/allowpaths/clusterRole.yaml deleted file mode 100644 index e9bc500b7..000000000 --- a/test/e2e/allowpaths/clusterRole.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy - namespace: default -rules: - - apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/allowpaths/clusterRoleBinding-client.yaml b/test/e2e/allowpaths/clusterRoleBinding-client.yaml deleted file mode 100644 index 4f93e2b8c..000000000 --- a/test/e2e/allowpaths/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: - - kind: ServiceAccount - name: default - namespace: default diff --git a/test/e2e/allowpaths/clusterRoleBinding.yaml b/test/e2e/allowpaths/clusterRoleBinding.yaml deleted file mode 100644 index f7be8fa4e..000000000 --- a/test/e2e/allowpaths/clusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: - - kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/allowpaths/deployment.yaml b/test/e2e/allowpaths/deployment.yaml deleted file mode 100644 index beae63daa..000000000 --- a/test/e2e/allowpaths/deployment.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--allow-paths=/metrics,/api/v1/label/*/values" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/test/e2e/allowpaths/service.yaml b/test/e2e/allowpaths/service.yaml deleted file mode 100644 index b1ae11686..000000000 --- a/test/e2e/allowpaths/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/allowpaths/serviceAccount.yaml b/test/e2e/allowpaths/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/allowpaths/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/basics.go b/test/e2e/basics.go deleted file mode 100644 index 4ef5dc001..000000000 --- a/test/e2e/basics.go +++ /dev/null @@ -1,528 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "fmt" - "testing" - - "github.com/brancz/kube-rbac-proxy/test/kubetest" - "k8s.io/client-go/kubernetes" -) - -func testBasics(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - 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` - - kubetest.Scenario{ - Name: "NoRBAC", - Description: ` - As a client without any RBAC rule access, - I fail with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "basics/clusterRole.yaml", - "basics/clusterRoleBinding.yaml", - "basics/deployment.yaml", - "basics/service.yaml", - "basics/serviceAccount.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientFails( - s.KubeClient, - command, - nil, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "WithRBAC", - Description: ` - As a client with the correct RBAC rules, - I succeed with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "basics/clusterRole.yaml", - "basics/clusterRoleBinding.yaml", - "basics/deployment.yaml", - "basics/service.yaml", - "basics/serviceAccount.yaml", - // This adds the clients cluster role to succeed - "basics/clusterRole-client.yaml", - "basics/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - command, - nil, - ), - ), - }.Run(t) - } -} - -func testTokenAudience(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - command := `curl --connect-timeout 5 -v -s -k --fail -H "Authorization: Bearer $(cat /var/run/secrets/tokens/requestedtoken)" https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics` - - kubetest.Scenario{ - Name: "IncorrectAudience", - Description: ` - As a client with the wrong token audience, - I fail with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "tokenrequest/clusterRole.yaml", - "tokenrequest/clusterRoleBinding.yaml", - "tokenrequest/deployment.yaml", - "tokenrequest/service.yaml", - "tokenrequest/serviceAccount.yaml", - "tokenrequest/clusterRole-client.yaml", - "tokenrequest/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientFails( - s.KubeClient, - command, - &kubetest.RunOptions{TokenAudience: "wrong-audience"}, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "CorrectAudience", - Description: ` - As a client with the correct token audience, - I succeed with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "tokenrequest/clusterRole.yaml", - "tokenrequest/clusterRoleBinding.yaml", - "tokenrequest/deployment.yaml", - "tokenrequest/service.yaml", - "tokenrequest/serviceAccount.yaml", - "tokenrequest/clusterRole-client.yaml", - "tokenrequest/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - command, - &kubetest.RunOptions{TokenAudience: "kube-rbac-proxy"}, - ), - ), - }.Run(t) - } -} - -func testClientCertificates(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - command := `curl --connect-timeout 5 -v -s -k --fail --cert /certs/tls.crt --key /certs/tls.key https://kube-rbac-proxy.default.svc.cluster.local:8443/metrics` - - kubetest.Scenario{ - Name: "NoRBAC", - Description: ` - As a client with client certificates authorization without RBAC, - I fail with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "clientcertificates/certificate.yaml", - "clientcertificates/clusterRole.yaml", - "clientcertificates/clusterRoleBinding.yaml", - "clientcertificates/deployment.yaml", - "clientcertificates/service.yaml", - "clientcertificates/serviceAccount.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientFails( - s.KubeClient, - command, - &kubetest.RunOptions{ClientCertificates: true}, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "WithRBAC", - Description: ` - As a client with client certificates authorization with RBAC, - I succeed with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "clientcertificates/certificate.yaml", - "clientcertificates/clusterRole.yaml", - "clientcertificates/clusterRoleBinding.yaml", - "clientcertificates/deployment.yaml", - "clientcertificates/service.yaml", - "clientcertificates/serviceAccount.yaml", - "clientcertificates/clusterRole-client.yaml", - "clientcertificates/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - command, - &kubetest.RunOptions{ClientCertificates: true}, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "WrongCA", - Description: ` - As a client with client certificates authorization with RBAC and with unmatched CA, - I fail with my request - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "clientcertificates/certificate.yaml", - "clientcertificates/clusterRole.yaml", - "clientcertificates/clusterRoleBinding.yaml", - "clientcertificates/deployment-wrongca.yaml", - "clientcertificates/service.yaml", - "clientcertificates/serviceAccount.yaml", - "clientcertificates/clusterRole-client.yaml", - "clientcertificates/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientFails( - s.KubeClient, - command, - &kubetest.RunOptions{ClientCertificates: true}, - ), - ), - }.Run(t) - } -} - -func testAllowPathsRegexp(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - command := `STATUS_CODE=$(curl --connect-timeout 5 -o /dev/null -v -s -k --write-out "%%{http_code}" -H "Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" https://kube-rbac-proxy.default.svc.cluster.local:8443%s); if [[ "$STATUS_CODE" != %d ]]; then echo "expecting %d status code, got $STATUS_CODE instead" > /proc/self/fd/2; exit 1; fi` - - kubetest.Scenario{ - Name: "WithPathhNotAllowed", - Description: ` - As a client with the correct RBAC rules, - I get a 404 response when requesting a path which isn't allowed by kube-rbac-proxy - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "allowpaths/clusterRole.yaml", - "allowpaths/clusterRoleBinding.yaml", - "allowpaths/deployment.yaml", - "allowpaths/service.yaml", - "allowpaths/serviceAccount.yaml", - "allowpaths/clusterRole-client.yaml", - "allowpaths/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/", 404, 404), - nil, - ), - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/api/v1/label/name", 404, 404), - nil, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "WithPathAllowed", - Description: ` - As a client with the correct RBAC rules, - I succeed with my request for a path that is allowed - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "allowpaths/clusterRole.yaml", - "allowpaths/clusterRoleBinding.yaml", - "allowpaths/deployment.yaml", - "allowpaths/service.yaml", - "allowpaths/serviceAccount.yaml", - "allowpaths/clusterRole-client.yaml", - "allowpaths/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/metrics", 200, 200), - nil, - ), - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/api/v1/label/job/values", 200, 200), - nil, - ), - ), - }.Run(t) - } -} - -func testIgnorePaths(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - commandWithoutAuth := `STATUS_CODE=$(curl --connect-timeout 5 -o /dev/null -v -s -k --write-out "%%{http_code}" https://kube-rbac-proxy.default.svc.cluster.local:8443%s); if [[ "$STATUS_CODE" != %d ]]; then echo "expecting %d status code, got $STATUS_CODE instead" > /proc/self/fd/2; exit 1; fi` - - kubetest.Scenario{ - Name: "WithIgnorePathMatch", - Description: ` - As a client without an auth token, - I get a 200 response when requesting a path included in ignorePaths - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "ignorepaths/clusterRole.yaml", - "ignorepaths/clusterRoleBinding.yaml", - "ignorepaths/deployment.yaml", - "ignorepaths/service.yaml", - "ignorepaths/serviceAccount.yaml", - "ignorepaths/clusterRole-client.yaml", - "ignorepaths/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(commandWithoutAuth, "/metrics", 200, 200), - nil, - ), - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(commandWithoutAuth, "/api/v1/labels", 200, 200), - nil, - ), - ), - }.Run(t) - - kubetest.Scenario{ - Name: "WithIgnorePathNoMatch", - Description: ` - As a client without an auth token, - I get a 401 response when requesting a path not included in ignorePaths - `, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "ignorepaths/clusterRole.yaml", - "ignorepaths/clusterRoleBinding.yaml", - "ignorepaths/deployment.yaml", - "ignorepaths/service.yaml", - "ignorepaths/serviceAccount.yaml", - "ignorepaths/clusterRole-client.yaml", - "ignorepaths/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(commandWithoutAuth, "/", 401, 401), - nil, - ), - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(commandWithoutAuth, "/api/v1/label/job/values", 401, 401), - nil, - ), - ), - }.Run(t) - } -} - -func ClientSucceeds(client kubernetes.Interface, command string, opts *kubetest.RunOptions) kubetest.Check { - return func(ctx *kubetest.ScenarioContext) error { - return kubetest.RunSucceeds( - client, - "quay.io/brancz/krp-curl:v0.0.2", - "kube-rbac-proxy-client", - []string{"/bin/sh", "-c", command}, - opts, - )(ctx) - } -} - -func ClientFails(client kubernetes.Interface, command string, opts *kubetest.RunOptions) kubetest.Check { - return func(ctx *kubetest.ScenarioContext) error { - return kubetest.RunFails( - client, - "quay.io/brancz/krp-curl:v0.0.2", - "kube-rbac-proxy-client", - []string{"/bin/sh", "-c", command}, - opts, - )(ctx) - } -} diff --git a/test/e2e/basics/clusterRole-client.yaml b/test/e2e/basics/clusterRole-client.yaml deleted file mode 100644 index 421a9d947..000000000 --- a/test/e2e/basics/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: - - nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/basics/clusterRole.yaml b/test/e2e/basics/clusterRole.yaml deleted file mode 100644 index e9bc500b7..000000000 --- a/test/e2e/basics/clusterRole.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy - namespace: default -rules: - - apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/basics/clusterRoleBinding-client.yaml b/test/e2e/basics/clusterRoleBinding-client.yaml deleted file mode 100644 index 4f93e2b8c..000000000 --- a/test/e2e/basics/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: - - kind: ServiceAccount - name: default - namespace: default diff --git a/test/e2e/basics/clusterRoleBinding.yaml b/test/e2e/basics/clusterRoleBinding.yaml deleted file mode 100644 index f7be8fa4e..000000000 --- a/test/e2e/basics/clusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: - - kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/basics/deployment.yaml b/test/e2e/basics/deployment.yaml deleted file mode 100644 index 086622c1c..000000000 --- a/test/e2e/basics/deployment.yaml +++ /dev/null @@ -1,31 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/test/e2e/basics/service.yaml b/test/e2e/basics/service.yaml deleted file mode 100644 index b1ae11686..000000000 --- a/test/e2e/basics/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/basics/serviceAccount.yaml b/test/e2e/basics/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/basics/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/clientcertificates/certificate.yaml b/test/e2e/clientcertificates/certificate.yaml deleted file mode 100644 index 14f5b4d63..000000000 --- a/test/e2e/clientcertificates/certificate.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - name: kube-rbac-proxy-client-certificates -type: kubernetes.io/tls -data: - tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURhakNDQWxLZ0F3SUJBZ0lVYzlWWlg2dDNqVHRwZWZycjQzcGQzVW8vNGFBd0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xERXFNQ2dHQTFVRUF4TWhhM1ZpWlMxeVltRmpMWEJ5YjNoNUxXTmxjblJwWm1sallYUmxjeTEwWlhOMApNQjRYRFRJeE1ETXhOakUzTWpVd01Gb1hEVE14TURNeE5ERTNNalV3TUZvd0xERXFNQ2dHQTFVRUF4TWhhM1ZpClpTMXlZbUZqTFhCeWIzaDVMV05sY25ScFptbGpZWFJsY3kxMFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUEvVjdzelZNdXl5ZFk1bHMwdkxyVWh0cE1kWmtVV2ZWQTIyQW5tbGhtNk5oeQowVjlMK1dKc3VZbTlicjl4VUJLV1JPaGVkNk5SaGYxRkczL1JBRWROM1l0MUM0eEw4TUxOTzUwbVYvTGdTL3lFCnlXaUlPdEhaRk9SM1NzcWVCVlJWd2N2ekhmdnFKQTl2Ujh4MVR4NVAyd1ZlRHpOWHVQSGJCSW1KREcwZXNSWjkKWTBZeGZCK3M2eTJaeUxRK3JXSDRheDRjVHlaWGVSSGZoZmhMdStkOTJScDIvSmx2aDRaUXJzcFIyQ0YxZE5CQgpxNnE3LzdreWd3TmVsTmZkeU9sbDlCT1hOVHBKQmdYa3FCQUE4RWllWkhuUGZ5TGJuYVdVSzFQS2REV2hwOTNWCnRiSU9IZklXamc0OTdSZ2RsazhGTlptTkxJbjI1dzB0VHVSWktOQzM2UUlEQVFBQm80R0RNSUdBTUE0R0ExVWQKRHdFQi93UUVBd0lGb0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREFqQU1CZ05WSFJNQkFmOEVBakFBTUIwRwpBMVVkRGdRV0JCUjdyTjFscFB2Qlk3YjdqUjMxbDF5aStaSDVRREFzQmdOVkhSRUVKVEFqZ2lGcmRXSmxMWEppCllXTXRjSEp2ZUhrdFkyVnlkR2xtYVdOaGRHVnpMWFJsYzNRd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFFZnQKUFkxc3RQSk1IeEE4UjVOQk01TTVwV0lDK3hENVZHc3RhV0M3a0RTWit5TjdMS1lSQjdVV0d5c2dCbkZsK2hqOApHWVBOQUgrbkNDOWJEODhSQi9aWkhBZ3dtREJPbG01OVUvSjUzL0pLQlhFS0l3cjg2WmI0SU9pYlVPbG94RDJBCnUwVTJteGRQb3ZBSjZ1akplN3k5YTh0QUFTV1BVck9xUElVWHNkbFR6RmJ2UktxN3hScTZXaWtKQndqRzhYd0oKd0NNc2Jja2pES2Q1T2tMWTk4WkJWWmlFcGoyaXFJdDNCSk95cnV0eEh1N05Pcm5UdEdCVmlSZlVrRlltcEVoTApDYkp3bnNCbitCTWFSd3FxNWRtZXJzV0RnREtYK1ZGYXZzUVZvN1VubGRFcmlvVzZlaTFxZnV1M1NsZDF5a3NPCkx2QW9ISDRxZXIwS2loTGMwZms9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K - tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBL1Y3c3pWTXV5eWRZNWxzMHZMclVodHBNZFprVVdmVkEyMkFubWxobTZOaHkwVjlMCitXSnN1WW05YnI5eFVCS1dST2hlZDZOUmhmMUZHMy9SQUVkTjNZdDFDNHhMOE1MTk81MG1WL0xnUy95RXlXaUkKT3RIWkZPUjNTc3FlQlZSVndjdnpIZnZxSkE5dlI4eDFUeDVQMndWZUR6Tlh1UEhiQkltSkRHMGVzUlo5WTBZeApmQitzNnkyWnlMUStyV0g0YXg0Y1R5WlhlUkhmaGZoTHUrZDkyUnAyL0psdmg0WlFyc3BSMkNGMWROQkJxNnE3Ci83a3lnd05lbE5mZHlPbGw5Qk9YTlRwSkJnWGtxQkFBOEVpZVpIblBmeUxibmFXVUsxUEtkRFdocDkzVnRiSU8KSGZJV2pnNDk3UmdkbGs4Rk5abU5MSW4yNXcwdFR1UlpLTkMzNlFJREFRQUJBb0lCQUNnMUNCOE5ORC9JM3JLdgpobzdzbHcxUFZ4TFNXQWh1Z3Z4TkpmdTRTNXhudk5DODdyR0VqUHhrZjBzejFpZCt5NW5qeGhuMk1ObXlkMlVGCnc0VG55OU44YmZhSExRWG40K214NW9QT1p3bW42T3FOVEJFSmZBbDB0L21HYmMwcXRQRXNERWlWMFhJbmdPRkQKOE5tOVZhN01DMEVlUksxMHMremtabnN5VmN5RUZFemRibzFHQnQ3Sjg2c3JkR3JGekV1Yk1wSHRvcHdLYkpCUApQVkE1eEo4dXJ5T0t0Rm9PZUM5M0NMaWozL1k3dE9iWTkzNGVVRFlmek5mbnNFajlSWjJlVkt5bnZSMjMvMDh4Cm1kZVdnVDIzMEFGai95U0JZT0c1bXRObHBVaVlySmZhRHpzbmViOUFuTElXVmU1WitlcnF2ZTB6MGkrb2lCK0EKWFIrVjVJRUNnWUVBL2xDQ3orbXc5Z25Rc1ZlZFRZMm5vSVkxSWNKcmttYnIwZ3dWNS9YVmg3QUpyZjJkUVpmcQpyUDIvWVNwNUY0Qkh3WXBzU0ZuZER4ZEMyQ24yUThzSWhZWm5MUC81eFd2UmlaVFpQcGdFamRYdksvUXBOdmorCk41MnZHUHBJLzN1TTRoTldtQytEUnhTOCtjOTUwbU5Jakt3R1AyTGQwc09BelJKb3RTS3lJMThDZ1lFQS93elEKR05jK0sxY2FTWmgrN1cwUWEvSWR6SXBjaDJTSkZ3N2NpbUpBdGI1QWUxcUNTV05VVEU3K2g0ZUoxRUVMeFdKSAo4ZVhwOXM2YmJqUUdhK1VnVWZ0Y2FGeTVsQUp5cUJlR0Yvb2d5NGVma1pmZm90dkhoamwrK0F4c2EzakZ5OWZCCnI3TE1DQVdxWUFNbjhVbDZEdDIrYU1TQ2FKVWJKb2wzeVF2ejhiY0NnWUFaMkF5ekhFaURlRlBnOGNwbWl6S3gKdVhIRTBJRW1DNWVEYlA3ODU1cWZnMkE0Y2tGODNQZFlSU0VodXJNN2xDbTJuVjZMcTdZdlJtbmdsY01VK0prUgpHS3Q3Z3pmYXZDNDdFUWxTdHhnZllkSkFZVHVlL29hM0dDc25HcWc0YmxITzE3QkJIdkwwVWtNeUQ4ZU5mZEZ0Cm1qMjRTMC9IajE2VGVIOXppT2NaZVFLQmdRQ1pMVmpOa25nRUQ0djZKMXdUdkN6Z3A4aTl6MXRDOVY1Z09zeTUKVDhrTlhmWGNINytmMDhnTkRHUlJnVldGNUlydFFObDBybUNWbWdBL2IzOXJ6WEJiekZyelVyMGg1MVoxSGF1cgpPczMzYnJ5bTlFK2J2K05VK2JNSHhtNVhIWEd0dXliWUhzbnJCM3dMcmRtUFVGRytHKzcvZlFYVlNiZkVyVXNECnMrb09nUUtCZ1FESDJrR2NsZkdqZWpPUThpZTFIeTViQUg4M2RpdzVzRWJHdUlabDRjRGc3VlpUY08zR3dPWG4KbGFyL1RVTVR0S0ROWHVWSU02ZWtKTVlZZ2V4V1VGaFRCTlN4VGc0cjUxR2w4a09UZ0tsMUFWemgzZHRYVzRhaAorWHp6QkJMOUsxZXpEajQzT2JaY3FVeEtraStSTzN5Y2RuaFFtMzZGVWVyVUlXRGNZVVV3SGc9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo= - ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURLRENDQWhDZ0F3SUJBZ0lVZkUvWU1TT2NzZkVIOGN2TWxvRFkvS1prUnA4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0xERXFNQ2dHQTFVRUF4TWhhM1ZpWlMxeVltRmpMWEJ5YjNoNUxXTmxjblJwWm1sallYUmxjeTEwWlhOMApNQjRYRFRJeE1ETXhOakUzTWpVd01Gb1hEVEkyTURNeE5URTNNalV3TUZvd0xERXFNQ2dHQTFVRUF4TWhhM1ZpClpTMXlZbUZqTFhCeWIzaDVMV05sY25ScFptbGpZWFJsY3kxMFpYTjBNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUYKQUFPQ0FROEFNSUlCQ2dLQ0FRRUFyeFJ4bGZOOFl5aG0rY0RheW0wNENLSmkzSlJ6d0FVQ1hPZkZidzd6VDBuZwo3SnNNQ0hONDVDZmFLSElTV0diL1AwWkRrSDBCUVpGcEczcmx2T2NDS2szbDFieHFCMGcwL0p4ekhvSWVTVW1wCndrRG1HSm5rcHQ5dVVaZFpKbGFCZkZNZ2RjUlNkaFZZdlZMYXRGdUNsTENlbmVvek9RcDkya3dPRStpUTBreWUKNTd6QXpWN0d0ZWd0UHVnQ2V3bmpvOFg5amg4bXlaRlZBbGFnRmVpUjJjNWZRbGJZLzMwS1VieTNkeTNodTRNWApmMlN6a3l0dFpSUkxhaHo4eWdieXptMExMOHBuZ1RPcFNNRGkrcDNnRFg3QmRUUnQ2QUgvUkp0aVVPdTJjS0hzCkdUZG51SEdScldLZFZJQ20zWUFhRVBXN3hwSG92Y3dzaGdrOTFpbXByUUlEQVFBQm8wSXdRREFPQmdOVkhROEIKQWY4RUJBTUNBUVl3RHdZRFZSMFRBUUgvQkFVd0F3RUIvekFkQmdOVkhRNEVGZ1FVQkRIcGEvNXlFSUh3VVF4aQoxS1loakJZQnQ0a3dEUVlKS29aSWh2Y05BUUVMQlFBRGdnRUJBQlZKQzIya2lrQXhlV0MycGVPQ2ZHQW96ZUtBCksvUTBpSDRWeXYzRnpCaExZMDRHcmEwYWpNbGZXU3hERVRXU2xYVHp5cnIwR1NMNEdJMWZlUHN5MTcwcVpBTnYKaTRCZGRWVHEvY0p6NittVythekNaeHFid2o3RDkvNDFUa3BhOW5xZ3ZBSVJwN3laQXcrSnY1T2ZuUXQ5VFkrcgphNDlqMEdVZ1VKUGlxZGc1M25NWUhmQWw0QThTN0U5VytrZWJpMXRBL1RYcVVhMGtGNjNMbUpWSGcybGVDUllRCjRmK1ZDd3g0TVZDOHhRdE9NZVp2T1YzQVNLRmxvV1Rab1drUFlwcURSaEdVaGdxMjhLMDdUZ2RYck0rYUhFdWUKK3hFN24rd3JJSUhxZTJZbkVwT010ajJpZThnUDJ6cmdTRVk5ZytVbjV0SzJlUFVBSGtmVm9mVE9ZZDA9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K diff --git a/test/e2e/clientcertificates/clusterRole-client.yaml b/test/e2e/clientcertificates/clusterRole-client.yaml deleted file mode 100644 index dd0d17d37..000000000 --- a/test/e2e/clientcertificates/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/clientcertificates/clusterRole.yaml b/test/e2e/clientcertificates/clusterRole.yaml deleted file mode 100644 index 30ba24d13..000000000 --- a/test/e2e/clientcertificates/clusterRole.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/clientcertificates/clusterRoleBinding-client.yaml b/test/e2e/clientcertificates/clusterRoleBinding-client.yaml deleted file mode 100644 index a81dddfcd..000000000 --- a/test/e2e/clientcertificates/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: User - name: kube-rbac-proxy-certificates-test diff --git a/test/e2e/clientcertificates/clusterRoleBinding.yaml b/test/e2e/clientcertificates/clusterRoleBinding.yaml deleted file mode 100644 index f2e8d8a0a..000000000 --- a/test/e2e/clientcertificates/clusterRoleBinding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/clientcertificates/deployment-wrongca.yaml b/test/e2e/clientcertificates/deployment-wrongca.yaml deleted file mode 100644 index 744a368d6..000000000 --- a/test/e2e/clientcertificates/deployment-wrongca.yaml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--client-ca-file=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - mountPath: /certs - name: certs - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: certs - secret: - secretName: kube-rbac-proxy-client-certificates diff --git a/test/e2e/clientcertificates/deployment.yaml b/test/e2e/clientcertificates/deployment.yaml deleted file mode 100644 index ed8c1808f..000000000 --- a/test/e2e/clientcertificates/deployment.yaml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--logtostderr=true" - - "--client-ca-file=/certs/ca.crt" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - mountPath: /certs - name: certs - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: certs - secret: - secretName: kube-rbac-proxy-client-certificates diff --git a/test/e2e/clientcertificates/service.yaml b/test/e2e/clientcertificates/service.yaml deleted file mode 100644 index 4e0f7d2e4..000000000 --- a/test/e2e/clientcertificates/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/clientcertificates/serviceAccount.yaml b/test/e2e/clientcertificates/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/clientcertificates/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/h2c-upstream/clusterRole-client.yaml b/test/e2e/h2c-upstream/clusterRole-client.yaml deleted file mode 100644 index 421a9d947..000000000 --- a/test/e2e/h2c-upstream/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: - - nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/h2c-upstream/clusterRole.yaml b/test/e2e/h2c-upstream/clusterRole.yaml deleted file mode 100644 index e9bc500b7..000000000 --- a/test/e2e/h2c-upstream/clusterRole.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy - namespace: default -rules: - - apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/h2c-upstream/clusterRoleBinding-client.yaml b/test/e2e/h2c-upstream/clusterRoleBinding-client.yaml deleted file mode 100644 index 4f93e2b8c..000000000 --- a/test/e2e/h2c-upstream/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: - - kind: ServiceAccount - name: default - namespace: default diff --git a/test/e2e/h2c-upstream/clusterRoleBinding.yaml b/test/e2e/h2c-upstream/clusterRoleBinding.yaml deleted file mode 100644 index f7be8fa4e..000000000 --- a/test/e2e/h2c-upstream/clusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: - - kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/h2c-upstream/deployment.yaml b/test/e2e/h2c-upstream/deployment.yaml deleted file mode 100644 index 5dcf88620..000000000 --- a/test/e2e/h2c-upstream/deployment.yaml +++ /dev/null @@ -1,33 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--upstream-force-h2c=true" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.4.0 - args: - - "--bind=127.0.0.1:8081" - - "--h2c=true" diff --git a/test/e2e/h2c-upstream/service.yaml b/test/e2e/h2c-upstream/service.yaml deleted file mode 100644 index b1ae11686..000000000 --- a/test/e2e/h2c-upstream/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/h2c-upstream/serviceAccount.yaml b/test/e2e/h2c-upstream/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/h2c-upstream/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/h2c_upstream.go b/test/e2e/h2c_upstream.go deleted file mode 100644 index 4397ba59e..000000000 --- a/test/e2e/h2c_upstream.go +++ /dev/null @@ -1,64 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "testing" - - "github.com/brancz/kube-rbac-proxy/test/kubetest" -) - -func testH2CUpstream(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - 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` - - kubetest.Scenario{ - Name: "With H2C Upstream", - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "h2c-upstream/clusterRole.yaml", - "h2c-upstream/clusterRoleBinding.yaml", - "h2c-upstream/deployment.yaml", - "h2c-upstream/service.yaml", - "h2c-upstream/serviceAccount.yaml", - "h2c-upstream/clusterRole-client.yaml", - "h2c-upstream/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - command, - nil, - ), - ), - }.Run(t) - } -} diff --git a/test/e2e/ignorepaths/clusterRole-client.yaml b/test/e2e/ignorepaths/clusterRole-client.yaml deleted file mode 100644 index 421a9d947..000000000 --- a/test/e2e/ignorepaths/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: - - nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/ignorepaths/clusterRole.yaml b/test/e2e/ignorepaths/clusterRole.yaml deleted file mode 100644 index e9bc500b7..000000000 --- a/test/e2e/ignorepaths/clusterRole.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy - namespace: default -rules: - - apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/ignorepaths/clusterRoleBinding-client.yaml b/test/e2e/ignorepaths/clusterRoleBinding-client.yaml deleted file mode 100644 index 4f93e2b8c..000000000 --- a/test/e2e/ignorepaths/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: - - kind: ServiceAccount - name: default - namespace: default diff --git a/test/e2e/ignorepaths/clusterRoleBinding.yaml b/test/e2e/ignorepaths/clusterRoleBinding.yaml deleted file mode 100644 index f7be8fa4e..000000000 --- a/test/e2e/ignorepaths/clusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: - - kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/ignorepaths/deployment.yaml b/test/e2e/ignorepaths/deployment.yaml deleted file mode 100644 index 8e1f545b3..000000000 --- a/test/e2e/ignorepaths/deployment.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--ignore-paths=/metrics,/api/v1/*" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/test/e2e/ignorepaths/service.yaml b/test/e2e/ignorepaths/service.yaml deleted file mode 100644 index b1ae11686..000000000 --- a/test/e2e/ignorepaths/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/ignorepaths/serviceAccount.yaml b/test/e2e/ignorepaths/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/ignorepaths/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/kind-config/kind-config.yaml b/test/e2e/kind-config/kind-config.yaml deleted file mode 100644 index 419147f0a..000000000 --- a/test/e2e/kind-config/kind-config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# this config file contains all config fields with comments -kind: Cluster -apiVersion: kind.x-k8s.io/v1alpha4 -# patch the generated kubeadm config with some extra settings -kubeadmConfigPatches: -- | - apiVersion: kubeadm.k8s.io/v1beta2 - kind: ClusterConfiguration - metadata: - name: config - apiServer: - extraArgs: - service-account-signing-key-file: /etc/kubernetes/pki/sa.key - service-account-issuer: kubernetes.default.svc - v: "10" diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go deleted file mode 100644 index 3b22e5c88..000000000 --- a/test/e2e/main_test.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "flag" - "log" - "os" - "testing" - - "github.com/brancz/kube-rbac-proxy/test/kubetest" -) - -// Sadly there's no way to pass Suite from TestMain to Test, -// so we need this global instance -var suite *kubetest.Suite - -// TestMain adds the kubeconfig flag to our tests -func TestMain(m *testing.M) { - kubeconfig := flag.String( - "kubeconfig", - "", - "path to kubeconfig", - ) - flag.Parse() - - var err error - suite, err = kubetest.NewSuiteFromKubeconfig(*kubeconfig) - if err != nil { - log.Fatal(err) - } - - os.Exit(m.Run()) -} - -func Test(t *testing.T) { - tests := map[string]kubetest.TestSuite{ - "Basics": testBasics(suite), - "H2CUpstream": testH2CUpstream(suite), - "ClientCertificates": testClientCertificates(suite), - "TokenAudience": testTokenAudience(suite), - "AllowPath": testAllowPathsRegexp(suite), - "IgnorePath": testIgnorePaths(suite), - "TLS": testTLS(suite), - "StaticAuthorizer": testStaticAuthorizer(suite), - } - - for name, tc := range tests { - t.Run(name, tc) - } -} diff --git a/test/e2e/static-auth/clusterRole.yaml b/test/e2e/static-auth/clusterRole.yaml deleted file mode 100644 index e9bc500b7..000000000 --- a/test/e2e/static-auth/clusterRole.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy - namespace: default -rules: - - apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] - - apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/static-auth/clusterRoleBinding.yaml b/test/e2e/static-auth/clusterRoleBinding.yaml deleted file mode 100644 index f7be8fa4e..000000000 --- a/test/e2e/static-auth/clusterRoleBinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy - namespace: default -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: - - kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/static-auth/configmap-non-resource.yaml b/test/e2e/static-auth/configmap-non-resource.yaml deleted file mode 100644 index 760d07896..000000000 --- a/test/e2e/static-auth/configmap-non-resource.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - static: - - user: - name: system:serviceaccount:default:default - resourceRequest: false - verbs: get - path: /metrics diff --git a/test/e2e/static-auth/configmap-resource.yaml b/test/e2e/static-auth/configmap-resource.yaml deleted file mode 100644 index 6261b5613..000000000 --- a/test/e2e/static-auth/configmap-resource.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-rbac-proxy -data: - config-file.yaml: |+ - authorization: - rewrites: - byQueryParameter: - name: "namespace" - resourceAttributes: - resource: namespaces - subresource: metrics - namespace: "{{ .Value }}" - static: - - user: - name: system:serviceaccount:default:default - resourceRequest: true - resource: namespaces - subresource: metrics - namespace: default - verbs: get diff --git a/test/e2e/static-auth/deployment.yaml b/test/e2e/static-auth/deployment.yaml deleted file mode 100644 index 21019bd60..000000000 --- a/test/e2e/static-auth/deployment.yaml +++ /dev/null @@ -1,43 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - securityContext: - runAsUser: 65532 - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--config-file=/etc/kube-rbac-proxy/config-file.yaml" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - volumeMounts: - - name: config - mountPath: /etc/kube-rbac-proxy - securityContext: - allowPrivilegeEscalation: false - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" - volumes: - - name: config - configMap: - name: kube-rbac-proxy diff --git a/test/e2e/static-auth/service.yaml b/test/e2e/static-auth/service.yaml deleted file mode 100644 index b1ae11686..000000000 --- a/test/e2e/static-auth/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/static-auth/serviceAccount.yaml b/test/e2e/static-auth/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/static-auth/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/static_authorizer.go b/test/e2e/static_authorizer.go deleted file mode 100644 index a80019f20..000000000 --- a/test/e2e/static_authorizer.go +++ /dev/null @@ -1,138 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "fmt" - "testing" - - "github.com/brancz/kube-rbac-proxy/test/kubetest" -) - -func testStaticAuthorizer(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - 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` - - for _, tc := range []struct { - name string - given []kubetest.Setup - check []kubetest.Check - }{ - { - name: "resource/namespace/metrics/query rewrite/granted", - given: []kubetest.Setup{ - kubetest.CreatedManifests( - s.KubeClient, - "static-auth/configmap-resource.yaml", - "static-auth/clusterRole.yaml", - "static-auth/clusterRoleBinding.yaml", - "static-auth/deployment.yaml", - "static-auth/service.yaml", - "static-auth/serviceAccount.yaml", - ), - }, - check: []kubetest.Check{ - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/metrics?namespace=default"), - nil, - ), - }, - }, - { - name: "resource/namespace/metrics/query rewrite/forbidden", - given: []kubetest.Setup{ - kubetest.CreatedManifests( - s.KubeClient, - "static-auth/configmap-resource.yaml", - "static-auth/clusterRole.yaml", - "static-auth/clusterRoleBinding.yaml", - "static-auth/deployment.yaml", - "static-auth/service.yaml", - "static-auth/serviceAccount.yaml", - ), - }, - check: []kubetest.Check{ - ClientFails( - s.KubeClient, - fmt.Sprintf(command, "/metrics?namespace=forbidden"), - nil, - ), - }, - }, - { - name: "non-resource/get/metrics/granted", - given: []kubetest.Setup{ - kubetest.CreatedManifests( - s.KubeClient, - "static-auth/configmap-non-resource.yaml", - "static-auth/clusterRole.yaml", - "static-auth/clusterRoleBinding.yaml", - "static-auth/deployment.yaml", - "static-auth/service.yaml", - "static-auth/serviceAccount.yaml", - ), - }, - check: []kubetest.Check{ - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, "/metrics"), - nil, - ), - }, - }, - { - name: "non-resource/get/metrics/forbidden", - given: []kubetest.Setup{ - kubetest.CreatedManifests( - s.KubeClient, - "static-auth/configmap-non-resource.yaml", - "static-auth/clusterRole.yaml", - "static-auth/clusterRoleBinding.yaml", - "static-auth/deployment.yaml", - "static-auth/service.yaml", - "static-auth/serviceAccount.yaml", - ), - }, - check: []kubetest.Check{ - ClientFails( - s.KubeClient, - fmt.Sprintf(command, "/forbidden"), - nil, - ), - }, - }, - } { - kubetest.Scenario{ - Name: tc.name, - Given: kubetest.Setups(tc.given...), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks(tc.check...), - }.Run(t) - } - } -} diff --git a/test/e2e/tls.go b/test/e2e/tls.go deleted file mode 100644 index dd69c5bc8..000000000 --- a/test/e2e/tls.go +++ /dev/null @@ -1,88 +0,0 @@ -/* -Copyright 2021 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package e2e - -import ( - "fmt" - "testing" - - "github.com/brancz/kube-rbac-proxy/test/kubetest" -) - -func testTLS(s *kubetest.Suite) kubetest.TestSuite { - return func(t *testing.T) { - 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` - - for _, tc := range []struct { - name string - tlsFlag string - }{ - { - name: "1.0", - tlsFlag: "--tlsv1.0", - }, - { - name: "1.1", - tlsFlag: "--tlsv1.1", - }, - { - name: "1.2", - tlsFlag: "--tlsv1.2", - }, - { - name: "1.3", - tlsFlag: "--tlsv1.3", - }, - } { - kubetest.Scenario{ - Name: tc.name, - - Given: kubetest.Setups( - kubetest.CreatedManifests( - s.KubeClient, - "basics/clusterRole.yaml", - "basics/clusterRoleBinding.yaml", - "basics/deployment.yaml", - "basics/service.yaml", - "basics/serviceAccount.yaml", - // This adds the clients cluster role to succeed - "basics/clusterRole-client.yaml", - "basics/clusterRoleBinding-client.yaml", - ), - ), - When: kubetest.Conditions( - kubetest.PodsAreReady( - s.KubeClient, - 1, - "app=kube-rbac-proxy", - ), - kubetest.ServiceIsReady( - s.KubeClient, - "kube-rbac-proxy", - ), - ), - Then: kubetest.Checks( - ClientSucceeds( - s.KubeClient, - fmt.Sprintf(command, tc.tlsFlag), - nil, - ), - ), - }.Run(t) - } - } -} diff --git a/test/e2e/tokenrequest/clusterRole-client.yaml b/test/e2e/tokenrequest/clusterRole-client.yaml deleted file mode 100644 index dd0d17d37..000000000 --- a/test/e2e/tokenrequest/clusterRole-client.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: metrics -rules: -- nonResourceURLs: ["/metrics"] - verbs: ["get"] diff --git a/test/e2e/tokenrequest/clusterRole.yaml b/test/e2e/tokenrequest/clusterRole.yaml deleted file mode 100644 index 30ba24d13..000000000 --- a/test/e2e/tokenrequest/clusterRole.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: kube-rbac-proxy -rules: -- apiGroups: ["authentication.k8s.io"] - resources: - - tokenreviews - verbs: ["create"] -- apiGroups: ["authorization.k8s.io"] - resources: - - subjectaccessreviews - verbs: ["create"] diff --git a/test/e2e/tokenrequest/clusterRoleBinding-client.yaml b/test/e2e/tokenrequest/clusterRoleBinding-client.yaml deleted file mode 100644 index d34563cfd..000000000 --- a/test/e2e/tokenrequest/clusterRoleBinding-client.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: metrics -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: metrics -subjects: -- kind: ServiceAccount - name: default - namespace: default diff --git a/test/e2e/tokenrequest/clusterRoleBinding.yaml b/test/e2e/tokenrequest/clusterRoleBinding.yaml deleted file mode 100644 index f2e8d8a0a..000000000 --- a/test/e2e/tokenrequest/clusterRoleBinding.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: kube-rbac-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-rbac-proxy -subjects: -- kind: ServiceAccount - name: kube-rbac-proxy - namespace: default diff --git a/test/e2e/tokenrequest/deployment.yaml b/test/e2e/tokenrequest/deployment.yaml deleted file mode 100644 index f30ecb0f6..000000000 --- a/test/e2e/tokenrequest/deployment.yaml +++ /dev/null @@ -1,32 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-rbac-proxy - namespace: default -spec: - replicas: 1 - selector: - matchLabels: - app: kube-rbac-proxy - template: - metadata: - labels: - app: kube-rbac-proxy - spec: - serviceAccountName: kube-rbac-proxy - containers: - - name: kube-rbac-proxy - image: quay.io/brancz/kube-rbac-proxy:local - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8081/" - - "--auth-token-audiences=kube-rbac-proxy" - - "--logtostderr=true" - - "--v=10" - ports: - - containerPort: 8443 - name: https - - name: prometheus-example-app - image: quay.io/brancz/prometheus-example-app:v0.1.0 - args: - - "--bind=127.0.0.1:8081" diff --git a/test/e2e/tokenrequest/service.yaml b/test/e2e/tokenrequest/service.yaml deleted file mode 100644 index 4e0f7d2e4..000000000 --- a/test/e2e/tokenrequest/service.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - app: kube-rbac-proxy - name: kube-rbac-proxy - namespace: default -spec: - ports: - - name: https - port: 8443 - targetPort: https - selector: - app: kube-rbac-proxy diff --git a/test/e2e/tokenrequest/serviceAccount.yaml b/test/e2e/tokenrequest/serviceAccount.yaml deleted file mode 100644 index 45feecc9c..000000000 --- a/test/e2e/tokenrequest/serviceAccount.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-rbac-proxy - namespace: default diff --git a/test/kubetest/kubernetes.go b/test/kubetest/kubernetes.go deleted file mode 100644 index af927e1fa..000000000 --- a/test/kubetest/kubernetes.go +++ /dev/null @@ -1,546 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package kubetest - -import ( - "bytes" - "context" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "time" - - "gopkg.in/yaml.v2" - appsv1 "k8s.io/api/apps/v1" - batchv1 "k8s.io/api/batch/v1" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - kubeyaml "k8s.io/apimachinery/pkg/util/yaml" - "k8s.io/client-go/kubernetes" -) - -func CreatedManifests(client kubernetes.Interface, paths ...string) Setup { - return func(ctx *ScenarioContext) error { - for _, path := range paths { - content, err := ioutil.ReadFile(path) - if err != nil { - return err - } - - if len(content) == 0 { - return fmt.Errorf("manifest has no content: %s", path) - } - - var meta metav1.TypeMeta - if err = yaml.Unmarshal(content, &meta); err != nil { - return err - } - - // TODO: This needs to be more generic! - - kind := strings.ToLower(meta.Kind) - switch kind { - case "clusterrole": - if err := createClusterRole(client, ctx, content); err != nil { - return err - } - case "clusterrolebinding": - if err := createClusterRoleBinding(client, ctx, content); err != nil { - return err - } - case "deployment": - if err := createDeployment(client, ctx, content); err != nil { - return err - } - case "service": - if err := createService(client, ctx, content); err != nil { - return err - } - case "serviceaccount": - if err := createServiceAccount(client, ctx, content); err != nil { - return err - } - case "secret": - if err := createSecret(client, ctx, content); err != nil { - return err - } - case "configmap": - if err := createConfigmap(client, ctx, content); err != nil { - return err - } - default: - return fmt.Errorf("unable to unmarshal manifest with unknown kind: %s", kind) - } - } - return nil - } -} - -func createClusterRole(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var cr *rbacv1.ClusterRole - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&cr); err != nil { - return err - } - - _, err := client.RbacV1().ClusterRoles().Create(context.TODO(), cr, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.RbacV1().ClusterRoles().Delete(context.TODO(), cr.Name, metav1.DeleteOptions{}) - }) - - return err -} - -func createClusterRoleBinding(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var crb *rbacv1.ClusterRoleBinding - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&crb); err != nil { - return err - } - - _, err := client.RbacV1().ClusterRoleBindings().Create(context.TODO(), crb, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.RbacV1().ClusterRoleBindings().Delete(context.TODO(), crb.Name, metav1.DeleteOptions{}) - }) - - return err -} - -func createDeployment(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var d appsv1.Deployment - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&d); err != nil { - return err - } - - d.Namespace = ctx.Namespace - - _, err := client.AppsV1().Deployments(d.Namespace).Create(context.TODO(), &d, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - dep, err := client.AppsV1().Deployments(d.Namespace).Get(context.TODO(), d.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - sel, err := metav1.LabelSelectorAsSelector(dep.Spec.Selector) - if err != nil { - return err - } - - dumpLogs(client, ctx, metav1.ListOptions{LabelSelector: sel.String()}) - - err = client.AppsV1().Deployments(dep.Namespace).Delete(context.TODO(), dep.Name, metav1.DeleteOptions{}) - if err != nil { - return err - } - - return PodsAreGone(client, sel.String())(ctx) - }) - - return err -} - -func dumpLogs(client kubernetes.Interface, ctx *ScenarioContext, opts metav1.ListOptions) { - pods, err := client.CoreV1().Pods(ctx.Namespace).List(context.TODO(), opts) - if err != nil { - return - } - - for _, p := range pods.Items { - for _, c := range p.Spec.Containers { - fmt.Println("=== LOGS", ctx.Namespace, p.Name, c.Name) - - rest := client.CoreV1().Pods(ctx.Namespace).GetLogs(p.GetName(), &corev1.PodLogOptions{ - Container: c.Name, - Follow: false, - }) - - stream, err := rest.Stream(context.TODO()) - if err != nil { - return - } - - io.Copy(os.Stdout, stream) - } - } -} - -func createService(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var s *corev1.Service - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&s); err != nil { - return err - } - - s.Namespace = ctx.Namespace - - _, err := client.CoreV1().Services(s.Namespace).Create(context.TODO(), s, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.CoreV1().Services(s.Namespace).Delete(context.TODO(), s.Name, metav1.DeleteOptions{}) - }) - - return err -} - -func createServiceAccount(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var sa *corev1.ServiceAccount - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&sa); err != nil { - return err - } - - sa.Namespace = ctx.Namespace - - _, err := client.CoreV1().ServiceAccounts(sa.Namespace).Create(context.TODO(), sa, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.CoreV1().ServiceAccounts(sa.Namespace).Delete(context.TODO(), sa.Name, metav1.DeleteOptions{}) - }) - - return err -} - -func createSecret(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var secret *corev1.Secret - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&secret); err != nil { - return err - } - - secret.Namespace = ctx.Namespace - - _, err := client.CoreV1().Secrets(secret.Namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.CoreV1().Secrets(secret.Namespace).Delete(context.TODO(), secret.Name, metav1.DeleteOptions{}) - }) - - return err -} - -func createConfigmap(client kubernetes.Interface, ctx *ScenarioContext, content []byte) error { - r := bytes.NewReader(content) - - var configmap *corev1.ConfigMap - if err := kubeyaml.NewYAMLOrJSONDecoder(r, r.Len()).Decode(&configmap); err != nil { - return err - } - - configmap.Namespace = ctx.Namespace - - _, err := client.CoreV1().ConfigMaps(configmap.Namespace).Create(context.TODO(), configmap, metav1.CreateOptions{}) - - ctx.AddFinalizer(func() error { - return client.CoreV1().ConfigMaps(configmap.Namespace).Delete(context.TODO(), configmap.Name, metav1.DeleteOptions{}) - }) - - return err -} - -// PodsAreReady waits for a number if replicas matching the given labels to be ready. -// Returns a func directly (not Setup or Conditions) as it can be used in Given and When steps -func PodsAreReady(client kubernetes.Interface, replicas int, labels string) func(*ScenarioContext) error { - return func(ctx *ScenarioContext) error { - return wait.Poll(time.Second, time.Minute, func() (bool, error) { - list, err := client.CoreV1().Pods(ctx.Namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: labels, - }) - if err != nil { - return false, fmt.Errorf("failed to list pods: %v", err) - } - - runningAndReady := 0 - for _, p := range list.Items { - isRunningAndReady, err := podRunningAndReady(p) - if err != nil { - return false, err - } - - if isRunningAndReady { - runningAndReady++ - } - } - - if runningAndReady == replicas { - return true, nil - } - return false, nil - }) - } -} - -// PodsAreGone waits for pods being gone for the given labels. -// Returns a func directly (not Setup or Conditions) as it can be used in Given and When steps -func PodsAreGone(client kubernetes.Interface, labels string) func(*ScenarioContext) error { - return func(ctx *ScenarioContext) error { - return wait.Poll(time.Second, time.Minute, func() (bool, error) { - list, err := client.CoreV1().Pods(ctx.Namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: labels, - }) - - if err != nil { - return false, fmt.Errorf("failed to list pods: %v", err) - } - - return len(list.Items) == 0, nil - }) - } -} - -// ServiceIsReady waits for given service to exist and have at least 1 endpoint. -// Returns a func directly (not Setup or Conditions) as it can be used in Given and When steps -func ServiceIsReady(client kubernetes.Interface, service string) func(*ScenarioContext) error { - return func(ctx *ScenarioContext) error { - return wait.Poll(time.Second, time.Minute, func() (bool, error) { - _, err := client.CoreV1().Services(ctx.Namespace).Get(context.TODO(), service, metav1.GetOptions{}) - if err != nil { - return false, fmt.Errorf("failed to get service: %v", err) - } - - endpoints, err := client.CoreV1().Endpoints(ctx.Namespace).Get(context.TODO(), service, metav1.GetOptions{}) - if err != nil { - return false, fmt.Errorf("failed to get endpoints: %v", err) - } - - amount := 0 - for _, s := range endpoints.Subsets { - amount = amount + len(s.Addresses) - } - if amount >= 1 { - return true, nil - } - - return false, nil - }) - } -} - -// podRunningAndReady returns whether a pod is running and each container has -// passed it's ready state. -func podRunningAndReady(pod corev1.Pod) (bool, error) { - switch pod.Status.Phase { - case corev1.PodFailed, corev1.PodSucceeded: - return false, fmt.Errorf("pod completed") - case corev1.PodRunning: - for _, cond := range pod.Status.Conditions { - if cond.Type != corev1.PodReady { - continue - } - return cond.Status == corev1.ConditionTrue, nil - } - return false, fmt.Errorf("pod ready condition not found") - } - return false, nil -} - -func Sleep(d time.Duration) Condition { - return func(ctx *ScenarioContext) error { - time.Sleep(d) - return nil - } -} - -type RunOptions struct { - ServiceAccount string - TokenAudience string - ClientCertificates bool -} - -func RunSucceeds(client kubernetes.Interface, image string, name string, command []string, opts *RunOptions) Check { - return func(ctx *ScenarioContext) error { - return run(client, ctx, image, name, command, opts) - } -} - -func RunFails(client kubernetes.Interface, image string, name string, command []string, opts *RunOptions) Check { - return func(ctx *ScenarioContext) error { - err := run(client, ctx, image, name, command, opts) - if err == nil { - return fmt.Errorf("expected run to fail") - } - if err != errRun { - return err - } - return nil - } -} - -var errRun = fmt.Errorf("failed to run") - -// run the command and return the Check with the container's logs -func run(client kubernetes.Interface, ctx *ScenarioContext, image string, name string, command []string, opts *RunOptions) error { - labels := map[string]string{ - "app": name, - } - pod := corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: labels, - }, - Spec: corev1.PodSpec{ - ServiceAccountName: "default", - Containers: []corev1.Container{{ - Name: name, - Image: image, - Command: command, - }}, - RestartPolicy: corev1.RestartPolicyNever, - }, - } - - if opts != nil && opts.ServiceAccount != "" { - pod.Spec.ServiceAccountName = opts.ServiceAccount - } - if opts != nil && opts.TokenAudience != "" { - pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{ - Name: "requestedtoken", - VolumeSource: corev1.VolumeSource{ - Projected: &corev1.ProjectedVolumeSource{ - Sources: []corev1.VolumeProjection{{ - ServiceAccountToken: &corev1.ServiceAccountTokenProjection{ - Audience: opts.TokenAudience, - Path: "requestedtoken", - }, - }}, - }, - }, - }) - pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, - corev1.VolumeMount{ - Name: "requestedtoken", - MountPath: "/var/run/secrets/tokens", - }, - ) - } - - if opts != nil && opts.ClientCertificates { - pod.Spec.Volumes = append(pod.Spec.Volumes, corev1.Volume{ - Name: "clientcertificates", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "kube-rbac-proxy-client-certificates", - }, - }, - }) - - pod.Spec.Containers[0].VolumeMounts = append(pod.Spec.Containers[0].VolumeMounts, - corev1.VolumeMount{ - Name: "clientcertificates", - MountPath: "/certs", - }, - ) - } - - parallelism := int32(1) - completions := int32(1) - activeDeadlineSeconds := int64(60) - backoffLimit := int32(10) - job := &batchv1.Job{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "kube-rbac-proxy-client-", - Namespace: ctx.Namespace, - }, - Spec: batchv1.JobSpec{ - Parallelism: ¶llelism, - Completions: &completions, - ActiveDeadlineSeconds: &activeDeadlineSeconds, - BackoffLimit: &backoffLimit, - Template: pod, - }, - } - - batch, err := client.BatchV1().Jobs(ctx.Namespace).Create(context.TODO(), job, metav1.CreateOptions{}) - if err != nil { - return fmt.Errorf("failed to create job: %v", err) - } - - ctx.AddFinalizer(func() error { - err := client.BatchV1().Jobs(ctx.Namespace).Delete(context.TODO(), batch.Name, metav1.DeleteOptions{}) - if err != nil { - return fmt.Errorf("failed to delete job: %v", err) - } - - return nil - }) - - watch, err := client.BatchV1().Jobs(ctx.Namespace).Watch(context.TODO(), metav1.SingleObject(batch.ObjectMeta)) - if err != nil { - return fmt.Errorf("failed to watch job: %v", err) - } - - for event := range watch.ResultChan() { - job := event.Object.(*batchv1.Job) - conditions := job.Status.Conditions - - failed := false - for _, c := range conditions { - if c.Type == batchv1.JobFailed { - failed = c.Status == corev1.ConditionTrue - } - } - - if failed { - dumpLogs(client, ctx, metav1.ListOptions{LabelSelector: "job-name=" + batch.Name}) - return errRun - } - - complete := false - for _, c := range conditions { - if c.Type == batchv1.JobComplete && c.Status == corev1.ConditionTrue { - complete = true - } - } - if complete && !failed { - dumpLogs(client, ctx, metav1.ListOptions{LabelSelector: "job-name=" + batch.Name}) - return nil - } - } - - return nil -} - -func CreateNamespace(client kubernetes.Interface, name string) error { - ns := &v1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - }, - } - - _, err := client.CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) - if err != nil { - return fmt.Errorf("failed to create namespace with name %v", name) - } - return nil -} - -func DeleteNamespace(client kubernetes.Interface, name string) error { - return client.CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{}) -} diff --git a/test/kubetest/kubetest.go b/test/kubetest/kubetest.go deleted file mode 100644 index 7d24c381f..000000000 --- a/test/kubetest/kubetest.go +++ /dev/null @@ -1,170 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package kubetest - -import ( - "testing" - "time" - - "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" -) - -type Suite struct { - KubeClient kubernetes.Interface -} - -func NewSuiteFromKubeconfig(path string) (*Suite, error) { - config, err := clientcmd.BuildConfigFromFlags("", path) - if err != nil { - return nil, err - } - - client, err := kubernetes.NewForConfig(config) - if err != nil { - return nil, err - } - - return &Suite{KubeClient: client}, nil -} - -type TestSuite func(t *testing.T) - -type Scenario struct { - KubeClient kubernetes.Interface - - Name string - Description string - - Given Setup - When Condition - Then Check -} - -type ScenarioContext struct { - Namespace string - Finalizer []Finalizer -} - -func (ctx *ScenarioContext) AddFinalizer(f Finalizer) { - ctx.Finalizer = append(ctx.Finalizer, f) -} - -type RunOpts func(ctx *ScenarioContext) *ScenarioContext - -func RandomNamespace(client kubernetes.Interface) RunOpts { - return func(ctx *ScenarioContext) *ScenarioContext { - ctx.Namespace = rand.String(8) - - ctx.AddFinalizer(func() error { - return DeleteNamespace(client, ctx.Namespace) - }) - - if err := CreateNamespace(client, ctx.Namespace); err != nil { - panic(err) - } - - return ctx - } -} - -func Timeout(d time.Duration) RunOpts { - return func(ctx *ScenarioContext) *ScenarioContext { - // TODO - return ctx - } -} - -func (s Scenario) Run(t *testing.T, opts ...RunOpts) bool { - ctx := &ScenarioContext{ - Namespace: "default", - } - - for _, o := range opts { - o(ctx) - } - - defer func(ctx *ScenarioContext) { - for _, f := range ctx.Finalizer { - if err := f(); err != nil { - panic(err) - } - } - }(ctx) - - return t.Run(s.Name, func(t *testing.T) { - if s.Given != nil { - if err := s.Given(ctx); err != nil { - t.Fatalf("failed to create given setup: %v", err) - } - } - - if s.When != nil { - if err := s.When(ctx); err != nil { - t.Errorf("failed to evaluate state: %v", err) - } - } - - if s.Given != nil { - if err := s.Then(ctx); err != nil { - t.Errorf("checks failed: %v", err) - } - } - }) -} - -type Setup func(ctx *ScenarioContext) error - -func Setups(ss ...Setup) Setup { - return func(ctx *ScenarioContext) error { - for _, s := range ss { - if err := s(ctx); err != nil { - return err - } - } - return nil - } -} - -type Condition func(ctx *ScenarioContext) error - -func Conditions(cs ...Condition) Condition { - return func(ctx *ScenarioContext) error { - for _, c := range cs { - if err := c(ctx); err != nil { - return err - } - } - return nil - } -} - -type Check func(ctx *ScenarioContext) error - -func Checks(cs ...Check) Check { - return func(ctx *ScenarioContext) error { - for _, c := range cs { - if err := c(ctx); err != nil { - return err - } - } - return nil - } -} - -type Finalizer func() error diff --git a/transport.go b/transport.go deleted file mode 100644 index 260912c76..000000000 --- a/transport.go +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "crypto/tls" - "crypto/x509" - "errors" - "fmt" - "io/ioutil" - "net" - "net/http" - "time" -) - -func initTransport(upstreamCAFile string) (http.RoundTripper, error) { - if upstreamCAFile == "" { - return http.DefaultTransport, nil - } - - rootPEM, err := ioutil.ReadFile(upstreamCAFile) - if err != nil { - return nil, fmt.Errorf("error reading upstream CA file: %v", err) - } - - roots := x509.NewCertPool() - if ok := roots.AppendCertsFromPEM([]byte(rootPEM)); !ok { - return nil, errors.New("error parsing upstream CA certificate") - } - - // http.Transport sourced from go 1.10.7 - transport := &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - TLSClientConfig: &tls.Config{RootCAs: roots}, - } - - return transport, nil -} diff --git a/transport_test.go b/transport_test.go deleted file mode 100644 index c45ccbe3d..000000000 --- a/transport_test.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2017 Frederic Branczyk All rights reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package main - -import ( - "net/http" - "testing" -) - -func TestInitTransportWithDefault(t *testing.T) { - roundTripper, err := initTransport("") - if err != nil { - t.Errorf("want err to be nil, but got %v", err) - return - } - if roundTripper == nil { - t.Error("expected roundtripper, got nil") - } -} - -func TestInitTransportWithCustomCA(t *testing.T) { - roundTripper, err := initTransport("test/ca.pem") - if err != nil { - t.Errorf("want err to be nil, but got %v", err) - return - } - transport := roundTripper.(*http.Transport) - if transport.TLSClientConfig.RootCAs == nil { - t.Error("expected root CA to be set, got nil") - } -}