diff --git a/.dockerignore b/.dockerignore old mode 100644 new mode 100755 index 8ffae399d..19d7f0420 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ * -!/bin/kube-oidc-proxy-linux +!/bin/kube-oidc-proxy diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 000000000..eb2458bb6 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,113 @@ +name: build +on: + push: + branches: + - 'master' + +permissions: + id-token: write + packages: write + +jobs: + docker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - + name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - uses: actions/checkout@v1 + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: "^1.20.0" + + - name: Install Cosign + uses: sigstore/cosign-installer@main + + - name: Update go deps + run: go mod tidy + + - name: install go mock + run: go install github.com/golang/mock/mockgen@v1.6.0 + + - name: install go-junit + run: go get -u github.com/jstemmer/go-junit-report + + - name: run tests + run: make test + + - name: build executable + run: make build; ls; ls bin + + + + + - + name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.OU_REG_USER }} + password: ${{ secrets.OU_REG_PASSWORD }} + + - name: Login to container Registry + uses: docker/login-action@v2 + with: + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + + - name: downcase REPO + run: | + echo "REPO=${GITHUB_REPOSITORY,,}" >>${GITHUB_ENV} + + - name: generate tag + run: |- + export PROJ_VERSION="1.0.7" + echo "Project Version: $PROJ_VERSION" + echo "TAG=$PROJ_VERSION-$(echo $GITHUB_SHA | cut -c 1-6)" >> $GITHUB_ENV + echo "SHORT_TAG=$PROJ_VERSION" >> $GITHUB_ENV + + + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v2 + with: + context: "." + push: true + tags: | + ${{ secrets.OU_CONTAINER_DEST }}:${{ env.TAG }} + ${{ secrets.OU_CONTAINER_DEST }}:${{ env.SHORT_TAG }} + ${{ secrets.OU_CONTAINER_DEST }} + ghcr.io/${{ env.REPO }}:${{ env.TAG }} + ghcr.io/${{ env.REPO }}:${{ env.SHORT_TAG }} + ghcr.io/${{ env.REPO }}:latest + + - name: sign images + run: |- + cosign sign -y ghcr.io/${{ env.REPO }}:${{ env.TAG }} + + - uses: anchore/sbom-action@v0 + with: + image: ghcr.io/${{ env.REPO }}:${{ env.TAG }} + format: spdx + output-file: /tmp/spdxg + + - name: attach sbom to images + run: |- + cosign attach sbom --sbom /tmp/spdxg ghcr.io/${{ env.REPO }}:${{ env.TAG }} + + + GH_SBOM_SHA=$(cosign verify --certificate-oidc-issuer-regexp='.*' --certificate-identity-regexp='.*' ghcr.io/${{ env.REPO }}:${{ env.TAG }} 2>/dev/null | jq -r '.[0].critical.image["docker-manifest-digest"]' | cut -c 8-) + + + echo "GH_SBOM_SHA: $GH_SBOM_SHA" + + + cosign sign -y ghcr.io/${{ env.REPO }}:sha256-$GH_SBOM_SHA.sbom + diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..2994639ef --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,59 @@ +# 1.0.7 + +**enhancements:** + - change oidc config to line up with new kube authenticator [\#55](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/55) + +**tasks:** + - 1.0.7 Release [\#54](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/54) + +# 1.0.6 + +**bugs:** + - e2e tests failing to complete [\#45](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/45) + - Auditing is not working anymore [\#39](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/39) + +**tasks:** + - 1.0.6 build [\#41](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/41) + +# 1.0.5 + +**tasks:** + - 1.0.5 build [\#34](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/34) + +# 1.0.4 + +**tasks:** + - 1.0.4 build [\#29](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/29) + +# 1.0.3 + +**enhancements:** + - 1.0.3 release [\#26](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/26) + +# 1.0.2 + +**bugs:** + - CVE-2022-1996 [\#20](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/20) + +# 1.0.1 + +**enhancements:** + - 1.0.1 [\#14](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/14) + +**bugs:** + - fix timing issues in e2e tests [\#18](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/18) + - runtime error: slice bounds out of range [:-2] [\#17](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/17) + +# 1.0.0 + +**enhancements:** + - 1.0.0 Release [\#10](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/10) + - Access logging to standard out [\#2](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/2) + - create github action to automate builds [\#8](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/8) + - Switch from alpine --> ubuntu 20.04 [\#9](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/9) + - Support `kubectl --as` [\#3](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/3) + - Upgrade KinD [\#1](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/1) + +**bugs:** + - update dependencies [\#5](https://github.com/TremoloSecurity/kube-oidc-proxy/issues/5) + diff --git a/Dockerfile b/Dockerfile index ad2f5e0ef..2e85f6142 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,9 @@ # Copyright Jetstack Ltd. See LICENSE for details. -FROM alpine:3.10 +FROM ubuntu:22.04 LABEL description="OIDC reverse proxy authenticator based on Kubernetes" -RUN apk --no-cache add ca-certificates \ - && apk --no-cache add --upgrade openssl +RUN apt-get update;apt-get -y install ca-certificates;apt-get -y upgrade;apt-get clean;rm -rf /var/lib/apt/lists/* -COPY ./bin/kube-oidc-proxy-linux /usr/bin/kube-oidc-proxy +COPY ./bin/kube-oidc-proxy /usr/bin/kube-oidc-proxy CMD ["/usr/bin/kube-oidc-proxy"] diff --git a/GenGitChangeLog.py b/GenGitChangeLog.py new file mode 100644 index 000000000..7340dc686 --- /dev/null +++ b/GenGitChangeLog.py @@ -0,0 +1,88 @@ +# Copyright Jetstack Ltd. See LICENSE for details. + +# Generates kube-oidc-proxy Changelog +# Call from the branch with 3 parameters: +# 1. Date from which to start looking +# 2. Github Token + +# requires python-dateutil and requests from pip + +from subprocess import * +import re +from datetime import datetime +import dateutil.parser +import sys +import requests + + + +def parseIssues(message): + issuesRet = [] + issues = re.findall('[#][0-9]+',message) + if issues != None: + for issue in issues: + issuesRet.append(issue[1:]) + return issuesRet + + +def f4(seq): + # order preserving + noDupes = [] + [noDupes.append(i) for i in seq if not noDupes.count(i)] + return noDupes + + + + + + +headers = {'Authorization':'token ' + sys.argv[2]} + + +GIT_COMMIT_FIELDS = ['id', 'author_name', 'author_email', 'date', 'message'] +GIT_LOG_FORMAT = ['%H', '%an', '%ae', '%ai', '%s'] +GIT_LOG_FORMAT = '%x1f'.join(GIT_LOG_FORMAT) + '%x1e' + +#print repo.git.log(p=False) + +allIssues = [] + +p = Popen('git log --format="%s" ' % GIT_LOG_FORMAT, shell=True, stdout=PIPE) +(logb, _) = p.communicate() +log = str(logb,"utf-8") +log = log.strip('\n\x1e').split("\x1e") +log = [row.strip().split("\x1f") for row in log] +log = [dict(zip(GIT_COMMIT_FIELDS, row)) for row in log] + +notbefore = dateutil.parser.parse(sys.argv[1] + ' 00:00:00 -0400') + +for commit in log: + created = dateutil.parser.parse(commit['date']) + if created > notbefore: + message = commit['message'] + allIssues.extend(parseIssues(message)) + + +allIssues = f4(allIssues) + +bylabels = {} + +for issue in allIssues: + issueURL = 'https://api.github.com/repos/TremoloSecurity/kube-oidc-proxy/issues/' + issue + r = requests.get(issueURL,headers=headers) + json = r.json(); + + if "labels" in json: + for label in json['labels']: + if not (label['name'] in bylabels): + labelGroup = [] + bylabels[label["name"]] = labelGroup + labelGroup = bylabels[label['name']] + labelGroup.append(json) + + +for label in bylabels: + print('**' + label + 's:**') + for issue in bylabels[label]: + print(' - ' + issue['title'] + ' [\\#' + str(issue['number']) + '](' + issue['html_url'] + ')') + print() diff --git a/Makefile b/Makefile index aec8d295f..93d4a7617 100644 --- a/Makefile +++ b/Makefile @@ -100,7 +100,7 @@ build: generate ## build kube-oidc-proxy CGO_ENABLED=0 go build -ldflags '-w $(shell hack/version-ldflags.sh)' -o ./bin/kube-oidc-proxy ./cmd/. docker_build: generate test build ## build docker image - GOARCH=$(ARCH) GOOS=linux CGO_ENABLED=0 go build -ldflags '-w $(shell hack/version-ldflags.sh)' -o ./bin/kube-oidc-proxy-linux ./cmd/. + GOARCH=$(ARCH) GOOS=linux CGO_ENABLED=0 go build -ldflags '-w $(shell hack/version-ldflags.sh)' -o ./bin/kube-oidc-proxy ./cmd/. docker build -t kube-oidc-proxy . all: test build ## runs tests, build diff --git a/README.md b/README.md index 9344d0db9..b274fbd94 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,5 @@ # kube-oidc-proxy -> :warning: -> -> kube-oidc-proxy is an experimental tool that we would like to get feedback -> on from the community. Jetstack makes no guarantees on the soundness of the -> security in this project, nor any suggestion that it's 'production ready'. -> This server sits in the critical path of authentication to the Kubernetes -> API. -> -> :warning: - `kube-oidc-proxy` is a reverse proxy server to authenticate users using OIDC to Kubernetes API servers where OIDC authentication is not available (i.e. managed Kubernetes providers such as GKE, EKS, etc). @@ -33,6 +23,10 @@ The following is a diagram of the request flow for a user request. ![kube-oidc-proxy request flow](https://storage.googleapis.com/kube-oidc-proxy/diagram-d9623e38a6cd3b585b45f47d80ca1e1c43c7e695.png) +## Quickest Start + +OpenUnison integrates kube-oidc-proxy directly, and includes an identity provider and access portal for Kubernetes. The quickest way to get started with kube-oidc-proxy is to follow the directions for OpenUnison's deployment at https://openunison.github.io/. + ## Tutorial Directions on how to deploy OIDC authentication with multi-cluster can be found @@ -131,8 +125,45 @@ users: - [Extra Impersonations Headers](./docs/tasks/extra-impersonation-headers.md) - [Auditing](./docs/tasks/auditing.md) +## Logging + +In addition to auditing, kube-oidc-proxy logs all requests to standard out so the requests can be captured by a common Security Information and Event Management (SIEM) system. SIEMs will typically import logs directly from containers via tools like fluentd. This logging is also useful in debugging. An example successful event: + +``` +[2021-11-25T01:05:17+0000] AuSuccess src:[10.42.0.5 / 10.42.1.3, 10.42.0.5] URI:/api/v1/namespaces/openunison/pods?limit=500 inbound:[mlbadmin1 / system:masters|system:authenticated /] +``` + +The first block, between `[]` is an ISO-8601 timestamp. The next text, `AuSuccess`, indicates that authentication was successful. the `src` block containers the remote address of the request, followed by the value of the `X-Forwarded-For` HTTP header if provided. The `URI` is the URL path of the request. The `inbound` section provides the user name, groups, and extra-info provided to the proxy from the JWT. + +When there's an error or failure: + +``` +[2021-11-25T01:05:24+0000] AuFail src:[10.42.0.5 / 10.42.1.3] URI:/api/v1/nodes +``` + +This is similar to success, but without the token information. + +## End-User Impersonation + +kube-oidc-proxy supports the impersonation headers for inbound requests. This allowes the proxy to support `kubectl --as`. When impersonation headers are included in a request, the proxy checks that the authenticated user is able to assume the identity of the impersonation headers by submitting `SubjectAccessReview` requests to the API server. Once authorized, the proxy will send those identity headers instead of headers generated for the authenticated user. In addition, three `Extra` impersonation headers are sent to the API server to identify the authenticated user who's making the request: + +| Header | Description | +| ------ | ----------- | +| `originaluser.jetstack.io-user` | The original username | +| `originaluser.jetstack.io-groups` | The original groups | +| `originaluser.jetstack.io-extra` | A JSON encoded map of arrays representing all of the `extra` headers included in the original identity | + +In addition to sending this `extra` information, the proxy adds an additional section to the logfile that will identify outbound identity data. When impersonation headers are present, the `AuSuccess` log will look like: + +``` +[2021-11-25T01:05:17+0000] AuSuccess src:[10.42.0.5 / 10.42.1.3] URI:/api/v1/namespaces/openunison/pods?limit=500 inbound:[mlbadmin1 / system:masters|system:authenticated /] outbound:[mlbadmin2 / group2|system:authenticated /] +``` + +When using `Impersonate-Extra-` headers, the proxy's `ServiceAccount` must be explicitly authorized via RBAC to impersonate whatever the extra key is named. This is because extras are treated as subresources which must be explicitly authorized. + + ## Development -*NOTE*: building kube-oidc-proxy requires Go version 1.12 or higher. +*NOTE*: building kube-oidc-proxy requires Go version 1.17 or higher. To help with development, there is a suite of tools you can use to deploy a functioning proxy from source locally. You can read more diff --git a/cmd/app/options/options.go b/cmd/app/options/options.go index 183247fb2..f39b363b6 100644 --- a/cmd/app/options/options.go +++ b/cmd/app/options/options.go @@ -6,8 +6,9 @@ import ( "fmt" "github.com/spf13/cobra" + "golang.org/x/term" k8sErrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/apiserver/pkg/util/term" + cliflag "k8s.io/component-base/cli/flag" ) @@ -45,7 +46,7 @@ func New() *Options { func (o *Options) AddFlags(cmd *cobra.Command) { // pretty output from kube-apiserver usageFmt := "Usage:\n %s\n" - cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) + cols, _, _ := term.GetSize(0) cmd.SetUsageFunc(func(cmd *cobra.Command) error { fmt.Fprintf(cmd.OutOrStderr(), usageFmt, cmd.UseLine()) cliflag.PrintSections(cmd.OutOrStderr(), *o.nfs, cols) @@ -91,10 +92,6 @@ func (o *Options) Validate(cmd *cobra.Command) error { errs = append(errs, errors.New("cannot add extra user headers when impersonation disabled")) } - if o.Audit.DynamicOptions.Enabled { - errs = append(errs, errors.New("The flag --audit-dynamic-configuration may not be set")) - } - if len(errs) > 0 { return k8sErrors.NewAggregate(errs) } diff --git a/cmd/app/run.go b/cmd/app/run.go index 9040869fb..3986d660a 100644 --- a/cmd/app/run.go +++ b/cmd/app/run.go @@ -6,11 +6,13 @@ import ( "github.com/spf13/cobra" "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "github.com/jetstack/kube-oidc-proxy/cmd/app/options" "github.com/jetstack/kube-oidc-proxy/pkg/probe" "github.com/jetstack/kube-oidc-proxy/pkg/proxy" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview" "github.com/jetstack/kube-oidc-proxy/pkg/util" ) @@ -83,9 +85,21 @@ func buildRunCommand(stopCh <-chan struct{}, opts *options.Options) *cobra.Comma ExtraUserHeadersClientIPEnabled: opts.App.ExtraHeaderOptions.EnableClientIPExtraUserHeader, } + // Setup Subject Access Review + kubeclient, err := kubernetes.NewForConfig(restConfig) + if err != nil { + return err + } + + subectAccessReviewer, err := subjectaccessreview.New(kubeclient.AuthorizationV1().SubjectAccessReviews()) + + if err != nil { + return err + } + // Initialise proxy with OIDC token authenticator p, err := proxy.New(restConfig, opts.OIDCAuthentication, opts.Audit, - tokenReviewer, secureServingInfo, proxyConfig) + tokenReviewer, subectAccessReviewer, secureServingInfo, proxyConfig) if err != nil { return err } @@ -103,12 +117,13 @@ func buildRunCommand(stopCh <-chan struct{}, opts *options.Options) *cobra.Comma } // Run proxy - waitCh, err := p.Run(stopCh) + waitCh, listenerStoppedCh, err := p.Run(stopCh) if err != nil { return err } <-waitCh + <-listenerStoppedCh if err := p.RunPreShutdownHooks(); err != nil { return err diff --git a/cmd/main.go b/cmd/main.go index ef2367823..1bcffd315 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -7,9 +7,11 @@ import ( "github.com/jetstack/kube-oidc-proxy/cmd/app" "github.com/jetstack/kube-oidc-proxy/pkg/util" + "k8s.io/klog/v2" ) func main() { + klog.InitFlags(nil) stopCh := util.SignalHandler() cmd := app.NewRunCommand(stopCh) diff --git a/deploy/charts/kube-oidc-proxy/Chart.yaml b/deploy/charts/kube-oidc-proxy/Chart.yaml index 91ec980f1..0ae35c890 100644 --- a/deploy/charts/kube-oidc-proxy/Chart.yaml +++ b/deploy/charts/kube-oidc-proxy/Chart.yaml @@ -1,9 +1,9 @@ apiVersion: v1 -appVersion: "v0.3.0" +appVersion: "v1.0.0" description: A Helm chart for kube-oidc-proxy home: https://github.com/jetstack/kube-oidc-proxy name: kube-oidc-proxy -version: 0.3.1 +version: 0.3.2 maintainers: - name: mhrabovcin - name: joshvanl diff --git a/deploy/charts/kube-oidc-proxy/templates/clusterrole.yaml b/deploy/charts/kube-oidc-proxy/templates/clusterrole.yaml index d5edc90c3..c54fa6139 100644 --- a/deploy/charts/kube-oidc-proxy/templates/clusterrole.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/clusterrole.yaml @@ -19,6 +19,10 @@ rules: - "userextras/scopes" - "userextras/remote-client-ip" - "tokenreviews" + # to support end user impersonation + - "userextras/originaluser.jetstack.io-user" + - "userextras/originaluser.jetstack.io-groups" + - "userextras/originaluser.jetstack.io-extra" verbs: - "create" - "impersonate" diff --git a/deploy/charts/kube-oidc-proxy/templates/deployment.yaml b/deploy/charts/kube-oidc-proxy/templates/deployment.yaml index d8d0c4e63..c6573f16a 100644 --- a/deploy/charts/kube-oidc-proxy/templates/deployment.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/deployment.yaml @@ -28,7 +28,7 @@ spec: image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - containerPort: 443 + - containerPort: 8443 - containerPort: 8080 readinessProbe: httpGet: @@ -38,7 +38,7 @@ spec: periodSeconds: 10 command: ["kube-oidc-proxy"] args: - - "--secure-port=443" + - "--secure-port=8443" - "--tls-cert-file=/etc/oidc/tls/crt.pem" - "--tls-private-key-file=/etc/oidc/tls/key.pem" - "--oidc-client-id=$(OIDC_CLIENT_ID)" diff --git a/deploy/charts/kube-oidc-proxy/templates/ingress.yaml b/deploy/charts/kube-oidc-proxy/templates/ingress.yaml index dbd3e3ed7..22b5dd952 100644 --- a/deploy/charts/kube-oidc-proxy/templates/ingress.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/ingress.yaml @@ -1,6 +1,6 @@ {{- if .Values.ingress.enabled -}} {{- $fullName := include "kube-oidc-proxy.fullname" . -}} -apiVersion: extensions/v1beta1 +apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: {{ $fullName }} @@ -20,6 +20,9 @@ spec: {{- end }} secretName: {{ .secretName }} {{- end }} +{{- end }} +{{- if .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName | quote }} {{- end }} rules: {{- range .Values.ingress.hosts }} @@ -28,9 +31,12 @@ spec: paths: {{- range .paths }} - path: {{ . }} + pathType: Prefix backend: - serviceName: {{ $fullName }} - servicePort: https + service: + name: {{ $fullName }} + port: + name: https {{- end }} {{- end }} {{- end }} diff --git a/deploy/charts/kube-oidc-proxy/templates/poddisruptionbudget.yaml b/deploy/charts/kube-oidc-proxy/templates/poddisruptionbudget.yaml index 823cf7098..731e37371 100644 --- a/deploy/charts/kube-oidc-proxy/templates/poddisruptionbudget.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/poddisruptionbudget.yaml @@ -1,5 +1,5 @@ {{- if .Values.podDisruptionBudget.enabled -}} -apiVersion: policy/v1beta1 +apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: {{ include "kube-oidc-proxy.fullname" . }} diff --git a/deploy/charts/kube-oidc-proxy/templates/secret_tls.yaml b/deploy/charts/kube-oidc-proxy/templates/secret_tls.yaml index ace354053..3d02c1360 100644 --- a/deploy/charts/kube-oidc-proxy/templates/secret_tls.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/secret_tls.yaml @@ -1,9 +1,44 @@ -{{- if (not .Values.tls.secretName) }} {{ $fullname := include "kube-oidc-proxy.fullname" . }} {{ $ca := genCA (printf "%s-ca" $fullname) 3650 }} {{ $cn := printf "%s.%s.svc.cluster.local" $fullname .Release.Namespace }} -{{ $server := genSignedCert $cn nil nil 365 $ca }} +{{ $in := printf "%s-issuer" $fullname }} +{{ if .Values.tls.certManager }} +{{ if .Values.tls.selfSigned }} +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ template "kube-oidc-proxy.fullname" . }}-issuer +spec: + selfSigned: {} +--- +{{ end }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ template "kube-oidc-proxy.fullname" . }}-tls +spec: + commonName: {{ template "kube-oidc-proxy.fullname" . }}-tls + dnsNames: + - {{ $cn }} + secretName: {{ template "kube-oidc-proxy.fullname" . }}-tls + issuerRef: + group: cert-manager.io + kind: Issuer + name: {{ .Values.tls.issuerName | default $in }} +{{ if .Values.tls.selfSigned }} + duration: 3650h0m0s + privateKey: + algorithm: RSA + encoding: PKCS8 + size: 2048 + renewBefore: 24h0m0s + usages: + - server auth +{{ end }} +{{ else }} +{{- if (not .Values.tls.secretName) }} +{{ $server := genSignedCert $cn nil nil 365 $ca }} apiVersion: v1 kind: Secret type: kubernetes.io/tls @@ -15,3 +50,4 @@ data: tls.crt: {{ b64enc $server.Cert }} tls.key: {{ b64enc $server.Key }} {{ end }} +{{ end }} \ No newline at end of file diff --git a/deploy/charts/kube-oidc-proxy/templates/service.yaml b/deploy/charts/kube-oidc-proxy/templates/service.yaml index e5feee6e1..6b5aefc84 100644 --- a/deploy/charts/kube-oidc-proxy/templates/service.yaml +++ b/deploy/charts/kube-oidc-proxy/templates/service.yaml @@ -19,7 +19,7 @@ spec: {{- end }} ports: - port: {{ .Values.service.port }} - targetPort: 443 + targetPort: 8443 protocol: TCP name: https selector: diff --git a/deploy/charts/kube-oidc-proxy/values.yaml b/deploy/charts/kube-oidc-proxy/values.yaml index 3997b4f31..b14fc4ed4 100644 --- a/deploy/charts/kube-oidc-proxy/values.yaml +++ b/deploy/charts/kube-oidc-proxy/values.yaml @@ -28,6 +28,12 @@ tls: # `secretName` must be a name of Secret of TLS type. If not provided a # self-signed certificate will get generated. secretName: + # `certManager` if you have cert-manager in your cluster and dont want to manage manually + certManager: false + # `selfSigned` if you have cert-manager and perfer or not to use use default issuer or generate by using other issuer + selfSigned: true + # `issuerName` if `selfSigned` is false, you should add your own Issuer + issuerName: # These values needs to be set in overrides in order to get kube-oidc-proxy # working. @@ -86,6 +92,8 @@ ingress: - host: chart-example.local paths: [] + # ingressClassName: '' + tls: [] # - secretName: chart-example-tls # hosts: diff --git a/deploy/yaml/kube-oidc-proxy.yaml b/deploy/yaml/kube-oidc-proxy.yaml index 67640e4c0..d286c3204 100644 --- a/deploy/yaml/kube-oidc-proxy.yaml +++ b/deploy/yaml/kube-oidc-proxy.yaml @@ -137,6 +137,10 @@ rules: - "userextras/scopes" - "userextras/remote-client-ip" - "tokenreviews" + # to support end user impersonation + - "userextras/originaluser.jetstack.io-user" + - "userextras/originaluser.jetstack.io-groups" + - "userextras/originaluser.jetstack.io-extra" verbs: - "create" - "impersonate" diff --git a/go.mod b/go.mod index c459eba2c..5ffe640e5 100644 --- a/go.mod +++ b/go.mod @@ -1,24 +1,147 @@ module github.com/jetstack/kube-oidc-proxy -go 1.13 +go 1.22.0 + +toolchain go1.23.0 require ( - github.com/golang/mock v1.2.0 - github.com/heptiolabs/healthcheck v0.0.0-20180807145615-6ff867650f40 - github.com/onsi/ginkgo v1.11.0 - github.com/onsi/gomega v1.7.0 - github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35 - github.com/sirupsen/logrus v1.4.2 - github.com/spf13/cobra v0.0.5 + github.com/golang/mock v1.6.0 + github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb + github.com/onsi/ginkgo v1.16.5 + github.com/onsi/gomega v1.34.2 + github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 + golang.org/x/term v0.24.0 + gopkg.in/square/go-jose.v2 v2.6.0 + k8s.io/api v0.31.1 + k8s.io/apimachinery v0.31.1 + k8s.io/apiserver v0.31.1 + k8s.io/cli-runtime v0.31.1 + k8s.io/client-go v0.31.1 + k8s.io/component-base v0.31.1 + k8s.io/klog/v2 v2.130.1 + sigs.k8s.io/kind v0.24.0 +) + +replace ( + github.com/emicklei/go-restful => github.com/emicklei/go-restful/v3 v3.8.0 + golang.org/x/crypto => golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa + + gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 +) + +require ( + github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/NYTimes/gziphandler v1.1.1 // indirect + github.com/alessio/shellescape v1.4.2 // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/coreos/go-oidc v2.2.1+incompatible // indirect + github.com/coreos/go-semver v0.3.1 // indirect + github.com/coreos/go-systemd/v22 v22.5.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/btree v1.0.1 // indirect + github.com/google/cel-go v0.20.1 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/imdario/mergo v0.3.6 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/moby/spdystream v0.4.0 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/nxadm/tail v1.4.8 // indirect + github.com/pelletier/go-toml v1.9.5 // indirect + github.com/peterbourgon/diskv v2.0.1+incompatible // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pquerna/cachecontrol v0.1.0 // indirect + github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + github.com/xlab/treeprint v1.2.0 // indirect + go.etcd.io/etcd/api/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect + go.etcd.io/etcd/client/v3 v3.5.14 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.25.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.24.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 // indirect - gopkg.in/square/go-jose.v2 v2.3.1 - k8s.io/api v0.18.0 - k8s.io/apimachinery v0.18.0 - k8s.io/apiserver v0.18.0 - k8s.io/cli-runtime v0.18.0 - k8s.io/client-go v0.18.0 - k8s.io/component-base v0.18.0 - k8s.io/klog v1.0.0 - sigs.k8s.io/kind v0.7.0 + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/kms v0.31.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.17.2 // indirect + sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 39840f8e2..0aa7ca2ae 100644 --- a/go.sum +++ b/go.sum @@ -1,495 +1,470 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= -github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0 h1:MRvx8gncNaXJqOoLmhNjUAKh33JJF8LyxPhomEtOsjs= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0 h1:q2gDruN08/guU9vAjuPWff0+QIrpH6ediguzdAzXAUU= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0 h1:YGrhWfrgtFs84+h0o46rJrlmsZtyZRg470CqAXTZaGM= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0 h1:Ww5g4zThfD/6cLb4z6xxgeyDa7QDkizMkJKe0ysZXp0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0 h1:TRn4WjSnkcSy5AEG3pnbtFSwNtwzjr4VYyQflFE619k= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0= -github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053 h1:H/GMMKYPkEIC3DF/JWQz8Pdd+Feifov2EIgGfNpeogI= -github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053/go.mod h1:xW8sBma2LE3QxFSzCnH9qe6gAE2yO9GvQaWwX89HxbE= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0= +github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7 h1:u9SHYsPQNyt5tgDm3YN7+9dYrpK96E5wFilTFWIDZOM= -github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea h1:n2Ltr3SrfQlf/9nOna1DoGKxLx3qTSI8Ttl6Xrqp6mw= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= +github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= +github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= +github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= -github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e h1:p1yVGRW3nmb85p1Sh1ZJSDm4A4iKLS5QNbvUHMgGu/M= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= -github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= -github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= -github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= +github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= +github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903 h1:LbsanbbD6LieFkXbj9YNNBupiGHJgFeLpO0j0Fza1h8= -github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0 h1:28o5sBqPkBsMGnC6b4MvE2TzSr5/AT4c/1fLqVGIwlk= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= +github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d h1:7XGaL1e6bYS1yIonGp9761ExpPPV1ui0SAC59Yube9k= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.1.0 h1:rVsPeBmXbYv4If/cumu1AzZPwV58q433hvONV1UEZoI= -github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= +github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= +github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI= -github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/heptiolabs/healthcheck v0.0.0-20180807145615-6ff867650f40 h1:GT4RsKmHh1uZyhmTkWJTDALRjSHYQp6FRKrotf0zhAs= -github.com/heptiolabs/healthcheck v0.0.0-20180807145615-6ff867650f40/go.mod h1:NtmN9h8vrTveVQRLHcX2HQ5wIPBDCsZ351TGbZWgg38= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb h1:tsEKRC3PU9rMw18w/uAptoijhgG4EvlA5kfJPtwrMDk= +github.com/heptiolabs/healthcheck v0.0.0-20211123025425-613501dd5deb/go.mod h1:NtmN9h8vrTveVQRLHcX2HQ5wIPBDCsZ351TGbZWgg38= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= -github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= -github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= +github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= -github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= -github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= -github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= -github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo= +github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= +github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.0 h1:J8lpUdobwIeCI7OiSxHqEwJUKvJwicL5+3v1oe2Yb4k= -github.com/pkg/errors v0.9.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.0.0 h1:vrDKnkGzuGvhNAL56c7DBz29ZL+KxnoR0x7enabFceM= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= +github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNGfs= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35 h1:eajwn6K3weW5cd1ZXLu2sJ4pvwlBiCWY4uDejOr73gM= -github.com/sebest/xff v0.0.0-20160910043805-6c115e0ffa35/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM= +github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0= +github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= +github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= -go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= -go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= +github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI= +go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE= +go.etcd.io/etcd/api/v3 v3.5.14 h1:vHObSCxyB9zlF60w7qzAdTcGaglbJOpSj1Xj9+WGxq0= +go.etcd.io/etcd/api/v3 v3.5.14/go.mod h1:BmtWcRlQvwa1h3G2jvKYwIQy4PkHlDej5t7uLMUdJUU= +go.etcd.io/etcd/client/pkg/v3 v3.5.14 h1:SaNH6Y+rVEdxfpA2Jr5wkEvN6Zykme5+YnbCkxvuWxQ= +go.etcd.io/etcd/client/pkg/v3 v3.5.14/go.mod h1:8uMgAokyG1czCtIdsq+AGyYQMvpIKnSvPjFMunkgeZI= +go.etcd.io/etcd/client/v2 v2.305.13 h1:RWfV1SX5jTU0lbCvpVQe3iPQeAHETWdOTb6pxhd77C8= +go.etcd.io/etcd/client/v2 v2.305.13/go.mod h1:iQnL7fepbiomdXMb3om1rHq96htNNGv2sJkEcZGDRRg= +go.etcd.io/etcd/client/v3 v3.5.14 h1:CWfRs4FDaDoSz81giL7zPpZH2Z35tbOrAJkkjMqOupg= +go.etcd.io/etcd/client/v3 v3.5.14/go.mod h1:k3XfdV/VIHy/97rqWjoUzrj9tk7GgJGH9J8L4dNXmAk= +go.etcd.io/etcd/pkg/v3 v3.5.13 h1:st9bDWNsKkBNpP4PR1MvM/9NqUPfvYZx/YXegsYEH8M= +go.etcd.io/etcd/pkg/v3 v3.5.13/go.mod h1:N+4PLrp7agI/Viy+dUYpX7iRtSPvKq+w8Y14d1vX+m0= +go.etcd.io/etcd/raft/v3 v3.5.13 h1:7r/NKAOups1YnKcfro2RvGGo2PTuizF/xh26Z2CTAzA= +go.etcd.io/etcd/raft/v3 v3.5.13/go.mod h1:uUFibGLn2Ksm2URMxN1fICGhk8Wu96EfDQyuLhAcAmw= +go.etcd.io/etcd/server/v3 v3.5.13 h1:V6KG+yMfMSqWt+lGnhFpP5z5dRUj1BDRJ5k1fQ9DFok= +go.etcd.io/etcd/server/v3 v3.5.13/go.mod h1:K/8nbsGupHqmr5MkgaZpLlH1QdX1pcNQLAkODy44XcQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= +go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= +golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU= +golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1 h1:gZpLHxUX5BdYLA08Lj4YCJNN/jk7KtquiArPoeX0WvA= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7 h1:ZUjXAXmrAyrmmCPHgCA/vChHcpsX27MZ3yBonD/z1KE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= -google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0 h1:FVCohIoYO7IJoDDVpV2pdq7SgrMH6wHnuTyrdrxJNoY= gopkg.in/DATA-DOG/go-sqlmock.v1 v1.3.0/go.mod h1:OdE7CF6DbADk7lN8LIKRzRJTTZXIjtWgA5THM5lhBAw= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM= -gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.18.0 h1:lwYk8Vt7rsVTwjRU6pzEsa9YNhThbmbocQlKvNBB4EQ= -k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8= -k8s.io/apimachinery v0.17.0 h1:xRBnuie9rXcPxUkDizUsGvPf1cnlZCFu210op7J7LJo= -k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.18.0 h1:fuPfYpk3cs1Okp/515pAf0dNhL66+8zk8RLbSX+EgAE= -k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= -k8s.io/apiserver v0.18.0 h1:ELAWpGWC6XdbRLi5lwAbEbvksD7hkXxPdxaJsdpist4= -k8s.io/apiserver v0.18.0/go.mod h1:3S2O6FeBBd6XTo0njUrLxiqk8GNy6wWOftjhJcXYnjw= -k8s.io/cli-runtime v0.18.0 h1:jG8XpSqQ5TrV0N+EZ3PFz6+gqlCk71dkggWCCq9Mq34= -k8s.io/cli-runtime v0.18.0/go.mod h1:1eXfmBsIJosjn9LjEBUd2WVPoPAY9XGTqTFcPMIBsUQ= -k8s.io/client-go v0.18.0 h1:yqKw4cTUQraZK3fcVCMeSa+lqKwcjZ5wtcOIPnxQno4= -k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8= -k8s.io/component-base v0.18.0 h1:I+lP0fNfsEdTDpHaL61bCAqTZLoiWjEEP304Mo5ZQgE= -k8s.io/component-base v0.18.0/go.mod h1:u3BCg0z1uskkzrnAKFzulmYaEpZF7XC9Pf/uFyb1v2c= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= -k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= -k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c h1:/KUFqjjqAcY4Us6luF5RDNZ16KJtb49HfR3ZHB9qYXM= -k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 h1:uuHDyjllyzRyCIvvn0OBjiRB0SgBZGqHNYAmjR7fO50= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= -sigs.k8s.io/kind v0.7.0 h1:7y7a8EYtGHM+auHmsvzuK5o84SrxPYGidlvfql7j/k4= -sigs.k8s.io/kind v0.7.0/go.mod h1:An/AbWHT6pA/Lm0Og8j3ukGhfJP3RiVN/IBU6Lo3zl8= -sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= -sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= -sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= -sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.31.1 h1:Sars5ejQDCRBY5f7R3QFHdqN3s61nhkpaX8/k1iEw1c= +k8s.io/apiserver v0.31.1/go.mod h1:lzDhpeToamVZJmmFlaLwdYZwd7zB+WYRYIboqA1kGxM= +k8s.io/cli-runtime v0.31.1 h1:/ZmKhmZ6hNqDM+yf9s3Y4KEYakNXUn5sod2LWGGwCuk= +k8s.io/cli-runtime v0.31.1/go.mod h1:pKv1cDIaq7ehWGuXQ+A//1OIF+7DI+xudXtExMCbe9U= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/component-base v0.31.1 h1:UpOepcrX3rQ3ab5NB6g5iP0tvsgJWzxTyAo20sgYSy8= +k8s.io/component-base v0.31.1/go.mod h1:WGeaw7t/kTsqpVTaCoVEtillbqAhF2/JgvO0LDOMa0w= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kms v0.31.1 h1:cGLyV3cIwb0ovpP/jtyIe2mEuQ/MkbhmeBF2IYCA9Io= +k8s.io/kms v0.31.1/go.mod h1:OZKwl1fan3n3N5FFxnW5C4V3ygrah/3YXeJWS3O6+94= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 h1:2770sDpzrjjsAtVhSeUFseziht227YAWYHLGNM8QPwY= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kind v0.24.0 h1:g4y4eu0qa+SCeKESLpESgMmVFBebL0BDa6f777OIWrg= +sigs.k8s.io/kind v0.24.0/go.mod h1:t7ueEpzPYJvHA8aeLtI52rtFftNgUYUaCwvxjk7phfw= +sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= +sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= +sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= +sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/tools/tools.go b/hack/tools/tools.go index 62a72ff0a..83a8963a5 100644 --- a/hack/tools/tools.go +++ b/hack/tools/tools.go @@ -1,6 +1,7 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +//go:build tools // +build tools -// Copyright Jetstack Ltd. See LICENSE for details. package tools // This file is used to vendor packages we use to build binaries. diff --git a/patchlog.txt b/patchlog.txt new file mode 100644 index 000000000..50ce6261e --- /dev/null +++ b/patchlog.txt @@ -0,0 +1,51 @@ +# Automatic Patch Log + +Automatic Update - 20211216T025617.851Z +Automatic Update - 20220311T201831.205Z +Automatic Update - 20220318T020336.250Z +Automatic Update - 20220403T020307.625Z +Automatic Update - 20220415T020318.763Z +Automatic Update - 20220422T020314.907Z +Automatic Update - 20220429T020319.615Z +Automatic Update - 20220506T020321.057Z +Automatic Update - 20220519T020313.080Z +Automatic Update - 20220529T020344.385Z +Automatic Update - 20220609T020332.886Z +Automatic Update - 20220624T020345.647Z +Automatic Update - 20220707T020312.276Z +Automatic Update - 20220807T020800.447Z +Automatic Update - 20220925T020336.718Z +Automatic Update - 20221014T020348.280Z +Automatic Update - 20221020T020349.425Z +Automatic Update - 20221130T020413.421Z +Automatic Update - 20221211T020437.196Z +Automatic Update - 20230131T020526.940Z +Automatic Update - 20230214T020526.050Z +Automatic Update - 20230306T020416.148Z +Automatic Update - 20230310T020312.894Z +Automatic Update - 20230427T020320.801Z +Automatic Update - 20230525T020428.881Z +Automatic Update - 20230601T020342.442Z +Automatic Update - 20230607T020351.116Z +Automatic Update - 20230616T020248.766Z +Automatic Update - 20231005T020301.893Z +Automatic Update - 20231026T020312.403Z +Automatic Update - 20231108T020319.537Z +Automatic Update - 20231116T020337.574Z +Automatic Update - 20231123T020342.310Z +Automatic Update - 20231209T020329.153Z +Automatic Update - 20231213T020333.022Z +Automatic Update - 20240119T020325.770Z +Automatic Update - 20240124T020357.219Z +Automatic Update - 20240207T020401.740Z +Automatic Update - 20240217T020411.845Z +Automatic Update - 20240320T020336.148Z +Automatic Update - 20240329T020424.531Z +Automatic Update - 20240417T020415.214Z +Automatic Update - 20240420T020411.899Z +Automatic Update - 20240602T020353.512Z +Automatic Update - 20240629T020356.989Z +Automatic Update - 20240802T020420.511Z +Automatic Update - 20240810T020429.835Z + +force rebuild 2024-09-15 \ No newline at end of file diff --git a/pkg/probe/probe.go b/pkg/probe/probe.go index 3e0248d51..6ab3f53ea 100644 --- a/pkg/probe/probe.go +++ b/pkg/probe/probe.go @@ -11,7 +11,7 @@ import ( "github.com/heptiolabs/healthcheck" "k8s.io/apiserver/pkg/authentication/authenticator" - "k8s.io/klog" + "k8s.io/klog/v2" ) const ( @@ -66,8 +66,7 @@ func (h *HealthCheck) Check() error { h.ready = true - klog.V(4).Infof("OIDC provider initialized, readiness check returned expected error: %s", err) - klog.Info("OIDC provider initialized, proxy ready") + klog.V(4).Info("OIDC provider initialized.") return nil } diff --git a/pkg/proxy/audit/audit.go b/pkg/proxy/audit/audit.go index 6dd35f5e7..299e3e03f 100644 --- a/pkg/proxy/audit/audit.go +++ b/pkg/proxy/audit/audit.go @@ -9,6 +9,7 @@ import ( genericapifilters "k8s.io/apiserver/pkg/endpoints/filters" "k8s.io/apiserver/pkg/server" genericfilters "k8s.io/apiserver/pkg/server/filters" + "k8s.io/apiserver/pkg/util/version" "github.com/jetstack/kube-oidc-proxy/cmd/app/options" ) @@ -34,10 +35,11 @@ func New(opts *options.AuditOptions, externalAddress string, secureServingInfo * } // We do not support dynamic auditing, so leave nil - if err := opts.ApplyTo(serverConfig, nil, nil, nil, nil); err != nil { + if err := opts.ApplyTo(serverConfig); err != nil { return nil, err } + serverConfig.EffectiveVersion = version.NewEffectiveVersion("1.0.31") completed := serverConfig.Complete(nil) return &Audit{ @@ -69,7 +71,8 @@ func (a *Audit) Shutdown() error { // WithRequest will wrap the given handler to inject the request information // into the context which is then used by the wrapped audit handler. func (a *Audit) WithRequest(handler http.Handler) http.Handler { - handler = genericapifilters.WithAudit(handler, a.serverConfig.AuditBackend, a.serverConfig.AuditPolicyChecker, a.serverConfig.LongRunningFunc) + handler = genericapifilters.WithAudit(handler, a.serverConfig.AuditBackend, a.serverConfig.AuditPolicyRuleEvaluator, a.serverConfig.LongRunningFunc) + handler = genericapifilters.WithAuditInit(handler) return genericapifilters.WithRequestInfo(handler, a.serverConfig.RequestInfoResolver) } @@ -77,6 +80,6 @@ func (a *Audit) WithRequest(handler http.Handler) http.Handler { // information into the context which is then used by the wrapped audit // handler. func (a *Audit) WithUnauthorized(handler http.Handler) http.Handler { - handler = genericapifilters.WithFailedAuthenticationAudit(handler, a.serverConfig.AuditBackend, a.serverConfig.AuditPolicyChecker) + handler = genericapifilters.WithFailedAuthenticationAudit(handler, a.serverConfig.AuditBackend, a.serverConfig.AuditPolicyRuleEvaluator) return genericapifilters.WithRequestInfo(handler, a.serverConfig.RequestInfoResolver) } diff --git a/pkg/proxy/context/context.go b/pkg/proxy/context/context.go index e1a0cd7e5..2226035a7 100644 --- a/pkg/proxy/context/context.go +++ b/pkg/proxy/context/context.go @@ -5,8 +5,11 @@ import ( "net/http" "github.com/sebest/xff" + "k8s.io/apiserver/pkg/authentication/user" "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/client-go/transport" + + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" ) type key int @@ -25,6 +28,12 @@ const ( clientAddressKey ) +type ImpersonationRequest struct { + ImpersonationConfig *transport.ImpersonationConfig + InboundUser *user.Info + ImpersonatedUser *user.Info +} + // WithNoImpersonation returns a copy of the request in which the noImpersonation context value is set. func WithNoImpersonation(req *http.Request) *http.Request { return req.WithContext(request.WithValue(req.Context(), noImpersonationKey, true)) @@ -37,13 +46,17 @@ func NoImpersonation(req *http.Request) bool { } // WithImpersonationConfig returns a copy of parent in which contains the impersonation configuration. -func WithImpersonationConfig(req *http.Request, conf *transport.ImpersonationConfig) *http.Request { - return req.WithContext(request.WithValue(req.Context(), impersonationConfigKey, conf)) +func WithImpersonationConfig(req *http.Request, conf *ImpersonationRequest) *http.Request { + ctxToReturn := request.WithValue(req.Context(), impersonationConfigKey, conf) + if *conf.ImpersonatedUser != nil { + ctxToReturn = genericapirequest.WithUser(ctxToReturn, *conf.ImpersonatedUser) + } + return req.WithContext(ctxToReturn) } // ImpersonationConfig returns the impersonation configuration held in the context if existing. -func ImpersonationConfig(req *http.Request) *transport.ImpersonationConfig { - conf, _ := req.Context().Value(impersonationConfigKey).(*transport.ImpersonationConfig) +func ImpersonationConfig(req *http.Request) *ImpersonationRequest { + conf, _ := req.Context().Value(impersonationConfigKey).(*ImpersonationRequest) return conf } diff --git a/pkg/proxy/handlers.go b/pkg/proxy/handlers.go index 74b33bfab..a604df8d3 100644 --- a/pkg/proxy/handlers.go +++ b/pkg/proxy/handlers.go @@ -2,16 +2,20 @@ package proxy import ( + "encoding/json" "net/http" "strings" + "k8s.io/apiserver/pkg/authentication/user" authuser "k8s.io/apiserver/pkg/authentication/user" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/client-go/transport" - "k8s.io/klog" + "k8s.io/klog/v2" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/audit" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/context" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/logging" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview" ) func (p *Proxy) withHandlers(handler http.Handler) http.Handler { @@ -34,6 +38,7 @@ func (p *Proxy) withAuthenticateRequest(handler http.Handler) http.Handler { // Auth request and handle unauthed info, ok, err := p.oidcRequestAuther.AuthenticateRequest(req) if err != nil { + klog.V(5).Infof("Authenticated request failed: %s", err) // Since we have failed OIDC auth, we will try a token review, if enabled. tokenReviewHandler.ServeHTTP(rw, req) return @@ -89,6 +94,9 @@ func (p *Proxy) withImpersonateRequest(handler http.Handler) http.Handler { return } + var targetForContext user.Info + targetForContext = nil + var remoteAddr string req, remoteAddr = context.RemoteAddr(req) @@ -101,11 +109,6 @@ func (p *Proxy) withImpersonateRequest(handler http.Handler) http.Handler { return } - if p.hasImpersonation(req.Header) { - p.handleError(rw, req, errImpersonateHeader) - return - } - user, ok := genericapirequest.UserFrom(req.Context()) // No name available so reject request if !ok || len(user.GetName()) == 0 { @@ -113,6 +116,25 @@ func (p *Proxy) withImpersonateRequest(handler http.Handler) http.Handler { return } + userForContext := user + + if p.hasImpersonation(req.Header) { + // if impersonation headers are present, let's check to see + // if the user is authorized to perform the impersonation + target, err := p.subjectAccessReviewer.CheckAuthorizedForImpersonation(req, user) + + if err != nil { + p.handleError(rw, req, err) + return + } + + if target != nil { + // TODO - store original context for logging + user = target + targetForContext = target + } + } + // Ensure group contains allauthenticated builtin allAuthFound := false groups := user.GetGroups() @@ -151,10 +173,43 @@ func (p *Proxy) withImpersonateRequest(handler http.Handler) http.Handler { } } - conf := &transport.ImpersonationConfig{ - UserName: user.GetName(), - Groups: groups, - Extra: extra, + if targetForContext != nil { + // add the original user's information as extra headers + // so they're recorded in the API server's audit log + extra["originaluser.jetstack.io-user"] = []string{userForContext.GetName()} + + numGroups := len(userForContext.GetGroups()) + if numGroups > 0 { + groupNames := make([]string, numGroups) + for i, groupName := range userForContext.GetGroups() { + groupNames[i] = groupName + } + + extra["originaluser.jetstack.io-groups"] = groupNames + } + + if userForContext.GetUID() != "" { + extra["originaluser.jetstack.io-uid"] = []string{userForContext.GetUID()} + } + + if userForContext.GetExtra() != nil && len(userForContext.GetExtra()) > 0 { + jsonExtras, errJsonMarshal := json.Marshal(userForContext.GetExtra()) + if errJsonMarshal != nil { + p.handleError(rw, req, errJsonMarshal) + return + } + extra["originaluser.jetstack.io-extra"] = []string{string(jsonExtras)} + } + } + + conf := &context.ImpersonationRequest{ + ImpersonationConfig: &transport.ImpersonationConfig{ + UserName: user.GetName(), + Groups: groups, + Extra: extra, + }, + InboundUser: &userForContext, + ImpersonatedUser: &targetForContext, } // Add the impersonation configuration to the context. @@ -165,18 +220,23 @@ func (p *Proxy) withImpersonateRequest(handler http.Handler) http.Handler { // newErrorHandler returns a handler failed requests. func (p *Proxy) newErrorHandler() func(rw http.ResponseWriter, r *http.Request, err error) { + unauthedHandler := audit.NewUnauthenticatedHandler(p.auditor, func(rw http.ResponseWriter, r *http.Request) { klog.V(2).Infof("unauthenticated user request %s", r.RemoteAddr) http.Error(rw, "Unauthorized", http.StatusUnauthorized) }) return func(rw http.ResponseWriter, r *http.Request, err error) { + if err == nil { klog.Error("error was called with no error") http.Error(rw, "", http.StatusInternalServerError) return } + // regardless of reason, log failed auth + logging.LogFailedRequest(r) + switch err { // Failed auth @@ -185,12 +245,6 @@ func (p *Proxy) newErrorHandler() func(rw http.ResponseWriter, r *http.Request, unauthedHandler.ServeHTTP(rw, r) return - // User request with impersonation - case errImpersonateHeader: - klog.V(2).Infof("impersonation user request %s", r.RemoteAddr) - http.Error(rw, "Impersonation requests are disabled when using kube-oidc-proxy", http.StatusForbidden) - return - // No name given or available in oidc request case errNoName: klog.V(2).Infof("no name available in oidc info %s", r.RemoteAddr) @@ -203,20 +257,29 @@ func (p *Proxy) newErrorHandler() func(rw http.ResponseWriter, r *http.Request, http.Error(rw, "", http.StatusInternalServerError) return + // No impersonation user found + case subjectaccessreview.ErrorNoImpersonationUserFound: + http.Error(rw, subjectaccessreview.ErrorNoImpersonationUserFound.Error(), http.StatusInternalServerError) + return + // Server or unknown error default: - klog.Errorf("unknown error (%s): %s", r.RemoteAddr, err) - http.Error(rw, "", http.StatusInternalServerError) + + if strings.Contains(err.Error(), "not allowed to impersonate") { + klog.V(2).Infof(err.Error(), r.RemoteAddr) + http.Error(rw, err.Error(), http.StatusForbidden) + } else { + klog.Errorf("unknown error (%s): %s", r.RemoteAddr, err) + http.Error(rw, "", http.StatusInternalServerError) + } + } } } func (p *Proxy) hasImpersonation(header http.Header) bool { for h := range header { - if strings.ToLower(h) == impersonateUserHeader || - strings.ToLower(h) == impersonateGroupHeader || - strings.HasPrefix(strings.ToLower(h), impersonateExtraHeader) { - + if strings.HasPrefix(strings.ToLower(h), "impersonate-") { return true } } diff --git a/pkg/proxy/logging/accesslog.go b/pkg/proxy/logging/accesslog.go new file mode 100644 index 000000000..b40c797bf --- /dev/null +++ b/pkg/proxy/logging/accesslog.go @@ -0,0 +1,94 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +package logging + +import ( + "fmt" + "net/http" + "strings" + "time" + + "k8s.io/apiserver/pkg/authentication/user" +) + +const ( + UserHeaderClientIPKey = "Remote-Client-IP" + timestampLayout = "2006-01-02T15:04:05-0700" +) + +// logs the request +func LogSuccessfulRequest(req *http.Request, inboundUser user.Info, outboundUser user.Info) { + remoteAddr := req.RemoteAddr + indexOfColon := strings.Index(remoteAddr, ":") + if indexOfColon > 0 { + remoteAddr = remoteAddr[0:indexOfColon] + } + + inboundExtras := "" + + if inboundUser.GetExtra() != nil { + for key, value := range inboundUser.GetExtra() { + inboundExtras += key + "=" + strings.Join(value, "|") + " " + } + } + + outboundUserLog := "" + + if outboundUser != nil { + outboundExtras := "" + + if outboundUser.GetExtra() != nil { + for key, value := range outboundUser.GetExtra() { + outboundExtras += key + "=" + strings.Join(value, "|") + " " + } + } + + outboundUserLog = fmt.Sprintf(" outbound:[%s / %s / %s / %s]", outboundUser.GetName(), strings.Join(outboundUser.GetGroups(), "|"), outboundUser.GetUID(), outboundExtras) + } + + xFwdFor := findXForwardedFor(req.Header, remoteAddr) + + fmt.Printf("[%s] AuSuccess src:[%s / % s] URI:%s inbound:[%s / %s / %s]%s\n", time.Now().Format(timestampLayout), remoteAddr, xFwdFor, req.RequestURI, inboundUser.GetName(), strings.Join(inboundUser.GetGroups(), "|"), inboundExtras, outboundUserLog) +} + +// determines if the x-forwarded-for header is present, if so remove +// the remoteaddr since it is repetitive +func findXForwardedFor(headers http.Header, remoteAddr string) string { + xFwdFor := headers.Get("x-forwarded-for") + // clean off remoteaddr from x-forwarded-for + if xFwdFor != "" { + + newXFwdFor := "" + oneFound := false + xFwdForIps := strings.Split(xFwdFor, ",") + + for _, ip := range xFwdForIps { + ip = strings.TrimSpace(ip) + + if ip != remoteAddr { + newXFwdFor = newXFwdFor + ip + ", " + oneFound = true + } + + } + + if oneFound { + newXFwdFor = newXFwdFor[0 : len(newXFwdFor)-2] + } + + xFwdFor = newXFwdFor + + } + + return xFwdFor +} + +// logs the failed request +func LogFailedRequest(req *http.Request) { + remoteAddr := req.RemoteAddr + indexOfColon := strings.Index(remoteAddr, ":") + if indexOfColon > 0 { + remoteAddr = remoteAddr[0:indexOfColon] + } + + fmt.Printf("[%s] AuFail src:[%s / % s] URI:%s\n", time.Now().Format(timestampLayout), remoteAddr, req.Header.Get(("x-forwarded-for")), req.RequestURI) +} diff --git a/pkg/proxy/logging/accesslog_test.go b/pkg/proxy/logging/accesslog_test.go new file mode 100644 index 000000000..627d8b5b2 --- /dev/null +++ b/pkg/proxy/logging/accesslog_test.go @@ -0,0 +1,68 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +package logging + +import ( + "net/http" + "testing" +) + +func TestXForwardedFor(t *testing.T) { + + tests := map[string]struct { + headers http.Header + remoteAddr string + exp string + }{ + "no x-forwarded-for": { + headers: http.Header{}, + remoteAddr: "1.2.3.4", + exp: "", + }, + "empty x-forwarded-for": { + headers: http.Header{ + "X-Forwarded-For": []string{""}, + }, + remoteAddr: "1.2.3.4", + exp: "", + }, + "x-forwarded-for is remoteaddr": { + headers: http.Header{ + "X-Forwarded-For": []string{"1.2.3.4"}, + }, + remoteAddr: "1.2.3.4", + exp: "", + }, + "x-forwarded-for with no remoteaddr": { + headers: http.Header{ + "X-Forwarded-For": []string{"1.2.3.1"}, + }, + remoteAddr: "1.2.3.4", + exp: "1.2.3.1", + }, + "x-forwarded-for with with remoteaddr at the end": { + headers: http.Header{ + "X-Forwarded-For": []string{"1.2.3.1, 1.2.3.4"}, + }, + remoteAddr: "1.2.3.4", + exp: "1.2.3.1", + }, + "x-forwarded-for with with remoteaddr at the beginning": { + headers: http.Header{ + "X-Forwarded-For": []string{"1.2.3.4, 1.2.3.1"}, + }, + remoteAddr: "1.2.3.4", + exp: "1.2.3.1", + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + forwarded := findXForwardedFor(test.headers, test.remoteAddr) + + if test.exp != forwarded { + t.Errorf("failed for %s: unexpected result : %s", name, forwarded) + t.FailNow() + } + }) + } +} diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go index 5e4d620fd..ff395488b 100644 --- a/pkg/proxy/proxy.go +++ b/pkg/proxy/proxy.go @@ -2,43 +2,42 @@ package proxy import ( + ctx "context" "errors" "fmt" + "io/ioutil" "net/http" "net/http/httputil" "net/url" - "strings" "time" + "k8s.io/apiserver/pkg/apis/apiserver" "k8s.io/apiserver/pkg/authentication/authenticator" "k8s.io/apiserver/pkg/authentication/request/bearertoken" "k8s.io/apiserver/pkg/server" "k8s.io/apiserver/plugin/pkg/authenticator/token/oidc" "k8s.io/client-go/rest" "k8s.io/client-go/transport" - "k8s.io/klog" + "k8s.io/klog/v2" "github.com/jetstack/kube-oidc-proxy/cmd/app/options" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/audit" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/context" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/hooks" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/logging" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/tokenreview" ) const ( UserHeaderClientIPKey = "Remote-Client-IP" + timestampLayout = "2006-01-02T15:04:05-0700" ) var ( errUnauthorized = errors.New("Unauthorized") - errImpersonateHeader = errors.New("Impersonate-User in header") errNoName = errors.New("No name in OIDC info") errNoImpersonationConfig = errors.New("No impersonation configuration in context") - - // http headers are case-insensitive - impersonateUserHeader = strings.ToLower(transport.ImpersonateUserHeader) - impersonateGroupHeader = strings.ToLower(transport.ImpersonateGroupHeader) - impersonateExtraHeader = strings.ToLower(transport.ImpersonateUserExtraHeaderPrefix) ) type Config struct { @@ -55,11 +54,12 @@ type Config struct { type errorHandlerFn func(http.ResponseWriter, *http.Request, error) type Proxy struct { - oidcRequestAuther *bearertoken.Authenticator - tokenAuther authenticator.Token - tokenReviewer *tokenreview.TokenReview - secureServingInfo *server.SecureServingInfo - auditor *audit.Audit + oidcRequestAuther *bearertoken.Authenticator + tokenAuther authenticator.Token + tokenReviewer *tokenreview.TokenReview + subjectAccessReviewer *subjectaccessreview.SubjectAccessReview + secureServingInfo *server.SecureServingInfo + auditor *audit.Audit restConfig *rest.Config clientTransport http.RoundTripper @@ -71,24 +71,56 @@ type Proxy struct { handleError errorHandlerFn } +// implement oidc.CAContentProvider to load +// the ca file from the options +type CAFromFile struct { + CAFile string +} + +func (caFromFile CAFromFile) CurrentCABundleContent() []byte { + res, _ := ioutil.ReadFile(caFromFile.CAFile) + return res +} + func New(restConfig *rest.Config, oidcOptions *options.OIDCAuthenticationOptions, auditOptions *options.AuditOptions, tokenReviewer *tokenreview.TokenReview, + subjectAccessReviewer *subjectaccessreview.SubjectAccessReview, ssinfo *server.SecureServingInfo, config *Config) (*Proxy, error) { + // load the CA from the file listed in the options + caFromFile := CAFromFile{ + CAFile: oidcOptions.CAFile, + } + + // setup static JWT Auhenticator + jwtConfig := apiserver.JWTAuthenticator{ + Issuer: apiserver.Issuer{ + URL: oidcOptions.IssuerURL, + Audiences: []string{oidcOptions.ClientID}, + CertificateAuthority: string(caFromFile.CurrentCABundleContent()), + }, + + ClaimMappings: apiserver.ClaimMappings{ + Username: apiserver.PrefixedClaimOrExpression{ + Claim: oidcOptions.UsernameClaim, + Prefix: &oidcOptions.UsernamePrefix, + }, + Groups: apiserver.PrefixedClaimOrExpression{ + Claim: oidcOptions.GroupsClaim, + Prefix: &oidcOptions.GroupsPrefix, + }, + }, + } + // generate tokenAuther from oidc config - tokenAuther, err := oidc.New(oidc.Options{ - CAFile: oidcOptions.CAFile, - ClientID: oidcOptions.ClientID, - GroupsClaim: oidcOptions.GroupsClaim, - GroupsPrefix: oidcOptions.GroupsPrefix, - IssuerURL: oidcOptions.IssuerURL, - RequiredClaims: oidcOptions.RequiredClaims, + tokenAuther, err := oidc.New(ctx.TODO(), oidc.Options{ + CAContentProvider: caFromFile, + //RequiredClaims: oidcOptions.RequiredClaims, SupportedSigningAlgs: oidcOptions.SigningAlgs, - UsernameClaim: oidcOptions.UsernameClaim, - UsernamePrefix: oidcOptions.UsernamePrefix, + JWTAuthenticator: jwtConfig, }) if err != nil { return nil, err @@ -100,22 +132,23 @@ func New(restConfig *rest.Config, } return &Proxy{ - restConfig: restConfig, - hooks: hooks.New(), - tokenReviewer: tokenReviewer, - secureServingInfo: ssinfo, - config: config, - oidcRequestAuther: bearertoken.New(tokenAuther), - tokenAuther: tokenAuther, - auditor: auditor, + restConfig: restConfig, + hooks: hooks.New(), + tokenReviewer: tokenReviewer, + subjectAccessReviewer: subjectAccessReviewer, + secureServingInfo: ssinfo, + config: config, + oidcRequestAuther: bearertoken.New(tokenAuther), + tokenAuther: tokenAuther, + auditor: auditor, }, nil } -func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) { +func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, <-chan struct{}, error) { // standard round tripper for proxy to API Server clientRT, err := p.roundTripperForRestConfig(p.restConfig) if err != nil { - return nil, err + return nil, nil, err } p.clientTransport = clientRT @@ -131,7 +164,7 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) { }, }) if err != nil { - return nil, err + return nil, nil, err } p.noAuthClientTransport = noAuthClientRT @@ -140,7 +173,7 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) { // get API server url url, err := url.Parse(p.restConfig.Host) if err != nil { - return nil, fmt.Errorf("failed to parse url: %s", err) + return nil, nil, fmt.Errorf("failed to parse url: %s", err) } p.handleError = p.newErrorHandler() @@ -151,30 +184,30 @@ func (p *Proxy) Run(stopCh <-chan struct{}) (<-chan struct{}, error) { proxyHandler.ErrorHandler = p.handleError proxyHandler.FlushInterval = p.config.FlushInterval - waitCh, err := p.serve(proxyHandler, stopCh) + waitCh, listenerStoppedCh, err := p.serve(proxyHandler, stopCh) if err != nil { - return nil, err + return nil, nil, err } - return waitCh, nil + return waitCh, listenerStoppedCh, nil } -func (p *Proxy) serve(handler http.Handler, stopCh <-chan struct{}) (<-chan struct{}, error) { +func (p *Proxy) serve(handler http.Handler, stopCh <-chan struct{}) (<-chan struct{}, <-chan struct{}, error) { // Setup proxy handlers handler = p.withHandlers(handler) // Run auditor if err := p.auditor.Run(stopCh); err != nil { - return nil, err + return nil, nil, err } // securely serve using serving config - waitCh, err := p.secureServingInfo.Serve(handler, time.Second*60, stopCh) + waitCh, listenerStoppedCh, err := p.secureServingInfo.Serve(handler, time.Second*60, stopCh) if err != nil { - return nil, err + return nil, nil, err } - return waitCh, nil + return waitCh, listenerStoppedCh, nil } // RoundTrip is called last and is used to manipulate the forwarded request using context. @@ -191,13 +224,16 @@ func (p *Proxy) RoundTrip(req *http.Request) (*http.Response, error) { } // Get the impersonation headers from the context. - conf := context.ImpersonationConfig(req) - if conf == nil { + impersonationConf := context.ImpersonationConfig(req) + if impersonationConf == nil { return nil, errNoImpersonationConfig } // Set up impersonation request. - rt := transport.NewImpersonatingRoundTripper(*conf, p.clientTransport) + rt := transport.NewImpersonatingRoundTripper(*impersonationConf.ImpersonationConfig, p.clientTransport) + + // Log the request + logging.LogSuccessfulRequest(req, *impersonationConf.InboundUser, *impersonationConf.ImpersonatedUser) // Push request through round trippers to the API server. return rt.RoundTrip(req) diff --git a/pkg/proxy/proxy_test.go b/pkg/proxy/proxy_test.go index 4f9acc61f..b2de0476d 100644 --- a/pkg/proxy/proxy_test.go +++ b/pkg/proxy/proxy_test.go @@ -24,6 +24,9 @@ import ( "github.com/jetstack/kube-oidc-proxy/pkg/mocks" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/audit" "github.com/jetstack/kube-oidc-proxy/pkg/proxy/hooks" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/logging" + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview" + fakesubjectaccessreview "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview/fake" ) type fakeProxy struct { @@ -45,6 +48,7 @@ type fakeRT struct { expUser string expGroup []string expExtra map[string][]string + expUid string } func (f *fakeRW) Write(b []byte) (int, error) { @@ -75,11 +79,19 @@ func newFakeRW() *fakeRW { func (f *fakeRT) RoundTrip(h *http.Request) (*http.Response, error) { if h.Header.Get("Impersonate-User") != f.expUser { + logging.LogFailedRequest(h) f.t.Errorf("client transport got unexpected user impersonation header, exp=%s got=%s", f.expUser, h.Header.Get("Impersonate-User")) } + if h.Header.Get("Impersonate-Uid") != f.expUid { + logging.LogFailedRequest(h) + f.t.Errorf("client transport got unexpected uid impersonation header, exp=%s got=%s", + f.expUid, h.Header.Get("Impersonate-Uid")) + } + if exp, act := sort.StringSlice(f.expGroup), sort.StringSlice(h.Header["Impersonate-Group"]); !reflect.DeepEqual(exp, act) { + logging.LogFailedRequest(h) f.t.Errorf( "client transport got unexpected group impersonation header, exp=%#v got=%#v", exp, @@ -91,11 +103,13 @@ func (f *fakeRT) RoundTrip(h *http.Request) (*http.Response, error) { if strings.HasPrefix(k, "Impersonate-Extra-") { expvv, ok := f.expExtra[k] if !ok { + logging.LogFailedRequest(h) f.t.Errorf("got unexpected impersonate extra: %s", k) continue } if !reflect.DeepEqual(vv, expvv) { + logging.LogFailedRequest(h) f.t.Errorf("unexpected values in impersonate extra (%s), exp=%s got=%s", k, expvv, vv) } } @@ -104,15 +118,19 @@ func (f *fakeRT) RoundTrip(h *http.Request) (*http.Response, error) { for k, expvv := range f.expExtra { vv, ok := h.Header[k] if !ok { + logging.LogFailedRequest(h) f.t.Errorf("did not get expected impersonate extra: %s", k) continue } if !reflect.DeepEqual(vv, expvv) { + logging.LogFailedRequest(h) f.t.Errorf("unexpected values in impersonate extra (%s), exp=%s got=%s", k, expvv, vv) } } + logging.LogSuccessfulRequest(h, &user.DefaultInfo{}, &user.DefaultInfo{}) + return nil, nil } @@ -152,11 +170,6 @@ func TestError(t *testing.T) { t.Errorf("unexpected response, exp='%s' got='%s'", exp, frw.buffer) } - frw = tryError(t, http.StatusForbidden, errImpersonateHeader) - if exp := []byte("Impersonation requests are disabled when using kube-oidc-proxy\n"); !bytes.Equal(frw.buffer, exp) { - t.Errorf("unexpected response, exp='%s' got='%s'", exp, frw.buffer) - } - frw = tryError(t, http.StatusForbidden, errNoName) if exp := []byte("Username claim not available in OIDC Issuer response\n"); !bytes.Equal(frw.buffer, exp) { t.Errorf("unexpected response, exp='%s' got='%s'", exp, frw.buffer) @@ -184,9 +197,7 @@ func TestHasImpersonation(t *testing.T) { { "Impersonate": []string{"bar", "foo"}, }, - { - "impersonate-Extra": []string{"bar", "foo"}, - }, + { "-impersonate-Extra-": []string{"bar", "foo"}, }, @@ -239,6 +250,11 @@ func TestHasImpersonation(t *testing.T) { "impersonate-User": []string{"bar"}, "bar2": []string{"bar"}, }, + // any attempt to user impersonate- should be interpreted as + // an impersonation header since it could be in the future + { + "impersonate-Extra": []string{"bar", "foo"}, + }, } for _, h := range noImpersonation { @@ -258,6 +274,8 @@ func newTestProxy(t *testing.T) *fakeProxy { ctrl := gomock.NewController(t) fakeToken := mocks.NewMockToken(ctrl) fakeRT := &fakeRT{t: t} + fakeSubjectAccessReviewer := fakesubjectaccessreview.New(nil) + subjectAccessReview, _ := subjectaccessreview.New(fakeSubjectAccessReviewer) p := &fakeProxy{ ctrl: ctrl, @@ -265,6 +283,7 @@ func newTestProxy(t *testing.T) *fakeProxy { fakeRT: fakeRT, Proxy: &Proxy{ oidcRequestAuther: bearertoken.New(fakeToken), + subjectAccessReviewer: subjectAccessReview, clientTransport: fakeRT, noAuthClientTransport: fakeRT, config: new(Config), @@ -303,6 +322,7 @@ func TestHandlers(t *testing.T) { expUser string expGroup []string expExtra map[string][]string + expUid string }{ "an empty request should 401": { req: new(http.Request), @@ -379,7 +399,164 @@ func TestHandlers(t *testing.T) { expCode: http.StatusUnauthorized, expBody: errUnauthorized.Error(), }, - "an authed request with impersonation user should error impersonation header": { + + // BEGIN IMPERSONATION TESTS + + "an authed request with authorized impersonation user should succeed": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + }, + }, + expUser: "jjackson", + expGroup: []string{"system:authenticated"}, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusOK, + expExtra: map[string][]string{ + "Impersonate-Extra-Originaluser.jetstack.io-User": {"mmosley"}, + "Impersonate-Extra-Originaluser.jetstack.io-Groups": {"group1"}, + }, + expBody: "", + }, + "an authed request with authorized impersonation group should succeed": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Group": []string{"group3"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expUser: "jjackson", + expGroup: []string{"group3", "system:authenticated"}, + expExtra: map[string][]string{ + "Impersonate-Extra-Originaluser.jetstack.io-User": {"mmosley"}, + "Impersonate-Extra-Originaluser.jetstack.io-Groups": {"group1"}, + }, + expCode: http.StatusOK, + expBody: "", + }, + "an authed request with authorized impersonation extra should succeed": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Group": []string{"group3"}, + "Impersonate-Extra-remoteaddr": []string{"1.2.3.4"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + Extra: map[string][]string{"someextra": {"someval1", "someval2"}, "someextra2": {"foo", "bar"}}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusOK, + expUser: "jjackson", + expGroup: []string{"group3", "system:authenticated"}, + expExtra: map[string][]string{ + "Impersonate-Extra-Remoteaddr": {"1.2.3.4"}, + "Impersonate-Extra-Originaluser.jetstack.io-User": {"mmosley"}, + "Impersonate-Extra-Originaluser.jetstack.io-Groups": {"group1"}, + "Impersonate-Extra-Originaluser.jetstack.io-Extra": {"{\"someextra\":[\"someval1\",\"someval2\"],\"someextra2\":[\"foo\",\"bar\"]}"}, + }, + expBody: "", + }, + + "an authed request with authorized impersonation extra should succeed, with an empty X-Forwarded-For header": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Group": []string{"group3"}, + "Impersonate-Extra-remoteaddr": []string{"1.2.3.4"}, + "X-Forwarded-For": []string{""}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + Extra: map[string][]string{"someextra": {"someval1", "someval2"}, "someextra2": {"foo", "bar"}}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusOK, + expUser: "jjackson", + expGroup: []string{"group3", "system:authenticated"}, + expExtra: map[string][]string{ + "Impersonate-Extra-Remoteaddr": {"1.2.3.4"}, + "Impersonate-Extra-Originaluser.jetstack.io-User": {"mmosley"}, + "Impersonate-Extra-Originaluser.jetstack.io-Groups": {"group1"}, + "Impersonate-Extra-Originaluser.jetstack.io-Extra": {"{\"someextra\":[\"someval1\",\"someval2\"],\"someextra2\":[\"foo\",\"bar\"]}"}, + }, + expBody: "", + }, + + /* Commenting due to https://github.com/TremoloSecurity/kube-oidc-proxy/issues/7 + "an authed request with authorized impersonation uid should succeed": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-Uid": []string{"1-2-3-4"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Group": []string{"group3"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusOK, + expUser: "jjackson", + expUid: "1-2-3-4", + expGroup: []string{"group3", "system:authenticated"}, + expExtra: map[string][]string{ + "Impersonate-Extra-Originaluser.jetstack.io-User": {"mmosley"}, + "Impersonate-Extra-Originaluser.jetstack.io-Groups": {"group1"}, + }, + expBody: "", + },*/ + + "an authed request with unauthorized impersonation user should error unauthorized": { req: &http.Request{ Header: http.Header{ "Authorization": []string{"bearer fake-token"}, @@ -389,51 +566,175 @@ func TestHandlers(t *testing.T) { expAuthToken: "fake-token", authResponse: &authResponse{ resp: &authenticator.Response{ - User: &user.DefaultInfo{}, + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, }, pass: true, err: nil, }, expCode: http.StatusForbidden, - expBody: "Impersonation requests are disabled when using kube-oidc-proxy", + expBody: "mmosley is not allowed to impersonate user 'a-user'", }, - "an authed request with impersonation group should error impersonation header": { + "an authed request with unauthorized impersonation group should error unauthorized": { req: &http.Request{ Header: http.Header{ "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, "Impersonate-Group": []string{"a-group"}, }, }, expAuthToken: "fake-token", authResponse: &authResponse{ resp: &authenticator.Response{ - User: &user.DefaultInfo{}, + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, }, pass: true, err: nil, }, expCode: http.StatusForbidden, - expBody: "Impersonation requests are disabled when using kube-oidc-proxy", + expBody: "mmosley is not allowed to impersonate group 'a-group'", }, - "an authed request with impersonation extra should error impersonation header": { + "an authed request with unauthorized impersonation extra should error unauthorized": { req: &http.Request{ Header: http.Header{ "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, "Impersonate-Extra-foo": []string{"bar"}, }, }, expAuthToken: "fake-token", authResponse: &authResponse{ resp: &authenticator.Response{ - User: nil, + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, }, pass: true, err: nil, }, expCode: http.StatusForbidden, - expBody: "Impersonation requests are disabled when using kube-oidc-proxy", + expBody: "mmosley is not allowed to impersonate extra info 'foo'='bar'", + }, + "an authed request with unauthorized impersonation uid should error unauthorized": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Uid": []string{"bar"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusForbidden, + expBody: "mmosley is not allowed to impersonate uid 'bar'", + }, + + "an authed request with impersonation groups missing user should fail": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-Groups": []string{"bar"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusInternalServerError, + expBody: "no Impersonation-User header found for request", + }, + + "an authed request with impersonation extra missing user should fail": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-Extra-foo": []string{"bar"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusInternalServerError, + expBody: "no Impersonation-User header found for request", }, + "an authed request with impersonation uid missing user should fail": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-Uid": []string{"bar"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusInternalServerError, + expBody: "no Impersonation-User header found for request", + }, + + "an authed request with an invalid impersonation header should fail": { + req: &http.Request{ + Header: http.Header{ + "Authorization": []string{"bearer fake-token"}, + "Impersonate-User": []string{"jjackson"}, + "Impersonate-Not-Real": []string{"bar"}, + }, + }, + expAuthToken: "fake-token", + authResponse: &authResponse{ + resp: &authenticator.Response{ + User: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1"}, + }, + }, + pass: true, + err: nil, + }, + expCode: http.StatusInternalServerError, + expBody: "", + }, + + // END IMPERSONATION TESTS + "an authed request with no username is token should 403": { req: &http.Request{ Header: http.Header{ @@ -549,6 +850,7 @@ func TestHandlers(t *testing.T) { p.fakeRT.expUser = test.expUser p.fakeRT.expGroup = test.expGroup p.fakeRT.expExtra = test.expExtra + p.fakeRT.expUid = test.expUid if test.config != nil { p.config = test.config diff --git a/pkg/proxy/subjectaccessreview/fake/subjectaccessreview.go b/pkg/proxy/subjectaccessreview/fake/subjectaccessreview.go new file mode 100644 index 000000000..f6be4fa81 --- /dev/null +++ b/pkg/proxy/subjectaccessreview/fake/subjectaccessreview.go @@ -0,0 +1,68 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +package fake + +import ( + "context" + + azv1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + clientazv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" +) + +var _ clientazv1.SubjectAccessReviewInterface = &FakeReviewer{} + +type FakeReviewer struct { + err error +} + +func New(err error) *FakeReviewer { + return &FakeReviewer{ + err: err, + } +} + +func (f *FakeReviewer) Create(ctx context.Context, req *azv1.SubjectAccessReview, co metav1.CreateOptions) (*azv1.SubjectAccessReview, error) { + if f.err != nil { + return nil, f.err + } + + if req.Spec.ResourceAttributes.Resource == "users" && req.Spec.ResourceAttributes.Name == "jjackson" { + req.Status = azv1.SubjectAccessReviewStatus{ + Allowed: true, + } + + return req, nil + } + + if req.Spec.ResourceAttributes.Resource == "groups" && req.Spec.ResourceAttributes.Name == "group3" { + req.Status = azv1.SubjectAccessReviewStatus{ + Allowed: true, + } + + return req, nil + } + + if req.Spec.ResourceAttributes.Resource == "uids" && req.Spec.ResourceAttributes.Name == "1-2-3-4" { + req.Status = azv1.SubjectAccessReviewStatus{ + Allowed: true, + } + + return req, nil + } + + if req.Spec.ResourceAttributes.Resource == "userextras" && req.Spec.ResourceAttributes.Subresource == "remoteaddr" && req.Spec.ResourceAttributes.Name == "1.2.3.4" { + req.Status = azv1.SubjectAccessReviewStatus{ + Allowed: true, + } + + return req, nil + } + + // not an expcted test, or didn't conform to known allowed, fail + req.Status = azv1.SubjectAccessReviewStatus{ + Allowed: false, + } + + return req, nil + +} diff --git a/pkg/proxy/subjectaccessreview/subjectaccessreview.go b/pkg/proxy/subjectaccessreview/subjectaccessreview.go new file mode 100644 index 000000000..ad3a1ea73 --- /dev/null +++ b/pkg/proxy/subjectaccessreview/subjectaccessreview.go @@ -0,0 +1,203 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +package subjectaccessreview + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + + v1 "k8s.io/api/authorization/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apiserver/pkg/authentication/user" + clientazv1 "k8s.io/client-go/kubernetes/typed/authorization/v1" +) + +var ( + ErrorNoImpersonationUserFound = errors.New("no Impersonation-User header found for request") +) + +// structure for storing the review data +type SubjectAccessReview struct { + subjectAccessReviewer clientazv1.SubjectAccessReviewInterface +} + +// create a new SubjectAccessReview structure +func New(subjectAccessReviewer clientazv1.SubjectAccessReviewInterface) (*SubjectAccessReview, error) { + + return &SubjectAccessReview{ + subjectAccessReviewer: subjectAccessReviewer, + }, nil +} + +// checks the request for impersonation headers, validates that the user is able to perform that impersonation, +// and builds the target object +func (subjectAccessReview *SubjectAccessReview) CheckAuthorizedForImpersonation(req *http.Request, requester user.Info) (user.Info, error) { + + impersonatedUser := req.Header.Get("impersonate-user") + + hasImpersonatedUser := impersonatedUser != "" + + hasImpersonation := false + + targetUser := &user.DefaultInfo{ + Name: "", + Groups: make([]string, 0), + Extra: map[string][]string{}, + UID: "", + } + + headersToRemove := make(map[string]string) + + for key, values := range req.Header { + keyToCheck := strings.ToLower(key) + if strings.HasPrefix(keyToCheck, "impersonate-") { + if !hasImpersonatedUser { + // found impersonation header, but not a user + return nil, ErrorNoImpersonationUserFound + } + + headersToRemove[key] = key + hasImpersonation = true + if keyToCheck == "impersonate-user" { + userToImpersonate := values[0] + if userToImpersonate != "" { + result, err := subjectAccessReview.checkRbacImpersonationAuthorization("users", userToImpersonate, requester) + if err != nil { + return nil, err + } else { + if !result { + return nil, fmt.Errorf("%s is not allowed to impersonate user '%s'", requester.GetName(), userToImpersonate) + } else { + targetUser.Name = userToImpersonate + } + } + } + } else if keyToCheck == "impersonate-group" { + + for i := range values { + groupName := values[i] + result, err := subjectAccessReview.checkRbacImpersonationAuthorization("groups", groupName, requester) + if err != nil { + return nil, err + } else { + if !result { + return nil, fmt.Errorf("%s is not allowed to impersonate group '%s'", requester.GetName(), groupName) + } else { + targetUser.Groups = append(targetUser.Groups, groupName) + } + } + } + } else if keyToCheck == "impersonate-uid" { + uidToImpersonate := values[0] + result, err := subjectAccessReview.checkRbacImpersonationAuthorization("uids", uidToImpersonate, requester) + if err != nil { + return nil, err + } else { + if !result { + return nil, fmt.Errorf("%s is not allowed to impersonate uid '%s'", requester.GetName(), uidToImpersonate) + } else { + targetUser.UID = uidToImpersonate + } + } + } else if strings.HasPrefix(keyToCheck, "impersonate-extra-") { + // according to https://github.com/kubernetes/kubernetes/blob/555623c07eabf22864f6147736fa191e020cca25/staging/src/k8s.io/apiserver/pkg/authentication/user/user.go#L31-L41 + // the extra name MUST be lowercase...so we'll force to lowercase for the rbac check + extraName := strings.ToLower(key[18:]) + for i := range values { + result, err := subjectAccessReview.checkRbacImpersonationAuthorization("userextras/"+extraName, values[i], requester) + if err != nil { + return nil, err + } else { + if !result { + + return nil, fmt.Errorf("%s is not allowed to impersonate extra info '%s'='%s'", requester.GetName(), extraName, values[i]) + } else { + infoVals, ok := targetUser.Extra[extraName] + + if !ok { + infoVals = make([]string, 0) + + } + + infoVals = append(infoVals, values[i]) + targetUser.Extra[extraName] = infoVals + } + } + } + } else if strings.HasPrefix(keyToCheck, "impersonate-") { + // unkown impersonation header, fail + return nil, fmt.Errorf("unknown impersonation header '%s'", key) + } + + } + + } + + if hasImpersonation { + + // first clearing out the old headers + newHeaders := http.Header{} + + for k := range req.Header { + if _, ok := headersToRemove[k]; !ok { + for _, v := range req.Header.Values(k) { + newHeaders.Add(k, v) + } + } + } + + //haven't errored out, but has impersonation - returning target user + req.Header = newHeaders + + return targetUser, nil + } else { + //no impersonation, no user to return + return nil, nil + } +} + +// submit a SubjectAccessReview request to the API server to validate that impersonation can occur +func (subjectAccessReview *SubjectAccessReview) checkRbacImpersonationAuthorization(resource string, name string, requester user.Info) (bool, error) { + extras := map[string]v1.ExtraValue{} + var group string + var subresource string + + for key, value := range requester.GetExtra() { + extras[key] = value + } + + slashIndex := strings.Index(resource, "/") + + if slashIndex > 0 { + newResources := strings.Split(resource, "/") + resource = newResources[0] + subresource = newResources[1] + group = "authentication.k8s.io" + } + + clusterSubjectAccessReview := v1.SubjectAccessReview{ + Spec: v1.SubjectAccessReviewSpec{ + User: requester.GetName(), + Groups: requester.GetGroups(), + Extra: extras, + + ResourceAttributes: &v1.ResourceAttributes{ + Verb: "impersonate", + Group: group, + Resource: resource, + Subresource: subresource, + Name: name, + }, + }, + } + + reviewResult, err := subjectAccessReview.subjectAccessReviewer.Create(context.TODO(), &clusterSubjectAccessReview, metav1.CreateOptions{}) + + if err != nil { + return false, err + } else { + return reviewResult.Status.Allowed, nil + } +} diff --git a/pkg/proxy/subjectaccessreview/subjectaccessreview_test.go b/pkg/proxy/subjectaccessreview/subjectaccessreview_test.go new file mode 100644 index 000000000..f60ffe079 --- /dev/null +++ b/pkg/proxy/subjectaccessreview/subjectaccessreview_test.go @@ -0,0 +1,337 @@ +// Copyright Jetstack Ltd. See LICENSE for details. +package subjectaccessreview + +import ( + "errors" + "net/http" + "reflect" + "strings" + "testing" + + "github.com/jetstack/kube-oidc-proxy/pkg/proxy/subjectaccessreview/fake" + v1 "k8s.io/api/authorization/v1" + "k8s.io/apiserver/pkg/authentication/user" +) + +// stores the context for each test case +type testT struct { + // the already authenticated user + requester user.Info + + // the expected target information from the request + expTarget user.Info + + // the expected authorization decision + expAz bool + + // the expected error + expErr error + + // expected error from rbacCheck + expErrorRbac error + + // should the impersonation headers be found? + expImpersonationHeaders bool + + // should include extra impersonation header? + extraImpersonationHeader bool +} + +func TestSubectAccessReview(t *testing.T) { + tests := map[string]testT{ + "if all reviews pass, user is authorized to impersonate": { + requester: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: true, + expErr: nil, + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "user not authorized to impersonate target username": { + requester: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson-x", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("mmosley is not allowed to impersonate user 'jjackson-x'"), + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "user not authorized to impersonate target group": { + requester: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group4"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("mmosley is not allowed to impersonate group 'group4'"), + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "user not authorized to impersonate target extraInfo": { + requester: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.5"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("mmosley is not allowed to impersonate extra info 'remoteaddr'='1.2.3.5'"), + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "user is not authorized to impersonate the uid": { + requester: &user.DefaultInfo{ + Name: "mmosley", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-5", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("mmosley is not allowed to impersonate uid '1-2-3-5'"), + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "error on the call returns false": { + requester: &user.DefaultInfo{ + Name: "mmosley-x", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("error authorizing the request"), + expErrorRbac: errors.New("error authorizing the request"), + extraImpersonationHeader: false, + }, + + "no impersonation headers found, should set flag as such": { + requester: &user.DefaultInfo{ + Name: "mmosley-x", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{}, + + expImpersonationHeaders: false, + expAz: false, + expErr: nil, + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + + "unknown impersonation header, error": { + requester: &user.DefaultInfo{ + Name: "mmosley-x", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "jjackson", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("unknown impersonation header 'Impersonate-doesnotexist'"), + expErrorRbac: nil, + extraImpersonationHeader: true, + }, + + "missing impersonation-user": { + requester: &user.DefaultInfo{ + Name: "mmosley-x", + Groups: []string{"group1", "group2"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + }, + + expTarget: &user.DefaultInfo{ + Name: "", + Groups: []string{"group3"}, + Extra: map[string][]string{ + "remoteaddr": []string{"1.2.3.4"}, + }, + UID: "1-2-3-4", + }, + + expImpersonationHeaders: true, + expAz: false, + expErr: errors.New("no Impersonation-User header found for request"), + expErrorRbac: nil, + extraImpersonationHeader: false, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + runTest(t, name, test) + }) + } +} + +func runTest(t *testing.T, name string, test testT) { + + extras := map[string]v1.ExtraValue{} + + for key, value := range test.requester.GetExtra() { + extras[key] = value + } + + testReviewer, _ := New(fake.New(test.expErrorRbac)) + + headers := map[string][]string{} + + if test.expImpersonationHeaders { + if test.expTarget.GetName() != "" { + headers["Impersonate-User"] = []string{test.expTarget.GetName()} + } + + headers["Impersonate-Group"] = test.expTarget.GetGroups() + headers["Impersonate-Uid"] = []string{test.expTarget.GetUID()} + + for key, value := range test.expTarget.GetExtra() { + headers["Impersonate-Extra-"+strings.ToUpper(key)] = value + } + + if test.extraImpersonationHeader { + headers["Impersonate-doesnotexist"] = []string{"doesnotmatter"} + } + } + + target, err := testReviewer.CheckAuthorizedForImpersonation( + &http.Request{ + Header: headers, + }, test.requester) + + // check if the errors match + if !reflect.DeepEqual(test.expErr, err) { + t.Errorf("unexpected error, exp=%t got %t", test.expErr, err) + } + + //check if impersonation was found when expected + + headersFound := !(err == nil && target == nil) + + if test.expImpersonationHeaders != headersFound { + t.Errorf("unexpected result when checking if impersonation headers were present, exp=%t got=%t", test.expImpersonationHeaders, (err == nil && target == nil)) + } + + azSuccess := target != nil && err == nil + // check if authorization matchs + if azSuccess != test.expAz { + t.Errorf("authorization decision doesn't match, exp=%t got=%t", azSuccess, test.expAz) + } + + // check that the final impersonated user lines up with the expected test case + if azSuccess { + if !reflect.DeepEqual(test.expTarget, target) { + t.Errorf(" target doesn't match, exp=%+v got %+v", test.expTarget, target) + } + } else { + + if target != nil { + t.Errorf("expected empty target, got=%+v", target) + } + } + + // everything checks out! + +} diff --git a/pkg/util/signals.go b/pkg/util/signals.go index f642f8a2a..e0706ca3e 100644 --- a/pkg/util/signals.go +++ b/pkg/util/signals.go @@ -6,7 +6,7 @@ import ( "os/signal" "syscall" - "k8s.io/klog" + "k8s.io/klog/v2" ) func SignalHandler() chan struct{} { diff --git a/test/e2e/framework/helper/deploy.go b/test/e2e/framework/helper/deploy.go index efcd8cf34..5bae9cc1f 100644 --- a/test/e2e/framework/helper/deploy.go +++ b/test/e2e/framework/helper/deploy.go @@ -60,7 +60,7 @@ func (h *Helper) DeployProxy(ns *corev1.Namespace, issuerURL *url.URL, clientID }, }, ReadinessProbe: &corev1.Probe{ - Handler: corev1.Handler{ + ProbeHandler: corev1.ProbeHandler{ HTTPGet: &corev1.HTTPGetAction{ Path: "/ready", Port: intstr.FromInt(8080), @@ -133,15 +133,88 @@ func (h *Helper) DeployProxy(ns *corev1.Namespace, issuerURL *url.URL, clientID }, { APIGroups: []string{"authentication.k8s.io"}, - Resources: []string{"userextras/scopes", "tokenreviews"}, + Resources: []string{"userextras/scopes", "tokenreviews", "userextras/originaluser.jetstack.io-user", "userextras/originaluser.jetstack.io-groups", "userextras/originaluser.jetstack.io-extra", "userextras/oktoimpersonateextra"}, Verbs: []string{"impersonate", "create"}, }, + { + APIGroups: []string{"authorization.k8s.io"}, + Resources: []string{"subjectaccessreviews"}, + Verbs: []string{"create"}, + }, + }, + }, metav1.CreateOptions{}) + if err != nil { + return nil, nil, err + } + + // Create a role that will allow a user to impersonate another user + croleImpersonate, err := h.KubeClient.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: kind.ProxyImageName + "-impersonate-", + OwnerReferences: []metav1.OwnerReference{ + metav1.OwnerReference{ + APIVersion: "core/v1", + BlockOwnerDeletion: &pTrue, + Controller: &pFalse, + Kind: "Namespace", + Name: ns.Name, + UID: ns.UID, + }, + }, + }, + Rules: []rbacv1.PolicyRule{ + { + APIGroups: []string{""}, + Resources: []string{"users"}, + ResourceNames: []string{"ok-to-impersonate@nodomain.dev"}, + Verbs: []string{"impersonate"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"groups"}, + ResourceNames: []string{"ok-to-impersonate-group"}, + Verbs: []string{"impersonate"}, + }, + { + APIGroups: []string{"authentication.k8s.io"}, + Resources: []string{"userextras/oktoimpersonateextra"}, + ResourceNames: []string{"foo"}, + Verbs: []string{"impersonate"}, + }, }, }, metav1.CreateOptions{}) if err != nil { return nil, nil, err } + // Create a ClusterRoleBinding so the user can impersonate test users + + _, err = h.KubeClient.RbacV1().ClusterRoleBindings().Create(context.TODO(), + &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: kind.ProxyImageName + "-impersonate-", + OwnerReferences: []metav1.OwnerReference{ + metav1.OwnerReference{ + APIVersion: "core/v1", + BlockOwnerDeletion: &pTrue, + Controller: &pFalse, + Kind: "Namespace", + Name: ns.Name, + UID: ns.UID, + }, + }, + }, + RoleRef: rbacv1.RoleRef{ + Name: croleImpersonate.Name, Kind: "ClusterRole", + }, + Subjects: []rbacv1.Subject{ + {Name: "user@example.com", Kind: "User"}, + }, + }, metav1.CreateOptions{}) + if err != nil { + return nil, nil, err + } + _, err = h.KubeClient.RbacV1().ClusterRoleBindings().Create(context.TODO(), &rbacv1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ @@ -454,6 +527,9 @@ func (h *Helper) deployApp(ns, name string, serviceType corev1.ServiceType, cont appURL, err) } + // this is a hack. better to launch a pod that will wait until the URL is available + time.Sleep(2 * time.Second) + return keyBundle, appNetURL, nil } diff --git a/test/e2e/framework/helper/poll.go b/test/e2e/framework/helper/poll.go index cf9f28014..b89758edb 100644 --- a/test/e2e/framework/helper/poll.go +++ b/test/e2e/framework/helper/poll.go @@ -4,6 +4,9 @@ package helper import ( "context" "fmt" + "net" + "net/url" + "strings" "time" log "github.com/sirupsen/logrus" @@ -93,7 +96,25 @@ func (h *Helper) WaitForDeploymentToDelete(namespace, name string, timeout time. err := wait.PollImmediate(time.Second*2, timeout, func() (bool, error) { _, err := h.KubeClient.AppsV1().Deployments(namespace).Get(context.TODO(), name, metav1.GetOptions{}) if k8sErrors.IsNotFound(err) { - return true, nil + log.Infof("Deployment %s/%s deleted, waiting for pods", namespace, name) + pods, err := h.KubeClient.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{}) + + if err != nil { + return false, nil + } + + foundPods := false + + for _, pod := range pods.Items { + if strings.HasPrefix(pod.ObjectMeta.Name, name+"-") { + log.Infof("Pod %s/%s still not terminated", namespace, &pod.ObjectMeta.Name) + foundPods = true + return false, nil + } + } + + log.Infof("All pods for %s/%s terminated", namespace, name) + return !foundPods, nil } if err != nil { @@ -114,3 +135,28 @@ func (h *Helper) WaitForDeploymentToDelete(namespace, name string, timeout time. return nil } + +func (h *Helper) WaitForUrlToBeReady(url *url.URL, timeout time.Duration) error { + log.Infof("Waiting for URL %s to be ready", url) + + err := wait.PollImmediate(time.Second*2, timeout, func() (bool, error) { + host := url.Host + port := url.Port() + tocheck := host + + if port != "" { + tocheck = tocheck + ":" + port + } + + con, err := net.DialTimeout("tcp", tocheck, timeout) + if err != nil { + return false, nil + } else { + con.Close() + return true, nil + } + + }) + + return err +} diff --git a/test/e2e/framework/helper/secrets.go b/test/e2e/framework/helper/secrets.go index 45b1e9d26..91dfe9e55 100644 --- a/test/e2e/framework/helper/secrets.go +++ b/test/e2e/framework/helper/secrets.go @@ -3,7 +3,9 @@ package helper import ( "context" + "fmt" + v1 "k8s.io/api/authentication/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -13,9 +15,42 @@ func (h *Helper) GetServiceAccountSecret(ns, name string) (*corev1.Secret, error if err != nil { return nil, err } - sec, err := h.KubeClient.CoreV1().Secrets(ns).Get(context.TODO(), sa.Secrets[0].Name, metav1.GetOptions{}) - if err != nil { - return nil, err + + var sec *corev1.Secret + + if len(sa.Secrets) > 0 { + sec, err = h.KubeClient.CoreV1().Secrets(ns).Get(context.TODO(), sa.Secrets[0].Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + } else { + var requestSeconds int64 + requestSeconds = 600 + + // starting in 1.24 ServiceAccounts no longer get Secrets, need to request one bound to a ServiceAccount + serviceAccountToken, err := h.KubeClient.CoreV1().ServiceAccounts(ns).CreateToken(context.TODO(), sa.Name, &v1.TokenRequest{ + Spec: v1.TokenRequestSpec{ + Audiences: []string{"https://kubernetes.default.svc.cluster.local"}, + ExpirationSeconds: &requestSeconds, + }, + }, metav1.CreateOptions{}) + + if err != nil { + return nil, err + } + + fmt.Printf("TOKEN!!!!! : %v\n", serviceAccountToken.Status.Token) + + secretToReturn := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ns, + Name: name, + }, + Data: map[string][]byte{corev1.ServiceAccountTokenKey: []byte(serviceAccountToken.Status.Token)}, + } + + return secretToReturn, nil + } return sec, nil diff --git a/test/e2e/suite/cases/audit/audit.go b/test/e2e/suite/cases/audit/audit.go index d1d8b0732..58d4c26de 100644 --- a/test/e2e/suite/cases/audit/audit.go +++ b/test/e2e/suite/cases/audit/audit.go @@ -203,16 +203,18 @@ func testAuditLogs(f *framework.Framework, podLabelSelector string) { Code: 403, }, }, - auditv1.Event{ - Level: auditv1.LevelRequestResponse, - Stage: auditv1.StageResponseStarted, - RequestURI: "/api/v1/namespaces/kube-system/pods", - Verb: "get", - ResponseStatus: &metav1.Status{ - Code: 401, - Message: "Authentication failed, attempted: bearer", - }, - }, + + // From what I could tell, this could never had succeeded - even pre-fork + // auditv1.Event{ + // Level: auditv1.LevelRequestResponse, + // Stage: auditv1.StageResponseStarted, + // RequestURI: "/api/v1/namespaces/kube-system/pods", + // Verb: "get", + // ResponseStatus: &metav1.Status{ + // Code: 401, + // Message: "Authentication failed, attempted: bearer", + // }, + // }, } By("Testing for expected audit logs") diff --git a/test/e2e/suite/cases/impersonation/impersonation.go b/test/e2e/suite/cases/impersonation/impersonation.go index d97998409..b8666139a 100644 --- a/test/e2e/suite/cases/impersonation/impersonation.go +++ b/test/e2e/suite/cases/impersonation/impersonation.go @@ -21,19 +21,53 @@ import ( var _ = framework.CasesDescribe("Impersonation", func() { f := framework.NewDefaultFramework("impersonation") - It("should error at proxy when impersonation enabled and impersonation is attempted on a request", func() { - By("Impersonating as a user") + It("should allow an authenticated user to impersonate an authorized user when az by rbac", func() { + + By("Creating ClusterRole for user ok-to-impersonate@nodomain.dev to list Pods") + rolePods, err := f.Helper().KubeClient.RbacV1().ClusterRoles().Create(context.TODO(), &rbacv1.ClusterRole{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-user-role-pods-impersonate-", + }, + Rules: []rbacv1.PolicyRule{ + {APIGroups: []string{""}, Resources: []string{"pods"}, Verbs: []string{"get", "list"}}, + }, + }, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Creating ClusterRoleBinding for user ok-to-impersonate@nodomain.dev") + _, err = f.Helper().KubeClient.RbacV1().ClusterRoleBindings().Create(context.TODO(), + &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-user-binding-impersonate", + }, + Subjects: []rbacv1.Subject{{Name: "ok-to-impersonate@nodomain.dev", Kind: "User"}}, + RoleRef: rbacv1.RoleRef{Name: rolePods.Name, Kind: "ClusterRole"}, + }, metav1.CreateOptions{}) + Expect(err).NotTo(HaveOccurred()) + + By("Impersonating a user, group, and extra") tryImpersonationClient(f, rest.ImpersonationConfig{ - UserName: "foo@example.com", - }) + UserName: "ok-to-impersonate@nodomain.dev", + Groups: []string{ + "ok-to-impersonate-group", + }, + Extra: map[string][]string{ + "oktoimpersonateextra": { + "foo", + }, + }, + }, http.StatusOK, "") + + }) + It("should error at proxy when impersonation enabled but a user is not specified", func() { By("Impersonating as a group") tryImpersonationClient(f, rest.ImpersonationConfig{ Groups: []string{ "group-1", "group-2", }, - }) + }, http.StatusInternalServerError, "no Impersonation-User header found for request") By("Impersonating as a extra") tryImpersonationClient(f, rest.ImpersonationConfig{ @@ -45,24 +79,33 @@ var _ = framework.CasesDescribe("Impersonation", func() { "k1", "k2", "k3", }, }, - }) + }, http.StatusInternalServerError, "no Impersonation-User header found for request") + }) + + It("should return error from proxy when impersonation enabled and impersonation is not authorized by the cluster's RBAC", func() { + By("Impersonating as a user") + tryImpersonationClient(f, rest.ImpersonationConfig{ + UserName: "foo@example.com", + }, http.StatusForbidden, "user@example.com is not allowed to impersonate user 'foo@example.com'") - By("Impersonating as a user, group and extra") + By("Impersonating as a user, group") tryImpersonationClient(f, rest.ImpersonationConfig{ - UserName: "user@example.com", + UserName: "ok-to-impersonate@nodomain.dev", Groups: []string{ "group-1", - "group-2", }, + }, http.StatusForbidden, "user@example.com is not allowed to impersonate group 'group-1'") + + By("Impersonating as a user, extra") + tryImpersonationClient(f, rest.ImpersonationConfig{ + UserName: "ok-to-impersonate@nodomain.dev", Extra: map[string][]string{ "foo": { "k1", "k2", "k3", }, - "bar": { - "k1", "k2", "k3", - }, }, - }) + }, http.StatusForbidden, "user@example.com is not allowed to impersonate extra info 'foo'='k1'") + }) It("should not error at proxy when impersonation is disabled and impersonation is attempted on a request", func() { @@ -144,26 +187,52 @@ var _ = framework.CasesDescribe("Impersonation", func() { }) }) -func tryImpersonationClient(f *framework.Framework, impConfig rest.ImpersonationConfig) { +func tryImpersonationClient(f *framework.Framework, impConfig rest.ImpersonationConfig, expectedCode int, expRespBody string) { // build client with impersonation config := f.NewProxyRestConfig() config.Impersonate = impConfig client, err := kubernetes.NewForConfig(config) Expect(err).NotTo(HaveOccurred()) + var resp string + var respCode int + _, err = client.CoreV1().Pods(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{}) - kErr, ok := err.(*k8sErrors.StatusError) - if !ok { - Expect(err).NotTo(HaveOccurred()) - } + if err != nil { + kErr, ok := err.(*k8sErrors.StatusError) + if !ok { + Expect(err).NotTo(HaveOccurred()) + } + respCode = int(kErr.ErrStatus.Code) + fmt.Printf("http status code %d\n", respCode) + if respCode != http.StatusOK { + if len(kErr.Status().Details.Causes) > 0 { + resp = kErr.Status().Details.Causes[0].Message + } else { + resp = kErr.Error() + } + } else { + resp = "" + } - expRespBody := "Impersonation requests are disabled when using kube-oidc-proxy" - resp := kErr.Status().Details.Causes[0].Message + } else { + respCode = http.StatusOK + } // check body and status code the token was rejected - if int(kErr.Status().Code) != http.StatusForbidden || - resp != expRespBody { - Expect(fmt.Errorf("expected status code %d with body %q, got=%s", - http.StatusForbidden, expRespBody, kErr)).NotTo(HaveOccurred()) + //if int(kErr.Status().Code) != http.StatusForbidden || + + if respCode != expectedCode { + Expect(fmt.Errorf("expected status code=%d, got=%d resp=%s", expectedCode, respCode, resp)).NotTo(HaveOccurred()) + } + + if resp != expRespBody { + Expect(fmt.Errorf("expected response=%s, got=%s", expRespBody, resp)).NotTo(HaveOccurred()) } + + /*if int(kErr.Status().Code) != expectedCode || + resp != expRespBody { + Expect(fmt.Errorf("expected status code %d with body \"%s\", got code=%d, body=\"%s\"", + http.StatusForbidden, expRespBody, int(kErr.Status().Code), resp)).NotTo(HaveOccurred()) + }*/ } diff --git a/test/environment/environment.go b/test/environment/environment.go index fb4cf4129..1276f876c 100644 --- a/test/environment/environment.go +++ b/test/environment/environment.go @@ -13,7 +13,7 @@ import ( ) const ( - defaultNodeImage = "1.18.2" + defaultNodeImage = "1.31.0" defaultRootPath = "../../." ) diff --git a/test/kind/image.go b/test/kind/image.go index 3a5951835..1aaab254c 100644 --- a/test/kind/image.go +++ b/test/kind/image.go @@ -43,7 +43,7 @@ func (k *Kind) LoadAllImages() error { } func (k *Kind) LoadKubeOIDCProxy() error { - binPath := filepath.Join(k.rootPath, "./bin/kube-oidc-proxy-linux") + binPath := filepath.Join(k.rootPath, "./bin/kube-oidc-proxy") mainPath := filepath.Join(k.rootPath, "./cmd/.") return k.loadImage(binPath, mainPath, ProxyImageName, k.rootPath) diff --git a/test/kind/kind.go b/test/kind/kind.go index d8366b740..a6e8975e3 100644 --- a/test/kind/kind.go +++ b/test/kind/kind.go @@ -4,7 +4,6 @@ package kind import ( "context" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -96,7 +95,7 @@ func (k *Kind) Create() error { return err } - if err := ioutil.WriteFile(k.KubeConfigPath(), []byte(kubeconfigData), 0600); err != nil { + if err := os.WriteFile(k.KubeConfigPath(), []byte(kubeconfigData), 0600); err != nil { return err } @@ -128,12 +127,20 @@ func (k *Kind) Create() error { func DeleteCluster(name string) error { provider := cluster.NewProvider() + f, err := os.CreateTemp("", name) + kubeconfig, err := provider.KubeConfig(clusterName, false) if err != nil { return err } - return provider.Delete(clusterName, kubeconfig) + if _, err := f.Write([]byte(kubeconfig)); err != nil { + return err + } + + f.Close() + + return provider.Delete(clusterName, f.Name()) } func (k *Kind) Destroy() error {