mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-01-30 09:32:26 +00:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c5214724b | ||
|
|
b2e3f84156 | ||
|
|
a58649faa6 | ||
|
|
a4883507b5 | ||
|
|
461e272d79 | ||
|
|
981004eec4 | ||
|
|
0332362598 | ||
|
|
f519b271d2 | ||
|
|
be7a4f781f | ||
|
|
0e3c815e9b | ||
|
|
3b4147f90e | ||
|
|
3b10cc3097 | ||
|
|
d8ec87d0e1 | ||
|
|
cdd38dd55e | ||
|
|
236a7cf3fb | ||
|
|
3e74b38a95 | ||
|
|
a05acadf80 | ||
|
|
c5d1f380d2 | ||
|
|
9883b4e236 | ||
|
|
348187d2f4 | ||
|
|
86ee66d21d | ||
|
|
2198b4820a | ||
|
|
4b7b9e4362 | ||
|
|
70f2bbf4f8 | ||
|
|
7a3efb9981 | ||
|
|
e1954b1df9 | ||
|
|
37c2ce53d7 | ||
|
|
9d3773e58a | ||
|
|
aa651973fc | ||
|
|
745852ef2e | ||
|
|
ca5ad85bbd | ||
|
|
8296093beb | ||
|
|
6d79fe5f4c | ||
|
|
ef6369d71e | ||
|
|
7616799adb | ||
|
|
dea3513125 | ||
|
|
5f4645d505 | ||
|
|
c439cc03a2 | ||
|
|
2603bbfcd6 | ||
|
|
dc1d563549 | ||
|
|
416a66f68a | ||
|
|
8f2da915aa | ||
|
|
aad74158ba | ||
|
|
98dde187bb | ||
|
|
ab71450c69 | ||
|
|
a4789e2b2c | ||
|
|
1c2829a326 | ||
|
|
9be8cd40d2 | ||
|
|
90a3538806 | ||
|
|
b68e7f3e9e | ||
|
|
4f15fc2123 | ||
|
|
2bc6c15d25 | ||
|
|
a740fb34c5 | ||
|
|
be1416b7b5 | ||
|
|
aad8dc50e7 | ||
|
|
47f6de58c3 | ||
|
|
61c630caf0 | ||
|
|
2985d55edf | ||
|
|
4f794571a2 | ||
|
|
d5ae3da893 | ||
|
|
80d5f42b57 | ||
|
|
d5aa682cbc | ||
|
|
b61557d3c3 | ||
|
|
d4e2622ea8 | ||
|
|
88a97033fb | ||
|
|
c4f9869e7c | ||
|
|
c455a17abe | ||
|
|
9a632134ae | ||
|
|
1b540181a7 | ||
|
|
1f8aa6c262 | ||
|
|
46bea27cb7 | ||
|
|
98bd12241d | ||
|
|
c3410c4b14 | ||
|
|
1e9f9181a1 | ||
|
|
07e9c5bd93 | ||
|
|
e10d21d678 | ||
|
|
e3d9eb7d82 | ||
|
|
97f6e8a07b | ||
|
|
865ef8d447 | ||
|
|
0a342a803c | ||
|
|
120b35a617 | ||
|
|
3f92a546df | ||
|
|
132e39c8fd | ||
|
|
634654578f | ||
|
|
18f95d3d1e | ||
|
|
b38723ece2 | ||
|
|
bf1366412a | ||
|
|
a6f7e05d3d | ||
|
|
660b155eaa | ||
|
|
29e939db7f | ||
|
|
3c2d921300 | ||
|
|
d1e5a9aff3 | ||
|
|
54d4879c69 | ||
|
|
78aa45a970 | ||
|
|
3c33c59aa9 | ||
|
|
b9b4d31c6b | ||
|
|
0501159ac0 | ||
|
|
779b084b53 | ||
|
|
f90f2334ba | ||
|
|
a8c35c6f7e | ||
|
|
ced08aeaf7 | ||
|
|
9c5bc763ac | ||
|
|
dd0039e94c | ||
|
|
9d836c789f | ||
|
|
ef291bb790 | ||
|
|
d4e3cf51b7 | ||
|
|
247123965e | ||
|
|
097a1ac3d3 | ||
|
|
ec532f622f | ||
|
|
d73acd6896 | ||
|
|
0c4e3aa5f1 |
@@ -7,52 +7,52 @@ run:
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
# default linters
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
# default linters
|
||||
- errcheck
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- staticcheck
|
||||
- typecheck
|
||||
- unused
|
||||
|
||||
# additional linters for this project (we should disable these if they get annoying).
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- depguard
|
||||
- dogsled
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- goheader
|
||||
- goimports
|
||||
- revive
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- misspell
|
||||
- nakedret
|
||||
- nestif
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- rowserrcheck
|
||||
- exportloopref
|
||||
- sqlclosecheck
|
||||
- unconvert
|
||||
- whitespace
|
||||
# additional linters for this project (we should disable these if they get annoying).
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
# - depguard
|
||||
- dogsled
|
||||
- exhaustive
|
||||
- exportloopref
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocritic
|
||||
- gocyclo
|
||||
- godot
|
||||
- goheader
|
||||
- goimports
|
||||
- revive
|
||||
- goprintffuncname
|
||||
- gosec
|
||||
- misspell
|
||||
- nakedret
|
||||
- nestif
|
||||
- noctx
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- rowserrcheck
|
||||
- exportloopref
|
||||
- sqlclosecheck
|
||||
- unconvert
|
||||
- whitespace
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
# exclude tests from some rules for things that are useful in a testing context.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- funlen
|
||||
- gochecknoglobals
|
||||
|
||||
linters-settings:
|
||||
funlen:
|
||||
@@ -64,7 +64,15 @@ linters-settings:
|
||||
# YYYY or YYYY-YYYY
|
||||
YEARS: \d\d\d\d(-\d\d\d\d)?
|
||||
template: |-
|
||||
Copyright {{YEARS}} the Pinniped contributors. All Rights Reserved.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
Copyright {{YEARS}} the Pinniped contributors. All Rights Reserved.
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
goimports:
|
||||
local-prefixes: go.pinniped.dev
|
||||
revive:
|
||||
max-open-files: 2048
|
||||
rules:
|
||||
- name: unused-parameter
|
||||
arguments:
|
||||
# Allow unused params that start with underscore. It can be nice to keep unused param names when implementing
|
||||
# an interface sometimes, to help readers understand why it is unused in that particular implementation.
|
||||
- allowRegex: "^_"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exclude: '^(site|generated)/'
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
# TODO: find a version of this to validate ytt templates?
|
||||
# - id: check-yaml
|
||||
|
||||
@@ -3,8 +3,11 @@
|
||||
# Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
ARG BUILD_IMAGE=golang:1.21.5@sha256:2ff79bcdaff74368a9fdcb06f6599e54a71caf520fd2357a55feddd504bcaffb
|
||||
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:91ca4720011393f4d4cab3a01fa5814ee2714b7d40e6c74f2505f74168398ca9
|
||||
|
||||
# Prepare to cross-compile by always running the build stage in the build platform, not the target platform.
|
||||
FROM --platform=$BUILDPLATFORM golang:1.21.2 as build-env
|
||||
FROM --platform=$BUILDPLATFORM $BUILD_IMAGE as build-env
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
@@ -36,7 +39,7 @@ RUN \
|
||||
# Note that we are not using --platform here, so it will choose the base image for the target platform, not the build platform.
|
||||
# By using "distroless/static" instead of "distroless/static-debianXX" we can float on the latest stable version of debian.
|
||||
# See https://github.com/GoogleContainerTools/distroless#base-operating-system
|
||||
FROM gcr.io/distroless/static:nonroot@sha256:2a9e2b4fa771d31fe3346a873be845bfc2159695b9f90ca08e950497006ccc2e
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# Copy the server binary from the build-env stage.
|
||||
COPY --from=build-env /usr/local/bin /usr/local/bin
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientauthv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
@@ -531,12 +530,9 @@ func TestLoginOIDCCommand(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
fakeClock := clocktesting.NewFakeClock(now)
|
||||
ctx := plog.TestZapOverrides(context.Background(), t, &buf, nil, zap.WithClock(plog.ZapClock(fakeClock)))
|
||||
ctx := plog.AddZapOverridesToContext(context.Background(), t, &buf, nil, clocktesting.NewFakeClock(now))
|
||||
|
||||
var (
|
||||
gotOptions []oidcclient.Option
|
||||
)
|
||||
var gotOptions []oidcclient.Option
|
||||
cmd := oidcLoginCommand(oidcLoginCommandDeps{
|
||||
lookupEnv: func(s string) (string, bool) {
|
||||
v, ok := tt.env[s]
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientauthv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
@@ -178,8 +177,7 @@ func TestLoginStaticCommand(t *testing.T) {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
fakeClock := clocktesting.NewFakeClock(now)
|
||||
ctx := plog.TestZapOverrides(context.Background(), t, &buf, nil, zap.WithClock(plog.ZapClock(fakeClock)))
|
||||
ctx := plog.AddZapOverridesToContext(context.Background(), t, &buf, nil, clocktesting.NewFakeClock(now))
|
||||
|
||||
cmd := staticLoginCommand(staticLoginDeps{
|
||||
lookupEnv: func(s string) (string, bool) {
|
||||
|
||||
@@ -31,6 +31,7 @@ func init() {
|
||||
|
||||
type whoamiFlags struct {
|
||||
outputFormat string // e.g., yaml, json, text
|
||||
timeout time.Duration
|
||||
|
||||
kubeconfigPath string
|
||||
kubeconfigContextOverride string
|
||||
@@ -58,6 +59,7 @@ func newWhoamiCommand(getClientset getConciergeClientsetFunc) *cobra.Command {
|
||||
f.StringVar(&flags.kubeconfigPath, "kubeconfig", os.Getenv("KUBECONFIG"), "Path to kubeconfig file")
|
||||
f.StringVar(&flags.kubeconfigContextOverride, "kubeconfig-context", "", "Kubeconfig context name (default: current active context)")
|
||||
f.StringVar(&flags.apiGroupSuffix, "api-group-suffix", groupsuffix.PinnipedDefaultSuffix, "Concierge API group suffix")
|
||||
f.DurationVar(&flags.timeout, "timeout", 0, "Timeout for the WhoAmI API request (default: 0, meaning no timeout)")
|
||||
|
||||
cmd.RunE = func(cmd *cobra.Command, _ []string) error {
|
||||
return runWhoami(cmd.OutOrStdout(), getClientset, flags)
|
||||
@@ -78,8 +80,22 @@ func runWhoami(output io.Writer, getClientset getConciergeClientsetFunc, flags *
|
||||
return fmt.Errorf("could not get current cluster info: %w", err)
|
||||
}
|
||||
|
||||
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*20)
|
||||
defer cancelFunc()
|
||||
// Making the WhoAmI request may cause client-go to invoke the credential plugin, which may
|
||||
// ask the user to interactively authenticate. The time that the user takes to authenticate
|
||||
// is included in the timeout time, but their authentication is not cancelled by exceeding
|
||||
// this timeout. Only the subsequent whoami API request is cancelled. Using a short timeout
|
||||
// causes the odd behavior of a successful login immediately followed by a whoami request failure
|
||||
// due to timeout. For comparison, kubectl uses an infinite timeout by default on API requests
|
||||
// but also allows the user to adjust this timeout with the `--request-timeout` CLI option,
|
||||
// so we will take a similar approach. Note that kubectl has the same behavior when a client-go
|
||||
// credential plugin is invoked and the user takes longer then the timeout to authenticate.
|
||||
ctx := context.Background()
|
||||
if flags.timeout > 0 {
|
||||
var cancelFunc context.CancelFunc
|
||||
ctx, cancelFunc = context.WithTimeout(ctx, flags.timeout)
|
||||
defer cancelFunc()
|
||||
}
|
||||
|
||||
whoAmI, err := clientset.IdentityV1alpha1().WhoAmIRequests().Create(ctx, &identityv1alpha1.WhoAmIRequest{}, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
hint := ""
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package cmd
|
||||
@@ -45,6 +45,7 @@ func TestWhoami(t *testing.T) {
|
||||
--kubeconfig string Path to kubeconfig file
|
||||
--kubeconfig-context string Kubeconfig context name (default: current active context)
|
||||
-o, --output string Output format (e.g., 'yaml', 'json', 'text') (default "text")
|
||||
--timeout duration Timeout for the WhoAmI API request (default: 0, meaning no timeout)
|
||||
`),
|
||||
},
|
||||
{
|
||||
@@ -312,7 +313,12 @@ func TestWhoami(t *testing.T) {
|
||||
stdout, stderr := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
|
||||
cmd.SetOut(stdout)
|
||||
cmd.SetErr(stderr)
|
||||
cmd.SetArgs(test.args)
|
||||
if test.args == nil {
|
||||
// cobra uses os.Args[1:] when SetArgs is called with nil, so avoid using nil for tests.
|
||||
cmd.SetArgs([]string{})
|
||||
} else {
|
||||
cmd.SetArgs(test.args)
|
||||
}
|
||||
|
||||
err := cmd.Execute()
|
||||
if test.wantError {
|
||||
|
||||
@@ -45,8 +45,9 @@ metadata:
|
||||
annotations:
|
||||
#! we need to create this service account before we create the secret
|
||||
kapp.k14s.io/change-group: "impersonation-proxy.concierge.pinniped.dev/serviceaccount"
|
||||
secrets: #! make sure the token controller does not create any other secrets
|
||||
- name: #@ defaultResourceNameWithSuffix("impersonation-proxy")
|
||||
kubernetes.io/enforce-mountable-secrets: "true"
|
||||
secrets: [] #! make sure the token controller does not create any secrets
|
||||
automountServiceAccountToken: false
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
@@ -77,6 +78,8 @@ data:
|
||||
impersonationCACertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-ca-certificate") @)
|
||||
impersonationSignerSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-signer-ca-certificate") @)
|
||||
agentServiceAccount: (@= defaultResourceNameWithSuffix("kube-cert-agent") @)
|
||||
impersonationProxyServiceAccount: (@= defaultResourceNameWithSuffix("impersonation-proxy") @)
|
||||
impersonationProxyLegacySecret: (@= defaultResourceNameWithSuffix("impersonation-proxy") @)
|
||||
labels: (@= json.encode(labels()).rstrip() @)
|
||||
kubeCertAgent:
|
||||
namePrefix: (@= defaultResourceNameWithSuffix("kube-cert-agent-") @)
|
||||
@@ -182,9 +185,6 @@ spec:
|
||||
- name: podinfo
|
||||
mountPath: /etc/podinfo
|
||||
readOnly: true
|
||||
- name: impersonation-proxy
|
||||
mountPath: /var/run/secrets/impersonation-proxy.concierge.pinniped.dev/serviceaccount
|
||||
readOnly: true
|
||||
env:
|
||||
#@ if data.values.https_proxy:
|
||||
- name: HTTPS_PROXY
|
||||
@@ -220,12 +220,6 @@ spec:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: #@ defaultResourceNameWithSuffix("config")
|
||||
- name: impersonation-proxy
|
||||
secret:
|
||||
secretName: #@ defaultResourceNameWithSuffix("impersonation-proxy")
|
||||
items: #! make sure our pod does not start until the token controller has a chance to populate the secret
|
||||
- key: token
|
||||
path: token
|
||||
- name: podinfo
|
||||
downwardAPI:
|
||||
items:
|
||||
@@ -347,17 +341,9 @@ spec:
|
||||
#@ if data.values.impersonation_proxy_spec.service.load_balancer_ip:
|
||||
loadBalancerIP: #@ data.values.impersonation_proxy_spec.service.load_balancer_ip
|
||||
#@ end
|
||||
#@ if data.values.impersonation_proxy_spec.service.annotations == None:
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "4000"
|
||||
#@ else:
|
||||
annotations: #@ data.values.impersonation_proxy_spec.service.annotations
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: #@ defaultResourceNameWithSuffix("impersonation-proxy")
|
||||
namespace: #@ namespace()
|
||||
labels: #@ labels()
|
||||
annotations:
|
||||
#! wait until the SA exists to create this secret so that the token controller does not delete it
|
||||
#! we have this secret at the end so that kubectl will create the service account first
|
||||
kapp.k14s.io/change-rule: "upsert after upserting impersonation-proxy.concierge.pinniped.dev/serviceaccount"
|
||||
kubernetes.io/service-account.name: #@ defaultResourceNameWithSuffix("impersonation-proxy")
|
||||
type: kubernetes.io/service-account-token
|
||||
#@ end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
#! SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#@ load("@ytt:data", "data")
|
||||
@@ -156,6 +156,13 @@ rules:
|
||||
- apiGroups: [ coordination.k8s.io ]
|
||||
resources: [ leases ]
|
||||
verbs: [ create, get, update ]
|
||||
#! We need to be able to get service accounts and create serviceaccounts/tokens so that we can create short-lived tokens for the impersonation proxy
|
||||
- apiGroups: [""]
|
||||
resources: [ serviceaccounts ]
|
||||
verbs: [ get ]
|
||||
- apiGroups: [""]
|
||||
resources: [ serviceaccounts/token ]
|
||||
verbs: [ create ]
|
||||
---
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
@@ -1,107 +1,227 @@
|
||||
#! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
#! SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#@data/values
|
||||
---
|
||||
#@ def validate_strings_map(obj):
|
||||
#@ # Returns True if obj is an associative data structure string→string, and False otherwise.
|
||||
#@ for key in obj:
|
||||
#@ if type(key) != "string" or type(obj[key]) != "string":
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ end
|
||||
#@ return True
|
||||
#@ end
|
||||
|
||||
#@data/values-schema
|
||||
---
|
||||
#@schema/title "App name"
|
||||
#@schema/desc "Used to help determine the names of various resources and labels."
|
||||
#@schema/validation min_len=1
|
||||
app_name: pinniped-concierge
|
||||
|
||||
#! Creates a new namespace statically in yaml with the given name and installs the app into that namespace.
|
||||
#@schema/title "Namespace"
|
||||
#@schema/desc "Creates a new namespace statically in yaml with the given name and installs the app into that namespace."
|
||||
#@schema/validation min_len=1
|
||||
namespace: pinniped-concierge
|
||||
#! If specified, assumes that a namespace of the given name already exists and installs the app into that namespace.
|
||||
#! If both `namespace` and `into_namespace` are specified, then only `into_namespace` is used.
|
||||
into_namespace: #! e.g. my-preexisting-namespace
|
||||
|
||||
#! All resources created statically by yaml at install-time and all resources created dynamically
|
||||
#! by controllers at runtime will be labelled with `app: $app_name` and also with the labels
|
||||
#! specified here. The value of `custom_labels` must be a map of string keys to string values.
|
||||
#! The app can be uninstalled either by:
|
||||
#! 1. Deleting the static install-time yaml resources including the static namespace, which will cascade and also delete
|
||||
#! resources that were dynamically created by controllers at runtime
|
||||
#! 2. Or, deleting all resources by label, which does not assume that there was a static install-time yaml namespace.
|
||||
custom_labels: {} #! e.g. {myCustomLabelName: myCustomLabelValue, otherCustomLabelName: otherCustomLabelValue}
|
||||
#@schema/title "Into namespace"
|
||||
#@ into_namespace_desc = "If specified, assumes that a namespace of the given name already exists and installs the app into that namespace. \
|
||||
#@ If both `namespace` and `into_namespace` are specified, then only `into_namespace` is used."
|
||||
#@schema/desc into_namespace_desc
|
||||
#@schema/examples ("The name of an existing namespace", "my-preexisting-namespace")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
into_namespace: ""
|
||||
|
||||
#! Specify how many replicas of the Pinniped server to run.
|
||||
#@schema/title "Custom labels"
|
||||
#@ custom_labels_desc = "All resources created statically by yaml at install-time and all resources created dynamically \
|
||||
#@ by controllers at runtime will be labelled with `app: $app_name` and also with the labels specified here. The value of \
|
||||
#@ `custom_labels` must be a map of string keys to string values. The app can be uninstalled either by: 1.) deleting the \
|
||||
#@ static install-time yaml resources including the static namespace, which will cascade and also delete \
|
||||
#@ resources that were dynamically created by controllers at runtime, or 2.) deleting all resources by label, which does \
|
||||
#@ not assume that there was a static install-time yaml namespace."
|
||||
#@schema/desc custom_labels_desc
|
||||
#@schema/examples ("Example set of labels", {"myCustomLabelName": "myCustomLabelValue", "otherCustomLabelName": "otherCustomLabelValue"})
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("a map of string keys and string values", validate_strings_map)
|
||||
custom_labels: { }
|
||||
|
||||
#@schema/title "Replicas"
|
||||
#@schema/desc "Specify how many replicas of the Pinniped server to run."
|
||||
replicas: 2
|
||||
|
||||
#! Specify either an image_digest or an image_tag. If both are given, only image_digest will be used.
|
||||
#@schema/title "Image repo"
|
||||
#@schema/desc "The repository for the Concierge container image."
|
||||
#@schema/validation min_len=1
|
||||
image_repo: projects.registry.vmware.com/pinniped/pinniped-server
|
||||
image_digest: #! e.g. sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8
|
||||
|
||||
#@schema/title "Image digest"
|
||||
#@schema/desc "The image digest for the Concierge container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Providing a digest", "sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_tag"] == None
|
||||
image_digest: ""
|
||||
|
||||
#@schema/title "Image tag"
|
||||
#@schema/desc "The image tag for the Concierge container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Providing a tag", "v0.25.0")
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_digest"] == None
|
||||
image_tag: latest
|
||||
|
||||
#! Optionally specify a different image for the "kube-cert-agent" pod which is scheduled
|
||||
#! on the control plane. This image needs only to include `sleep` and `cat` binaries.
|
||||
#! By default, the same image specified for image_repo/image_digest/image_tag will be re-used.
|
||||
kube_cert_agent_image:
|
||||
#@schema/title "Kube Cert Agent image"
|
||||
#@ kube_cert_agent_image = "Optionally specify a different image for the 'kube-cert-agent' pod which is scheduled \
|
||||
#@ on the control plane. This image needs only to include `sleep` and `cat` binaries. \
|
||||
#@ By default, the same image specified for image_repo/image_digest/image_tag will be re-used."
|
||||
#@schema/desc kube_cert_agent_image
|
||||
#@schema/examples ("Image including tag or digest", "projects.registry.vmware.com/pinniped/pinniped-server:latest")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
kube_cert_agent_image: ""
|
||||
|
||||
#! Specifies a secret to be used when pulling the above `image_repo` container image.
|
||||
#! Can be used when the above image_repo is a private registry.
|
||||
#! Typically the value would be the output of: kubectl create secret docker-registry x --docker-server=https://example.io --docker-username="USERNAME" --docker-password="PASSWORD" --dry-run=client -o json | jq -r '.data[".dockerconfigjson"]'
|
||||
#! Optional.
|
||||
image_pull_dockerconfigjson: #! e.g. {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}
|
||||
#@schema/title "Image pull dockerconfigjson"
|
||||
#@ image_pull_dockerconfigjson_desc = "A base64 encoded secret to be used when pulling the `image_repo` container image. \
|
||||
#@ Can be used when the image_repo is a private registry. Typically, the value would be the output of: \
|
||||
#@ kubectl create secret docker-registry x --docker-server=https://example.io --docker-username='USERNAME' --docker-password='PASSWORD' --dry-run=client -o json | jq -r '.data[\".dockerconfigjson\"]'"
|
||||
#@schema/desc image_pull_dockerconfigjson_desc
|
||||
#@ example_desc = 'base64 encoding of: {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}'
|
||||
#@ example_value = "eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUuaW8iOnsidXNlcm5hbWUiOiJVU0VSTkFNRSIsInBhc3N3b3JkIjoiUEFTU1dPUkQiLCJhdXRoIjoiVlZORlVrNUJUVVU2VUVGVFUxZFBVa1E9In19fQ=="
|
||||
#@schema/examples (example_desc, example_value)
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
image_pull_dockerconfigjson: ""
|
||||
|
||||
#! Pinniped will try to guess the right K8s API URL for sharing that information with potential clients.
|
||||
#! This setting allows the guess to be overridden.
|
||||
#! Optional.
|
||||
discovery_url: #! e.g., https://example.com
|
||||
#@schema/title "Discovery URL"
|
||||
#@schema/desc "Pinniped will try to guess the right K8s API URL for sharing that information with potential clients. This setting allows the guess to be overridden."
|
||||
#@schema/examples ("Kubernetes API URL","https://example.com")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
discovery_url: ""
|
||||
|
||||
#! Specify the duration and renewal interval for the API serving certificate.
|
||||
#! The defaults are set to expire the cert about every 30 days, and to rotate it
|
||||
#! about every 25 days.
|
||||
#@schema/title "API serving certificate duration seconds"
|
||||
#@ api_serving_certificate_duration_seconds_desc = "Specify the duration for the API serving certificate. \
|
||||
#@ The default is set to expire the cert about every 30 days. \
|
||||
#@ Specify this as an integer or as a string which contains an integer value."
|
||||
#@schema/desc api_serving_certificate_duration_seconds_desc
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("an int or string which contains an integer value", lambda v: type(v) in ["int", "string"])
|
||||
api_serving_certificate_duration_seconds: 2592000
|
||||
|
||||
#@schema/title "API serving certificate renew before seconds"
|
||||
#@ api_serving_certificate_renew_before_seconds_desc = "Specify the renewal interval for the API serving certificate. \
|
||||
#@ The default is set to rotate it about every 25 days. \
|
||||
#@ Specify this as an integer or as a string which contains an integer value."
|
||||
#@schema/desc api_serving_certificate_renew_before_seconds_desc
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("an int or string which contains an integer value", lambda v: type(v) in ["int", "string"])
|
||||
api_serving_certificate_renew_before_seconds: 2160000
|
||||
|
||||
#! Specify the verbosity of logging: info ("nice to know" information), debug (developer
|
||||
#! information), trace (timing information), all (kitchen sink).
|
||||
log_level: #! By default, when this value is left unset, only warnings and errors are printed. There is no way to suppress warning and error logs.
|
||||
#! Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs).
|
||||
#! By default, when this value is left unset, logs are formatted in json.
|
||||
#! This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json.
|
||||
deprecated_log_format:
|
||||
#@schema/title "Log level"
|
||||
#@ log_level_desc = "Specify the verbosity of logging: info (\"nice to know\" information), debug (developer information), trace (timing information), \
|
||||
#@ or all (kitchen sink). Do not use trace or all on production systems, as credentials may get logged. \
|
||||
#@ When this value is left unset, only warnings and errors are printed. There is no way to suppress warning and error logs."
|
||||
#@schema/desc log_level_desc
|
||||
#@schema/examples ("Developer logging information","debug")
|
||||
#@schema/nullable
|
||||
#@schema/validation one_of=["info", "debug", "trace", "all"]
|
||||
log_level: ""
|
||||
|
||||
run_as_user: 65532 #! run_as_user specifies the user ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
run_as_group: 65532 #! run_as_group specifies the group ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
#@schema/title "Log format"
|
||||
#@ deprecated_log_format_desc = "Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs). \
|
||||
#@ By default, when this value is left unset, logs are formatted in json. \
|
||||
#@ This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
|
||||
#@schema/desc deprecated_log_format_desc
|
||||
#@schema/examples ("Set logs to JSON format","json")
|
||||
#@schema/nullable
|
||||
#@schema/validation one_of=["json", "text"]
|
||||
#@schema/deprecated "This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
|
||||
deprecated_log_format: ""
|
||||
|
||||
#! Specify the API group suffix for all Pinniped API groups. By default, this is set to
|
||||
#! pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev,
|
||||
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
|
||||
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
|
||||
#@schema/title "Run as user"
|
||||
#@schema/desc "The user ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_user: 65532
|
||||
|
||||
#@schema/title "Run as group"
|
||||
#@schema/desc "The group ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_group: 65532
|
||||
|
||||
#@schema/title "API group suffix"
|
||||
#@ api_group_suffix_desc = "Specify the API group suffix for all Pinniped API groups. By default, this is set to \
|
||||
#@ pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev, \
|
||||
#@ authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then \
|
||||
#@ Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc."
|
||||
#@schema/desc api_group_suffix_desc
|
||||
#@schema/validation min_len=1
|
||||
api_group_suffix: pinniped.dev
|
||||
|
||||
#! Customize CredentialIssuer.spec.impersonationProxy to change how the concierge
|
||||
#! handles impersonation.
|
||||
#@schema/title "Impersonation proxy spec"
|
||||
#@schema/desc "Customize CredentialIssuer.spec.impersonationProxy to change how the concierge handles impersonation."
|
||||
impersonation_proxy_spec:
|
||||
#! options are "auto", "disabled" or "enabled".
|
||||
#! If auto, the impersonation proxy will run only if the cluster signing key is not available
|
||||
#! and the other strategy does not work.
|
||||
#! If disabled, the impersonation proxy will never run, which could mean that the concierge
|
||||
#! doesn't work at all.
|
||||
#! If enabled, the impersonation proxy will always run regardless of other strategies available.
|
||||
mode: auto
|
||||
#! The endpoint which the client should use to connect to the impersonation proxy.
|
||||
#! If left unset, the client will default to connecting based on the ClusterIP or LoadBalancer
|
||||
#! endpoint.
|
||||
external_endpoint:
|
||||
service:
|
||||
#! Options are "LoadBalancer", "ClusterIP" and "None".
|
||||
#! LoadBalancer automatically provisions a Service of type LoadBalancer pointing at
|
||||
#! the impersonation proxy. Some cloud providers will allocate
|
||||
#! a public IP address by default even on private clusters.
|
||||
#! ClusterIP automatically provisions a Service of type ClusterIP pointing at the
|
||||
#! impersonation proxy.
|
||||
#! None does not provision either and assumes that you have set the external_endpoint
|
||||
#! and set up your own ingress to connect to the impersonation proxy.
|
||||
type: LoadBalancer
|
||||
#! The annotations that should be set on the ClusterIP or LoadBalancer Service.
|
||||
annotations:
|
||||
{service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "4000"}
|
||||
#! When mode LoadBalancer is set, this will set the LoadBalancer Service's Spec.LoadBalancerIP.
|
||||
load_balancer_ip:
|
||||
|
||||
#! Set the standard golang HTTPS_PROXY and NO_PROXY environment variables on the Concierge containers.
|
||||
#! These will be used when the Concierge makes backend-to-backend calls to authenticators using HTTPS,
|
||||
#! e.g. when the Concierge fetches discovery documents, JWKS keys, and POSTs to token webhooks.
|
||||
#! The Concierge never makes insecure HTTP calls, so there is no reason to set HTTP_PROXY.
|
||||
#! Optional.
|
||||
https_proxy: #! e.g. http://proxy.example.com
|
||||
no_proxy: "$(KUBERNETES_SERVICE_HOST),169.254.169.254,127.0.0.1,localhost,.svc,.cluster.local" #! do not proxy Kubernetes endpoints
|
||||
#@schema/title "Mode"
|
||||
#@ impersonation_mode_desc = "Enables or disables the impersonation proxy. Options are 'auto', 'disabled' or 'enabled'. \
|
||||
#@ If auto, the impersonation proxy will run only if the cluster signing key is \
|
||||
#@ not available and the other strategy does not work. \
|
||||
#@ If enabled, the impersonation proxy will always run regardless of other strategies available. \
|
||||
#@ If disabled, the impersonation proxy will never run, which could mean \
|
||||
#@ that the concierge doesn't work at all."
|
||||
#@schema/desc impersonation_mode_desc
|
||||
#@schema/validation one_of=["auto", "disabled", "enabled"]
|
||||
mode: auto
|
||||
|
||||
#@schema/title "External endpoint"
|
||||
#@ external_endpoint_desc = "The endpoint which the client should use to connect to the impersonation proxy. \
|
||||
#@ If left unset, the client will default to connecting based on the ClusterIP or LoadBalancer endpoint."
|
||||
#@schema/desc external_endpoint_desc
|
||||
#@schema/examples ("Specified impersonation proxy endpoint", "https://1.2.3.4:5678")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
external_endpoint: ""
|
||||
|
||||
#@schema/title "Service"
|
||||
#@schema/desc "The impersonation proxy service configuration"
|
||||
service:
|
||||
|
||||
#@schema/title "Type"
|
||||
#@ impersonation_service_type_desc = "Service backing the impersonation proxy. Options are 'LoadBalancer', 'ClusterIP' \
|
||||
#@ and 'None'. LoadBalancer automatically provisions a Service of type LoadBalancer pointing at the impersonation \
|
||||
#@ proxy. Some cloud providers will allocate a public IP address by default even on private clusters. ClusterIP \
|
||||
#@ automatically provisions a Service of type ClusterIP pointing at the impersonation proxy. None does not provision \
|
||||
#@ either and assumes that you have set the external_endpoint and set up your own ingress to connect to the impersonation proxy."
|
||||
#@schema/desc impersonation_service_type_desc
|
||||
#@schema/validation one_of=["LoadBalancer", "ClusterIP", "None"]
|
||||
type: LoadBalancer
|
||||
|
||||
#@schema/title "Annotations"
|
||||
#@ annotations_desc = "The annotations that should be set on the ClusterIP or LoadBalancer Service. The default includes \
|
||||
#@ a value for the AWS-specific service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout annotation, which will \
|
||||
#@ be ignored except when using AWS to provide load balancer Services."
|
||||
#@schema/desc annotations_desc
|
||||
#@schema/nullable
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("a map of string keys and string values", validate_strings_map)
|
||||
annotations:
|
||||
|
||||
#@schema/title "Load balancer IP"
|
||||
#@schema/desc "When mode LoadBalancer is set, this will set the LoadBalancer Service's spec.loadBalancerIP."
|
||||
#@schema/examples ("Specifying an IP", "1.2.3.4")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
load_balancer_ip: ""
|
||||
|
||||
#@schema/title "HTTPS proxy"
|
||||
#@ https_proxy_desc = "Set the standard golang HTTPS_PROXY and NO_PROXY environment variables on the Concierge containers. \
|
||||
#@ These will be used when the Concierge makes backend-to-backend calls to authenticators using HTTPS, \
|
||||
#@ e.g. when the Concierge fetches discovery documents and JWKS keys for JWTAuthenticators and POSTs to webhooks for WebhookAuthenticators. \
|
||||
#@ The Concierge never makes insecure HTTP calls, so there is no reason to set HTTP_PROXY."
|
||||
#@schema/desc https_proxy_desc
|
||||
#@schema/examples ("Providing a proxy endpoint","http://proxy.example.com")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
https_proxy: ""
|
||||
|
||||
#@schema/title "No proxy"
|
||||
#@ no_proxy_desc = "Endpoints that should not be proxied. Defaults to not proxying internal Kubernetes endpoints, \
|
||||
#@ localhost endpoints, and the known instance metadata IP address for public cloud providers."
|
||||
#@schema/desc no_proxy_desc
|
||||
no_proxy: "$(KUBERNETES_SERVICE_HOST),169.254.169.254,127.0.0.1,localhost,.svc,.cluster.local"
|
||||
|
||||
@@ -1,19 +1,44 @@
|
||||
#! Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
#! SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#@data/values
|
||||
#@data/values-schema
|
||||
---
|
||||
|
||||
#! Specify either an image_digest or an image_tag. If both are given, only image_digest will be used.
|
||||
#@schema/title "Image repo"
|
||||
#@schema/desc "The repository for the local-user-authenticator container image."
|
||||
#@schema/validation min_len=1
|
||||
image_repo: projects.registry.vmware.com/pinniped/pinniped-server
|
||||
image_digest: #! e.g. sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8
|
||||
|
||||
#@schema/title "Image digest"
|
||||
#@schema/desc "The image digest for the local-user-authenticator container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Providing a digest", "sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_tag"] == None
|
||||
image_digest: ""
|
||||
|
||||
#@schema/title "Image tag"
|
||||
#@schema/desc "The image tag for the local-user-authenticator container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Providing a tag", "v0.25.0")
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_digest"] == None
|
||||
image_tag: latest
|
||||
|
||||
#! Specifies a secret to be used when pulling the above `image_repo` container image.
|
||||
#! Can be used when the above image_repo is a private registry.
|
||||
#! Typically the value would be the output of: kubectl create secret docker-registry x --docker-server=https://example.io --docker-username="USERNAME" --docker-password="PASSWORD" --dry-run=client -o json | jq -r '.data[".dockerconfigjson"]'
|
||||
#! Optional.
|
||||
image_pull_dockerconfigjson: #! e.g. {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}
|
||||
#@schema/title "Image pull dockerconfigjson"
|
||||
#@ image_pull_dockerconfigjson_desc = "A base64 encoded secret to be used when pulling the `image_repo` container image. \
|
||||
#@ Can be used when the image_repo is a private registry. Typically, the value would be the output of: \
|
||||
#@ kubectl create secret docker-registry x --docker-server=https://example.io --docker-username='USERNAME' --docker-password='PASSWORD' --dry-run=client -o json | jq -r '.data[\".dockerconfigjson\"]'"
|
||||
#@schema/desc image_pull_dockerconfigjson_desc
|
||||
#@ example_desc = 'base64 encoding of: {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}'
|
||||
#@ example_value = "eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUuaW8iOnsidXNlcm5hbWUiOiJVU0VSTkFNRSIsInBhc3N3b3JkIjoiUEFTU1dPUkQiLCJhdXRoIjoiVlZORlVrNUJUVVU2VUVGVFUxZFBVa1E9In19fQ=="
|
||||
#@schema/examples (example_desc, example_value)
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
image_pull_dockerconfigjson: ""
|
||||
|
||||
run_as_user: 65532 #! run_as_user specifies the user ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
run_as_group: 65532 #! run_as_group specifies the group ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
#@schema/title "Run as user"
|
||||
#@schema/desc "The user ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_user: 65532
|
||||
|
||||
#@schema/title "Run as group"
|
||||
#@schema/desc "The group ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_group: 65532
|
||||
|
||||
@@ -1,133 +1,260 @@
|
||||
#! Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
#! SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#@data/values
|
||||
---
|
||||
#@ def validate_strings_map(obj):
|
||||
#@ # Returns True if obj is an associative data structure string→string, and False otherwise.
|
||||
#@ for key in obj:
|
||||
#@ if type(key) != "string" or type(obj[key]) != "string":
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ end
|
||||
#@ return True
|
||||
#@ end
|
||||
|
||||
#@data/values-schema
|
||||
---
|
||||
#@schema/title "App name"
|
||||
#@schema/desc "Used to help determine the names of various resources and labels."
|
||||
#@schema/validation min_len=1
|
||||
app_name: pinniped-supervisor
|
||||
|
||||
#! Creates a new namespace statically in yaml with the given name and installs the app into that namespace.
|
||||
#@schema/title "Namespace"
|
||||
#@schema/desc "Creates a new namespace statically in yaml with the given name and installs the app into that namespace."
|
||||
#@schema/validation min_len=1
|
||||
namespace: pinniped-supervisor
|
||||
#! If specified, assumes that a namespace of the given name already exists and installs the app into that namespace.
|
||||
#! If both `namespace` and `into_namespace` are specified, then only `into_namespace` is used.
|
||||
into_namespace: #! e.g. my-preexisting-namespace
|
||||
|
||||
#! All resources created statically by yaml at install-time and all resources created dynamically
|
||||
#! by controllers at runtime will be labelled with `app: $app_name` and also with the labels
|
||||
#! specified here. The value of `custom_labels` must be a map of string keys to string values.
|
||||
#! The app can be uninstalled either by:
|
||||
#! 1. Deleting the static install-time yaml resources including the static namespace, which will cascade and also delete
|
||||
#! resources that were dynamically created by controllers at runtime
|
||||
#! 2. Or, deleting all resources by label, which does not assume that there was a static install-time yaml namespace.
|
||||
custom_labels: {} #! e.g. {myCustomLabelName: myCustomLabelValue, otherCustomLabelName: otherCustomLabelValue}
|
||||
#@schema/title "Into namespace"
|
||||
#@ into_namespace_desc = "If specified, assumes that a namespace of the given name already exists and installs the app into that namespace. \
|
||||
#@ If both `namespace` and `into_namespace` are specified, then only `into_namespace` is used."
|
||||
#@schema/desc into_namespace_desc
|
||||
#@schema/examples ("The name of an existing namespace", "my-preexisting-namespace")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
into_namespace: ""
|
||||
|
||||
#! Specify how many replicas of the Pinniped server to run.
|
||||
#@schema/title "Custom labels"
|
||||
#@ custom_labels_desc = "All resources created statically by yaml at install-time and all resources created dynamically \
|
||||
#@ by controllers at runtime will be labelled with `app: $app_name` and also with the labels specified here. The value of \
|
||||
#@ `custom_labels` must be a map of string keys to string values. The app can be uninstalled either by: 1.) deleting the \
|
||||
#@ static install-time yaml resources including the static namespace, which will cascade and also delete \
|
||||
#@ resources that were dynamically created by controllers at runtime, or 2.) deleting all resources by label, which does \
|
||||
#@ not assume that there was a static install-time yaml namespace."
|
||||
#@schema/desc custom_labels_desc
|
||||
#@schema/examples ("Example set of labels", {"myCustomLabelName": "myCustomLabelValue", "otherCustomLabelName": "otherCustomLabelValue"})
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("a map of keys and values", validate_strings_map)
|
||||
custom_labels: { }
|
||||
|
||||
#@schema/title "Replicas"
|
||||
#@schema/desc "Specify how many replicas of the Pinniped server to run."
|
||||
replicas: 2
|
||||
|
||||
#! Specify either an image_digest or an image_tag. If both are given, only image_digest will be used.
|
||||
#@schema/title "Image repo"
|
||||
#@schema/desc "The repository for the Supervisor container image."
|
||||
#@schema/validation min_len=1
|
||||
image_repo: projects.registry.vmware.com/pinniped/pinniped-server
|
||||
image_digest: #! e.g. sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8
|
||||
|
||||
#@schema/title "Image digest"
|
||||
#@schema/desc "The image digest for the Supervisor container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Digest", "sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_tag"] == None
|
||||
image_digest: ""
|
||||
|
||||
#@schema/title "Image tag"
|
||||
#@schema/desc "The image tag for the Supervisor container image. If both image_digest or an image_tag are given, only image_digest will be used."
|
||||
#@schema/examples ("Tag", "v0.25.0")
|
||||
#@schema/validation min_len=1, when=lambda _, ctx: ctx.parent["image_digest"] == None
|
||||
image_tag: latest
|
||||
|
||||
#! Specifies a secret to be used when pulling the above `image_repo` container image.
|
||||
#! Can be used when the above image_repo is a private registry.
|
||||
#! Typically the value would be the output of: kubectl create secret docker-registry x --docker-server=https://example.io --docker-username="USERNAME" --docker-password="PASSWORD" --dry-run=client -o json | jq -r '.data[".dockerconfigjson"]'
|
||||
#! Optional.
|
||||
image_pull_dockerconfigjson: #! e.g. {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}
|
||||
#@schema/title "Image pull dockerconfigjson"
|
||||
#@ image_pull_dockerconfigjson_desc = "A base64 encoded secret to be used when pulling the `image_repo` container image. \
|
||||
#@ Can be used when the image_repo is a private registry. Typically, the value would be the output of: \
|
||||
#@ kubectl create secret docker-registry x --docker-server=https://example.io --docker-username='USERNAME' --docker-password='PASSWORD' --dry-run=client -o json | jq -r '.data[\".dockerconfigjson\"]'"
|
||||
#@schema/desc image_pull_dockerconfigjson_desc
|
||||
#@ example_desc = 'base64 encoding of: {"auths":{"https://registry.example.com":{"username":"USERNAME","password":"PASSWORD","auth":"BASE64_ENCODED_USERNAME_COLON_PASSWORD"}}}'
|
||||
#@ example_value = "eyJhdXRocyI6eyJodHRwczovL2V4YW1wbGUuaW8iOnsidXNlcm5hbWUiOiJVU0VSTkFNRSIsInBhc3N3b3JkIjoiUEFTU1dPUkQiLCJhdXRoIjoiVlZORlVrNUJUVVU2VUVGVFUxZFBVa1E9In19fQ=="
|
||||
#@schema/examples (example_desc, example_value)
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
image_pull_dockerconfigjson: ""
|
||||
|
||||
#! Specify how to expose the Supervisor app's HTTPS port as a Service.
|
||||
#! Typically, you would set a value for only one of the following service types.
|
||||
#! Setting any of these values means that a Service of that type will be created. They are all optional.
|
||||
#! Note that all port numbers should be numbers (not strings), i.e. use ytt's `--data-value-yaml` instead of `--data-value`.
|
||||
#! Several of these values have been deprecated and will be removed in a future release. Their names have been changed to
|
||||
#! mark them as deprecated and to make it obvious upon upgrade to anyone who was using them that they have been deprecated.
|
||||
deprecated_service_http_nodeport_port: #! will be removed in a future release; when specified, creates a NodePort Service with this `port` value, with port 8080 as its `targetPort`; e.g. 31234
|
||||
deprecated_service_http_nodeport_nodeport: #! will be removed in a future release; the `nodePort` value of the NodePort Service, optional when `deprecated_service_http_nodeport_port` is specified; e.g. 31234
|
||||
deprecated_service_http_loadbalancer_port: #! will be removed in a future release; when specified, creates a LoadBalancer Service with this `port` value, with port 8080 as its `targetPort`; e.g. 8443
|
||||
deprecated_service_http_clusterip_port: #! will be removed in a future release; when specified, creates a ClusterIP Service with this `port` value, with port 8080 as its `targetPort`; e.g. 8443
|
||||
service_https_nodeport_port: #! when specified, creates a NodePort Service with this `port` value, with port 8443 as its `targetPort`; e.g. 31243
|
||||
service_https_nodeport_nodeport: #! the `nodePort` value of the NodePort Service, optional when `service_https_nodeport_port` is specified; e.g. 31243
|
||||
service_https_loadbalancer_port: #! when specified, creates a LoadBalancer Service with this `port` value, with port 8443 as its `targetPort`; e.g. 8443
|
||||
service_https_clusterip_port: #! when specified, creates a ClusterIP Service with this `port` value, with port 8443 as its `targetPort`; e.g. 8443
|
||||
#! The `loadBalancerIP` value of the LoadBalancer Service.
|
||||
#! Ignored unless service_https_loadbalancer_port is provided.
|
||||
#! Optional.
|
||||
service_loadbalancer_ip: #! e.g. 1.2.3.4
|
||||
#@schema/title "Deprecated service HTTP nodeport port"
|
||||
#@schema/desc "When specified, creates a NodePort Service with this `port` value, with port 8080 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",31234)
|
||||
#@schema/nullable
|
||||
#@schema/deprecated "This data value will be removed in a future release"
|
||||
deprecated_service_http_nodeport_port: 0
|
||||
|
||||
#! Specify the verbosity of logging: info ("nice to know" information), debug (developer information), trace (timing information),
|
||||
#! or all (kitchen sink). Do not use trace or all on production systems, as credentials may get logged.
|
||||
log_level: #! By default, when this value is left unset, only warnings and errors are printed. There is no way to suppress warning and error logs.
|
||||
#! Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs).
|
||||
#! By default, when this value is left unset, logs are formatted in json.
|
||||
#! This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json.
|
||||
deprecated_log_format:
|
||||
#@schema/title "Deprecated service http nodeport nodeport"
|
||||
#@schema/desc "The `nodePort` value of the NodePort Service, optional when `deprecated_service_http_nodeport_port` is specified"
|
||||
#@schema/examples ("Specify port",31234)
|
||||
#@schema/nullable
|
||||
#@schema/deprecated "This data value will be removed in a future release"
|
||||
deprecated_service_http_nodeport_nodeport: 0
|
||||
|
||||
run_as_user: 65532 #! run_as_user specifies the user ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
run_as_group: 65532 #! run_as_group specifies the group ID that will own the process, see the Dockerfile for the reasoning behind this choice
|
||||
#@schema/title "Deprecated service http loadbalancer port"
|
||||
#@schema/desc "When specified, creates a LoadBalancer Service with this `port` value, with port 8080 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",8443)
|
||||
#@schema/nullable
|
||||
#@schema/deprecated "This data value will be removed in a future release"
|
||||
deprecated_service_http_loadbalancer_port: 0
|
||||
|
||||
#! Specify the API group suffix for all Pinniped API groups. By default, this is set to
|
||||
#! pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev,
|
||||
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
|
||||
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
|
||||
#@schema/title "Deprecated service http clusterip port"
|
||||
#@schema/desc "Creates a ClusterIP Service with this `port` value, with port 8080 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",8443)
|
||||
#@schema/nullable
|
||||
#@schema/deprecated "This data value will be removed in a future release"
|
||||
deprecated_service_http_clusterip_port: 0
|
||||
|
||||
#@schema/title "Service https nodeport port"
|
||||
#@schema/desc "When specified, creates a NodePort Service with this `port` value, with port 8443 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",31243)
|
||||
#@schema/nullable
|
||||
service_https_nodeport_port: 0
|
||||
|
||||
#@schema/title "Service https nodeport nodeport"
|
||||
#@schema/desc "The `nodePort` value of the NodePort Service, optional when `service_https_nodeport_port` is specified"
|
||||
#@schema/examples ("Specify port",31243)
|
||||
#@schema/nullable
|
||||
service_https_nodeport_nodeport: 0
|
||||
|
||||
#@schema/title "Service https loadbalancer port"
|
||||
#@schema/desc "When specified, creates a LoadBalancer Service with this `port` value, with port 8443 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",8443)
|
||||
#@schema/nullable
|
||||
service_https_loadbalancer_port: 0
|
||||
|
||||
#@schema/title "Service https clusterip port"
|
||||
#@schema/desc "When specified, creates a ClusterIP Service with this `port` value, with port 8443 as its `targetPort`"
|
||||
#@schema/examples ("Specify port",8443)
|
||||
#@schema/nullable
|
||||
service_https_clusterip_port: 0
|
||||
|
||||
#@schema/title "Service loadbalancer ip"
|
||||
#@schema/desc "The `loadBalancerIP` value of the LoadBalancer Service. Ignored unless service_https_loadbalancer_port is provided."
|
||||
#@schema/examples ("Example IP address","1.2.3.4")
|
||||
#@schema/nullable
|
||||
service_loadbalancer_ip: ""
|
||||
|
||||
#@schema/title "Log level"
|
||||
#@ log_level_desc = "Specify the verbosity of logging: info (\"nice to know\" information), debug (developer information), trace (timing information), \
|
||||
#@ or all (kitchen sink). Do not use trace or all on production systems, as credentials may get logged. \
|
||||
#@ When this value is left unset, only warnings and errors are printed. There is no way to suppress warning and error logs."
|
||||
#@schema/desc log_level_desc
|
||||
#@schema/examples ("Developer logging information","debug")
|
||||
#@schema/nullable
|
||||
#@schema/validation one_of=["info", "debug", "trace", "all"]
|
||||
log_level: ""
|
||||
|
||||
#@schema/title "Log format"
|
||||
#@ deprecated_log_format_desc = "Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs). \
|
||||
#@ By default, when this value is left unset, logs are formatted in json. \
|
||||
#@ This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
|
||||
#@schema/desc deprecated_log_format_desc
|
||||
#@schema/examples ("Set logs to JSON format","json")
|
||||
#@schema/nullable
|
||||
#@schema/validation one_of=["json", "text"]
|
||||
#@schema/deprecated "This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
|
||||
deprecated_log_format: ""
|
||||
|
||||
#@schema/title "Run as user"
|
||||
#@schema/desc "The user ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_user: 65532
|
||||
|
||||
#@schema/title "Run as group"
|
||||
#@schema/desc "The group ID that will own the process."
|
||||
#! See the Dockerfile for the reasoning behind this default value.
|
||||
run_as_group: 65532
|
||||
|
||||
#@schema/title "API group suffix"
|
||||
#@ api_group_suffix_desc = "Specify the API group suffix for all Pinniped API groups. By default, this is set to \
|
||||
#@ pinniped.dev, so Pinniped API groups will look like foo.pinniped.dev, \
|
||||
#@ config.supervisor.pinniped.dev, etc. As an example, if this is set to tuna.io, then \
|
||||
#@ Pinniped API groups will look like foo.tuna.io. config.supervisor.tuna.io, etc."
|
||||
#@schema/desc api_group_suffix_desc
|
||||
#@schema/validation min_len=1
|
||||
api_group_suffix: pinniped.dev
|
||||
|
||||
#! Set the standard golang HTTPS_PROXY and NO_PROXY environment variables on the Supervisor containers.
|
||||
#! These will be used when the Supervisor makes backend-to-backend calls to upstream identity providers using HTTPS,
|
||||
#! e.g. when the Supervisor fetches discovery documents, JWKS keys, and tokens from an upstream OIDC Provider.
|
||||
#! The Supervisor never makes insecure HTTP calls, so there is no reason to set HTTP_PROXY.
|
||||
#! Optional.
|
||||
https_proxy: #! e.g. http://proxy.example.com
|
||||
no_proxy: "$(KUBERNETES_SERVICE_HOST),169.254.169.254,127.0.0.1,localhost,.svc,.cluster.local" #! do not proxy Kubernetes endpoints
|
||||
#@schema/title "HTTPS proxy"
|
||||
#@ https_proxy_desc = "Set the standard golang HTTPS_PROXY and NO_PROXY environment variables on the Supervisor containers. \
|
||||
#@ These will be used when the Supervisor makes backend-to-backend calls to upstream identity providers using HTTPS, \
|
||||
#@ e.g. when the Supervisor fetches discovery documents, JWKS keys, and tokens from an upstream OIDC Provider. \
|
||||
#@ The Supervisor never makes insecure HTTP calls, so there is no reason to set HTTP_PROXY."
|
||||
#@schema/desc https_proxy_desc
|
||||
#@schema/examples ("Providing a proxy endpoint","http://proxy.example.com")
|
||||
#@schema/nullable
|
||||
#@schema/validation min_len=1
|
||||
https_proxy: ""
|
||||
|
||||
#! Control the HTTP and HTTPS listeners of the Supervisor.
|
||||
#!
|
||||
#! The schema of this config is as follows:
|
||||
#!
|
||||
#! endpoints:
|
||||
#! https:
|
||||
#! network: tcp | unix | disabled
|
||||
#! address: host:port when network=tcp or /pinniped_socket/socketfile.sock when network=unix
|
||||
#! http:
|
||||
#! network: same as above
|
||||
#! address: same as above, except that when network=tcp then the address is only allowed to bind to loopback interfaces
|
||||
#!
|
||||
#! Setting network to disabled turns off that particular listener.
|
||||
#! See https://pkg.go.dev/net#Listen and https://pkg.go.dev/net#Dial for a description of what can be
|
||||
#! specified in the address parameter based on the given network parameter. To aid in the use of unix
|
||||
#! domain sockets, a writable empty dir volume is mounted at /pinniped_socket when network is set to "unix."
|
||||
#!
|
||||
#! The current defaults are:
|
||||
#!
|
||||
#! endpoints:
|
||||
#! https:
|
||||
#! network: tcp
|
||||
#! address: :8443
|
||||
#! http:
|
||||
#! network: disabled
|
||||
#!
|
||||
#! These defaults mean: For HTTPS listening, bind to all interfaces using TCP on port 8443.
|
||||
#! Disable HTTP listening by default.
|
||||
#!
|
||||
#! The HTTP listener can only be bound to loopback interfaces. This allows the listener to accept
|
||||
#! traffic from within the pod, e.g. from a service mesh sidecar. The HTTP listener should not be
|
||||
#! used to accept traffic from outside the pod, since that would mean that the network traffic could be
|
||||
#! transmitted unencrypted. The HTTPS listener should be used instead to accept traffic from outside the pod.
|
||||
#! Ingresses and load balancers that terminate TLS connections should re-encrypt the data and route traffic
|
||||
#! to the HTTPS listener. Unix domain sockets may also be used for integrations with service meshes.
|
||||
#!
|
||||
#! Changing the HTTPS port number must be accompanied by matching changes to the service and deployment
|
||||
#! manifests. Changes to the HTTPS listener must be coordinated with the deployment health checks.
|
||||
#!
|
||||
#! Optional.
|
||||
endpoints:
|
||||
#@schema/title "No proxy"
|
||||
#@ no_proxy_desc = "Endpoints that should not be proxied. Defaults to not proxying internal Kubernetes endpoints, \
|
||||
#@ localhost endpoints, and the known instance metadata IP address for public cloud providers."
|
||||
#@schema/desc no_proxy_desc
|
||||
no_proxy: "$(KUBERNETES_SERVICE_HOST),169.254.169.254,127.0.0.1,localhost,.svc,.cluster.local"
|
||||
|
||||
#! Optionally override the validation on the endpoints.http value which checks that only loopback interfaces are used.
|
||||
#! When deprecated_insecure_accept_external_unencrypted_http_requests is true, the HTTP listener is allowed to bind to any
|
||||
#! interface, including interfaces that are listening for traffic from outside the pod. This value is being introduced
|
||||
#! to ease the transition to the new loopback interface validation for the HTTP port for any users who need more time
|
||||
#! to change their ingress strategy to avoid using plain HTTP into the Supervisor pods.
|
||||
#! This value is immediately deprecated upon its introduction. It will be removed in some future release, at which time
|
||||
#! traffic from outside the pod will need to be sent to the HTTPS listener instead, with no simple workaround available.
|
||||
#! Allowed values are true (boolean), "true" (string), false (boolean), and "false" (string). The default is false.
|
||||
#! Optional.
|
||||
#@schema/title "Endpoints"
|
||||
#@ endpoints_desc = "Control the HTTP and HTTPS listeners of the Supervisor. The current defaults are: \
|
||||
#@ {\"https\":{\"network\":\"tcp\",\"address\":\":8443\"},\"http\":\"disabled\"}. \
|
||||
#@ These defaults mean: 1.) for HTTPS listening, bind to all interfaces using TCP on port 8443 and \
|
||||
#@ 2.) disable HTTP listening by default. \
|
||||
#@ The schema of this config is as follows: \
|
||||
#@ {\"https\":{\"network\":\"tcp | unix | disabled\",\"address\":\"host:port when network=tcp or /pinniped_socket/socketfile.sock when network=unix\"},\"http\":{\"network\":\"tcp | unix | disabled\",\"address\":\"same as https, except that when network=tcp then the address is only allowed to bind to loopback interfaces\"}} \
|
||||
#@ The HTTP listener can only be bound to loopback interfaces. This allows the listener to accept \
|
||||
#@ traffic from within the pod, e.g. from a service mesh sidecar. The HTTP listener should not be \
|
||||
#@ used to accept traffic from outside the pod, since that would mean that the network traffic could be \
|
||||
#@ transmitted unencrypted. The HTTPS listener should be used instead to accept traffic from outside the pod. \
|
||||
#@ Ingresses and load balancers that terminate TLS connections should re-encrypt the data and route traffic \
|
||||
#@ to the HTTPS listener. Unix domain sockets may also be used for integrations with service meshes. \
|
||||
#@ Changing the HTTPS port number must be accompanied by matching changes to the service and deployment \
|
||||
#@ manifests. Changes to the HTTPS listener must be coordinated with the deployment health checks."
|
||||
#@schema/desc endpoints_desc
|
||||
#@schema/examples ("Example matching default settings", '{"https":{"network":"tcp","address":":8443"},"http":"disabled"}')
|
||||
#@schema/type any=True
|
||||
#@ def validate_endpoint(endpoint):
|
||||
#@ if(type(endpoint) not in ["yamlfragment", "string"]):
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ if(type(endpoint) in ["string"]):
|
||||
#@ if (endpoint != "disabled"):
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ end
|
||||
#@ if(type(endpoint) in ["yamlfragment"]):
|
||||
#@ if (endpoint["network"] not in ["tcp", "unix", "disabled"]):
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ if (type(endpoint["address"]) not in ["string"]):
|
||||
#@ return False
|
||||
#@ end
|
||||
#@ end
|
||||
#@ return True
|
||||
#@ end
|
||||
#@ def validate_endpoints(endpoints):
|
||||
#@ """
|
||||
#@ Returns True if endpoints fulfill the expected structure
|
||||
#@ """
|
||||
#@ http_val = endpoints["http"]
|
||||
#@ https_val = endpoints["https"]
|
||||
#@ return validate_endpoint(http_val) and validate_endpoint(https_val)
|
||||
#@ end
|
||||
#@schema/nullable
|
||||
#@schema/validation ("a map with keys 'http' and 'https', whose values are either the string 'disabled' or a map having keys 'network' and 'address', and the value of 'network' must be one of the allowed values", validate_endpoints)
|
||||
endpoints: { }
|
||||
|
||||
#@ deprecated_insecure_accept_external_unencrypted_http_requests_desc = "Optionally override the validation on the endpoints.http \
|
||||
#@ value which checks that only loopback interfaces are used. \
|
||||
#@ When deprecated_insecure_accept_external_unencrypted_http_requests is true, the HTTP listener is allowed to bind to any \
|
||||
#@ interface, including interfaces that are listening for traffic from outside the pod. This value is being introduced \
|
||||
#@ to ease the transition to the new loopback interface validation for the HTTP port for any users who need more time \
|
||||
#@ to change their ingress strategy to avoid using plain HTTP into the Supervisor pods. \
|
||||
#@ This value is immediately deprecated upon its introduction. It will be removed in some future release, at which time \
|
||||
#@ traffic from outside the pod will need to be sent to the HTTPS listener instead, with no simple workaround available. \
|
||||
#@ Allowed values are true (boolean), 'true' (string), false (boolean), and 'false' (string). The default is false."
|
||||
#@schema/desc deprecated_insecure_accept_external_unencrypted_http_requests_desc
|
||||
#@schema/type any=True
|
||||
#@schema/validation ("a boolean or string version of boolean", lambda v: type(v) in ["string", "boolean"])
|
||||
#@schema/validation one_of=["true", "false", True, False]
|
||||
#@schema/deprecated "This data value will be removed in a future release"
|
||||
deprecated_insecure_accept_external_unencrypted_http_requests: false
|
||||
|
||||
85
generated/1.21/README.adoc
generated
85
generated/1.21/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-21-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
85
generated/1.22/README.adoc
generated
85
generated/1.22/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-22-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
85
generated/1.23/README.adoc
generated
85
generated/1.23/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-23-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
85
generated/1.24/README.adoc
generated
85
generated/1.24/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-24-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
85
generated/1.25/README.adoc
generated
85
generated/1.25/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-25-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
4
generated/1.25/apis/go.mod
generated
4
generated/1.25/apis/go.mod
generated
@@ -4,6 +4,6 @@ module go.pinniped.dev/generated/1.25/apis
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
k8s.io/api v0.25.14
|
||||
k8s.io/apimachinery v0.25.14
|
||||
k8s.io/api v0.25.16
|
||||
k8s.io/apimachinery v0.25.16
|
||||
)
|
||||
|
||||
25
generated/1.25/apis/go.sum
generated
25
generated/1.25/apis/go.sum
generated
@@ -126,6 +126,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
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=
|
||||
@@ -153,8 +154,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
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=
|
||||
@@ -185,19 +187,22 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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=
|
||||
@@ -259,10 +264,10 @@ 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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.25.14 h1:HoIR3IorzJkd0LPfCVq1Q3lRwij3+lZWJRmyp7YcL7o=
|
||||
k8s.io/api v0.25.14/go.mod h1:goGtHI224Qh0tcHk8gOYPhTyCZNwQFwUMHsdabnSnSs=
|
||||
k8s.io/apimachinery v0.25.14 h1:SI5uE46G9GAvEHPGDcbiIaKTGHOX2anWKfBtI7/4ScQ=
|
||||
k8s.io/apimachinery v0.25.14/go.mod h1:IFwbcNi3gKkfDhuy0VYu3+BwbxbiIov3p6FR8ge1Epc=
|
||||
k8s.io/api v0.25.16 h1:6VsSxn0vCdHuAVh82EZCKoM457LuUpQQb6YXfQunz7Q=
|
||||
k8s.io/api v0.25.16/go.mod h1:7pehrlB/DJ0qzxicMELX7IZlgL6J5lnSOBPey/cuGBs=
|
||||
k8s.io/apimachinery v0.25.16 h1:Mk5h4zbHVZh4ZkgRnciYdLRqOREt2dAGTJesDY0WO7U=
|
||||
k8s.io/apimachinery v0.25.16/go.mod h1:34oJjP2pnWhz64k0GETsMvDeAp2A2v+gKa/u3tV/+6k=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
4
generated/1.25/client/go.mod
generated
4
generated/1.25/client/go.mod
generated
@@ -5,8 +5,8 @@ go 1.13
|
||||
|
||||
require (
|
||||
go.pinniped.dev/generated/1.25/apis v0.0.0
|
||||
k8s.io/apimachinery v0.25.14
|
||||
k8s.io/client-go v0.25.14
|
||||
k8s.io/apimachinery v0.25.16
|
||||
k8s.io/client-go v0.25.16
|
||||
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1
|
||||
)
|
||||
|
||||
|
||||
34
generated/1.25/client/go.sum
generated
34
generated/1.25/client/go.sum
generated
@@ -299,7 +299,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -383,8 +383,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -473,13 +474,15 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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=
|
||||
@@ -490,8 +493,9 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -721,12 +725,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.25.14 h1:HoIR3IorzJkd0LPfCVq1Q3lRwij3+lZWJRmyp7YcL7o=
|
||||
k8s.io/api v0.25.14/go.mod h1:goGtHI224Qh0tcHk8gOYPhTyCZNwQFwUMHsdabnSnSs=
|
||||
k8s.io/apimachinery v0.25.14 h1:SI5uE46G9GAvEHPGDcbiIaKTGHOX2anWKfBtI7/4ScQ=
|
||||
k8s.io/apimachinery v0.25.14/go.mod h1:IFwbcNi3gKkfDhuy0VYu3+BwbxbiIov3p6FR8ge1Epc=
|
||||
k8s.io/client-go v0.25.14 h1:/OdBAeSSlheFUb1i2SsWNo+LLyheJxDuQmWnWkzY4bc=
|
||||
k8s.io/client-go v0.25.14/go.mod h1:F3dMnLGu/iNIhYxVUsSen5WAIYM/DZPxDKZX/VYzZ7o=
|
||||
k8s.io/api v0.25.16 h1:6VsSxn0vCdHuAVh82EZCKoM457LuUpQQb6YXfQunz7Q=
|
||||
k8s.io/api v0.25.16/go.mod h1:7pehrlB/DJ0qzxicMELX7IZlgL6J5lnSOBPey/cuGBs=
|
||||
k8s.io/apimachinery v0.25.16 h1:Mk5h4zbHVZh4ZkgRnciYdLRqOREt2dAGTJesDY0WO7U=
|
||||
k8s.io/apimachinery v0.25.16/go.mod h1:34oJjP2pnWhz64k0GETsMvDeAp2A2v+gKa/u3tV/+6k=
|
||||
k8s.io/client-go v0.25.16 h1:Lf8gd4vP9hR2sDuSU+9id9Mj23u8X58nESZ5m1JcI24=
|
||||
k8s.io/client-go v0.25.16/go.mod h1:6y5hyLavOErqO5LWUzk5rwKpRqmwZsE3oe3RW0cgs9s=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
85
generated/1.26/README.adoc
generated
85
generated/1.26/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-26-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
4
generated/1.26/apis/go.mod
generated
4
generated/1.26/apis/go.mod
generated
@@ -4,6 +4,6 @@ module go.pinniped.dev/generated/1.26/apis
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
k8s.io/api v0.26.9
|
||||
k8s.io/apimachinery v0.26.9
|
||||
k8s.io/api v0.26.11
|
||||
k8s.io/apimachinery v0.26.11
|
||||
)
|
||||
|
||||
32
generated/1.26/apis/go.sum
generated
32
generated/1.26/apis/go.sum
generated
@@ -47,6 +47,7 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
@@ -116,11 +117,13 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
||||
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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
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.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
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.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
@@ -130,6 +133,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
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=
|
||||
@@ -159,8 +163,9 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
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=
|
||||
@@ -192,12 +197,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -205,8 +212,9 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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=
|
||||
@@ -247,7 +255,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -270,10 +278,10 @@ 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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.26.9 h1:s8Y+G1u2JM55b90+Yo2RVb3PGT/hkWNVPN4idPERxJg=
|
||||
k8s.io/api v0.26.9/go.mod h1:W/W4fEWRVzPD36820LlVUQfNBiSbiq0VPWRFJKwzmUg=
|
||||
k8s.io/apimachinery v0.26.9 h1:5yAV9cFR7Z4gIorKcAjWnx4uxtxiFsERwq4Pvmx0CCg=
|
||||
k8s.io/apimachinery v0.26.9/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
|
||||
k8s.io/api v0.26.11 h1:hLhTZRdYc3vBBOY4wbEyTLWgMyieOAk2Ws9NG57QqO4=
|
||||
k8s.io/api v0.26.11/go.mod h1:bSr/A0TKRt5W2OMDdexkM/ER1NxOxiQqNNFXW2nMZrM=
|
||||
k8s.io/apimachinery v0.26.11 h1:w//840HHdwSRKqD15j9YX9HLlU6RPlfrvW0xEhLk2+0=
|
||||
k8s.io/apimachinery v0.26.11/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
4
generated/1.26/client/go.mod
generated
4
generated/1.26/client/go.mod
generated
@@ -5,8 +5,8 @@ go 1.13
|
||||
|
||||
require (
|
||||
go.pinniped.dev/generated/1.26/apis v0.0.0
|
||||
k8s.io/apimachinery v0.26.9
|
||||
k8s.io/client-go v0.26.9
|
||||
k8s.io/apimachinery v0.26.11
|
||||
k8s.io/client-go v0.26.11
|
||||
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280
|
||||
)
|
||||
|
||||
|
||||
315
generated/1.26/client/go.sum
generated
315
generated/1.26/client/go.sum
generated
@@ -1,38 +1,6 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
@@ -43,7 +11,6 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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=
|
||||
@@ -53,17 +20,12 @@ github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkg
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -82,23 +44,11 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
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=
|
||||
@@ -107,10 +57,9 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
|
||||
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.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
@@ -118,9 +67,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
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.4.1/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
@@ -128,36 +74,19 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -210,66 +139,34 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
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/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.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
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/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
@@ -279,59 +176,34 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/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-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -339,32 +211,12 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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=
|
||||
@@ -378,72 +230,38 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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-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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
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.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
@@ -454,72 +272,17 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
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/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
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/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
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/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
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.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
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=
|
||||
@@ -529,19 +292,17 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
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=
|
||||
@@ -558,18 +319,13 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
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-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.26.9 h1:s8Y+G1u2JM55b90+Yo2RVb3PGT/hkWNVPN4idPERxJg=
|
||||
k8s.io/api v0.26.9/go.mod h1:W/W4fEWRVzPD36820LlVUQfNBiSbiq0VPWRFJKwzmUg=
|
||||
k8s.io/apimachinery v0.26.9 h1:5yAV9cFR7Z4gIorKcAjWnx4uxtxiFsERwq4Pvmx0CCg=
|
||||
k8s.io/apimachinery v0.26.9/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0=
|
||||
k8s.io/client-go v0.26.9 h1:TGWi/6guEjIgT0Hg871Gsmx0qFuoGyGFjlFedrk7It0=
|
||||
k8s.io/client-go v0.26.9/go.mod h1:tU1FZS0bwAmAFyPYpZycUQrQnUMzQ5MHloop7EbX6ow=
|
||||
k8s.io/api v0.26.11 h1:hLhTZRdYc3vBBOY4wbEyTLWgMyieOAk2Ws9NG57QqO4=
|
||||
k8s.io/api v0.26.11/go.mod h1:bSr/A0TKRt5W2OMDdexkM/ER1NxOxiQqNNFXW2nMZrM=
|
||||
k8s.io/apimachinery v0.26.11 h1:w//840HHdwSRKqD15j9YX9HLlU6RPlfrvW0xEhLk2+0=
|
||||
k8s.io/apimachinery v0.26.11/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y=
|
||||
k8s.io/client-go v0.26.11 h1:RjfZr5+vQjjTRmk4oCqHyC0cgrZXPjw+X+ge35sk4GI=
|
||||
k8s.io/client-go v0.26.11/go.mod h1:+emNszw9va/uRJIM5ALTBtFnlZMTjwBrNjRfEh0iuw8=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
@@ -580,9 +336,6 @@ k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhkl
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d h1:0Smp/HP1OH4Rvhe+4B8nWGERtlqAGSftbSbbmm45oFs=
|
||||
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
|
||||
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
|
||||
85
generated/1.27/README.adoc
generated
85
generated/1.27/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-27-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
4
generated/1.27/apis/go.mod
generated
4
generated/1.27/apis/go.mod
generated
@@ -4,6 +4,6 @@ module go.pinniped.dev/generated/1.27/apis
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
k8s.io/api v0.27.6
|
||||
k8s.io/apimachinery v0.27.6
|
||||
k8s.io/api v0.27.8
|
||||
k8s.io/apimachinery v0.27.8
|
||||
)
|
||||
|
||||
33
generated/1.27/apis/go.sum
generated
33
generated/1.27/apis/go.sum
generated
@@ -144,6 +144,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
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=
|
||||
@@ -156,6 +158,7 @@ golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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=
|
||||
@@ -179,8 +182,11 @@ golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
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=
|
||||
@@ -190,6 +196,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -216,6 +223,9 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -224,6 +234,9 @@ golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -232,9 +245,12 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -251,6 +267,7 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
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=
|
||||
@@ -278,7 +295,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -301,10 +318,10 @@ 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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
k8s.io/api v0.27.6 h1:PBWu/lywJe2qQcshMjubzcBg7+XDZOo7O8JJAWuYtUo=
|
||||
k8s.io/api v0.27.6/go.mod h1:AQYj0UsFCp3qJE7bOVnUuy4orCsXVkvHefnbYQiNWgk=
|
||||
k8s.io/apimachinery v0.27.6 h1:mGU8jmBq5o8mWBov+mLjdTBcU+etTE19waies4AQ6NE=
|
||||
k8s.io/apimachinery v0.27.6/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||
k8s.io/api v0.27.8 h1:Ja93gbyII5c3TJzWefEwGhlqC5SZksWhzRS+OYHIocU=
|
||||
k8s.io/api v0.27.8/go.mod h1:2HuWJC6gpx4UScY+ezziNzv6j6Jqd2q0rGgobYSSjcs=
|
||||
k8s.io/apimachinery v0.27.8 h1:Xg+ogjDm8s7KmV3vZGf7uOZ0jrC6FPy2Lk/h7BIRmvg=
|
||||
k8s.io/apimachinery v0.27.8/go.mod h1:EIXLxLt/b1muPITiF5zlrcm7I+YnXsIgM+0GdnPTQvA=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
4
generated/1.27/client/go.mod
generated
4
generated/1.27/client/go.mod
generated
@@ -5,8 +5,8 @@ go 1.13
|
||||
|
||||
require (
|
||||
go.pinniped.dev/generated/1.27/apis v0.0.0
|
||||
k8s.io/apimachinery v0.27.6
|
||||
k8s.io/client-go v0.27.6
|
||||
k8s.io/apimachinery v0.27.8
|
||||
k8s.io/client-go v0.27.8
|
||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f
|
||||
)
|
||||
|
||||
|
||||
317
generated/1.27/client/go.sum
generated
317
generated/1.27/client/go.sum
generated
@@ -1,38 +1,6 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
@@ -41,7 +9,6 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
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/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
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=
|
||||
@@ -50,17 +17,12 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
@@ -77,23 +39,11 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
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=
|
||||
@@ -105,8 +55,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
|
||||
github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
|
||||
@@ -114,9 +62,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
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.4.1/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.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
@@ -124,38 +69,21 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||
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/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/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/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
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/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -217,7 +145,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||
@@ -229,58 +156,26 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
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/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
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 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
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/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
@@ -288,41 +183,23 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
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-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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
@@ -333,57 +210,34 @@ golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
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/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
||||
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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/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=
|
||||
@@ -400,8 +254,12 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -409,11 +267,13 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
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/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -422,55 +282,21 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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-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-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
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.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
@@ -478,79 +304,25 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
||||
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=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
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/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
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/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
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.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
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=
|
||||
@@ -560,13 +332,12 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
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.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -588,18 +359,13 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
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-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.27.6 h1:PBWu/lywJe2qQcshMjubzcBg7+XDZOo7O8JJAWuYtUo=
|
||||
k8s.io/api v0.27.6/go.mod h1:AQYj0UsFCp3qJE7bOVnUuy4orCsXVkvHefnbYQiNWgk=
|
||||
k8s.io/apimachinery v0.27.6 h1:mGU8jmBq5o8mWBov+mLjdTBcU+etTE19waies4AQ6NE=
|
||||
k8s.io/apimachinery v0.27.6/go.mod h1:XNfZ6xklnMCOGGFNqXG7bUrQCoR04dh/E7FprV6pb+E=
|
||||
k8s.io/client-go v0.27.6 h1:vzI8804gpUtpMCNaFjIFyJrifH7u//LJCJPy8fQuYQg=
|
||||
k8s.io/client-go v0.27.6/go.mod h1:PMsXcDKiJTW7PHJ64oEsIUJF319wm+EFlCj76oE5QXM=
|
||||
k8s.io/api v0.27.8 h1:Ja93gbyII5c3TJzWefEwGhlqC5SZksWhzRS+OYHIocU=
|
||||
k8s.io/api v0.27.8/go.mod h1:2HuWJC6gpx4UScY+ezziNzv6j6Jqd2q0rGgobYSSjcs=
|
||||
k8s.io/apimachinery v0.27.8 h1:Xg+ogjDm8s7KmV3vZGf7uOZ0jrC6FPy2Lk/h7BIRmvg=
|
||||
k8s.io/apimachinery v0.27.8/go.mod h1:EIXLxLt/b1muPITiF5zlrcm7I+YnXsIgM+0GdnPTQvA=
|
||||
k8s.io/client-go v0.27.8 h1:uXIsGniqc85kKQ8FV0iAwspb0JHtS1UybqrqzHaQ9hc=
|
||||
k8s.io/client-go v0.27.8/go.mod h1:Ka6MUpObn3LRTfFPvjzyettp8LXCbhqLzZfi8TD4fP8=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
@@ -611,9 +377,6 @@ k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY=
|
||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
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/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
|
||||
|
||||
85
generated/1.28/README.adoc
generated
85
generated/1.28/README.adoc
generated
@@ -480,8 +480,9 @@ ImpersonationProxyServiceSpec describes how the Concierge should provision a Ser
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`type`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxyservicetype[$$ImpersonationProxyServiceType$$]__ | Type specifies the type of Service to provision for the impersonation proxy. +
|
||||
|
||||
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||
|===
|
||||
@@ -514,10 +515,12 @@ ImpersonationProxySpec describes the intended configuration of the Concierge imp
|
||||
| Field | Description
|
||||
| *`mode`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxymode[$$ImpersonationProxyMode$$]__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS.
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name. +
|
||||
|
||||
This field must be non-empty when spec.impersonationProxy.service.type is "None".
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-concierge-config-v1alpha1-impersonationproxytlsspec[$$ImpersonationProxyTLSSpec$$]__ | TLS contains information about how the Concierge impersonation proxy should serve TLS. +
|
||||
|
||||
If this field is empty, the impersonation proxy will generate its own TLS certificate.
|
||||
|===
|
||||
|
||||
|
||||
@@ -683,12 +686,15 @@ FederationDomainSpec is a struct that describes an OIDC Provider.
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint).
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`issuer`* __string__ | Issuer is the OIDC Provider's issuer, per the OIDC Discovery Metadata document, as well as the identifier that it will use for the iss claim in issued JWTs. This field will also be used as the base URL for any endpoints used by the OIDC Provider (e.g., if your issuer is https://example.com/foo, then your authorization endpoint will look like https://example.com/foo/some/path/to/auth/endpoint). +
|
||||
|
||||
See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.
|
||||
| *`tls`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomaintlsspec[$$FederationDomainTLSSpec$$]__ | TLS specifies a secret which will contain Transport Layer Security (TLS) configuration for the FederationDomain.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain.
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider.
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
| *`identityProviders`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomainidentityprovider[$$FederationDomainIdentityProvider$$] array__ | IdentityProviders is the list of identity providers available for use by this FederationDomain. +
|
||||
|
||||
An identity provider CR (e.g. OIDCIdentityProvider or LDAPIdentityProvider) describes how to connect to a server, how to talk in a specific protocol for authentication, and how to use the schema of that server/protocol to extract a normalized user identity. Normalized user identities include a username and a list of group names. In contrast, IdentityProviders describes how to use that normalized identity in those Kubernetes clusters which belong to this FederationDomain. Each entry in IdentityProviders can be configured with arbitrary transformations on that normalized identity. For example, a transformation can add a prefix to all usernames to help avoid accidental conflicts when multiple identity providers have different users with the same username (e.g. "idp1:ryan" versus "idp2:ryan"). Each entry in IdentityProviders can also implement arbitrary authentication rejection policies. Even though a user was able to authenticate with the identity provider, a policy can disallow the authentication to the Kubernetes clusters that belong to this FederationDomain. For example, a policy could disallow the authentication unless the user belongs to a specific group in the identity provider. +
|
||||
|
||||
For backwards compatibility with versions of Pinniped which predate support for multiple identity providers, an empty IdentityProviders list will cause the FederationDomain to use all available identity providers which exist in the same namespace, but also to reject all authentication requests when there is more than one identity provider currently defined. In this backwards compatibility mode, the name of the identity provider resource (e.g. the Name of an OIDCIdentityProvider resource) will be used as the name of the identity provider in this FederationDomain. This mode is provided to make upgrading from older versions easier. However, instead of relying on this backwards compatibility mode, please consider this mode to be deprecated and please instead explicitly list the identity provider using this IdentityProviders field.
|
||||
|===
|
||||
|
||||
|
||||
@@ -724,11 +730,15 @@ FederationDomainTLSSpec is a struct that describes the TLS configuration for an
|
||||
[cols="25a,75a", options="header"]
|
||||
|===
|
||||
| Field | Description
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS.
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers.
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers.
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere.
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
| *`secretName`* __string__ | SecretName is an optional name of a Secret in the same namespace, of type `kubernetes.io/tls`, which contains the TLS serving certificate for the HTTPS endpoints served by this FederationDomain. When provided, the TLS Secret named here must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS. +
|
||||
|
||||
Server Name Indication (SNI) is an extension to the Transport Layer Security (TLS) supported by all major browsers. +
|
||||
|
||||
SecretName is required if you would like to use different TLS certificates for issuers of different hostnames. SNI requests do not include port numbers, so all issuers with the same DNS hostname must use the same SecretName value even if they have different port numbers. +
|
||||
|
||||
SecretName is not required when you would like to use only the HTTP endpoints (e.g. when the HTTP listener is configured to listen on loopback interfaces or UNIX domain sockets for traffic from a service mesh sidecar). It is also not required when you would like all requests to this OIDC Provider's HTTPS endpoints to use the default TLS certificate, which is configured elsewhere. +
|
||||
|
||||
When your Issuer URL's host is an IP address, then this field is ignored. SNI does not work for IP addresses.
|
||||
|===
|
||||
|
||||
|
||||
@@ -746,10 +756,13 @@ FederationDomainTransforms defines identity transformations for an identity prov
|
||||
|===
|
||||
| Field | Description
|
||||
| *`constants`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomaintransformsconstant[$$FederationDomainTransformsConstant$$] array__ | Constants defines constant variables and their values which will be made available to the transform expressions.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings.
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants.
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression.
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`expressions`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomaintransformsexpression[$$FederationDomainTransformsExpression$$] array__ | Expressions are an optional list of transforms and policies to be executed in the order given during every authentication attempt, including during every session refresh. Each is a CEL expression. It may use the basic CEL language as defined in https://github.com/google/cel-spec/blob/master/doc/langdef.md plus the CEL string extensions defined in https://github.com/google/cel-go/tree/master/ext#strings. +
|
||||
|
||||
The username and groups extracted from the identity provider, and the constants defined in this CR, are available as variables in all expressions. The username is provided via a variable called `username` and the list of group names is provided via a variable called `groups` (which may be an empty list). Each user-provided constants is provided via a variable named `strConst.varName` for string constants and `strListConst.varName` for string list constants. +
|
||||
|
||||
The only allowed types for expressions are currently policy/v1, username/v1, and groups/v1. Each policy/v1 must return a boolean, and when it returns false, no more expressions from the list are evaluated and the authentication attempt is rejected. Transformations of type policy/v1 do not return usernames or group names, and therefore cannot change the username or group names. Each username/v1 transform must return the new username (a string), which can be the same as the old username. Transformations of type username/v1 do not return group names, and therefore cannot change the group names. Each groups/v1 transform must return the new groups list (list of strings), which can be the same as the old groups list. Transformations of type groups/v1 do not return usernames, and therefore cannot change the usernames. After each expression, the new (potentially changed) username or groups get passed to the following expression. +
|
||||
|
||||
Any compilation or static type-checking failure of any expression will cause an error status on the FederationDomain. During an authentication attempt, any unexpected runtime evaluation errors (e.g. division by zero) cause the authentication attempt to fail. When all expressions evaluate successfully, then the (potentially changed) username and group names have been decided for that authentication attempt.
|
||||
| *`examples`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-federationdomaintransformsexample[$$FederationDomainTransformsExample$$] array__ | Examples can optionally be used to ensure that the sequence of transformation expressions are working as expected. Examples define sample input identities which are then run through the expression list, and the results are compared to the expected results. If any example in this list fails, then this identity provider will not be available for use within this FederationDomain, and the error(s) will be added to the FederationDomain status. This can be used to help guard against programming mistakes in the expressions, and also act as living documentation for other administrators to better understand the expressions.
|
||||
|===
|
||||
|
||||
@@ -892,10 +905,12 @@ OIDCClientSpec is a struct that describes an OIDCClient.
|
||||
|===
|
||||
| Field | Description
|
||||
| *`allowedRedirectURIs`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-redirecturi[$$RedirectURI$$] array__ | allowedRedirectURIs is a list of the allowed redirect_uri param values that should be accepted during OIDC flows with this client. Any other uris will be rejected. Must be a URI with the https scheme, unless the hostname is 127.0.0.1 or ::1 which may use the http scheme. Port numbers are not required for 127.0.0.1 or ::1 and are ignored when checking for a matching redirect_uri.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client.
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
| *`allowedGrantTypes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-granttype[$$GrantType$$] array__ | allowedGrantTypes is a list of the allowed grant_type param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - authorization_code: allows the client to perform the authorization code grant flow, i.e. allows the webapp to authenticate users. This grant must always be listed. - refresh_token: allows the client to perform refresh grants for the user to extend the user's session. This grant must be listed if allowedScopes lists offline_access. - urn:ietf:params:oauth:grant-type:token-exchange: allows the client to perform RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. This grant must be listed if allowedScopes lists pinniped:request-audience.
|
||||
| *`allowedScopes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-config-v1alpha1-scope[$$Scope$$] array__ | allowedScopes is a list of the allowed scopes param values that should be accepted during OIDC flows with this client. +
|
||||
|
||||
Must only contain the following values: - openid: The client is allowed to request ID tokens. ID tokens only include the required claims by default (iss, sub, aud, exp, iat). This scope must always be listed. - offline_access: The client is allowed to request an initial refresh token during the authorization code grant flow. This scope must be listed if allowedGrantTypes lists refresh_token. - pinniped:request-audience: The client is allowed to request a new audience value during a RFC8693 token exchange, which is a step in the process to be able to get a cluster credential for the user. openid, username and groups scopes must be listed when this scope is present. This scope must be listed if allowedGrantTypes lists urn:ietf:params:oauth:grant-type:token-exchange. - username: The client is allowed to request that ID tokens contain the user's username. Without the username scope being requested and allowed, the ID token will not contain the user's username. - groups: The client is allowed to request that ID tokens contain the user's group membership, if their group membership is discoverable by the Supervisor. Without the groups scope being requested and allowed, the ID token will not contain groups.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1221,10 +1236,13 @@ ActiveDirectoryIdentityProvider describes the configuration of an upstream Micro
|
||||
| *`filter`* __string__ | Filter is the ActiveDirectory search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. E.g. "member={}" or "&(objectClass=groupOfNames)(member={})". For more information about ActiveDirectory filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the filter were specified as "(&(objectClass=group)(member:1.2.840.113556.1.4.1941:={})". This searches nested groups by default. Note that nested group search can be slow for some Active Directory servers. To disable it, you can set the filter to "(&(objectClass=group)(member={})"
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-idp-v1alpha1-activedirectoryidentityprovidergroupsearchattributes[$$ActiveDirectoryIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each ActiveDirectory entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
@@ -1389,10 +1407,13 @@ LDAPIdentityProvider describes the configuration of an upstream Lightweight Dire
|
||||
| *`filter`* __string__ | Filter is the LDAP search filter which should be applied when searching for groups for a user. The pattern "{}" must occur in the filter at least once and will be dynamically replaced by the value of an attribute of the user entry found as a result of the user search. Which attribute's value is used to replace the placeholder(s) depends on the value of UserAttributeForFilter. For more information about LDAP filters, see https://ldap.com/ldap-filters. Note that the dn (distinguished name) is not an attribute of an entry, so "dn={}" cannot be used. Optional. When not specified, the default will act as if the Filter were specified as "member={}".
|
||||
| *`userAttributeForFilter`* __string__ | UserAttributeForFilter specifies which attribute's value from the user entry found as a result of the user search will be used to replace the "{}" placeholder(s) in the group search Filter. For example, specifying "uid" as the UserAttributeForFilter while specifying "&(objectClass=posixGroup)(memberUid={})" as the Filter would search for groups by replacing the "{}" placeholder in the Filter with the value of the user's "uid" attribute. Optional. When not specified, the default will act as if "dn" were specified. For example, leaving UserAttributeForFilter unspecified while specifying "&(objectClass=groupOfNames)(member={})" as the Filter would search for groups by replacing the "{}" placeholder(s) with the dn (distinguished name) of the user.
|
||||
| *`attributes`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-28-apis-supervisor-idp-v1alpha1-ldapidentityprovidergroupsearchattributes[$$LDAPIdentityProviderGroupSearchAttributes$$]__ | Attributes specifies how the group's information should be read from each LDAP entry which was found as the result of the group search.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider.
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base.
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login.
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
| *`skipGroupRefresh`* __boolean__ | The user's group membership is refreshed as they interact with the supervisor to obtain new credentials (as their old credentials expire). This allows group membership changes to be quickly reflected into Kubernetes clusters. Since group membership is often used to bind authorization policies, it is important to keep the groups observed in Kubernetes clusters in-sync with the identity provider. +
|
||||
|
||||
In some environments, frequent group membership queries may result in a significant performance impact on the identity provider and/or the supervisor. The best approach to handle performance impacts is to tweak the group query to be more performant, for example by disabling nested group search or by using a more targeted group search base. +
|
||||
|
||||
If the group search query cannot be made performant and you are willing to have group memberships remain static for approximately a day, then set skipGroupRefresh to true. This is an insecure configuration as authorization policies that are bound to group membership will not notice if a user has been removed from a particular group until their next login. +
|
||||
|
||||
This is an experimental feature that may be removed or significantly altered in the future. Consumers of this configuration should carefully read all release notes before upgrading to ensure that the meaning of this field has not changed.
|
||||
|===
|
||||
|
||||
|
||||
|
||||
4
generated/1.28/apis/go.mod
generated
4
generated/1.28/apis/go.mod
generated
@@ -4,6 +4,6 @@ module go.pinniped.dev/generated/1.28/apis
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
k8s.io/api v0.28.2
|
||||
k8s.io/apimachinery v0.28.2
|
||||
k8s.io/api v0.28.4
|
||||
k8s.io/apimachinery v0.28.4
|
||||
)
|
||||
|
||||
24
generated/1.28/apis/go.sum
generated
24
generated/1.28/apis/go.sum
generated
@@ -138,7 +138,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
@@ -169,8 +169,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/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/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -205,7 +205,7 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -216,7 +216,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -227,8 +227,8 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -258,7 +258,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
@@ -277,10 +277,10 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
|
||||
k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg=
|
||||
k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
|
||||
k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
|
||||
k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
|
||||
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
|
||||
k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
|
||||
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
4
generated/1.28/client/go.mod
generated
4
generated/1.28/client/go.mod
generated
@@ -5,8 +5,8 @@ go 1.13
|
||||
|
||||
require (
|
||||
go.pinniped.dev/generated/1.28/apis v0.0.0
|
||||
k8s.io/apimachinery v0.28.2
|
||||
k8s.io/client-go v0.28.2
|
||||
k8s.io/apimachinery v0.28.4
|
||||
k8s.io/client-go v0.28.4
|
||||
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9
|
||||
)
|
||||
|
||||
|
||||
34
generated/1.28/client/go.sum
generated
34
generated/1.28/client/go.sum
generated
@@ -164,7 +164,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
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.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
@@ -197,8 +197,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
|
||||
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
|
||||
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -236,8 +236,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
|
||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -248,8 +248,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
|
||||
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
|
||||
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -261,8 +261,8 @@ golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
|
||||
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
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=
|
||||
@@ -296,8 +296,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
@@ -316,12 +316,12 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
k8s.io/api v0.28.2 h1:9mpl5mOb6vXZvqbQmankOfPIGiudghwCoLl1EYfUZbw=
|
||||
k8s.io/api v0.28.2/go.mod h1:RVnJBsjU8tcMq7C3iaRSGMeaKt2TWEUXcpIt/90fjEg=
|
||||
k8s.io/apimachinery v0.28.2 h1:KCOJLrc6gu+wV1BYgwik4AF4vXOlVJPdiqn0yAWWwXQ=
|
||||
k8s.io/apimachinery v0.28.2/go.mod h1:RdzF87y/ngqk9H4z3EL2Rppv5jj95vGS/HaFXrLDApU=
|
||||
k8s.io/client-go v0.28.2 h1:DNoYI1vGq0slMBN/SWKMZMw0Rq+0EQW6/AK4v9+3VeY=
|
||||
k8s.io/client-go v0.28.2/go.mod h1:sMkApowspLuc7omj1FOSUxSoqjr+d5Q0Yc0LOFnYFJY=
|
||||
k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
|
||||
k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
|
||||
k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
|
||||
k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
|
||||
k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
|
||||
k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
|
||||
178
go.mod
178
go.mod
@@ -2,70 +2,90 @@ module go.pinniped.dev
|
||||
|
||||
go 1.20
|
||||
|
||||
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.28.2/go.mod#L14
|
||||
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.28.4/go.mod#L14
|
||||
replace github.com/google/cel-go => github.com/google/cel-go v0.16.1
|
||||
|
||||
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.28.2/go.mod#L50
|
||||
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.28.4/go.mod#L50
|
||||
replace k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9
|
||||
|
||||
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.28.4/go.mod#L40
|
||||
replace google.golang.org/grpc => google.golang.org/grpc v1.56.3
|
||||
|
||||
// Fostite depends on ory/x which depends on more recent versions of opentelemetry.
|
||||
// We need to use the older versions of opentelemetry which are the direct dependencies of
|
||||
// https://github.com/kubernetes/apiserver/blob/v0.28.4/go.mod. Wherever they clash, replace
|
||||
// with the version which is more consistent with kubernetes/apiserver. We will update these
|
||||
// when kubernetes/apiserver v0.29.x is released and it bumps these dependencies.
|
||||
replace (
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace => go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.35.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1
|
||||
go.opentelemetry.io/otel => go.opentelemetry.io/otel v1.10.0
|
||||
go.opentelemetry.io/otel/exporters/jaeger => go.opentelemetry.io/otel/exporters/jaeger v1.10.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace => go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.10.0
|
||||
go.opentelemetry.io/otel/exporters/zipkin => go.opentelemetry.io/otel/exporters/zipkin v1.10.0
|
||||
go.opentelemetry.io/otel/metric => go.opentelemetry.io/otel/metric v0.31.0
|
||||
go.opentelemetry.io/otel/sdk => go.opentelemetry.io/otel/sdk v1.10.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/MakeNowJust/heredoc/v2 v2.0.1
|
||||
github.com/chromedp/cdproto v0.0.0-20231007061347-18b01cd81617
|
||||
github.com/chromedp/chromedp v0.9.2
|
||||
github.com/coreos/go-oidc/v3 v3.6.0
|
||||
github.com/chromedp/cdproto v0.0.0-20231205062650-00455a960d61
|
||||
github.com/chromedp/chromedp v0.9.3
|
||||
github.com/coreos/go-oidc/v3 v3.9.0
|
||||
github.com/coreos/go-semver v0.3.1
|
||||
github.com/creack/pty v1.1.18
|
||||
github.com/creack/pty v1.1.21
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/felixge/httpsnoop v1.0.3
|
||||
github.com/felixge/httpsnoop v1.0.4
|
||||
github.com/go-jose/go-jose/v3 v3.0.1
|
||||
github.com/go-ldap/ldap/v3 v3.4.6
|
||||
github.com/go-logr/logr v1.2.4
|
||||
github.com/go-logr/logr v1.3.0
|
||||
github.com/go-logr/stdr v1.2.2
|
||||
github.com/go-logr/zapr v1.2.4
|
||||
github.com/go-logr/zapr v1.3.0
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/cel-go v0.18.1
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/google/cel-go v0.18.2
|
||||
github.com/google/go-cmp v0.6.0
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/google/uuid v1.3.1
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/gorilla/securecookie v1.1.2
|
||||
github.com/gorilla/websocket v1.5.1
|
||||
github.com/joshlf/go-acl v0.0.0-20200411065538-eae00ae38531
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||
github.com/ory/fosite v0.44.0
|
||||
github.com/ory/fosite v0.44.1-0.20231113125121-dfa2c0a1b63c
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/sclevine/spec v1.4.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tdewolff/minify/v2 v2.12.9
|
||||
github.com/tdewolff/minify/v2 v2.20.9
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/net v0.16.0
|
||||
golang.org/x/oauth2 v0.13.0
|
||||
golang.org/x/sync v0.4.0
|
||||
golang.org/x/term v0.13.0
|
||||
golang.org/x/text v0.13.0
|
||||
gopkg.in/square/go-jose.v2 v2.6.0
|
||||
k8s.io/api v0.28.2
|
||||
k8s.io/apiextensions-apiserver v0.28.2
|
||||
k8s.io/apimachinery v0.28.2
|
||||
k8s.io/apiserver v0.28.2
|
||||
k8s.io/client-go v0.28.2
|
||||
k8s.io/component-base v0.28.2
|
||||
golang.org/x/crypto v0.16.0
|
||||
golang.org/x/net v0.19.0
|
||||
golang.org/x/oauth2 v0.15.0
|
||||
golang.org/x/sync v0.5.0
|
||||
golang.org/x/term v0.15.0
|
||||
golang.org/x/text v0.14.0
|
||||
k8s.io/api v0.28.4
|
||||
k8s.io/apiextensions-apiserver v0.28.4
|
||||
k8s.io/apimachinery v0.28.4
|
||||
k8s.io/apiserver v0.28.4
|
||||
k8s.io/client-go v0.28.4
|
||||
k8s.io/component-base v0.28.4
|
||||
k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01
|
||||
k8s.io/klog/v2 v2.100.1
|
||||
k8s.io/kube-aggregator v0.28.2
|
||||
k8s.io/kube-openapi v0.0.0-20231009201959-f62364c3c354
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
|
||||
sigs.k8s.io/yaml v1.3.0
|
||||
k8s.io/klog/v2 v2.110.1
|
||||
k8s.io/kube-aggregator v0.28.4
|
||||
k8s.io/kube-openapi v0.0.0-20231206194836-bf4651e18aa8
|
||||
k8s.io/utils v0.0.0-20231127182322-b307cd553661
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
@@ -73,53 +93,54 @@ require (
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/creasty/defaults v1.7.0 // indirect
|
||||
github.com/cristalhq/jwt/v4 v4.0.2 // indirect
|
||||
github.com/dave/jennifer v1.4.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.0 // indirect
|
||||
github.com/dave/jennifer v1.6.1 // indirect
|
||||
github.com/dgraph-io/ristretto v0.1.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/ecordell/optgen v0.0.6 // indirect
|
||||
github.com/ecordell/optgen v0.0.9 // indirect
|
||||
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.0 // 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.3 // indirect
|
||||
github.com/gobuffalo/pop/v6 v6.0.8 // indirect
|
||||
github.com/gobwas/httphead v0.1.0 // indirect
|
||||
github.com/gobwas/pool v0.2.1 // indirect
|
||||
github.com/gobwas/ws v1.2.1 // indirect
|
||||
github.com/gobwas/ws v1.3.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/glog v1.1.0 // indirect
|
||||
github.com/golang/glog v1.1.1 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/gnostic-models v0.6.8 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.13 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/joshlf/testutil v0.0.0-20170608050642-b5d8aa79d93d // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/goveralls v0.0.11 // indirect
|
||||
github.com/mattn/goveralls v0.0.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/ory/go-acc v0.2.8 // indirect
|
||||
github.com/openzipkin/zipkin-go v0.4.1 // indirect
|
||||
github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe // indirect
|
||||
github.com/ory/go-convenience v0.1.0 // indirect
|
||||
github.com/ory/viper v1.7.5 // indirect
|
||||
github.com/ory/x v0.0.409 // indirect
|
||||
github.com/pborman/uuid v1.2.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/ory/x v0.0.575 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.9 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/pquerna/cachecontrol v0.1.0 // indirect
|
||||
github.com/prometheus/client_golang v1.16.0 // indirect
|
||||
@@ -127,43 +148,54 @@ require (
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.10.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/spf13/afero v1.9.5 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/viper v1.16.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.4.0 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.6.8 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
github.com/tdewolff/parse/v2 v2.7.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.1 // indirect
|
||||
go.opentelemetry.io/otel v1.10.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.10.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.42.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.42.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.17.0 // indirect
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.17.0 // indirect
|
||||
go.opentelemetry.io/contrib/samplers/jaegerremote v0.11.0 // indirect
|
||||
go.opentelemetry.io/otel v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.10.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.31.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.10.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.10.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/zipkin v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.16.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.16.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/mod v0.10.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220827204233-334a2380cb91 // indirect
|
||||
golang.org/x/mod v0.12.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.8.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect
|
||||
golang.org/x/tools v0.11.1 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230731193218-e0aa005b6bdf // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
|
||||
google.golang.org/grpc v1.57.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.66.6 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/kms v0.28.2 // indirect
|
||||
k8s.io/kms v0.28.4 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.1.2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
# See https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md
|
||||
# and https://kupczynski.info/posts/fips-golang/ for details.
|
||||
|
||||
ARG BUILD_IMAGE=golang:1.21.5@sha256:2ff79bcdaff74368a9fdcb06f6599e54a71caf520fd2357a55feddd504bcaffb
|
||||
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:91ca4720011393f4d4cab3a01fa5814ee2714b7d40e6c74f2505f74168398ca9
|
||||
|
||||
# This is not currently using --platform to prepare to cross-compile because we use gcc below to build
|
||||
# platform-specific GCO code. This makes multi-arch builds slow due to target platform emulation.
|
||||
FROM golang:1.21.2 as build-env
|
||||
FROM $BUILD_IMAGE as build-env
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
@@ -66,7 +69,7 @@ RUN \
|
||||
# Note that we are not using --platform here, so it will choose the base image for the target platform, not the build platform.
|
||||
# By using "distroless/static" instead of "distroless/static-debianXX" we can float on the latest stable version of debian.
|
||||
# See https://github.com/GoogleContainerTools/distroless#base-operating-system
|
||||
FROM gcr.io/distroless/static:nonroot@sha256:2a9e2b4fa771d31fe3346a873be845bfc2159695b9f90ca08e950497006ccc2e
|
||||
FROM $BASE_IMAGE
|
||||
|
||||
# Copy the server binary from the build-env stage.
|
||||
COPY --from=build-env /usr/local/bin /usr/local/bin
|
||||
|
||||
232
hack/debug-ldapidentityprovider.sh
Executable file
232
hack/debug-ldapidentityprovider.sh
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# This script is a rough approximation of what the Pinniped Supervisor Golang code does to search an LDAP provider
|
||||
# during an end-user's login. This is intended to be helpful for debugging your LDAPIdentityProvider spec settings.
|
||||
# Because it is implemented in bash, it is not necessarily exactly the same as the actual Supervisor code.
|
||||
# Note that this does not yet support ActiveDirectoryIdentityProvider, which has some more complex behavior to
|
||||
# determine default values for some of the spec fields.
|
||||
|
||||
pinniped_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$pinniped_path" || exit 1
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
#
|
||||
# Handle argument parsing and help message
|
||||
#
|
||||
help=no
|
||||
resource_type_and_name=""
|
||||
namespace=""
|
||||
username=""
|
||||
|
||||
while (("$#")); do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
help=yes
|
||||
shift
|
||||
;;
|
||||
-r | --resource)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-r|--resource requires a resource type and name to be specified as type/name"
|
||||
exit 1
|
||||
fi
|
||||
resource_type_and_name=$1
|
||||
shift
|
||||
;;
|
||||
-n | --namespace)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-n|--namespace requires a namespace name to be specified"
|
||||
exit 1
|
||||
fi
|
||||
namespace=$1
|
||||
shift
|
||||
;;
|
||||
-u | --username)
|
||||
shift
|
||||
# If there are no more command line arguments, or there is another command line argument but it starts with a dash, then error
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "-u|--username requires a username to be specified"
|
||||
exit 1
|
||||
fi
|
||||
username=$1
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
log_error "Unsupported flag $1" >&2
|
||||
if [[ "$1" == *"active-directory"* ]]; then
|
||||
log_error "Did you mean --get-active-directory-vars?"
|
||||
fi
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported positional arg $1" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$help" == "yes" ]]; then
|
||||
me="$(basename "${BASH_SOURCE[0]}")"
|
||||
log_note "Usage:"
|
||||
log_note " $me [flags]"
|
||||
log_note
|
||||
log_note "Flags:"
|
||||
log_note " -h, --help: print this usage"
|
||||
log_note " -r, --resource: specify the resource type and name (e.g. ldapidentityprovider/my-ldap-idp) - required"
|
||||
log_note " -n, --namespace: specify the namespace in which the resource exists - required"
|
||||
log_note " -u, --username: specify a username, as an end-user would type it during a login - required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$namespace" ]]; then
|
||||
log_error "-n|--namespace is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$resource_type_and_name" ]]; then
|
||||
log_error "-r|--resource is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$resource_type_and_name" != ldapidentityprovider/* ]]; then
|
||||
log_error "-r|--resource currently only supports ldapidentityprovider type resources."
|
||||
log_error "Please specify the value as \"ldapidentityprovider/name-of-resource\"."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$username" ]]; then
|
||||
log_error "-u|--username is required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RESOURCE_FILE=$(mktemp)
|
||||
trap "rm $RESOURCE_FILE" EXIT
|
||||
|
||||
kubectl get "$resource_type_and_name" \
|
||||
--namespace "$namespace" \
|
||||
--output yaml >"$RESOURCE_FILE"
|
||||
|
||||
# See docs for LDAPIdentityProvider.spec for details about these settings.
|
||||
# https://github.com/vmware-tanzu/pinniped/blob/main/generated/1.28/README.adoc#k8s-api-go-pinniped-dev-generated-1-28-apis-supervisor-idp-v1alpha1-ldapidentityproviderspec
|
||||
LDAP_HOST=$(yq '.spec.host' "$RESOURCE_FILE") # required
|
||||
LDAP_CA_BUNDLE=$(yq '.spec.tls.certificateAuthorityData // ""' "$RESOURCE_FILE") # optional
|
||||
LDAP_BIND_SECRETNAME=$(yq '.spec.bind.secretName' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_BASE=$(yq '.spec.userSearch.base' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_FILTER=$(yq '.spec.userSearch.filter // ""' "$RESOURCE_FILE") # optional unless Attributes.Username is set to "dn"
|
||||
LDAP_USER_SEARCH_ATTRIBUTES_USERNAME=$(yq '.spec.userSearch.attributes.username' "$RESOURCE_FILE") # required
|
||||
LDAP_USER_SEARCH_ATTRIBUTES_UID=$(yq '.spec.userSearch.attributes.uid' "$RESOURCE_FILE") # required
|
||||
LDAP_GROUP_SEARCH_BASE=$(yq '.spec.groupSearch.base // ""' "$RESOURCE_FILE") # optional, disables group search when blank
|
||||
LDAP_GROUP_SEARCH_FILTER=$(yq '.spec.groupSearch.filter // ""' "$RESOURCE_FILE") # optional, defaults to member={}
|
||||
LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER=$(yq '.spec.groupSearch.userAttributeForFilter // ""' "$RESOURCE_FILE") # optional, defaults to using dn
|
||||
LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME=$(yq '.spec.groupSearch.attributes.groupName // ""' "$RESOURCE_FILE") # optional, defaults to using dn
|
||||
|
||||
# Set defaults for missing optional values.
|
||||
if [[ -z "$LDAP_USER_SEARCH_FILTER" ]]; then
|
||||
LDAP_USER_SEARCH_FILTER="${LDAP_USER_SEARCH_ATTRIBUTES_USERNAME}={}"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_FILTER" ]]; then
|
||||
LDAP_GROUP_SEARCH_FILTER="member={}"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER" ]]; then
|
||||
LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER="dn"
|
||||
fi
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME" ]]; then
|
||||
LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME="dn"
|
||||
fi
|
||||
|
||||
# LDAP filters must be surrounded by parens. Pinniped will automatically add
|
||||
# the missing parens, if needed, as a convenience, so do that here too.
|
||||
if [[ "$LDAP_USER_SEARCH_FILTER" != "("* ]]; then
|
||||
LDAP_USER_SEARCH_FILTER="(${LDAP_USER_SEARCH_FILTER})"
|
||||
fi
|
||||
if [[ "$LDAP_GROUP_SEARCH_FILTER" != "("* ]]; then
|
||||
LDAP_GROUP_SEARCH_FILTER="(${LDAP_GROUP_SEARCH_FILTER})"
|
||||
fi
|
||||
|
||||
LDAP_BIND_SECRET_FILE=$(mktemp)
|
||||
trap "rm $LDAP_BIND_SECRET_FILE" EXIT
|
||||
|
||||
kubectl get secret "$LDAP_BIND_SECRETNAME" \
|
||||
--namespace "$namespace" \
|
||||
--output yaml >"$LDAP_BIND_SECRET_FILE"
|
||||
|
||||
LDAP_BIND_DN=$(yq '.data.username | @base64d' "$LDAP_BIND_SECRET_FILE") # required
|
||||
LDAP_BIND_PASSWORD=$(yq '.data.password | @base64d' "$LDAP_BIND_SECRET_FILE") # required
|
||||
|
||||
basic_cmd=()
|
||||
|
||||
if [[ -n "${LDAP_CA_BUNDLE}" ]]; then
|
||||
LDAP_CA_BUNDLE_FILE="/tmp/ldap_tls_cacert.pem"
|
||||
echo "$LDAP_CA_BUNDLE" | base64 -d >$LDAP_CA_BUNDLE_FILE
|
||||
|
||||
basic_cmd+=("LDAPTLS_CACERT=$LDAP_CA_BUNDLE_FILE")
|
||||
fi
|
||||
|
||||
basic_cmd+=("ldapsearch" "-x")
|
||||
basic_cmd+=("-H" "'ldaps://$LDAP_HOST'")
|
||||
|
||||
if [[ -n "${LDAP_BIND_DN}" ]]; then
|
||||
basic_cmd+=("-D" "'$LDAP_BIND_DN'")
|
||||
fi
|
||||
|
||||
if [[ -n "${LDAP_BIND_PASSWORD}" ]]; then
|
||||
basic_cmd+=("-w" "'$LDAP_BIND_PASSWORD'")
|
||||
fi
|
||||
|
||||
# Construct a command which will print the whole user record, if found.
|
||||
find_user_cmd=${basic_cmd[*]}
|
||||
find_user_cmd+=("-b" "'$LDAP_USER_SEARCH_BASE'")
|
||||
find_user_cmd+=("-z" "1") # limit one result
|
||||
find_user_cmd+=("-s" "sub")
|
||||
find_user_cmd+=("'${LDAP_USER_SEARCH_FILTER//\{\}/"$username"}'")
|
||||
|
||||
log_note "# The following commands are provided to aid in debugging."
|
||||
log_note "# Copy and paste these commands into a bash shell to run them."
|
||||
|
||||
echo
|
||||
log_note "# Use the following command to search for the user's LDAP record."
|
||||
log_note "# The value of the \"$LDAP_USER_SEARCH_ATTRIBUTES_USERNAME\" attribute will be their Kubernetes username"
|
||||
log_note "# (not including any configured transformations on the FederationDomain),"
|
||||
log_note "# and the value of the \"$LDAP_USER_SEARCH_ATTRIBUTES_UID\" attribute will be their Supervisor UID."
|
||||
echo "${find_user_cmd[*]}"
|
||||
|
||||
if [[ -z "$LDAP_GROUP_SEARCH_BASE" ]]; then
|
||||
echo
|
||||
log_note "# Group search is not enabled because spec.groupSearch.base is empty."
|
||||
exit
|
||||
fi
|
||||
|
||||
# Add more to the user search command to get only the value of the configured username attribute.
|
||||
find_user_cmd+=("$LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER" "-LLL")
|
||||
find_user_cmd+=("|" "grep" "-E" "'^${LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER}: '")
|
||||
find_user_cmd+=("|" "sed" "'s/^${LDAP_GROUP_SEARCH_USER_ATTRIBUTE_FOR_FILTER}: //'")
|
||||
|
||||
# Construct a command that will print a list of group names to which the user belongs.
|
||||
find_groups_cmd=${basic_cmd[*]}
|
||||
find_groups_cmd+=("-b" "'$LDAP_GROUP_SEARCH_BASE'")
|
||||
find_groups_cmd+=("-s" "sub")
|
||||
find_groups_cmd+=('${LDAP_GROUP_SEARCH_FILTER//\{\}/"$GROUP_SEARCH_KEY"}')
|
||||
find_groups_cmd+=("${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}")
|
||||
find_groups_cmd+=("-LLL")
|
||||
find_groups_cmd+=("|" "grep" "-E" "'^${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}: '")
|
||||
find_groups_cmd+=("|" "sed" "'s/^${LDAP_GROUP_SEARCH_ATTRIBUTES_GROUPNAME}: //'")
|
||||
|
||||
echo
|
||||
log_note "# Use the following three commands to search for the user's group memberships."
|
||||
log_note "# The third command should result in their list of group names for Kubernetes"
|
||||
log_note "# (not including any configured transformations on the FederationDomain)."
|
||||
echo "LDAP_GROUP_SEARCH_FILTER=\"${LDAP_GROUP_SEARCH_FILTER}\""
|
||||
echo
|
||||
echo "GROUP_SEARCH_KEY=\$( ${find_user_cmd[*]} ) && echo \$GROUP_SEARCH_KEY"
|
||||
echo
|
||||
echo "${find_groups_cmd[*]}"
|
||||
echo
|
||||
@@ -15,7 +15,7 @@ go version
|
||||
# so you can get the same results when running the linter locally.
|
||||
# Whenever the linter is updated in the CI pipelines, it should also be
|
||||
# updated here to make local development more convenient.
|
||||
go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2
|
||||
go install -v github.com/golangci/golangci-lint/cmd/golangci-lint@v1.55.1
|
||||
golangci-lint --version
|
||||
|
||||
echo "Finished. You may need to run 'rehash' in your current shell before using the new version (e.g. if you are using gvm)."
|
||||
|
||||
@@ -1,11 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
||||
# Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${ROOT}"
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
reg_name='kind-registry.local'
|
||||
|
||||
# If the container is running...
|
||||
if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" == 'true' ]; then
|
||||
# Disconnect it from the kind network, if it was connected.
|
||||
if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" != 'null' ]; then
|
||||
docker network disconnect "kind" "${reg_name}" >/dev/null
|
||||
fi
|
||||
|
||||
log_note "Stopping container $reg_name ..."
|
||||
docker stop "${reg_name}" >/dev/null
|
||||
|
||||
# Delete it.
|
||||
docker rm "${reg_name}" >/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
kind delete cluster --name pinniped
|
||||
|
||||
@@ -8,13 +8,60 @@ set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${ROOT}"
|
||||
|
||||
if [[ "${PINNIPED_USE_CONTOUR:-}" != "" ]]; then
|
||||
echo "Adding Contour port mapping to Kind config."
|
||||
ytt -f "${ROOT}/hack/lib/kind-config/single-node.yaml" \
|
||||
-f "${ROOT}/hack/lib/kind-config/contour-overlay.yaml" >/tmp/kind-config.yaml
|
||||
kind create cluster --config /tmp/kind-config.yaml --name pinniped
|
||||
else
|
||||
# To choose a specific version of kube, add this option to the command below: `--image kindest/node:v1.28.0`.
|
||||
# To debug the kind config, add this option to the command below: `-v 10`
|
||||
kind create cluster --config "hack/lib/kind-config/single-node.yaml" --name pinniped
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
# Create registry container unless it already exists.
|
||||
reg_name='kind-registry.local'
|
||||
reg_port='5000'
|
||||
if [ "$(docker inspect -f '{{.State.Running}}' "${reg_name}" 2>/dev/null || true)" != 'true' ]; then
|
||||
log_note "Running the registry:2 docker image..."
|
||||
docker run \
|
||||
--detach \
|
||||
--restart=always \
|
||||
--publish "127.0.0.1:${reg_port}:5000" \
|
||||
--name "${reg_name}" \
|
||||
registry:2
|
||||
fi
|
||||
fi
|
||||
|
||||
use_contour_registry=""
|
||||
if [[ "${PINNIPED_USE_CONTOUR:-}" != "" ]]; then
|
||||
log_note "Adding Contour port mapping to Kind config."
|
||||
use_contour_registry="--file=${ROOT}/hack/lib/kind-config/contour-overlay.yaml"
|
||||
fi
|
||||
|
||||
use_kind_registry=""
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
log_note "Adding local registry to Kind config."
|
||||
use_kind_registry="--file=${ROOT}/hack/lib/kind-config/kind-registry-overlay.yaml"
|
||||
fi
|
||||
|
||||
# Do not quote ${use_kind_registry} ${use_contour_registry} in this command because they might be empty.
|
||||
ytt ${use_kind_registry} ${use_contour_registry} --file="${ROOT}"/hack/lib/kind-config/single-node.yaml >/tmp/kind-config.yaml
|
||||
|
||||
# To choose a specific version of kube, add this option to the command below: `--image kindest/node:v1.28.0`.
|
||||
# To debug the kind config, add this option to the command below: `-v 10`
|
||||
kind create cluster --config /tmp/kind-config.yaml --name pinniped
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
# Connect the registry to the cluster network if not already connected.
|
||||
if [ "$(docker inspect -f='{{json .NetworkSettings.Networks.kind}}' "${reg_name}")" == 'null' ]; then
|
||||
docker network connect "kind" "${reg_name}"
|
||||
fi
|
||||
|
||||
# Document the local registry.
|
||||
# See https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
|
||||
cat <<EOF | kubectl apply -f -
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: local-registry-hosting
|
||||
namespace: kube-public
|
||||
data:
|
||||
localRegistryHosting.v1: |
|
||||
host: "localhost:${reg_port}"
|
||||
help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
|
||||
EOF
|
||||
|
||||
fi
|
||||
|
||||
135
hack/lib/carvel_packages/build.sh
Executable file
135
hack/lib/carvel_packages/build.sh
Executable file
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#
|
||||
# This script can be used in conjunction with prepare-for-integration-tests.sh.
|
||||
# When invoked with the PINNIPED_USE_LOCAL_KIND_REGISTRY environment variable set to a non-empty value,
|
||||
# the prepare-for-integration-tests.sh script will create a local docker registry and configure kind to use the registry.
|
||||
# This script will build the Pinniped binary and container image.
|
||||
# This script will then create Carvel Packages for supervisor, concierge, and local-user-authenticator.
|
||||
# It will also create a Carvel PackageRepository.
|
||||
# The PackageRepository will be installed on the kind cluster.
|
||||
#
|
||||
# Example usage:
|
||||
# PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/prepare-for-integration-tests.sh --clean --pre-install ./hack/lib/carvel_packages/build.sh --alternate-deploy ./hack/lib/carvel_packages/deploy.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# This script is best invoked from the root directory.
|
||||
# It is designed to be passed as --pre-install flag to hack/prepare-for-integration-tests.sh.
|
||||
hack_lib_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${hack_lib_path}/../../" || exit 1
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
# Check for dependencies
|
||||
check_dependency kbld "Please install kbld. e.g. 'brew tap vmware-tanzu/carvel && brew install kbld' for MacOS"
|
||||
check_dependency imgpkg "Please install imgpkg. e.g. 'brew tap vmware-tanzu/carvel && brew install imgpkg' for MacOS"
|
||||
check_dependency vendir "Please install vendir. e.g. 'brew tap vmware-tanzu/carvel && brew install vendir' for MacOS"
|
||||
|
||||
# Expected arguments.
|
||||
app=${1:-"app-argument-not-provided"}
|
||||
tag=${2:-"tag-argument-not-provided"}
|
||||
registry=${3:-"registry-argument-not-provided"}
|
||||
repo=${4:-"repo-argument-not-provided"}
|
||||
|
||||
log_note "build.sh called with app: ${app} tag: ${tag} registry: ${registry} repo: ${repo}"
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" == "" ]]; then
|
||||
log_error "Building the Carvel package requires configuring kind with a local registry."
|
||||
log_error "please set the environment variable PINNIPED_USE_LOCAL_KIND_REGISTRY"
|
||||
log_error "for example:"
|
||||
log_error " PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/prepare-for-integration-tests.sh --clean --pre-install ./hack/lib/carvel_packages/build.sh --alternate-deploy ./hack/lib/carvel_packages/deploy.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pinniped_package_version="${tag}" # ie, "0.25.0"
|
||||
registry_repo="$registry/$repo"
|
||||
|
||||
api_group_suffix="pinniped.dev"
|
||||
|
||||
# Package prefix for pinniped-concierge, pinniped-supervisor, local-user-authenticator
|
||||
package_repo_prefix="${registry_repo}/package" # + $resource_name + ":" + $tag
|
||||
|
||||
# Pinniped Package repository
|
||||
package_repository_repo="pinniped-package-repository"
|
||||
package_repository_repo_tag="${registry_repo}/${package_repository_repo}:${tag}"
|
||||
|
||||
carvel_package_src="hack/lib/carvel_packages"
|
||||
template_src_dir="${carvel_package_src}/templates"
|
||||
|
||||
dest_dir="deploy_carvel_tmp"
|
||||
# clean the root carvel package directory
|
||||
rm -rf "${dest_dir}"
|
||||
mkdir -p "${dest_dir}"
|
||||
|
||||
# Generate the OpenAPI v3 Schema files, imgpkg images.yml files
|
||||
declare -a packages_to_build=("local-user-authenticator" "pinniped-concierge" "pinniped-supervisor")
|
||||
for resource_name in "${packages_to_build[@]}"; do
|
||||
resource_qualified_name="${resource_name}.${api_group_suffix}"
|
||||
package_repo_tag="${package_repo_prefix}-${resource_name}:${tag}"
|
||||
|
||||
# sources
|
||||
resource_package_template_source_dir="${template_src_dir}/${resource_name}"
|
||||
# destinations
|
||||
resource_destination_dir="${dest_dir}/${resource_name}"
|
||||
resource_config_destination_dir="${resource_destination_dir}/config"
|
||||
|
||||
log_note "Copying static template files for ${resource_name}..."
|
||||
mkdir "${resource_destination_dir}"
|
||||
cp "${resource_package_template_source_dir}/metadata.yml" "${resource_destination_dir}/metadata.yml"
|
||||
cp "${resource_package_template_source_dir}/build.yml" "${resource_destination_dir}/build.yml"
|
||||
cp "${resource_package_template_source_dir}/vendir.yml" "${resource_destination_dir}/vendir.yml"
|
||||
cp "${resource_package_template_source_dir}/release_notes.txt" "${resource_destination_dir}/release_notes.txt" # dummy
|
||||
log_note "Vendir sync deploy directory for ${resource_name} to package bundle..."
|
||||
|
||||
pushd "${resource_destination_dir}" >/dev/null
|
||||
vendir sync
|
||||
popd >/dev/null
|
||||
|
||||
log_note "Generating OpenAPI v3 schema for ${resource_name}..."
|
||||
ytt \
|
||||
--file "${resource_config_destination_dir}" \
|
||||
--data-values-schema-inspect \
|
||||
--output openapi-v3 > \
|
||||
"${resource_destination_dir}/schema-openapi.yml"
|
||||
|
||||
log_note "Generating .imgpkg/images.yml for ${resource_name}..."
|
||||
mkdir -p "${resource_destination_dir}/.imgpkg"
|
||||
ytt \
|
||||
--file "${resource_config_destination_dir}" |
|
||||
kbld -f- --imgpkg-lock-output "${resource_destination_dir}/.imgpkg/images.yml"
|
||||
|
||||
log_note "Pushing Pinniped ${resource_name} Package bundle..."
|
||||
imgpkg push --bundle "${package_repo_tag}" --file "${resource_destination_dir}"
|
||||
|
||||
log_note "Generating PackageRepository Package entry for ${resource_name}"
|
||||
# Publish package versions to package repository.
|
||||
packages_dir="${dest_dir}/package_repository/packages/"
|
||||
package_repository_dir="${packages_dir}/${resource_qualified_name}"
|
||||
mkdir -p "${packages_dir}"
|
||||
rm -rf "${package_repository_dir}"
|
||||
mkdir "${package_repository_dir}"
|
||||
|
||||
ytt \
|
||||
--file "${resource_package_template_source_dir}/package-template.yml" \
|
||||
--data-value-file openapi="${resource_destination_dir}/schema-openapi.yml" \
|
||||
--data-value-file releaseNotes="${resource_destination_dir}/release_notes.txt" \
|
||||
--data-value repo_host="${package_repo_prefix}-${resource_name}" \
|
||||
--data-value version="${pinniped_package_version}" >"${package_repository_dir}/${pinniped_package_version}.yml"
|
||||
cp "${resource_package_template_source_dir}/metadata.yml" "${package_repository_dir}/metadata.yml"
|
||||
done
|
||||
|
||||
log_note "Generating .imgpkg/images.yml for Pinniped PackageRepository bundle..."
|
||||
mkdir -p "${dest_dir}/package_repository/.imgpkg"
|
||||
kbld --file "${dest_dir}/package_repository/packages/" --imgpkg-lock-output "${dest_dir}/package_repository/.imgpkg/images.yml"
|
||||
|
||||
log_note "Pushing Pinniped PackageRepository bundle.... "
|
||||
imgpkg push --bundle "${package_repository_repo_tag}" --file "${dest_dir}/package_repository"
|
||||
|
||||
# manually validate the package bundle by pulling it from the registry and examining its contents:
|
||||
# imgpkg pull --bundle "${package_repository_repo_tag}" --output "/tmp/${package_repository_repo_tag}"
|
||||
|
||||
log_note "Building Carvel Packages for Supervisor, Concierge & local-user-authenticator complete."
|
||||
177
hack/lib/carvel_packages/deploy.sh
Executable file
177
hack/lib/carvel_packages/deploy.sh
Executable file
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#
|
||||
# This script can be used in conjunction with prepare-for-integration-tests.sh.
|
||||
# When invoked with the PINNIPED_USE_LOCAL_KIND_REGISTRY environment variable set to a non-empty value,
|
||||
# the prepare-for-integration-tests.sh script will create a local docker registry and configure kind to use the registry.
|
||||
# This script will deploy the Carvel Packages for supervisor, concierge, or local-user-authenticator.
|
||||
#
|
||||
# Example usage:
|
||||
# PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/prepare-for-integration-tests.sh --clean --pre-install ./hack/lib/carvel_packages/build.sh --alternate-deploy ./hack/lib/carvel_packages/deploy.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# This script is best invoked from the root directory.
|
||||
# It is designed to be passed as --alternate-deploy flag to hack/prepare-for-integration-tests.sh.
|
||||
hack_lib_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$hack_lib_path/../../" || exit 1
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
# Expected arguments.
|
||||
app=${1:-"app-argument-not-provided"}
|
||||
tag=${2:-"tag-argument-not-provided"}
|
||||
registry=${3:-"registry-argument-not-provided"}
|
||||
repo=${4:-"repo-argument-not-provided"}
|
||||
data_values_file=${5:-"ytt-data-values-file-argument-not-provided"}
|
||||
|
||||
log_note "deploy.sh called with app: ${app} tag: ${tag} registry: ${registry} repo: ${repo} data_values_file: ${data_values_file}"
|
||||
|
||||
log_note "Begin deploy of carvel package for ${app}..."
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" == "" ]]; then
|
||||
log_error "Building the Carvel package requires configuring kind with a local registry."
|
||||
log_error "Please set the environment variable PINNIPED_USE_LOCAL_KIND_REGISTRY."
|
||||
log_error "For example:"
|
||||
log_error " PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/prepare-for-integration-tests.sh --clean --pre-install ./hack/lib/carvel_packages/build.sh --alternate-deploy ./hack/lib/carvel_packages/deploy.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pinniped_package_version="${tag}" # ie, "0.25.0"
|
||||
registry_repo="$registry/$repo"
|
||||
|
||||
# Pinniped Package repository
|
||||
package_repository_repo="pinniped-package-repository"
|
||||
package_repository_repo_tag="${registry_repo}/${package_repository_repo}:${tag}"
|
||||
|
||||
# Use the same directory as build.sh.
|
||||
dest_dir="deploy_carvel_tmp"
|
||||
|
||||
# Deploy kapp-controller onto kind cluster.
|
||||
log_note "Installing kapp-controller on cluster..."
|
||||
KAPP_CONTROLLER_GLOBAL_NAMESPACE="kapp-controller-packaging-global"
|
||||
kapp deploy --app kapp-controller --file "https://github.com/vmware-tanzu/carvel-kapp-controller/releases/latest/download/release.yml" -y
|
||||
|
||||
# Ensure this directory exists though this script will run several times.
|
||||
mkdir -p "${dest_dir}/install"
|
||||
|
||||
log_note "Deploying Pinniped PackageRepository..."
|
||||
pinniped_package_repository_name="pinniped-package-repository"
|
||||
pinniped_package_repository_file="${dest_dir}/install/packagerepository.${pinniped_package_version}.yml"
|
||||
cat <<EOT >"${pinniped_package_repository_file}"
|
||||
---
|
||||
apiVersion: packaging.carvel.dev/v1alpha1
|
||||
kind: PackageRepository
|
||||
metadata:
|
||||
name: "${pinniped_package_repository_name}"
|
||||
namespace: "${KAPP_CONTROLLER_GLOBAL_NAMESPACE}"
|
||||
spec:
|
||||
fetch:
|
||||
imgpkgBundle:
|
||||
image: "${package_repository_repo_tag}"
|
||||
EOT
|
||||
|
||||
kapp deploy --app "${pinniped_package_repository_name}" --file "${pinniped_package_repository_file}" -y
|
||||
kapp inspect --app "${pinniped_package_repository_name}" --tree
|
||||
|
||||
resource_name="${app}"
|
||||
|
||||
log_note "Creating RBAC for ${resource_name} PackageInstall..."
|
||||
|
||||
namespace="${resource_name}-install-ns"
|
||||
pinniped_package_rbac_prefix="pinniped-package-rbac-${resource_name}"
|
||||
pinniped_package_rbac_file="${dest_dir}/install/${pinniped_package_rbac_prefix}-${resource_name}-rbac.yml"
|
||||
# NOTE: This script is for development purposes running on a local kind cluster.
|
||||
# For any other use case, the generated artifacts should be properly reviewed.
|
||||
# For example, the RBAC generated here should be adjusted to conform to the
|
||||
# principle of LEAST privilege.
|
||||
cat <<EOF >"${pinniped_package_rbac_file}"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: "${namespace}"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: "${pinniped_package_rbac_prefix}-sa-superadmin-dangerous"
|
||||
namespace: "${namespace}"
|
||||
---
|
||||
kind: ClusterRole
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: "${pinniped_package_rbac_prefix}-role-superadmin-dangerous"
|
||||
rules:
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs: ["*"]
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: "${pinniped_package_rbac_prefix}-role-binding-superadmin-dangerous"
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: "${pinniped_package_rbac_prefix}-sa-superadmin-dangerous"
|
||||
namespace: "${namespace}"
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: "${pinniped_package_rbac_prefix}-role-superadmin-dangerous"
|
||||
|
||||
EOF
|
||||
|
||||
kapp deploy --app "${pinniped_package_rbac_prefix}" --file "${pinniped_package_rbac_file}" -y
|
||||
|
||||
log_note "Creating ${resource_name} PackageInstall..."
|
||||
NAMESPACE="${resource_name}-install-ns"
|
||||
PINNIPED_PACKAGE_RBAC_PREFIX="pinniped-package-rbac-${resource_name}"
|
||||
RESOURCE_PACKAGE_VERSION="${resource_name}.pinniped.dev"
|
||||
PACKAGE_INSTALL_FILE_NAME="${dest_dir}/install/${resource_name}-pkginstall.yml"
|
||||
SECRET_NAME="${resource_name}-package-install-secret"
|
||||
|
||||
log_note "Generating ${PACKAGE_INSTALL_FILE_NAME}..."
|
||||
cat >"${PACKAGE_INSTALL_FILE_NAME}" <<EOF
|
||||
---
|
||||
apiVersion: packaging.carvel.dev/v1alpha1
|
||||
kind: PackageInstall
|
||||
metadata:
|
||||
# name, does not have to be versioned, versionSelection.constraints below will handle
|
||||
name: "${resource_name}-package-install"
|
||||
namespace: "${NAMESPACE}"
|
||||
spec:
|
||||
serviceAccountName: "${PINNIPED_PACKAGE_RBAC_PREFIX}-sa-superadmin-dangerous"
|
||||
packageRef:
|
||||
refName: "${RESOURCE_PACKAGE_VERSION}"
|
||||
versionSelection:
|
||||
constraints: "${pinniped_package_version}"
|
||||
values:
|
||||
- secretRef:
|
||||
name: "${SECRET_NAME}"
|
||||
EOF
|
||||
|
||||
log_note "Creating secret ${SECRET_NAME} with ${data_values_file}..."
|
||||
kubectl create secret generic "${SECRET_NAME}" --namespace "${NAMESPACE}" --from-file "${data_values_file}" --dry-run=client -o yaml | kubectl apply -f-
|
||||
|
||||
KAPP_CONTROLLER_APP_NAME="${resource_name}-pkginstall"
|
||||
log_note "Deploying ${KAPP_CONTROLLER_APP_NAME}..."
|
||||
kapp deploy --app "${KAPP_CONTROLLER_APP_NAME}" --file "${PACKAGE_INSTALL_FILE_NAME}" -y
|
||||
|
||||
log_note "Verifying PackageInstall resources..."
|
||||
kubectl get PackageInstall -A | grep pinniped
|
||||
kubectl get secret -A | grep pinniped
|
||||
|
||||
log_note "Listing all package resources (PackageRepository, Package, PackageInstall)..."
|
||||
kubectl get pkgi && kubectl get pkgr && kubectl get pkg
|
||||
|
||||
log_note "Listing all kapp cli apps..."
|
||||
kapp ls --all-namespaces
|
||||
|
||||
log_note "Listing all kapp-controller apps..."
|
||||
kubectl get app --all-namespaces
|
||||
|
||||
log_note "Complete deploy of carvel package for ${app}..."
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: kbld.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
minimumRequiredVersion: 0.31.0
|
||||
overrides:
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: PackageMetadata
|
||||
metadata:
|
||||
name: local-user-authenticator.pinniped.dev
|
||||
spec:
|
||||
displayName: "local-user-authenticator"
|
||||
longDescription: "The local-user-authenticator app is an identity provider used for integration testing and demos. Note that this is not recommended for
|
||||
production use."
|
||||
shortDescription: "The local-user-authenticator app is an identity provider used for integration testing and demos."
|
||||
categories:
|
||||
- auth
|
||||
@@ -0,0 +1,28 @@
|
||||
#@ load("@ytt:data", "data") # for reading data values (generated via ytt's data-values-schema-inspect mode).
|
||||
#@ load("@ytt:yaml", "yaml") # for dynamically decoding the output of ytt's data-values-schema-inspect
|
||||
---
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: Package
|
||||
metadata:
|
||||
name: #@ "local-user-authenticator.pinniped.dev." + data.values.version
|
||||
spec:
|
||||
refName: local-user-authenticator.pinniped.dev
|
||||
version: #@ data.values.version
|
||||
releaseNotes: #@ yaml.decode(data.values.releaseNotes)
|
||||
valuesSchema:
|
||||
openAPIv3: #@ yaml.decode(data.values.openapi)["components"]["schemas"]["dataValues"]
|
||||
template:
|
||||
spec:
|
||||
fetch:
|
||||
- imgpkgBundle:
|
||||
image: #@ data.values.repo_host + ":" + data.values.version
|
||||
template:
|
||||
- ytt:
|
||||
paths:
|
||||
- "config/"
|
||||
- kbld:
|
||||
paths:
|
||||
- ".imgpkg/images.yml"
|
||||
- "-"
|
||||
deploy:
|
||||
- kapp: {}
|
||||
@@ -0,0 +1,4 @@
|
||||
Dummy Release Notes for local-user-authenticator
|
||||
- foo
|
||||
- bar
|
||||
- baz
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: vendir.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
directories:
|
||||
- path: config
|
||||
contents:
|
||||
- path: .
|
||||
directory:
|
||||
path: ../../deploy/local-user-authenticator
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: kbld.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
minimumRequiredVersion: 0.31.0
|
||||
overrides:
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: PackageMetadata
|
||||
metadata:
|
||||
name: pinniped-concierge.pinniped.dev
|
||||
spec:
|
||||
displayName: "Pinniped Concierge"
|
||||
longDescription: "Pinniped concierge enables consistent login across Kubernetes clusters on public cloud providers such as AKS, EKS and GKE"
|
||||
shortDescription: "Pinniped concierge enables consistent login across public clouds"
|
||||
categories:
|
||||
- auth
|
||||
@@ -0,0 +1,28 @@
|
||||
#@ load("@ytt:data", "data") # for reading data values (generated via ytt's data-values-schema-inspect mode).
|
||||
#@ load("@ytt:yaml", "yaml") # for dynamically decoding the output of ytt's data-values-schema-inspect
|
||||
---
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: Package
|
||||
metadata:
|
||||
name: #@ "pinniped-concierge.pinniped.dev." + data.values.version
|
||||
spec:
|
||||
refName: pinniped-concierge.pinniped.dev
|
||||
version: #@ data.values.version
|
||||
releaseNotes: #@ yaml.decode(data.values.releaseNotes)
|
||||
valuesSchema:
|
||||
openAPIv3: #@ yaml.decode(data.values.openapi)["components"]["schemas"]["dataValues"]
|
||||
template:
|
||||
spec:
|
||||
fetch:
|
||||
- imgpkgBundle:
|
||||
image: #@ data.values.repo_host + ":" + data.values.version
|
||||
template:
|
||||
- ytt:
|
||||
paths:
|
||||
- "config/"
|
||||
- kbld:
|
||||
paths:
|
||||
- ".imgpkg/images.yml"
|
||||
- "-"
|
||||
deploy:
|
||||
- kapp: {}
|
||||
@@ -0,0 +1,4 @@
|
||||
Dummy Release Notes for Concierge
|
||||
- foo
|
||||
- bar
|
||||
- baz
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: vendir.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
directories:
|
||||
- path: config
|
||||
contents:
|
||||
- path: .
|
||||
directory:
|
||||
path: ../../deploy/concierge
|
||||
@@ -0,0 +1,4 @@
|
||||
apiVersion: kbld.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
minimumRequiredVersion: 0.31.0
|
||||
overrides:
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: PackageMetadata
|
||||
metadata:
|
||||
name: pinniped-supervisor.pinniped.dev
|
||||
spec:
|
||||
displayName: "Pinniped Supervisor"
|
||||
longDescription: "Pinniped supervisor allows seamless login across one or many Kubernetes clusters including AKS, EKS and GKE"
|
||||
shortDescription: "Pinniped supervisor provides login capabilities"
|
||||
categories:
|
||||
- auth
|
||||
@@ -0,0 +1,28 @@
|
||||
#@ load("@ytt:data", "data") # for reading data values (generated via ytt's data-values-schema-inspect mode).
|
||||
#@ load("@ytt:yaml", "yaml") # for dynamically decoding the output of ytt's data-values-schema-inspect
|
||||
---
|
||||
apiVersion: data.packaging.carvel.dev/v1alpha1
|
||||
kind: Package
|
||||
metadata:
|
||||
name: #@ "pinniped-supervisor.pinniped.dev." + data.values.version
|
||||
spec:
|
||||
refName: pinniped-supervisor.pinniped.dev
|
||||
version: #@ data.values.version
|
||||
releaseNotes: #@ yaml.decode(data.values.releaseNotes)
|
||||
valuesSchema:
|
||||
openAPIv3: #@ yaml.decode(data.values.openapi)["components"]["schemas"]["dataValues"]
|
||||
template:
|
||||
spec:
|
||||
fetch:
|
||||
- imgpkgBundle:
|
||||
image: #@ data.values.repo_host + ":" + data.values.version
|
||||
template:
|
||||
- ytt:
|
||||
paths:
|
||||
- "config/"
|
||||
- kbld:
|
||||
paths:
|
||||
- ".imgpkg/images.yml"
|
||||
- "-"
|
||||
deploy:
|
||||
- kapp: {}
|
||||
@@ -0,0 +1,4 @@
|
||||
Dummy Release Notes for Supervisor
|
||||
- foo
|
||||
- bar
|
||||
- baz
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: vendir.k14s.io/v1alpha1
|
||||
kind: Config
|
||||
directories:
|
||||
- path: config
|
||||
contents:
|
||||
- path: .
|
||||
directory:
|
||||
path: ../../deploy/supervisor
|
||||
34
hack/lib/helpers.sh
Normal file
34
hack/lib/helpers.sh
Normal file
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
function log_note() {
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
||||
echo -e "${GREEN}$*${NC}"
|
||||
else
|
||||
echo "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
function log_error() {
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
||||
echo -e "🙁${RED} Error: $* ${NC}"
|
||||
else
|
||||
echo ":( Error: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_dependency() {
|
||||
if ! command -v "$1" >/dev/null; then
|
||||
log_error "Missing dependency..."
|
||||
log_error "$2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
11
hack/lib/kind-config/kind-registry-overlay.yaml
Normal file
11
hack/lib/kind-config/kind-registry-overlay.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
#! Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
#! SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#@ load("@ytt:overlay", "overlay")
|
||||
#@overlay/match by=overlay.subset({"kind": "Cluster"}), expects=1
|
||||
---
|
||||
#@overlay/match missing_ok=True
|
||||
containerdConfigPatches:
|
||||
- |-
|
||||
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."kind-registry.local:5000"]
|
||||
endpoint = ["http://kind-registry.local:5000"]
|
||||
@@ -1,7 +1,7 @@
|
||||
1.28.2
|
||||
1.27.6
|
||||
1.26.9
|
||||
1.25.14
|
||||
1.28.4
|
||||
1.27.8
|
||||
1.26.11
|
||||
1.25.16
|
||||
1.24.17
|
||||
1.23.17
|
||||
1.22.17
|
||||
|
||||
@@ -6,41 +6,21 @@
|
||||
#
|
||||
# This script can be used to prepare a kind cluster and deploy the app.
|
||||
# You can call this script again to redeploy the app.
|
||||
# It will also output instructions on how to run the integration.
|
||||
# It will also output instructions on how to run the integration tests.
|
||||
#
|
||||
# When invoked with the PINNIPED_USE_LOCAL_KIND_REGISTRY environment variable set to a non-empty value, then
|
||||
# this script will create a local registry and configure kind to use that registry. This is normally unnecessary.
|
||||
# However, if an alternative build and deploy approach is used, such as via a Carvel packaging mechanism, then a local
|
||||
# registry could be needed (e.g. the kbld tool requires a registry to resolve images to shas).
|
||||
# For example, to alternatively build and deploy Pinniped as a Carvel package, use:
|
||||
# PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/prepare-for-integration-tests.sh --clean --pre-install ./hack/lib/carvel_packages/build.sh --alternate-deploy ./hack/lib/carvel_packages/deploy.sh
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
function log_note() {
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
||||
echo -e "${GREEN}$*${NC}"
|
||||
else
|
||||
echo "$*"
|
||||
fi
|
||||
}
|
||||
pinniped_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$pinniped_path" || exit 1
|
||||
|
||||
function log_error() {
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
||||
echo -e "🙁${RED} Error: $* ${NC}"
|
||||
else
|
||||
echo ":( Error: $*"
|
||||
fi
|
||||
}
|
||||
|
||||
function check_dependency() {
|
||||
if ! command -v "$1" >/dev/null; then
|
||||
log_error "Missing dependency..."
|
||||
log_error "$2"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
#
|
||||
# Handle argument parsing and help message
|
||||
@@ -52,14 +32,8 @@ api_group_suffix="pinniped.dev" # same default as in the values.yaml ytt file
|
||||
dockerfile_path=""
|
||||
get_active_directory_vars="" # specify a filename for a script to get AD related env variables
|
||||
alternate_deploy="undefined"
|
||||
alternate_deploy_supervisor="undefined"
|
||||
alternate_deploy_concierge="undefined"
|
||||
alternate_deploy_local_user_authenticator="undefined"
|
||||
pre_install="undefined"
|
||||
|
||||
# supported variable style:
|
||||
# --dockerfile-path ./foo.sh
|
||||
# unsupported variable style (using = will fail the script):
|
||||
# --dockerfile-path=./foo.sh
|
||||
while (("$#")); do
|
||||
case "$1" in
|
||||
-h | --help)
|
||||
@@ -113,31 +87,13 @@ while (("$#")); do
|
||||
alternate_deploy=$1
|
||||
shift
|
||||
;;
|
||||
--alternate-deploy-supervisor)
|
||||
--pre-install)
|
||||
shift
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "--alternate-deploy-supervisor requires a script path to be specified"
|
||||
log_error "--pre-install requires a script path to be specified"
|
||||
exit 1
|
||||
fi
|
||||
alternate_deploy_supervisor=$1
|
||||
shift
|
||||
;;
|
||||
--alternate-deploy-concierge)
|
||||
shift
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "--alternate-deploy-concierge requires a script path to be specified"
|
||||
exit 1
|
||||
fi
|
||||
alternate_deploy_concierge=$1
|
||||
shift
|
||||
;;
|
||||
--alternate-deploy-local-user-authenticator)
|
||||
shift
|
||||
if [[ "$#" == "0" || "$1" == -* ]]; then
|
||||
log_error "--alternate-deploy-local-user-authenticator requires a script path to be specified"
|
||||
exit 1
|
||||
fi
|
||||
alternate_deploy_local_user_authenticator=$1
|
||||
pre_install=$1
|
||||
shift
|
||||
;;
|
||||
-*)
|
||||
@@ -160,21 +116,16 @@ if [[ "$help" == "yes" ]]; then
|
||||
log_note " $me [flags]"
|
||||
log_note
|
||||
log_note "Flags:"
|
||||
log_note " -h, --help: print this usage"
|
||||
log_note " -c, --clean: destroy the current kind cluster and make a new one"
|
||||
log_note " -g, --api-group-suffix: deploy Pinniped with an alternate API group suffix"
|
||||
log_note " -s, --skip-build: reuse the most recently built image of the app instead of building"
|
||||
log_note " -a, --get-active-directory-vars: specify a script that exports active directory environment variables"
|
||||
log_note " --alternate-deploy: specify an alternate deploy script to install all components of Pinniped"
|
||||
log_note " --alternate-deploy-supervisor: specify an alternate deploy script to install Pinniped Supervisor"
|
||||
log_note " --alternate-deploy-concierge: specify an alternate deploy script to install Pinniped Concierge"
|
||||
log_note " --alternate-deploy-local-user-authenticator: specify an alternate deploy script to install Pinniped local-user-authenticator"
|
||||
log_note " -h, --help: print this usage"
|
||||
log_note " -c, --clean: destroy the current kind cluster and make a new one"
|
||||
log_note " -g, --api-group-suffix: deploy Pinniped with an alternate API group suffix"
|
||||
log_note " -s, --skip-build: reuse the most recently built image of the app instead of building"
|
||||
log_note " -a, --get-active-directory-vars: specify a script that exports active directory environment variables"
|
||||
log_note " --alternate-deploy: specify an alternate deploy script to install all components of Pinniped"
|
||||
log_note " --pre-install: specify an pre-install script such as a build script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pinniped_path="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$pinniped_path" || exit 1
|
||||
|
||||
#
|
||||
# Check for dependencies
|
||||
#
|
||||
@@ -221,12 +172,33 @@ else
|
||||
fi
|
||||
|
||||
registry="pinniped.local"
|
||||
registry_with_port="$registry"
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
registry="kind-registry.local"
|
||||
registry_with_port="$registry:5000"
|
||||
fi
|
||||
|
||||
repo="test/build"
|
||||
registry_repo="$registry/$repo"
|
||||
tag=$(uuidgen) # always a new tag to force K8s to reload the image on redeploy
|
||||
registry_repo="$registry_with_port/$repo"
|
||||
tag="0.0.0-$(uuidgen)" # always a new tag to force K8s to reload the image on redeploy
|
||||
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
etc_hosts_local_registry_missing=no
|
||||
if ! grep -q "$registry" /etc/hosts; then
|
||||
etc_hosts_local_registry_missing=yes
|
||||
fi
|
||||
if [[ "$etc_hosts_local_registry_missing" == "yes" ]]; then
|
||||
echo
|
||||
log_error "In order to configure the kind cluster to use the local registry properly,"
|
||||
log_error "please run this command to edit /etc/hosts, and then run this script again with the same options."
|
||||
echo "sudo bash -c \"echo '127.0.0.1 $registry' >> /etc/hosts\""
|
||||
log_error "When you are finished with your Kind cluster, you can remove this line from /etc/hosts."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$skip_build" == "yes" ]]; then
|
||||
most_recent_tag=$(docker images "$registry/$repo" --format "{{.Tag}}" | head -1)
|
||||
most_recent_tag=$(docker images "$registry_repo" --format "{{.Tag}}" | head -1)
|
||||
if [[ -n "$most_recent_tag" ]]; then
|
||||
tag="$most_recent_tag"
|
||||
do_build=no
|
||||
@@ -243,7 +215,7 @@ registry_repo_tag="${registry_repo}:${tag}"
|
||||
if [[ "$do_build" == "yes" ]]; then
|
||||
# Rebuild the code
|
||||
testing_version="${KUBE_GIT_VERSION:-}"
|
||||
if [[ "$dockerfile_path" != "" ]]; then
|
||||
if [[ "$dockerfile_path" != "" ]]; then
|
||||
log_note "Docker building the app with dockerfile $dockerfile_path and KUBE_GIT_VERSION='$testing_version'"
|
||||
DOCKER_BUILDKIT=1 docker build . --tag "$registry_repo_tag" --file "$dockerfile_path" --build-arg "KUBE_GIT_VERSION=$testing_version"
|
||||
else
|
||||
@@ -253,31 +225,39 @@ if [[ "$do_build" == "yes" ]]; then
|
||||
fi
|
||||
fi
|
||||
|
||||
# Load it into the cluster
|
||||
log_note "Loading the app's container image into the kind cluster..."
|
||||
kind load docker-image "$registry_repo_tag" --name pinniped
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
# If registry used, push to the registry.
|
||||
log_note "Loading the app's container image into the local registry ($registry_with_port)..."
|
||||
docker push "$registry_repo_tag"
|
||||
else
|
||||
# Otherwise, side-load directly.
|
||||
log_note "Loading the app's container image into the kind cluster..."
|
||||
kind load docker-image "$registry_repo_tag" --name pinniped
|
||||
fi
|
||||
|
||||
if [ "$pre_install" != "undefined" ]; then
|
||||
log_note "Calling the pre-install script with args: $tag $registry_with_port $repo ..."
|
||||
$pre_install pre-install-script "$tag" $registry_with_port $repo
|
||||
fi
|
||||
|
||||
#
|
||||
# Deploy local-user-authenticator
|
||||
#
|
||||
manifest=/tmp/pinniped-local-user-authenticator.yaml
|
||||
data_values_file=/tmp/local-user-authenticator-values.yml
|
||||
cat <<EOF >"$data_values_file"
|
||||
---
|
||||
image_repo: $registry_repo
|
||||
image_tag: $tag
|
||||
EOF
|
||||
|
||||
if [ "$alternate_deploy" != "undefined" ] || [ "$alternate_deploy_local_user_authenticator" != "undefined" ] ; then
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The Pinniped local-user-authenticator will be deployed with $alternate_deploy local-user-authenticator $tag..."
|
||||
$alternate_deploy local-user-authenticator $tag
|
||||
fi
|
||||
if [ "$alternate_deploy_local_user_authenticator" != "undefined" ]; then
|
||||
log_note "The Pinniped local-user-authenticator will be deployed with $alternate_deploy_local_user_authenticator local-user-authenticator $tag..."
|
||||
$alternate_deploy_local_user_authenticator local-user-authenticator $tag
|
||||
fi
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The local-user-authenticator will be deployed with $alternate_deploy local-user-authenticator $tag $registry_with_port $repo $data_values_file ..."
|
||||
$alternate_deploy local-user-authenticator "$tag" $registry_with_port $repo $data_values_file
|
||||
else
|
||||
log_note "Deploying the local-user-authenticator app to the cluster using kapp..."
|
||||
pushd deploy/local-user-authenticator >/dev/null
|
||||
ytt --file . \
|
||||
--data-value "image_repo=$registry_repo" \
|
||||
--data-value "image_tag=$tag" >"$manifest"
|
||||
|
||||
ytt --file . --data-values-file "$data_values_file" >"$manifest"
|
||||
kapp deploy --yes --app local-user-authenticator --diff-changes --file "$manifest"
|
||||
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
||||
popd >/dev/null
|
||||
@@ -297,28 +277,15 @@ ytt --file . \
|
||||
--data-value "pinny_ldap_password=$ldap_test_password" \
|
||||
--data-value "pinny_bcrypt_passwd_hash=$(htpasswd -nbBC 10 x "$dex_test_password" | sed -e "s/^x://")" \
|
||||
>"$manifest"
|
||||
|
||||
kapp deploy --yes --app tools --diff-changes --file "$manifest"
|
||||
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
||||
|
||||
popd >/dev/null
|
||||
|
||||
test_username="test-username"
|
||||
test_groups="test-group-0,test-group-1"
|
||||
test_password="$(openssl rand -hex 16)"
|
||||
log_note "Creating test user '$test_username'..."
|
||||
kubectl create secret generic "$test_username" \
|
||||
--namespace local-user-authenticator \
|
||||
--from-literal=groups="$test_groups" \
|
||||
--from-literal=passwordHash="$(htpasswd -nbBC 10 x "$test_password" | sed -e "s/^x://")" \
|
||||
--dry-run=client \
|
||||
--output yaml |
|
||||
kubectl apply -f -
|
||||
|
||||
#
|
||||
# Deploy the Pinniped Supervisor
|
||||
#
|
||||
manifest=/tmp/pinniped-supervisor.yaml
|
||||
data_values_file=/tmp/supervisor-values.yml
|
||||
supervisor_app_name="pinniped-supervisor"
|
||||
supervisor_namespace="supervisor"
|
||||
supervisor_custom_labels="{mySupervisorCustomLabelName: mySupervisorCustomLabelValue}"
|
||||
@@ -326,32 +293,27 @@ log_level="debug"
|
||||
service_https_nodeport_port="443"
|
||||
service_https_nodeport_nodeport="31243"
|
||||
service_https_clusterip_port="443"
|
||||
cat <<EOF >"$data_values_file"
|
||||
---
|
||||
app_name: $supervisor_app_name
|
||||
namespace: $supervisor_namespace
|
||||
api_group_suffix: $api_group_suffix
|
||||
image_repo: $registry_repo
|
||||
image_tag: $tag
|
||||
log_level: $log_level
|
||||
custom_labels: $supervisor_custom_labels
|
||||
service_https_nodeport_port: $service_https_nodeport_port
|
||||
service_https_nodeport_nodeport: $service_https_nodeport_nodeport
|
||||
service_https_clusterip_port: $service_https_clusterip_port
|
||||
EOF
|
||||
|
||||
if [ "$alternate_deploy" != "undefined" ] || [ "$alternate_deploy_supervisor" != "undefined" ] ; then
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The Pinniped Supervisor will be deployed with $alternate_deploy pinniped-supervisor $tag..."
|
||||
$alternate_deploy pinniped-supervisor $tag
|
||||
fi
|
||||
if [ "$alternate_deploy_supervisor" != "undefined" ]; then
|
||||
log_note "The Pinniped Supervisor will be deployed with $alternate_deploy_supervisor pinniped-supervisor $tag..."
|
||||
$alternate_deploy_supervisor pinniped-supervisor $tag
|
||||
fi
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The Pinniped Supervisor will be deployed with $alternate_deploy pinniped-supervisor $tag $registry_with_port $repo $data_values_file ..."
|
||||
$alternate_deploy pinniped-supervisor "$tag" $registry_with_port $repo $data_values_file
|
||||
else
|
||||
log_note "Deploying the Pinniped Supervisor app to the cluster using kapp..."
|
||||
pushd deploy/supervisor >/dev/null
|
||||
ytt --file . \
|
||||
--data-value "app_name=$supervisor_app_name" \
|
||||
--data-value "namespace=$supervisor_namespace" \
|
||||
--data-value "api_group_suffix=$api_group_suffix" \
|
||||
--data-value "image_repo=$registry_repo" \
|
||||
--data-value "image_tag=$tag" \
|
||||
--data-value "log_level=$log_level" \
|
||||
--data-value-yaml "custom_labels=$supervisor_custom_labels" \
|
||||
--data-value-yaml "service_https_nodeport_port=$service_https_nodeport_port" \
|
||||
--data-value-yaml "service_https_nodeport_nodeport=$service_https_nodeport_nodeport" \
|
||||
--data-value-yaml "service_https_clusterip_port=$service_https_clusterip_port" \
|
||||
>"$manifest"
|
||||
|
||||
ytt --file . --data-values-file "$data_values_file" >"$manifest"
|
||||
kapp deploy --yes --app "$supervisor_app_name" --diff-changes --file "$manifest"
|
||||
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
||||
popd >/dev/null
|
||||
@@ -361,41 +323,55 @@ fi
|
||||
# Deploy the Pinniped Concierge
|
||||
#
|
||||
manifest=/tmp/pinniped-concierge.yaml
|
||||
data_values_file=/tmp/concierge-values.yml
|
||||
concierge_app_name="pinniped-concierge"
|
||||
concierge_namespace="concierge"
|
||||
webhook_url="https://local-user-authenticator.local-user-authenticator.svc/authenticate"
|
||||
webhook_ca_bundle="$(kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')"
|
||||
discovery_url="$(TERM=dumb kubectl cluster-info | awk '/master|control plane/ {print $NF}')"
|
||||
concierge_custom_labels="{myConciergeCustomLabelName: myConciergeCustomLabelValue}"
|
||||
log_level="debug"
|
||||
cat <<EOF >"$data_values_file"
|
||||
---
|
||||
app_name: $concierge_app_name
|
||||
namespace: $concierge_namespace
|
||||
api_group_suffix: $api_group_suffix
|
||||
log_level: $log_level
|
||||
custom_labels: $concierge_custom_labels
|
||||
image_repo: $registry_repo
|
||||
image_tag: $tag
|
||||
discovery_url: $discovery_url
|
||||
EOF
|
||||
|
||||
if [ "$alternate_deploy" != "undefined" ] || [ "$alternate_deploy_concierge" != "undefined" ] ; then
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The Pinniped Concierge will be deployed with $alternate_deploy pinniped-concierge $tag..."
|
||||
$alternate_deploy pinniped-concierge $tag
|
||||
fi
|
||||
if [ "$alternate_deploy_concierge" != "undefined" ]; then
|
||||
log_note "The Pinniped Concierge will be deployed with $alternate_deploy_concierge pinniped-concierge $tag..."
|
||||
$alternate_deploy_concierge pinniped-concierge $tag
|
||||
fi
|
||||
if [ "$alternate_deploy" != "undefined" ]; then
|
||||
log_note "The Pinniped Concierge will be deployed with $alternate_deploy pinniped-concierge $tag $registry_with_port $repo $data_values_file ..."
|
||||
$alternate_deploy pinniped-concierge "$tag" $registry_with_port $repo $data_values_file
|
||||
else
|
||||
log_note "Deploying the Pinniped Concierge app to the cluster using kapp..."
|
||||
pushd deploy/concierge >/dev/null
|
||||
ytt --file . \
|
||||
--data-value "app_name=$concierge_app_name" \
|
||||
--data-value "namespace=$concierge_namespace" \
|
||||
--data-value "api_group_suffix=$api_group_suffix" \
|
||||
--data-value "log_level=$log_level" \
|
||||
--data-value-yaml "custom_labels=$concierge_custom_labels" \
|
||||
--data-value "image_repo=$registry_repo" \
|
||||
--data-value "image_tag=$tag" \
|
||||
--data-value "discovery_url=$discovery_url" >"$manifest"
|
||||
|
||||
ytt --file . --data-values-file "$data_values_file" >"$manifest"
|
||||
kapp deploy --yes --app "$concierge_app_name" --diff-changes --file "$manifest"
|
||||
kubectl apply --dry-run=client -f "$manifest" # Validate manifest schema.
|
||||
popd >/dev/null
|
||||
fi
|
||||
|
||||
#
|
||||
# Create a test user in the local-user-authenticator and get its CA bundle.
|
||||
#
|
||||
log_note "Creating test user for local-user-authenticator..."
|
||||
test_username="test-username"
|
||||
test_groups="test-group-0,test-group-1"
|
||||
test_password="$(openssl rand -hex 16)"
|
||||
|
||||
kubectl create secret generic "$test_username" \
|
||||
--namespace local-user-authenticator \
|
||||
--from-literal=groups="$test_groups" \
|
||||
--from-literal=passwordHash="$(htpasswd -nbBC 10 x "$test_password" | sed -e "s/^x://")" \
|
||||
--dry-run=client \
|
||||
--output yaml |
|
||||
kubectl apply -f -
|
||||
|
||||
webhook_ca_bundle="$(kubectl get secret local-user-authenticator-tls-serving-certificate --namespace local-user-authenticator -o 'jsonpath={.data.caCertificate}')"
|
||||
|
||||
#
|
||||
# Download the test CA bundle that was generated in the Dex pod.
|
||||
# Note that this returns a base64 encoded value.
|
||||
@@ -500,4 +476,8 @@ log_note "You can rerun this script to redeploy local production code changes wh
|
||||
log_note
|
||||
log_note "To delete the deployments, run:"
|
||||
log_note " kapp delete -a local-user-authenticator -y && kapp delete -a $concierge_app_name -y && kapp delete -a $supervisor_app_name -y"
|
||||
log_note "When you're finished, use './hack/kind-down.sh' to tear down the cluster."
|
||||
if [[ "${PINNIPED_USE_LOCAL_KIND_REGISTRY:-}" != "" ]]; then
|
||||
log_note "When you're finished, use 'PINNIPED_USE_LOCAL_KIND_REGISTRY=1 ./hack/kind-down.sh' to tear down the cluster."
|
||||
else
|
||||
log_note "When you're finished, use './hack/kind-down.sh' to tear down the cluster."
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
# Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#
|
||||
@@ -26,6 +26,8 @@ LOCAL_HOST="127.0.0.1:${LOCAL_PORT}"
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
# Build the CLI for use later in the script.
|
||||
go build ./cmd/pinniped
|
||||
|
||||
@@ -85,10 +87,10 @@ EOF
|
||||
# Wait for the CredentialIssuer's impersonator status to update to be successful.
|
||||
while [[ -z "$(kubectl get credentialissuer pinniped-concierge-config -o json |
|
||||
jq '.status.strategies[] | select((.type=="ImpersonationProxy") and (.status=="Success"))')" ]]; do
|
||||
echo "Waiting for a successful ImpersonationProxy strategy on CredentialIssuer..."
|
||||
log_note "Waiting for a successful ImpersonationProxy strategy on CredentialIssuer..."
|
||||
sleep 2
|
||||
done
|
||||
echo "Impersonator is available on https://${LOCAL_HOST}"
|
||||
log_note "Impersonator is available on https://${LOCAL_HOST}"
|
||||
|
||||
# Make the impersonation proxy's port from the inside the cluster available locally.
|
||||
kubectl port-forward -n $CONCIERGE_NAMESPACE deployment/$CONCIERGE_DEPLOYMENT ${LOCAL_PORT}:${IMPERSONATION_PROXY_PORT} &
|
||||
@@ -97,14 +99,14 @@ port_forward_pid=$!
|
||||
# Kill the kubectl port-forward command whenever the script is control-c cancelled or otherwise ends.
|
||||
function cleanup() {
|
||||
echo
|
||||
echo "Cleaning up cluster resources..."
|
||||
log_note "Cleaning up cluster resources..."
|
||||
kubectl delete secret -n $LOCAL_USER_AUTHENTICATOR_NAMESPACE pinny-the-seal
|
||||
kubectl delete configmap -n $CONCIERGE_NAMESPACE pinniped-concierge-impersonation-proxy-config
|
||||
kubectl delete clusterrolebinding pinny-the-seal-can-edit
|
||||
kubectl delete webhookauthenticator local-user-authenticator
|
||||
echo "Stopping kubectl port-forward and exiting..."
|
||||
log_note "Stopping kubectl port-forward and exiting..."
|
||||
# It may have already shut down, so ignore errors.
|
||||
kill -9 $port_forward_pid &> /dev/null || true
|
||||
kill -9 $port_forward_pid &>/dev/null || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
@@ -113,7 +115,7 @@ trap cleanup EXIT
|
||||
--static-token "pinny-the-seal:password123" \
|
||||
--concierge-mode ImpersonationProxy >/tmp/kubeconfig
|
||||
|
||||
echo
|
||||
echo 'Ready. In another tab, use "kubectl --kubeconfig /tmp/kubeconfig <cmd>" to make requests through the impersonation proxy.'
|
||||
echo "When done, cancel with ctrl-C to clean up."
|
||||
log_note
|
||||
log_note 'Ready. In another tab, use "kubectl --kubeconfig /tmp/kubeconfig <cmd>" to make requests through the impersonation proxy.'
|
||||
log_note "When done, cancel with ctrl-C to clean up."
|
||||
wait $port_forward_pid
|
||||
|
||||
@@ -37,15 +37,7 @@ set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
function log_error() {
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
if [[ ${COLORTERM:-unknown} =~ ^(truecolor|24bit)$ ]]; then
|
||||
echo -e "🙁${RED} Error: $* ${NC}"
|
||||
else
|
||||
echo ":( Error: $*"
|
||||
fi
|
||||
}
|
||||
source hack/lib/helpers.sh
|
||||
|
||||
use_oidc_upstream=no
|
||||
use_ldap_upstream=no
|
||||
@@ -122,8 +114,8 @@ if [[ "${PINNIPED_USE_CONTOUR:-}" != "" ]]; then
|
||||
|
||||
# Wait for its pods to be ready.
|
||||
echo "Waiting for Contour to be ready..."
|
||||
kubectl wait --for 'jsonpath={.status.phase}=Succeeded' pods -l 'app=contour-certgen' -n projectcontour --timeout 60s
|
||||
kubectl wait --for 'jsonpath={.status.phase}=Running' pods -l 'app!=contour-certgen' -n projectcontour --timeout 60s
|
||||
kubectl wait --for 'jsonpath={.status.phase}=Succeeded' pods -l 'app=contour-certgen' -n projectcontour --timeout 60s
|
||||
kubectl wait --for 'jsonpath={.status.phase}=Running' pods -l 'app!=contour-certgen' -n projectcontour --timeout 60s
|
||||
|
||||
# Create an ingress for the Supervisor which uses TLS passthrough to allow the Supervisor to terminate TLS.
|
||||
cat <<EOF | kubectl apply --namespace "$PINNIPED_TEST_SUPERVISOR_NAMESPACE" -f -
|
||||
@@ -320,7 +312,7 @@ kubectl create secret tls -n "$PINNIPED_TEST_SUPERVISOR_NAMESPACE" my-federation
|
||||
|
||||
# Make a FederationDomain using the TLS Secret and identity providers from above in a temp file.
|
||||
fd_file="/tmp/federationdomain.yaml"
|
||||
cat << EOF > $fd_file
|
||||
cat <<EOF >$fd_file
|
||||
apiVersion: config.supervisor.pinniped.dev/v1alpha1
|
||||
kind: FederationDomain
|
||||
metadata:
|
||||
@@ -334,7 +326,7 @@ EOF
|
||||
|
||||
if [[ "$use_oidc_upstream" == "yes" ]]; then
|
||||
# Indenting the heredoc by 4 spaces to make it indented the correct amount in the FederationDomain below.
|
||||
cat << EOF >> $fd_file
|
||||
cat <<EOF >>$fd_file
|
||||
|
||||
- displayName: "My OIDC IDP 🚀"
|
||||
objectRef:
|
||||
@@ -358,7 +350,7 @@ fi
|
||||
|
||||
if [[ "$use_ldap_upstream" == "yes" ]]; then
|
||||
# Indenting the heredoc by 4 spaces to make it indented the correct amount in the FederationDomain below.
|
||||
cat << EOF >> $fd_file
|
||||
cat <<EOF >>$fd_file
|
||||
|
||||
- displayName: "My LDAP IDP 🚀"
|
||||
objectRef:
|
||||
@@ -412,7 +404,7 @@ fi
|
||||
|
||||
if [[ "$use_ad_upstream" == "yes" ]]; then
|
||||
# Indenting the heredoc by 4 spaces to make it indented the correct amount in the FederationDomain below.
|
||||
cat << EOF >> $fd_file
|
||||
cat <<EOF >>$fd_file
|
||||
|
||||
- displayName: "My AD IDP"
|
||||
objectRef:
|
||||
|
||||
@@ -2,4 +2,4 @@ module go.pinniped.dev/update-go-mod
|
||||
|
||||
go 1.20
|
||||
|
||||
require golang.org/x/mod v0.13.0
|
||||
require golang.org/x/mod v0.14.0
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
|
||||
@@ -8,21 +8,37 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
)
|
||||
|
||||
func main() {
|
||||
goModFilepath := filepath.Clean(os.Args[1])
|
||||
overridesFilepath := filepath.Clean(os.Args[2])
|
||||
|
||||
if _, err := os.Stat(goModFilepath); err != nil {
|
||||
log.Fatalf("File '%s' does not exist\n", goModFilepath)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(overridesFilepath); err != nil {
|
||||
log.Fatalf("File '%s' does not exist\n", overridesFilepath)
|
||||
}
|
||||
|
||||
var (
|
||||
bytes []byte
|
||||
err error
|
||||
bytes []byte
|
||||
overrides map[string]string
|
||||
err error
|
||||
)
|
||||
|
||||
if bytes, err = os.ReadFile(overridesFilepath); err != nil {
|
||||
log.Fatalf("Unable to read file '%s'\n", overridesFilepath)
|
||||
}
|
||||
|
||||
if overrides, err = parseOverrides(string(bytes)); err != nil {
|
||||
log.Fatalf("Parse error in file '%s': %s\n", overridesFilepath, err.Error())
|
||||
}
|
||||
|
||||
if bytes, err = os.ReadFile(goModFilepath); err != nil {
|
||||
log.Fatalf("Unable to read file '%s'\n", goModFilepath)
|
||||
}
|
||||
@@ -34,9 +50,41 @@ func main() {
|
||||
|
||||
for _, require := range file.Require {
|
||||
if !require.Indirect {
|
||||
fmt.Printf("go get %s &&\n", require.Mod.Path)
|
||||
mod := require.Mod.Path
|
||||
overrideMod, hasOverride := overrides[mod]
|
||||
if hasOverride {
|
||||
mod = overrideMod
|
||||
}
|
||||
fmt.Printf("go get %s &&\n", mod)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("./hack/module.sh tidy\n")
|
||||
}
|
||||
|
||||
func parseOverrides(overridesText string) (map[string]string, error) {
|
||||
overridesMap := map[string]string{}
|
||||
|
||||
lines := strings.Split(overridesText, "\n")
|
||||
|
||||
for i, line := range lines {
|
||||
trimmedLine := strings.TrimSpace(line)
|
||||
|
||||
if strings.HasPrefix(trimmedLine, "#") || len(trimmedLine) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
splitLine := strings.Split(trimmedLine, " ")
|
||||
|
||||
if len(splitLine) != 2 {
|
||||
return nil, fmt.Errorf(
|
||||
"error on line %d: found %d tokens instead of 2 tokens",
|
||||
i+1, len(splitLine),
|
||||
)
|
||||
}
|
||||
|
||||
overridesMap[splitLine[0]] = splitLine[1]
|
||||
}
|
||||
|
||||
return overridesMap, nil
|
||||
}
|
||||
|
||||
5
hack/update-go-mod/overrides.conf
Normal file
5
hack/update-go-mod/overrides.conf
Normal file
@@ -0,0 +1,5 @@
|
||||
# Format:
|
||||
# package_name_as_it_appears_in_go_mod package_name_as_it_should_be_used_with_go_get
|
||||
|
||||
# Fosite has not had a release for a long time, so use the head of their main branch.
|
||||
github.com/ory/fosite github.com/ory/fosite@master
|
||||
@@ -11,9 +11,12 @@ ROOT_DIR="$SCRIPT_DIR/../.."
|
||||
GO_MOD="${ROOT_DIR}/go.mod"
|
||||
|
||||
pushd "${SCRIPT_DIR}" > /dev/null
|
||||
script=$(go run . "${GO_MOD}")
|
||||
script=$(go run . "${GO_MOD}" overrides.conf)
|
||||
popd > /dev/null
|
||||
|
||||
# Print to screen for debugging purposes.
|
||||
echo "$script"
|
||||
|
||||
pushd "${ROOT_DIR}" > /dev/null
|
||||
eval "$script"
|
||||
popd > /dev/null
|
||||
|
||||
43
internal/backoff/infinitebackoff.go
Normal file
43
internal/backoff/infinitebackoff.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type InfiniteBackoff struct {
|
||||
// The initial duration.
|
||||
Duration time.Duration
|
||||
|
||||
// Factor is used to scale up the Duration until it reaches MaxDuration.
|
||||
// Should be at least 1.0.
|
||||
Factor float64
|
||||
|
||||
// A limit on step size. Once reached, this value will be used as the interval.
|
||||
MaxDuration time.Duration
|
||||
|
||||
hasStepped bool
|
||||
}
|
||||
|
||||
// Step returns the next duration in the backoff sequence.
|
||||
// It modifies the receiver and is not thread-safe.
|
||||
func (b *InfiniteBackoff) Step() time.Duration {
|
||||
if !b.hasStepped {
|
||||
b.hasStepped = true
|
||||
return b.Duration
|
||||
}
|
||||
|
||||
var next time.Duration
|
||||
b.Factor = math.Max(1, b.Factor)
|
||||
// Grow by the factor (which could be 1).
|
||||
next = time.Duration(float64(b.Duration) * b.Factor)
|
||||
// Stop growing the intervals once we exceed the max duration.
|
||||
if b.MaxDuration > 0 && next > b.MaxDuration {
|
||||
next = b.MaxDuration
|
||||
}
|
||||
b.Duration = next
|
||||
return next
|
||||
}
|
||||
94
internal/backoff/infinitebackoff_test.go
Normal file
94
internal/backoff/infinitebackoff_test.go
Normal file
@@ -0,0 +1,94 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInfiniteBackoff(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
stepper Stepper
|
||||
expectedSequence []time.Duration
|
||||
}{
|
||||
{
|
||||
name: "zero initialization results in 0ns steps",
|
||||
stepper: &InfiniteBackoff{},
|
||||
expectedSequence: func() []time.Duration {
|
||||
results := make([]time.Duration, 1000)
|
||||
for i := 0; i < 1000; i++ {
|
||||
results[i] = time.Duration(0)
|
||||
}
|
||||
return results
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "double 5 ns forever",
|
||||
stepper: &InfiniteBackoff{
|
||||
Duration: 5 * time.Nanosecond,
|
||||
Factor: 2,
|
||||
},
|
||||
expectedSequence: func() []time.Duration {
|
||||
// limit to 60 to prevent int64 overflow
|
||||
results := make([]time.Duration, 60)
|
||||
results[0] = 5 * time.Nanosecond
|
||||
for i := 1; i < 60; i++ {
|
||||
results[i] = 2 * results[i-1]
|
||||
}
|
||||
return results
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "grows slowly until limit",
|
||||
stepper: &InfiniteBackoff{
|
||||
Duration: 20 * time.Nanosecond,
|
||||
Factor: 1.1,
|
||||
MaxDuration: 40 * time.Nanosecond,
|
||||
},
|
||||
expectedSequence: func() []time.Duration {
|
||||
results := make([]time.Duration, 1000)
|
||||
results[0] = 20 * time.Nanosecond
|
||||
for i := 1; i < 1000; i++ {
|
||||
nanoseconds := 1.1 * float64(results[i-1])
|
||||
results[i] = time.Duration(math.Min(nanoseconds, 40))
|
||||
}
|
||||
return results
|
||||
}(),
|
||||
},
|
||||
{
|
||||
name: "factor less than 1.0 is replaced with 1.0",
|
||||
stepper: &InfiniteBackoff{
|
||||
Duration: 20 * time.Nanosecond,
|
||||
Factor: 0.9,
|
||||
},
|
||||
expectedSequence: func() []time.Duration {
|
||||
results := make([]time.Duration, 1000)
|
||||
for i := 0; i < 1000; i++ {
|
||||
results[i] = 20 * time.Nanosecond
|
||||
}
|
||||
return results
|
||||
}(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
require.NotEmpty(t, tt.expectedSequence)
|
||||
for i, expected := range tt.expectedSequence {
|
||||
actual := tt.stepper.Step()
|
||||
require.Equalf(t, expected, actual, "incorrect result on step #%d, previous steps are %v", i, tt.expectedSequence[:i])
|
||||
}
|
||||
|
||||
backoff, ok := tt.stepper.(*InfiniteBackoff)
|
||||
require.True(t, ok)
|
||||
require.NotNil(t, backoff)
|
||||
require.GreaterOrEqual(t, backoff.Factor, 1.0)
|
||||
})
|
||||
}
|
||||
}
|
||||
56
internal/backoff/stepping.go
Normal file
56
internal/backoff/stepping.go
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
type Stepper interface {
|
||||
Step() time.Duration
|
||||
}
|
||||
|
||||
func wrapConditionWithNoPanics(ctx context.Context, condition wait.ConditionWithContextFunc) (done bool, err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if err2, ok := r.(error); ok {
|
||||
err = err2
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return condition(ctx)
|
||||
}
|
||||
|
||||
func WithContext(ctx context.Context, backoff Stepper, condition wait.ConditionWithContextFunc) error {
|
||||
// Loop forever, unless we reach one of the return statements below.
|
||||
for {
|
||||
// Stop if the context is done.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
// Stop trying unless the condition function returns false.
|
||||
// Allow cancellation during the attempt if the condition function respects the ctx.
|
||||
if ok, err := wrapConditionWithNoPanics(ctx, condition); err != nil || ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// Calculate how long to wait before the next step.
|
||||
waitBeforeRetry := backoff.Step()
|
||||
|
||||
// Wait before running again, allowing cancellation during the wait.
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-time.After(waitBeforeRetry):
|
||||
}
|
||||
}
|
||||
}
|
||||
124
internal/backoff/stepping_test.go
Normal file
124
internal/backoff/stepping_test.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
)
|
||||
|
||||
type MockStepper struct {
|
||||
steps []time.Duration
|
||||
currentStep int
|
||||
}
|
||||
|
||||
func (m *MockStepper) Step() time.Duration {
|
||||
result := m.steps[m.currentStep]
|
||||
m.currentStep++
|
||||
return result
|
||||
}
|
||||
|
||||
func TestWithContext(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
steps []time.Duration
|
||||
finalCondition wait.ConditionWithContextFunc
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
name: "cancelling results in cancellation error",
|
||||
steps: []time.Duration{
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
},
|
||||
finalCondition: func(ctx context.Context) (done bool, err error) {
|
||||
return false, nil
|
||||
},
|
||||
expectedErr: context.Canceled,
|
||||
},
|
||||
{
|
||||
name: "when condition is done, exit early",
|
||||
steps: []time.Duration{
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
},
|
||||
finalCondition: func(ctx context.Context) (done bool, err error) {
|
||||
return true, nil
|
||||
},
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
name: "when condition returns error, exit early",
|
||||
steps: []time.Duration{
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
time.Duration(0),
|
||||
},
|
||||
finalCondition: func(ctx context.Context) (done bool, err error) {
|
||||
return false, errors.New("error from condition")
|
||||
},
|
||||
expectedErr: errors.New("error from condition"),
|
||||
},
|
||||
{
|
||||
name: "when condition panics, cover and exit",
|
||||
steps: []time.Duration{
|
||||
time.Duration(0),
|
||||
},
|
||||
finalCondition: func(ctx context.Context) (done bool, err error) {
|
||||
panic(errors.New("panic error"))
|
||||
},
|
||||
expectedErr: errors.New("panic error"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
testContext, cancel := context.WithCancel(context.Background())
|
||||
backoff := &MockStepper{
|
||||
steps: tt.steps,
|
||||
}
|
||||
actualConditionCalls := 0
|
||||
|
||||
err := WithContext(testContext, backoff, func(ctx context.Context) (done bool, err error) {
|
||||
actualConditionCalls++
|
||||
|
||||
if backoff.currentStep >= (len(backoff.steps) - 1) {
|
||||
cancel()
|
||||
return tt.finalCondition(ctx)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
})
|
||||
require.Equal(t, tt.expectedErr, err)
|
||||
require.Equal(t, len(backoff.steps), actualConditionCalls)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("does not invoke any functions when run with a cancelled context", func(t *testing.T) {
|
||||
testContext, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
|
||||
stepper := &MockStepper{}
|
||||
|
||||
conditionCalls := 0
|
||||
condition := func(context.Context) (done bool, err error) {
|
||||
conditionCalls++
|
||||
return false, nil
|
||||
}
|
||||
|
||||
err := WithContext(testContext, stepper, condition)
|
||||
require.Equal(t, context.Canceled, err)
|
||||
require.Equal(t, 0, conditionCalls)
|
||||
require.Equal(t, 0, stepper.currentStep)
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2021-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package clusterhost
|
||||
@@ -8,20 +8,18 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestHasControlPlaneNodes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
nodes []*v1.Node
|
||||
nodes []*corev1.Node
|
||||
listNodesErr error
|
||||
wantErr error
|
||||
wantReturnValue bool
|
||||
@@ -33,12 +31,12 @@ func TestHasControlPlaneNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Fetching nodes returns an empty array",
|
||||
nodes: []*v1.Node{},
|
||||
nodes: []*corev1.Node{},
|
||||
wantErr: errors.New("no nodes found"),
|
||||
},
|
||||
{
|
||||
name: "Nodes found, but not control plane nodes",
|
||||
nodes: []*v1.Node{
|
||||
nodes: []*corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node-1",
|
||||
@@ -59,7 +57,7 @@ func TestHasControlPlaneNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Nodes found, including a control-plane role in node-role.kubernetes.io/<role> format",
|
||||
nodes: []*v1.Node{
|
||||
nodes: []*corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node-1",
|
||||
@@ -80,7 +78,7 @@ func TestHasControlPlaneNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Nodes found, including a master role in node-role.kubernetes.io/<role> format",
|
||||
nodes: []*v1.Node{
|
||||
nodes: []*corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node-1",
|
||||
@@ -101,7 +99,7 @@ func TestHasControlPlaneNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Nodes found, including a control-plane role in kubernetes.io/node-role=<role> format",
|
||||
nodes: []*v1.Node{
|
||||
nodes: []*corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node-1",
|
||||
@@ -122,7 +120,7 @@ func TestHasControlPlaneNodes(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Nodes found, including a master role in kubernetes.io/node-role=<role> format",
|
||||
nodes: []*v1.Node{
|
||||
nodes: []*corev1.Node{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "node-1",
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"go.pinniped.dev/internal/pversion"
|
||||
"go.pinniped.dev/internal/registry/credentialrequest"
|
||||
"go.pinniped.dev/internal/registry/whoamirequest"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -36,6 +37,7 @@ type ExtraConfig struct {
|
||||
NegotiatedSerializer runtime.NegotiatedSerializer
|
||||
LoginConciergeGroupVersion schema.GroupVersion
|
||||
IdentityConciergeGroupVersion schema.GroupVersion
|
||||
TokenClient *tokenclient.TokenClient
|
||||
}
|
||||
|
||||
type PinnipedServer struct {
|
||||
@@ -134,6 +136,24 @@ func (c completedConfig) New() (*PinnipedServer, error) {
|
||||
},
|
||||
)
|
||||
|
||||
s.GenericAPIServer.AddPostStartHookOrDie("fetch-impersonation-proxy-tokens",
|
||||
func(postStartContext genericapiserver.PostStartHookContext) error {
|
||||
plog.Debug("fetch-impersonation-proxy-tokens start hook starting")
|
||||
defer plog.Debug("fetch-impersonation-proxy-tokens start hook completed")
|
||||
|
||||
controllersShutdownWaitGroup.Add(1)
|
||||
go func() {
|
||||
defer controllersShutdownWaitGroup.Done()
|
||||
|
||||
// Start the token client
|
||||
c.ExtraConfig.TokenClient.Start(controllersCtx)
|
||||
plog.Debug("fetch-impersonation-proxy-tokens start hook's background goroutine has finished")
|
||||
}()
|
||||
|
||||
return nil
|
||||
},
|
||||
)
|
||||
|
||||
s.GenericAPIServer.AddPreShutdownHookOrDie("stop-controllers",
|
||||
func() error {
|
||||
plog.Debug("stop-controllers pre shutdown hook starting")
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -56,6 +55,7 @@ import (
|
||||
"go.pinniped.dev/internal/httputil/securityheader"
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
"go.pinniped.dev/internal/valuelesscontext"
|
||||
)
|
||||
|
||||
@@ -68,26 +68,38 @@ type FactoryFunc func(
|
||||
port int,
|
||||
dynamicCertProvider dynamiccert.Private,
|
||||
impersonationProxySignerCA dynamiccert.Public,
|
||||
impersonationProxyTokenCache tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
) (func(stopCh <-chan struct{}) error, error)
|
||||
|
||||
func New(
|
||||
port int,
|
||||
dynamicCertProvider dynamiccert.Private,
|
||||
impersonationProxySignerCA dynamiccert.Public,
|
||||
impersonationProxyTokenCache tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
) (func(stopCh <-chan struct{}) error, error) {
|
||||
return newInternal(port, dynamicCertProvider, impersonationProxySignerCA, kubeclient.Secure, nil, nil, nil)
|
||||
return newInternal(port, dynamicCertProvider, impersonationProxySignerCA, kubeclient.Secure, impersonationProxyTokenCache, nil, nil, nil)
|
||||
}
|
||||
|
||||
func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
//nolint:funlen // It is definitely too complicated. New calls newInternal, which makes another function.
|
||||
func newInternal(
|
||||
port int,
|
||||
dynamicCertProvider dynamiccert.Private,
|
||||
impersonationProxySignerCA dynamiccert.Public,
|
||||
restConfigFunc ptls.RestConfigFunc, // for unit testing, should always be kubeclient.Secure in production
|
||||
clientOpts []kubeclient.Option, // for unit testing, should always be nil in production
|
||||
cache tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
baseConfig *rest.Config, // for unit testing, should always be nil in production
|
||||
recOpts func(*genericoptions.RecommendedOptions), // for unit testing, should always be nil in production
|
||||
recConfig func(*genericapiserver.RecommendedConfig), // for unit testing, should always be nil in production
|
||||
) (func(stopCh <-chan struct{}) error, error) {
|
||||
var listener net.Listener
|
||||
var err error
|
||||
|
||||
if baseConfig == nil {
|
||||
baseConfig, err = rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
constructServer := func() (func(stopCh <-chan struct{}) error, error) {
|
||||
// Bare minimum server side scheme to allow for status messages to be encoded.
|
||||
@@ -117,7 +129,7 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
// along with the Kube API server's CA.
|
||||
// Note: any changes to the Authentication stack need to be kept in sync with any assumptions made
|
||||
// by getTransportForUser, especially if we ever update the TCR API to start returning bearer tokens.
|
||||
kubeClientUnsafeForProxying, err := kubeclient.New(clientOpts...)
|
||||
kubeClientUnsafeForProxying, err := kubeclient.New(kubeclient.WithConfig(baseConfig))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -168,7 +180,8 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
)
|
||||
|
||||
// use the custom impersonation proxy service account credentials when reverse proxying to the API server
|
||||
kubeClientForProxy, err := getReverseProxyClient(clientOpts)
|
||||
|
||||
kubeClientForProxy, err := getReverseProxyClient(baseConfig, cache)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to build reverse proxy client: %w", err)
|
||||
}
|
||||
@@ -321,11 +334,6 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
return nil, fmt.Errorf("invalid mutation of impersonation authorizer detected: %#v", preparedRun.Authorizer)
|
||||
}
|
||||
|
||||
// Sanity check. Assert that we have a functioning token file to use and no bearer token.
|
||||
if len(preparedRun.LoopbackClientConfig.BearerToken) != 0 || len(preparedRun.LoopbackClientConfig.BearerTokenFile) == 0 {
|
||||
return nil, constable.Error("invalid impersonator loopback rest config has wrong bearer token semantics")
|
||||
}
|
||||
|
||||
return preparedRun.Run, nil
|
||||
}
|
||||
|
||||
@@ -341,28 +349,16 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func getReverseProxyClient(clientOpts []kubeclient.Option) (*kubeclient.Client, error) {
|
||||
// just use the overrides given during unit tests
|
||||
if len(clientOpts) != 0 {
|
||||
return kubeclient.New(clientOpts...)
|
||||
func getReverseProxyClient(baseConfig *rest.Config, cache tokenclient.ExpiringSingletonTokenCacheGet) (*kubeclient.Client, error) {
|
||||
impersonationProxyRestConfig := kubeclient.SecureAnonymousClientConfig(baseConfig)
|
||||
|
||||
authRoundTripper := func(base http.RoundTripper) http.RoundTripper {
|
||||
return &authorizationRoundTripper{
|
||||
cache: cache,
|
||||
base: base,
|
||||
}
|
||||
}
|
||||
|
||||
// this is the magic path where the impersonation proxy SA token is mounted
|
||||
const tokenFile = "/var/run/secrets/impersonation-proxy.concierge.pinniped.dev/serviceaccount/token" //nolint:gosec // this is not a credential
|
||||
|
||||
// make sure the token file we need exists before trying to use it
|
||||
if _, err := os.Stat(tokenFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// build an in cluster config that uses the impersonation proxy token file
|
||||
impersonationProxyRestConfig, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
impersonationProxyRestConfig = kubeclient.SecureAnonymousClientConfig(impersonationProxyRestConfig)
|
||||
impersonationProxyRestConfig.BearerTokenFile = tokenFile
|
||||
|
||||
impersonationProxyRestConfig.Wrap(authRoundTripper)
|
||||
return kubeclient.New(kubeclient.WithConfig(impersonationProxyRestConfig))
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ import (
|
||||
"go.pinniped.dev/internal/httputil/roundtripper"
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
"go.pinniped.dev/internal/testutil/tlsserver"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
func TestImpersonator(t *testing.T) {
|
||||
@@ -84,24 +85,23 @@ func TestImpersonator(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.APIPriorityAndFairness, false)()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
clientCert *clientCert
|
||||
clientImpersonateUser rest.ImpersonationConfig
|
||||
clientMutateHeaders func(http.Header)
|
||||
clientNextProtos []string
|
||||
kubeAPIServerClientBearerTokenFile string
|
||||
kubeAPIServerStatusCode int
|
||||
kubeAPIServerHealthz http.Handler
|
||||
anonymousAuthDisabled bool
|
||||
wantKubeAPIServerRequestHeaders http.Header
|
||||
wantError string
|
||||
wantConstructionError string
|
||||
wantAuthorizerAttributes []authorizer.AttributesRecord
|
||||
name string
|
||||
clientCert *clientCert
|
||||
clientImpersonateUser rest.ImpersonationConfig
|
||||
clientMutateHeaders func(http.Header)
|
||||
clientNextProtos []string
|
||||
kubeAPIServerStatusCode int
|
||||
kubeAPIServerHealthz http.Handler
|
||||
anonymousAuthDisabled bool
|
||||
noServiceAcctTokenInCache bool // when true, no available service account token for the impersonator to use
|
||||
wantKubeAPIServerRequestHeaders http.Header
|
||||
wantError string
|
||||
wantConstructionError string
|
||||
wantAuthorizerAttributes []authorizer.AttributesRecord
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"test-username"},
|
||||
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
|
||||
@@ -119,9 +119,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with forbidden healthz",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path with forbidden healthz",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
_, _ = w.Write([]byte("no healthz for you"))
|
||||
@@ -143,9 +142,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with unauthorized healthz",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path with unauthorized healthz",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
_, _ = w.Write([]byte("no healthz for you"))
|
||||
@@ -168,9 +166,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with upgrade",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path with upgrade",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header.Add("Connection", "Upgrade")
|
||||
header.Add("Upgrade", "spdy/3.1")
|
||||
@@ -199,9 +196,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path ignores forwarded header",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path ignores forwarded header",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header.Add("X-Forwarded-For", "example.com")
|
||||
},
|
||||
@@ -222,9 +218,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path ignores forwarded header canonicalization",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "happy path ignores forwarded header canonicalization",
|
||||
clientCert: newClientCert(t, ca, "test-username2", []string{"test-group3", "test-group4"}),
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["x-FORWARDED-for"] = append(header["x-FORWARDED-for"], "example.com")
|
||||
},
|
||||
@@ -245,11 +240,10 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user is authenticated but the kube API request returns an error",
|
||||
kubeAPIServerStatusCode: http.StatusNotFound,
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: `the server could not find the requested resource (get namespaces)`,
|
||||
name: "user is authenticated but the kube API request returns an error",
|
||||
kubeAPIServerStatusCode: http.StatusNotFound,
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
wantError: `the server could not find the requested resource (get namespaces)`,
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"test-username"},
|
||||
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
|
||||
@@ -267,9 +261,8 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "when there is no client cert on request, it is an anonymous request",
|
||||
clientCert: &clientCert{},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "when there is no client cert on request, it is an anonymous request",
|
||||
clientCert: &clientCert{},
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"system:anonymous"},
|
||||
"Impersonate-Group": {"system:unauthenticated"},
|
||||
@@ -294,7 +287,6 @@ func TestImpersonator(t *testing.T) {
|
||||
req := &http.Request{Header: header}
|
||||
req.SetBasicAuth("foo", "bar")
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"system:anonymous"},
|
||||
"Impersonate-Group": {"system:unauthenticated"},
|
||||
@@ -313,17 +305,15 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "failed client cert authentication",
|
||||
clientCert: newClientCert(t, unrelatedCA, "test-username", []string{"test-group1"}),
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: "Unauthorized",
|
||||
wantAuthorizerAttributes: nil,
|
||||
name: "failed client cert authentication",
|
||||
clientCert: newClientCert(t, unrelatedCA, "test-username", []string{"test-group1"}),
|
||||
wantError: "Unauthorized",
|
||||
wantAuthorizerAttributes: nil,
|
||||
},
|
||||
{
|
||||
name: "nested impersonation by regular users calls delegating authorizer",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
clientImpersonateUser: rest.ImpersonationConfig{UserName: "some-other-username"},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
name: "nested impersonation by regular users calls delegating authorizer",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
clientImpersonateUser: rest.ImpersonationConfig{UserName: "some-other-username"},
|
||||
// this fails because the delegating authorizer in this test only allows system:masters and fails everything else
|
||||
wantError: `users "some-other-username" is forbidden: User "test-username" ` +
|
||||
`cannot impersonate resource "users" in API group "" at the cluster scope: ` +
|
||||
@@ -359,7 +349,6 @@ func TestImpersonator(t *testing.T) {
|
||||
"alpha.kubernetes.io/identity/user/domain/name": {"a-domain-name"},
|
||||
},
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"fire"},
|
||||
"Impersonate-Group": {"elements", "system:authenticated"},
|
||||
@@ -477,8 +466,7 @@ func TestImpersonator(t *testing.T) {
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["Impersonate-Uid"] = []string{"root"}
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{
|
||||
{
|
||||
User: &user.DefaultInfo{Name: "test-admin", UID: "", Groups: []string{"test-group2", "system:masters", "system:authenticated"}, Extra: nil},
|
||||
@@ -501,8 +489,7 @@ func TestImpersonator(t *testing.T) {
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["imPerSoNaTE-uid"] = []string{"magic"}
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{
|
||||
{
|
||||
User: &user.DefaultInfo{Name: "test-admin", UID: "", Groups: []string{"test-group2", "system:masters", "system:authenticated"}, Extra: nil},
|
||||
@@ -529,8 +516,7 @@ func TestImpersonator(t *testing.T) {
|
||||
"something.impersonation-proxy.concierge.pinniped.dev": {"bad data"},
|
||||
},
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{
|
||||
{
|
||||
User: &user.DefaultInfo{Name: "test-admin", UID: "", Groups: []string{"test-group2", "system:masters", "system:authenticated"}, Extra: nil},
|
||||
@@ -569,8 +555,7 @@ func TestImpersonator(t *testing.T) {
|
||||
"party~~time": {"danger"},
|
||||
},
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantError: "Internal error occurred: unimplemented functionality - unable to act as current user",
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{
|
||||
{
|
||||
User: &user.DefaultInfo{Name: "test-admin", UID: "", Groups: []string{"test-group2", "system:masters", "system:authenticated"}, Extra: nil},
|
||||
@@ -600,7 +585,6 @@ func TestImpersonator(t *testing.T) {
|
||||
"ROAR": {"tiger"}, // by the time our code sees this key, it is lowercased to "roar"
|
||||
},
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantKubeAPIServerRequestHeaders: http.Header{
|
||||
"Impersonate-User": {"panda"},
|
||||
"Impersonate-Group": {"other-peeps", "system:authenticated"},
|
||||
@@ -631,11 +615,6 @@ func TestImpersonator(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no bearer token file in Kube API server client config",
|
||||
wantConstructionError: "invalid impersonator loopback rest config has wrong bearer token semantics",
|
||||
wantAuthorizerAttributes: nil,
|
||||
},
|
||||
{
|
||||
name: "unexpected healthz response",
|
||||
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -651,7 +630,6 @@ func TestImpersonator(t *testing.T) {
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["imPerSonaTE-USer"] = []string{"PANDA"}
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: `users "PANDA" is forbidden: User "test-username" ` +
|
||||
`cannot impersonate resource "users" in API group "" at the cluster scope: ` +
|
||||
`decision made by impersonation-proxy.concierge.pinniped.dev`,
|
||||
@@ -668,9 +646,8 @@ func TestImpersonator(t *testing.T) {
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["imPerSonaTE-uid"] = []string{"007"}
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: `an error on the server ("Internal Server Error: \"/api/v1/namespaces\": requested [{UID 007 authentication.k8s.io/v1 }] without impersonating a user") has prevented the request from succeeding (get namespaces)`,
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{},
|
||||
wantError: `an error on the server ("Internal Server Error: \"/api/v1/namespaces\": requested [{UID 007 authentication.k8s.io/v1 }] without impersonating a user") has prevented the request from succeeding (get namespaces)`,
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{},
|
||||
},
|
||||
{
|
||||
name: "future UID header", // no longer future as it exists in Kube v1.22
|
||||
@@ -678,9 +655,21 @@ func TestImpersonator(t *testing.T) {
|
||||
clientMutateHeaders: func(header http.Header) {
|
||||
header["Impersonate-Uid"] = []string{"008"}
|
||||
},
|
||||
kubeAPIServerClientBearerTokenFile: "required-to-be-set",
|
||||
wantError: `an error on the server ("Internal Server Error: \"/api/v1/namespaces\": requested [{UID 008 authentication.k8s.io/v1 }] without impersonating a user") has prevented the request from succeeding (get namespaces)`,
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{},
|
||||
wantError: `an error on the server ("Internal Server Error: \"/api/v1/namespaces\": requested [{UID 008 authentication.k8s.io/v1 }] without impersonating a user") has prevented the request from succeeding (get namespaces)`,
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{},
|
||||
},
|
||||
{
|
||||
name: "when there is no service account token cached for the impersonator to use to call the KAS",
|
||||
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
|
||||
noServiceAcctTokenInCache: true,
|
||||
wantKubeAPIServerRequestHeaders: nil, // no request should have been made to the KAS on behalf of the user
|
||||
wantError: `an error on the server ("") has prevented the request from succeeding (get namespaces)`,
|
||||
wantAuthorizerAttributes: []authorizer.AttributesRecord{
|
||||
{
|
||||
User: &user.DefaultInfo{Name: "test-username", UID: "", Groups: []string{"test-group1", "test-group2", "system:authenticated"}, Extra: nil},
|
||||
Verb: "list", Namespace: "", APIGroup: "", APIVersion: "v1", Resource: "namespaces", Subresource: "", Name: "", ResourceRequest: true, Path: "/api/v1/namespaces",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -697,7 +686,9 @@ func TestImpersonator(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// After failing to start and after shutdown, the impersonator port should be available again.
|
||||
defer requireCanBindToPort(t, port)
|
||||
t.Cleanup(func() {
|
||||
requireCanBindToPort(t, port)
|
||||
})
|
||||
|
||||
if tt.kubeAPIServerStatusCode == 0 {
|
||||
tt.kubeAPIServerStatusCode = http.StatusOK
|
||||
@@ -830,11 +821,8 @@ func TestImpersonator(t *testing.T) {
|
||||
// Create the client config that the impersonation server should use to talk to the Kube API server.
|
||||
testKubeAPIServerKubeconfig := rest.Config{
|
||||
Host: testKubeAPIServer.URL,
|
||||
BearerToken: "some-service-account-token",
|
||||
TLSClientConfig: rest.TLSClientConfig{CAData: tlsserver.TLSTestServerCA(testKubeAPIServer)},
|
||||
BearerTokenFile: tt.kubeAPIServerClientBearerTokenFile,
|
||||
}
|
||||
clientOpts := []kubeclient.Option{kubeclient.WithConfig(&testKubeAPIServerKubeconfig)}
|
||||
|
||||
// Punch out just enough stuff to make New actually run without error.
|
||||
recOpts := func(options *genericoptions.RecommendedOptions) {
|
||||
@@ -872,8 +860,13 @@ func TestImpersonator(t *testing.T) {
|
||||
return kubeclient.Secure(config)
|
||||
}
|
||||
|
||||
serviceTokenCache := tokenclient.NewExpiringSingletonTokenCache()
|
||||
if !tt.noServiceAcctTokenInCache {
|
||||
serviceTokenCache.Set("some-service-account-token", 1*time.Hour)
|
||||
}
|
||||
|
||||
// Create an impersonator. Use an invalid port number to make sure our listener override works.
|
||||
runner, constructionErr := newInternal(-1000, certKeyContent, caContent, restConfigFunc, clientOpts, recOpts, recConfig)
|
||||
runner, constructionErr := newInternal(-1000, certKeyContent, caContent, restConfigFunc, serviceTokenCache, &testKubeAPIServerKubeconfig, recOpts, recConfig)
|
||||
if len(tt.wantConstructionError) > 0 {
|
||||
require.EqualError(t, constructionErr, tt.wantConstructionError)
|
||||
require.Nil(t, runner)
|
||||
@@ -891,6 +884,13 @@ func TestImpersonator(t *testing.T) {
|
||||
errCh <- stopErr
|
||||
}()
|
||||
|
||||
// Stop the impersonator server at the end of the test, even if it fails.
|
||||
t.Cleanup(func() {
|
||||
close(stopCh)
|
||||
exitErr := <-errCh
|
||||
require.NoError(t, exitErr)
|
||||
})
|
||||
|
||||
// Create a kubeconfig to talk to the impersonator as a client.
|
||||
clientKubeconfig := &rest.Config{
|
||||
Host: "https://127.0.0.1:" + strconv.Itoa(port),
|
||||
@@ -922,7 +922,7 @@ func TestImpersonator(t *testing.T) {
|
||||
client, err := kubeclient.New(kubeclient.WithConfig(clientKubeconfig))
|
||||
require.NoError(t, err)
|
||||
|
||||
// The fake Kube API server knows how to to list namespaces, so make that request using the client
|
||||
// The fake Kube API server knows how to list namespaces, so make that request using the client
|
||||
// through the impersonator.
|
||||
listResponse, err := client.Kubernetes.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
|
||||
if len(tt.wantError) > 0 {
|
||||
@@ -944,6 +944,12 @@ func TestImpersonator(t *testing.T) {
|
||||
// of the original request mutated by the impersonator. Otherwise the headers should be nil.
|
||||
require.Equal(t, tt.wantKubeAPIServerRequestHeaders, testKubeAPIServerSawHeaders)
|
||||
|
||||
// The rest of the test doesn't make sense for when there is no service account token available in the cache.
|
||||
// In this case, the impersonator cannot make any calls to the Kube API server on behalf of any user.
|
||||
if tt.noServiceAcctTokenInCache {
|
||||
return
|
||||
}
|
||||
|
||||
// these authorization checks are caused by the anonymous auth checks below
|
||||
tt.wantAuthorizerAttributes = append(tt.wantAuthorizerAttributes,
|
||||
authorizer.AttributesRecord{
|
||||
@@ -1046,11 +1052,6 @@ func TestImpersonator(t *testing.T) {
|
||||
_, errBadCert := tcrBadCert.PinnipedConcierge.LoginV1alpha1().TokenCredentialRequests().Create(ctx, &loginv1alpha1.TokenCredentialRequest{}, metav1.CreateOptions{})
|
||||
require.True(t, errors.IsUnauthorized(errBadCert), errBadCert)
|
||||
require.EqualError(t, errBadCert, "Unauthorized")
|
||||
|
||||
// Stop the impersonator server.
|
||||
close(stopCh)
|
||||
exitErr := <-errCh
|
||||
require.NoError(t, exitErr)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
43
internal/concierge/impersonator/roundtripper.go
Normal file
43
internal/concierge/impersonator/roundtripper.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package impersonator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
utilnet "k8s.io/apimachinery/pkg/util/net"
|
||||
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
type authorizationRoundTripper struct {
|
||||
cache tokenclient.ExpiringSingletonTokenCacheGet
|
||||
base http.RoundTripper
|
||||
}
|
||||
|
||||
var _ utilnet.RoundTripperWrapper = (*authorizationRoundTripper)(nil)
|
||||
|
||||
func (rt *authorizationRoundTripper) WrappedRoundTripper() http.RoundTripper {
|
||||
return rt.base
|
||||
}
|
||||
|
||||
func (rt *authorizationRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
req = utilnet.CloneRequest(req)
|
||||
|
||||
token := rt.cache.Get()
|
||||
|
||||
if token == "" {
|
||||
plog.Error("could not RoundTrip impersonation proxy request to API server",
|
||||
errors.New("no service account token available in in-memory cache"))
|
||||
|
||||
return nil, fmt.Errorf("no impersonator service account token available")
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||
|
||||
return rt.base.RoundTrip(req)
|
||||
}
|
||||
106
internal/concierge/impersonator/roundtripper_test.go
Normal file
106
internal/concierge/impersonator/roundtripper_test.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package impersonator
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
func TestWrappedRoundTripper(t *testing.T) {
|
||||
var base = new(oauth2.Transport)
|
||||
|
||||
roundTripper := authorizationRoundTripper{
|
||||
base: base,
|
||||
}
|
||||
|
||||
require.Equal(t, base, roundTripper.WrappedRoundTripper())
|
||||
}
|
||||
|
||||
type fakeRoundTripper struct {
|
||||
request *http.Request
|
||||
response *http.Response
|
||||
err error
|
||||
}
|
||||
|
||||
func (t *fakeRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
|
||||
t.request = request
|
||||
return t.response, t.err
|
||||
}
|
||||
|
||||
var _ http.RoundTripper = (*fakeRoundTripper)(nil)
|
||||
|
||||
type fakeCache struct {
|
||||
token string
|
||||
}
|
||||
|
||||
func (c *fakeCache) Get() string {
|
||||
return c.token
|
||||
}
|
||||
|
||||
var _ tokenclient.ExpiringSingletonTokenCacheGet = (*fakeCache)(nil)
|
||||
|
||||
func TestRoundTrip(t *testing.T) {
|
||||
fakeResponse := new(http.Response)
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
token string
|
||||
baseResponse *http.Response
|
||||
baseError string
|
||||
wantResponse *http.Response
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
name: "happy path - mutate the request and return whatever the base returns",
|
||||
token: "token",
|
||||
baseResponse: fakeResponse,
|
||||
baseError: "error from base",
|
||||
wantResponse: fakeResponse,
|
||||
wantError: "error from base",
|
||||
},
|
||||
{
|
||||
name: "no token available",
|
||||
token: "", // since the cache always returns a non-pointer string, this indicates empty
|
||||
wantError: "no impersonator service account token available",
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
base := &fakeRoundTripper{
|
||||
response: new(http.Response),
|
||||
err: errors.New(tt.baseError),
|
||||
}
|
||||
|
||||
cache := &fakeCache{
|
||||
token: tt.token,
|
||||
}
|
||||
|
||||
roundTripper := &authorizationRoundTripper{
|
||||
cache: cache,
|
||||
base: base,
|
||||
}
|
||||
|
||||
request, err := http.NewRequestWithContext(context.Background(), "GET", "https://example.com", http.NoBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
//nolint:bodyclose // response.Body is nil so you can't call .Close() on it
|
||||
response, err := roundTripper.RoundTrip(request)
|
||||
require.Equal(t, tt.wantResponse, response)
|
||||
require.ErrorContains(t, err, tt.wantError)
|
||||
|
||||
if tt.token != "" {
|
||||
require.Equal(t, "Bearer "+tt.token, base.request.Header.Get("Authorization"))
|
||||
} else {
|
||||
require.Empty(t, base.request)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ import (
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/pversion"
|
||||
"go.pinniped.dev/internal/registry/credentialrequest"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
// App is an object that represents the pinniped-concierge application.
|
||||
@@ -102,6 +103,11 @@ func addCommandlineFlagsToCommand(cmd *cobra.Command, app *App) {
|
||||
// Boot the aggregated API server, which will in turn boot the controllers.
|
||||
// In practice, the ctx passed in should be one which will be cancelled when the process receives SIGTERM or SIGINT.
|
||||
func (a *App) runServer(ctx context.Context) error {
|
||||
// We tried to enable the feature gate from https://github.com/kubernetes/kubernetes/pull/121120,
|
||||
// but it causes errors when there are lots of parallel anonymous requests for our aggregated API endpoints.
|
||||
// We will need to figure out if that is a bug in Kubernetes before we enable this again.
|
||||
// featuregates.EnableKubeFeatureGate(features.UnauthenticatedHTTP2DOSMitigation)
|
||||
|
||||
// Read the server config file.
|
||||
cfg, err := concierge.FromPath(ctx, a.configPath)
|
||||
if err != nil {
|
||||
@@ -136,6 +142,8 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
// injected suffix).
|
||||
scheme, loginGV, identityGV := conciergescheme.New(*cfg.APIGroupSuffix)
|
||||
|
||||
impersonationProxyTokenCache := tokenclient.NewExpiringSingletonTokenCache()
|
||||
|
||||
// Prepare to start the controllers, but defer actually starting them until the
|
||||
// post start hook of the aggregated API server.
|
||||
buildControllers, err := controllermanager.PrepareControllers(
|
||||
@@ -154,6 +162,7 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
AuthenticatorCache: authenticators,
|
||||
// This port should be safe to cast because the config reader already validated it.
|
||||
ImpersonationProxyServerPort: int(*cfg.ImpersonationProxyServerPort),
|
||||
ImpersonationProxyTokenCache: impersonationProxyTokenCache,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -181,6 +190,23 @@ func (a *App) runServer(ctx context.Context) error {
|
||||
return fmt.Errorf("could not configure aggregated API server: %w", err)
|
||||
}
|
||||
|
||||
// Configure a token client that retrieves relatively short-lived tokens from the API server.
|
||||
// It uses a k8s client without leader election because all pods need tokens.
|
||||
// This k8s client should not be reused for other purposes.
|
||||
// The token client will retrieve tokens in the background for the lifetime of the concierge process,
|
||||
// whether the impersonation proxy is enabled or not.
|
||||
oneDayInSeconds := int64(24 * 60 * 60)
|
||||
k8sClient, err := kubeclient.New()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not create default kubernetes client: %w", err)
|
||||
}
|
||||
aggregatedAPIServerConfig.ExtraConfig.TokenClient = tokenclient.New(
|
||||
cfg.NamesConfig.ImpersonationProxyServiceAccount,
|
||||
k8sClient.Kubernetes.CoreV1().ServiceAccounts(podInfo.Namespace),
|
||||
impersonationProxyTokenCache.Set,
|
||||
plog.New(),
|
||||
tokenclient.WithExpirationSeconds(oneDayInSeconds))
|
||||
|
||||
// Complete the aggregated API server config and make a server instance.
|
||||
server, err := aggregatedAPIServerConfig.Complete().New()
|
||||
if err != nil {
|
||||
|
||||
@@ -161,6 +161,12 @@ func validateNames(names *NamesConfigSpec) error {
|
||||
if names.AgentServiceAccount == "" {
|
||||
missingNames = append(missingNames, "agentServiceAccount")
|
||||
}
|
||||
if names.ImpersonationProxyServiceAccount == "" {
|
||||
missingNames = append(missingNames, "impersonationProxyServiceAccount")
|
||||
}
|
||||
if names.ImpersonationProxyLegacySecret == "" {
|
||||
missingNames = append(missingNames, "impersonationProxyLegacySecret")
|
||||
}
|
||||
if len(missingNames) > 0 {
|
||||
return constable.Error("missing required names: " + strings.Join(missingNames, ", "))
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
extraName: extraName-value
|
||||
labels:
|
||||
myLabelKey1: myLabelValue1
|
||||
@@ -80,6 +82,8 @@ func TestFromPath(t *testing.T) {
|
||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||
AgentServiceAccount: "agentServiceAccount-value",
|
||||
ImpersonationProxyServiceAccount: "impersonationProxyServiceAccount-value",
|
||||
ImpersonationProxyLegacySecret: "impersonationProxyLegacySecret-value",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"myLabelKey1": "myLabelValue1",
|
||||
@@ -121,6 +125,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
extraName: extraName-value
|
||||
labels:
|
||||
myLabelKey1: myLabelValue1
|
||||
@@ -156,6 +162,8 @@ func TestFromPath(t *testing.T) {
|
||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||
AgentServiceAccount: "agentServiceAccount-value",
|
||||
ImpersonationProxyServiceAccount: "impersonationProxyServiceAccount-value",
|
||||
ImpersonationProxyLegacySecret: "impersonationProxyLegacySecret-value",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"myLabelKey1": "myLabelValue1",
|
||||
@@ -197,6 +205,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
extraName: extraName-value
|
||||
labels:
|
||||
myLabelKey1: myLabelValue1
|
||||
@@ -233,6 +243,8 @@ func TestFromPath(t *testing.T) {
|
||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||
AgentServiceAccount: "agentServiceAccount-value",
|
||||
ImpersonationProxyServiceAccount: "impersonationProxyServiceAccount-value",
|
||||
ImpersonationProxyLegacySecret: "impersonationProxyLegacySecret-value",
|
||||
},
|
||||
Labels: map[string]string{
|
||||
"myLabelKey1": "myLabelValue1",
|
||||
@@ -264,6 +276,7 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
log:
|
||||
level: all
|
||||
format: snorlax
|
||||
@@ -284,6 +297,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantConfig: &Config{
|
||||
DiscoveryInfo: DiscoveryInfoSpec{
|
||||
@@ -308,6 +323,8 @@ func TestFromPath(t *testing.T) {
|
||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||
AgentServiceAccount: "agentServiceAccount-value",
|
||||
ImpersonationProxyServiceAccount: "impersonationProxyServiceAccount-value",
|
||||
ImpersonationProxyLegacySecret: "impersonationProxyLegacySecret-value",
|
||||
},
|
||||
Labels: map[string]string{},
|
||||
KubeCertAgentConfig: KubeCertAgentSpec{
|
||||
@@ -322,7 +339,7 @@ func TestFromPath(t *testing.T) {
|
||||
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuer, " +
|
||||
"apiService, impersonationLoadBalancerService, " +
|
||||
"impersonationClusterIPService, impersonationTLSCertificateSecret, impersonationCACertificateSecret, " +
|
||||
"impersonationSignerSecret, agentServiceAccount",
|
||||
"impersonationSignerSecret, agentServiceAccount, impersonationProxyServiceAccount, impersonationProxyLegacySecret",
|
||||
},
|
||||
{
|
||||
name: "Missing apiService name",
|
||||
@@ -337,6 +354,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: apiService",
|
||||
},
|
||||
@@ -353,6 +372,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: credentialIssuer",
|
||||
},
|
||||
@@ -369,6 +390,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: servingCertificateSecret",
|
||||
},
|
||||
@@ -385,6 +408,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationLoadBalancerService",
|
||||
},
|
||||
@@ -401,6 +426,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationClusterIPService",
|
||||
},
|
||||
@@ -417,6 +444,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationTLSCertificateSecret",
|
||||
},
|
||||
@@ -433,6 +462,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationCACertificateSecret",
|
||||
},
|
||||
@@ -449,9 +480,47 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationSignerSecret",
|
||||
},
|
||||
{
|
||||
name: "Missing impersonationProxyServiceAccount name",
|
||||
yaml: here.Doc(`
|
||||
---
|
||||
names:
|
||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||
credentialIssuer: pinniped-config
|
||||
apiService: pinniped-api
|
||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||
impersonationClusterIPService: impersonationClusterIPService-value
|
||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationProxyServiceAccount",
|
||||
},
|
||||
{
|
||||
name: "Missing impersonationProxyLegacySecret name",
|
||||
yaml: here.Doc(`
|
||||
---
|
||||
names:
|
||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||
credentialIssuer: pinniped-config
|
||||
apiService: pinniped-api
|
||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||
impersonationClusterIPService: impersonationClusterIPService-value
|
||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: impersonationProxyLegacySecret",
|
||||
},
|
||||
{
|
||||
name: "Missing several required names",
|
||||
yaml: here.Doc(`
|
||||
@@ -464,6 +533,8 @@ func TestFromPath(t *testing.T) {
|
||||
impersonationClusterIPService: impersonationClusterIPService-value
|
||||
impersonationSignerSecret: impersonationSignerSecret-value
|
||||
agentServiceAccount: agentServiceAccount-value
|
||||
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
|
||||
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
|
||||
`),
|
||||
wantError: "validate names: missing required names: " +
|
||||
"impersonationTLSCertificateSecret, impersonationCACertificateSecret",
|
||||
|
||||
@@ -45,6 +45,8 @@ type NamesConfigSpec struct {
|
||||
ImpersonationCACertificateSecret string `json:"impersonationCACertificateSecret"`
|
||||
ImpersonationSignerSecret string `json:"impersonationSignerSecret"`
|
||||
AgentServiceAccount string `json:"agentServiceAccount"`
|
||||
ImpersonationProxyServiceAccount string `json:"impersonationProxyServiceAccount"`
|
||||
ImpersonationProxyLegacySecret string `json:"impersonationProxyLegacySecret"`
|
||||
}
|
||||
|
||||
// ServingCertificateConfigSpec contains the configuration knobs for the API's
|
||||
|
||||
25
internal/config/featuregates/featuregates.go
Normal file
25
internal/config/featuregates/featuregates.go
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package featuregates
|
||||
|
||||
import (
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/component-base/featuregate"
|
||||
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
func EnableKubeFeatureGate(f featuregate.Feature) {
|
||||
initialValue := feature.DefaultFeatureGate.Enabled(f)
|
||||
|
||||
if err := feature.DefaultMutableFeatureGate.SetFromMap(map[string]bool{string(f): true}); err != nil {
|
||||
panic(err) // this should never happen as long as a feature gate still exists
|
||||
}
|
||||
|
||||
plog.Always("feature gate status",
|
||||
"name", f,
|
||||
"initialEnabledValue", initialValue,
|
||||
"updatedEnabledValue", feature.DefaultFeatureGate.Enabled(f),
|
||||
)
|
||||
}
|
||||
28
internal/config/featuregates/featuregates_test.go
Normal file
28
internal/config/featuregates/featuregates_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package featuregates
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
)
|
||||
|
||||
func TestEnableKubeFeatureGate(t *testing.T) {
|
||||
f := features.UnauthenticatedHTTP2DOSMitigation
|
||||
|
||||
// This feature gate is currently disabled by default in the Kubernetes library.
|
||||
// Assert this as a precondition so if that ever changes during a dependency bump
|
||||
// we will be forced to take note and decide if any code deserves to change.
|
||||
require.False(t, feature.DefaultFeatureGate.Enabled(f))
|
||||
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, feature.DefaultFeatureGate, f, false)()
|
||||
|
||||
require.False(t, feature.DefaultFeatureGate.Enabled(f))
|
||||
EnableKubeFeatureGate(f)
|
||||
require.True(t, feature.DefaultFeatureGate.Enabled(f))
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
||||
@@ -38,7 +38,7 @@ func TestAPIServiceUpdaterControllerOptions(t *testing.T) {
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
secretsInformer := k8sinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
_ = NewAPIServiceUpdaterController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
@@ -110,7 +110,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
var subject controllerlib.Controller
|
||||
var aggregatorAPIClient *aggregatorfake.Clientset
|
||||
var kubeInformerClient *kubernetesfake.Clientset
|
||||
var kubeInformers kubeinformers.SharedInformerFactory
|
||||
var kubeInformers k8sinformers.SharedInformerFactory
|
||||
var cancelContext context.Context
|
||||
var cancelContextCancelFunc context.CancelFunc
|
||||
var syncContext *controllerlib.Context
|
||||
@@ -149,7 +149,7 @@ func TestAPIServiceUpdaterControllerSync(t *testing.T) {
|
||||
cancelContext, cancelContextCancelFunc = context.WithCancel(context.Background())
|
||||
|
||||
kubeInformerClient = kubernetesfake.NewSimpleClientset()
|
||||
kubeInformers = kubeinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
kubeInformers = k8sinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
aggregatorAPIClient = aggregatorfake.NewSimpleClientset()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubetesting "k8s.io/client-go/testing"
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestExpirerControllerFilters(t *testing.T) {
|
||||
t.Run(test.name+"-"+test.namespace, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(
|
||||
secretsInformer := k8sinformers.NewSharedInformerFactory(
|
||||
kubernetesfake.NewSimpleClientset(),
|
||||
0,
|
||||
).Core().V1().Secrets()
|
||||
@@ -253,7 +253,7 @@ func TestExpirerControllerSync(t *testing.T) {
|
||||
require.NoError(t, kubeInformerClient.Tracker().Add(secret))
|
||||
}
|
||||
|
||||
kubeInformers := kubeinformers.NewSharedInformerFactory(
|
||||
kubeInformers := k8sinformers.NewSharedInformerFactory(
|
||||
kubeInformerClient,
|
||||
0,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestManagerControllerOptions(t *testing.T) {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
observableWithInitialEventOption = testutil.NewObservableWithInitialEventOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
secretsInformer := k8sinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
_ = NewCertsManagerController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
@@ -125,7 +125,7 @@ func TestManagerControllerSync(t *testing.T) {
|
||||
var subject controllerlib.Controller
|
||||
var kubeAPIClient *kubernetesfake.Clientset
|
||||
var kubeInformerClient *kubernetesfake.Clientset
|
||||
var kubeInformers kubeinformers.SharedInformerFactory
|
||||
var kubeInformers k8sinformers.SharedInformerFactory
|
||||
var cancelContext context.Context
|
||||
var cancelContextCancelFunc context.CancelFunc
|
||||
var syncContext *controllerlib.Context
|
||||
@@ -171,7 +171,7 @@ func TestManagerControllerSync(t *testing.T) {
|
||||
cancelContext, cancelContextCancelFunc = context.WithCancel(context.Background())
|
||||
|
||||
kubeInformerClient = kubernetesfake.NewSimpleClientset()
|
||||
kubeInformers = kubeinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
kubeInformers = k8sinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
kubeAPIClient = kubernetesfake.NewSimpleClientset()
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package apicerts
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"go.pinniped.dev/internal/certauthority"
|
||||
@@ -35,7 +35,7 @@ func TestObserverControllerInformerFilters(t *testing.T) {
|
||||
it.Before(func() {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
secretsInformer := k8sinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
_ = NewCertsObserverController(
|
||||
installedInNamespace,
|
||||
certsSecretResourceName,
|
||||
@@ -106,7 +106,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
|
||||
var subject controllerlib.Controller
|
||||
var kubeInformerClient *kubernetesfake.Clientset
|
||||
var kubeInformers kubeinformers.SharedInformerFactory
|
||||
var kubeInformers k8sinformers.SharedInformerFactory
|
||||
var cancelContext context.Context
|
||||
var cancelContextCancelFunc context.CancelFunc
|
||||
var syncContext *controllerlib.Context
|
||||
@@ -145,7 +145,7 @@ func TestObserverControllerSync(t *testing.T) {
|
||||
cancelContext, cancelContextCancelFunc = context.WithCancel(context.Background())
|
||||
|
||||
kubeInformerClient = kubernetesfake.NewSimpleClientset()
|
||||
kubeInformers = kubeinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
kubeInformers = k8sinformers.NewSharedInformerFactory(kubeInformerClient, 0)
|
||||
dynamicCertProvider = dynamiccert.NewServingCert(name)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
||||
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package jwtcachefiller implements a controller for filling an authncache.Cache with each
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"time"
|
||||
|
||||
coreosoidc "github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-logr/logr"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apiserver/pkg/authentication/authenticator"
|
||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/oidc"
|
||||
|
||||
@@ -19,10 +19,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
"gopkg.in/square/go-jose.v2/jwt"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
@@ -7,22 +7,22 @@ import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
// MergeIDPConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions.
|
||||
func MergeIDPConditions(conditions []*v1.Condition, observedGeneration int64, conditionsToUpdate *[]v1.Condition, log plog.MinLogger) bool {
|
||||
func MergeIDPConditions(conditions []*metav1.Condition, observedGeneration int64, conditionsToUpdate *[]metav1.Condition, log plog.MinLogger) bool {
|
||||
hadErrorCondition := false
|
||||
for i := range conditions {
|
||||
cond := conditions[i].DeepCopy()
|
||||
cond.LastTransitionTime = v1.Now()
|
||||
cond.LastTransitionTime = metav1.Now()
|
||||
cond.ObservedGeneration = observedGeneration
|
||||
if mergeIDPCondition(conditionsToUpdate, cond) {
|
||||
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
|
||||
}
|
||||
if cond.Status == v1.ConditionFalse {
|
||||
if cond.Status == metav1.ConditionFalse {
|
||||
hadErrorCondition = true
|
||||
}
|
||||
}
|
||||
@@ -32,11 +32,11 @@ func MergeIDPConditions(conditions []*v1.Condition, observedGeneration int64, co
|
||||
return hadErrorCondition
|
||||
}
|
||||
|
||||
// mergeIDPCondition merges a new v1.Condition into a slice of existing conditions. It returns true
|
||||
// mergeIDPCondition merges a new metav1.Condition into a slice of existing conditions. It returns true
|
||||
// if the condition has meaningfully changed.
|
||||
func mergeIDPCondition(existing *[]v1.Condition, new *v1.Condition) bool {
|
||||
func mergeIDPCondition(existing *[]metav1.Condition, new *metav1.Condition) bool {
|
||||
// Find any existing condition with a matching type.
|
||||
var old *v1.Condition
|
||||
var old *metav1.Condition
|
||||
for i := range *existing {
|
||||
if (*existing)[i].Type == new.Type {
|
||||
old = &(*existing)[i]
|
||||
@@ -67,7 +67,7 @@ func mergeIDPCondition(existing *[]v1.Condition, new *v1.Condition) bool {
|
||||
}
|
||||
|
||||
// MergeConfigConditions merges conditions into conditionsToUpdate. If returns true if it merged any error conditions.
|
||||
func MergeConfigConditions(conditions []*v1.Condition, observedGeneration int64, conditionsToUpdate *[]v1.Condition, log plog.MinLogger, now v1.Time) bool {
|
||||
func MergeConfigConditions(conditions []*metav1.Condition, observedGeneration int64, conditionsToUpdate *[]metav1.Condition, log plog.MinLogger, now metav1.Time) bool {
|
||||
hadErrorCondition := false
|
||||
for i := range conditions {
|
||||
cond := conditions[i].DeepCopy()
|
||||
@@ -76,7 +76,7 @@ func MergeConfigConditions(conditions []*v1.Condition, observedGeneration int64,
|
||||
if mergeConfigCondition(conditionsToUpdate, cond) {
|
||||
log.Info("updated condition", "type", cond.Type, "status", cond.Status, "reason", cond.Reason, "message", cond.Message)
|
||||
}
|
||||
if cond.Status == v1.ConditionFalse {
|
||||
if cond.Status == metav1.ConditionFalse {
|
||||
hadErrorCondition = true
|
||||
}
|
||||
}
|
||||
@@ -86,11 +86,11 @@ func MergeConfigConditions(conditions []*v1.Condition, observedGeneration int64,
|
||||
return hadErrorCondition
|
||||
}
|
||||
|
||||
// mergeConfigCondition merges a new v1.Condition into a slice of existing conditions. It returns true
|
||||
// mergeConfigCondition merges a new metav1.Condition into a slice of existing conditions. It returns true
|
||||
// if the condition has meaningfully changed.
|
||||
func mergeConfigCondition(existing *[]v1.Condition, new *v1.Condition) bool {
|
||||
func mergeConfigCondition(existing *[]metav1.Condition, new *metav1.Condition) bool {
|
||||
// Find any existing condition with a matching type.
|
||||
var old *v1.Condition
|
||||
var old *metav1.Condition
|
||||
for i := range *existing {
|
||||
if (*existing)[i].Type == new.Type {
|
||||
old = &(*existing)[i]
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/equality"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -34,7 +33,7 @@ import (
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||
conciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||
conciergeconfiginformers "go.pinniped.dev/generated/latest/client/concierge/informers/externalversions/config/v1alpha1"
|
||||
"go.pinniped.dev/internal/certauthority"
|
||||
"go.pinniped.dev/internal/clusterhost"
|
||||
@@ -47,6 +46,7 @@ import (
|
||||
"go.pinniped.dev/internal/dynamiccert"
|
||||
"go.pinniped.dev/internal/endpointaddr"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -70,7 +70,7 @@ type impersonatorConfigController struct {
|
||||
impersonationSignerSecretName string
|
||||
|
||||
k8sClient kubernetes.Interface
|
||||
pinnipedAPIClient pinnipedclientset.Interface
|
||||
pinnipedAPIClient conciergeclientset.Interface
|
||||
|
||||
credIssuerInformer conciergeconfiginformers.CredentialIssuerInformer
|
||||
servicesInformer corev1informers.ServiceInformer
|
||||
@@ -87,13 +87,15 @@ type impersonatorConfigController struct {
|
||||
tlsServingCertDynamicCertProvider dynamiccert.Private
|
||||
infoLog logr.Logger
|
||||
debugLog logr.Logger
|
||||
|
||||
impersonationProxyTokenCache tokenclient.ExpiringSingletonTokenCacheGet
|
||||
}
|
||||
|
||||
func NewImpersonatorConfigController(
|
||||
namespace string,
|
||||
credentialIssuerResourceName string,
|
||||
k8sClient kubernetes.Interface,
|
||||
pinnipedAPIClient pinnipedclientset.Interface,
|
||||
pinnipedAPIClient conciergeclientset.Interface,
|
||||
credentialIssuerInformer conciergeconfiginformers.CredentialIssuerInformer,
|
||||
servicesInformer corev1informers.ServiceInformer,
|
||||
secretsInformer corev1informers.SecretInformer,
|
||||
@@ -109,6 +111,7 @@ func NewImpersonatorConfigController(
|
||||
impersonationSignerSecretName string,
|
||||
impersonationSigningCertProvider dynamiccert.Provider,
|
||||
log logr.Logger,
|
||||
impersonationProxyTokenCache tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
) controllerlib.Controller {
|
||||
secretNames := sets.NewString(tlsSecretName, caSecretName, impersonationSignerSecretName)
|
||||
log = log.WithName("impersonator-config-controller")
|
||||
@@ -136,6 +139,7 @@ func NewImpersonatorConfigController(
|
||||
tlsServingCertDynamicCertProvider: dynamiccert.NewServingCert("impersonation-proxy-serving-cert"),
|
||||
infoLog: log.V(plog.KlogLevelInfo),
|
||||
debugLog: log.V(plog.KlogLevelDebug),
|
||||
impersonationProxyTokenCache: impersonationProxyTokenCache,
|
||||
},
|
||||
},
|
||||
withInformer(credentialIssuerInformer,
|
||||
@@ -435,7 +439,7 @@ func (c *impersonatorConfigController) shouldHaveClusterIPService(config *v1alph
|
||||
return c.shouldHaveImpersonator(config) && config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeClusterIP
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) serviceExists(serviceName string) (bool, *v1.Service, error) {
|
||||
func (c *impersonatorConfigController) serviceExists(serviceName string) (bool, *corev1.Service, error) {
|
||||
service, err := c.servicesInformer.Lister().Services(c.namespace).Get(serviceName)
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if notFound {
|
||||
@@ -447,7 +451,7 @@ func (c *impersonatorConfigController) serviceExists(serviceName string) (bool,
|
||||
return true, service, nil
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) tlsSecretExists() (bool, *v1.Secret, error) {
|
||||
func (c *impersonatorConfigController) tlsSecretExists() (bool, *corev1.Secret, error) {
|
||||
secret, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.tlsSecretName)
|
||||
notFound := k8serrors.IsNotFound(err)
|
||||
if notFound {
|
||||
@@ -488,6 +492,7 @@ func (c *impersonatorConfigController) ensureImpersonatorIsStarted(syncCtx contr
|
||||
c.impersonationProxyPort,
|
||||
c.tlsServingCertDynamicCertProvider,
|
||||
c.impersonationSigningCertProvider,
|
||||
c.impersonationProxyTokenCache,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -534,14 +539,14 @@ func (c *impersonatorConfigController) ensureImpersonatorIsStopped(shouldCloseEr
|
||||
|
||||
func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.Context, config *v1alpha1.ImpersonationProxySpec) error {
|
||||
appNameLabel := c.labels[appLabelKey]
|
||||
loadBalancer := v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeLoadBalancer,
|
||||
Ports: []v1.ServicePort{
|
||||
loadBalancer := corev1.Service{
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeLoadBalancer,
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
TargetPort: intstr.FromInt(c.impersonationProxyPort),
|
||||
Port: defaultHTTPSPort,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
Protocol: corev1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
LoadBalancerIP: config.Service.LoadBalancerIP,
|
||||
@@ -580,14 +585,14 @@ func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.C
|
||||
|
||||
func (c *impersonatorConfigController) ensureClusterIPServiceIsStarted(ctx context.Context, config *v1alpha1.ImpersonationProxySpec) error {
|
||||
appNameLabel := c.labels[appLabelKey]
|
||||
clusterIP := v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
Ports: []v1.ServicePort{
|
||||
clusterIP := corev1.Service{
|
||||
Spec: corev1.ServiceSpec{
|
||||
Type: corev1.ServiceTypeClusterIP,
|
||||
Ports: []corev1.ServicePort{
|
||||
{
|
||||
TargetPort: intstr.FromInt(c.impersonationProxyPort),
|
||||
Port: defaultHTTPSPort,
|
||||
Protocol: v1.ProtocolTCP,
|
||||
Protocol: corev1.ProtocolTCP,
|
||||
},
|
||||
},
|
||||
Selector: map[string]string{appLabelKey: appNameLabel},
|
||||
@@ -623,7 +628,7 @@ func (c *impersonatorConfigController) ensureClusterIPServiceIsStopped(ctx conte
|
||||
return utilerrors.FilterOut(err, k8serrors.IsNotFound)
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) createOrUpdateService(ctx context.Context, desiredService *v1.Service) error {
|
||||
func (c *impersonatorConfigController) createOrUpdateService(ctx context.Context, desiredService *corev1.Service) error {
|
||||
log := c.infoLog.WithValues("serviceType", desiredService.Spec.Type, "service", klog.KObj(desiredService))
|
||||
|
||||
// Prepare to remember which annotation keys were added from the CredentialIssuer spec, both for
|
||||
@@ -769,8 +774,8 @@ func (c *impersonatorConfigController) ensureTLSSecret(ctx context.Context, name
|
||||
return c.ensureTLSSecretIsCreatedAndLoaded(ctx, nameInfo, secretFromInformer, ca)
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatchDesiredState(ctx context.Context, nameInfo *certNameInfo, ca *certauthority.CA, secret *v1.Secret) (bool, error) {
|
||||
certPEM := secret.Data[v1.TLSCertKey]
|
||||
func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatchDesiredState(ctx context.Context, nameInfo *certNameInfo, ca *certauthority.CA, secret *corev1.Secret) (bool, error) {
|
||||
certPEM := secret.Data[corev1.TLSCertKey]
|
||||
block, _ := pem.Decode(certPEM)
|
||||
if block == nil {
|
||||
c.infoLog.Info("found missing or not PEM-encoded data in TLS Secret",
|
||||
@@ -796,7 +801,7 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
||||
return true, nil
|
||||
}
|
||||
|
||||
keyPEM := secret.Data[v1.TLSPrivateKeyKey]
|
||||
keyPEM := secret.Data[corev1.TLSPrivateKeyKey]
|
||||
_, err = tls.X509KeyPair(certPEM, keyPEM)
|
||||
if err != nil {
|
||||
c.infoLog.Error(err, "found invalid private key PEM data in TLS Secret",
|
||||
@@ -864,7 +869,7 @@ func certHostnameAndIPMatchDesiredState(desiredIPs []net.IP, actualIPs []net.IP,
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) ensureTLSSecretIsCreatedAndLoaded(ctx context.Context, nameInfo *certNameInfo, secret *v1.Secret, ca *certauthority.CA) error {
|
||||
func (c *impersonatorConfigController) ensureTLSSecretIsCreatedAndLoaded(ctx context.Context, nameInfo *certNameInfo, secret *corev1.Secret, ca *certauthority.CA) error {
|
||||
if secret != nil {
|
||||
err := c.loadTLSCertFromSecret(secret)
|
||||
if err != nil {
|
||||
@@ -922,7 +927,7 @@ func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*cer
|
||||
return nil, err
|
||||
}
|
||||
|
||||
secret := v1.Secret{
|
||||
secret := corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.caSecretName,
|
||||
Namespace: c.namespace,
|
||||
@@ -932,7 +937,7 @@ func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*cer
|
||||
caCrtKey: impersonationCA.Bundle(),
|
||||
caKeyKey: caPrivateKeyPEM,
|
||||
},
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
|
||||
c.infoLog.Info("creating CA certificates for impersonation proxy",
|
||||
@@ -1025,7 +1030,7 @@ func (c *impersonatorConfigController) findTLSCertificateNameFromClusterIPServic
|
||||
return &certNameInfo{ready: false}, nil
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, ca *certauthority.CA, ips []net.IP, hostname string) (*v1.Secret, error) {
|
||||
func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, ca *certauthority.CA, ips []net.IP, hostname string) (*corev1.Secret, error) {
|
||||
var hostnames []string
|
||||
if hostname != "" {
|
||||
hostnames = []string{hostname}
|
||||
@@ -1041,17 +1046,17 @@ func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, c
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newTLSSecret := &v1.Secret{
|
||||
newTLSSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: c.tlsSecretName,
|
||||
Namespace: c.namespace,
|
||||
Labels: c.labels,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
v1.TLSPrivateKeyKey: keyPEM,
|
||||
v1.TLSCertKey: certPEM,
|
||||
corev1.TLSPrivateKeyKey: keyPEM,
|
||||
corev1.TLSCertKey: certPEM,
|
||||
},
|
||||
Type: v1.SecretTypeTLS,
|
||||
Type: corev1.SecretTypeTLS,
|
||||
}
|
||||
|
||||
c.infoLog.Info("creating TLS certificates for impersonation proxy",
|
||||
@@ -1062,9 +1067,9 @@ func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, c
|
||||
return c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, newTLSSecret, metav1.CreateOptions{})
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) loadTLSCertFromSecret(tlsSecret *v1.Secret) error {
|
||||
certPEM := tlsSecret.Data[v1.TLSCertKey]
|
||||
keyPEM := tlsSecret.Data[v1.TLSPrivateKeyKey]
|
||||
func (c *impersonatorConfigController) loadTLSCertFromSecret(tlsSecret *corev1.Secret) error {
|
||||
certPEM := tlsSecret.Data[corev1.TLSCertKey]
|
||||
keyPEM := tlsSecret.Data[corev1.TLSPrivateKeyKey]
|
||||
|
||||
if err := c.tlsServingCertDynamicCertProvider.SetCertKeyContent(certPEM, keyPEM); err != nil {
|
||||
return fmt.Errorf("could not parse TLS cert PEM data from Secret: %w", err)
|
||||
|
||||
@@ -30,7 +30,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
k8sinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
coretesting "k8s.io/client-go/testing"
|
||||
clocktesting "k8s.io/utils/clock/testing"
|
||||
@@ -45,6 +45,7 @@ import (
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/internal/tokenclient"
|
||||
)
|
||||
|
||||
func TestImpersonatorConfigControllerOptions(t *testing.T) {
|
||||
@@ -68,7 +69,7 @@ func TestImpersonatorConfigControllerOptions(t *testing.T) {
|
||||
r = require.New(t)
|
||||
observableWithInformerOption = testutil.NewObservableWithInformerOption()
|
||||
pinnipedInformerFactory := pinnipedinformers.NewSharedInformerFactory(nil, 0)
|
||||
sharedInformerFactory := kubeinformers.NewSharedInformerFactory(nil, 0)
|
||||
sharedInformerFactory := k8sinformers.NewSharedInformerFactory(nil, 0)
|
||||
credIssuerInformer := pinnipedInformerFactory.Config().V1alpha1().CredentialIssuers()
|
||||
servicesInformer := sharedInformerFactory.Core().V1().Services()
|
||||
secretsInformer := sharedInformerFactory.Core().V1().Secrets()
|
||||
@@ -93,6 +94,7 @@ func TestImpersonatorConfigControllerOptions(t *testing.T) {
|
||||
caSignerName,
|
||||
nil,
|
||||
plog.Logr(), //nolint:staticcheck // old test with no log assertions
|
||||
nil,
|
||||
)
|
||||
credIssuerInformerFilter = observableWithInformerOption.GetFilterForInformer(credIssuerInformer)
|
||||
servicesInformerFilter = observableWithInformerOption.GetFilterForInformer(servicesInformer)
|
||||
@@ -272,6 +274,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
const httpsPort = ":443"
|
||||
const fakeServerResponseBody = "hello, world!"
|
||||
const externallyProvidedTLSSecretName = "external-tls-secret" //nolint:gosec // this is not a credential
|
||||
var fakeExpiringSingletonTokenCacheGet = tokenclient.NewExpiringSingletonTokenCache()
|
||||
var labels = map[string]string{"app": "app-name", "other-key": "other-value"}
|
||||
|
||||
var r *require.Assertions
|
||||
@@ -282,7 +285,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
var pinnipedInformerClient *pinnipedfake.Clientset
|
||||
var pinnipedInformers pinnipedinformers.SharedInformerFactory
|
||||
var kubeInformerClient *kubernetesfake.Clientset
|
||||
var kubeInformers kubeinformers.SharedInformerFactory
|
||||
var kubeInformers k8sinformers.SharedInformerFactory
|
||||
var cancelContext context.Context
|
||||
var cancelContextCancelFunc context.CancelFunc
|
||||
var syncContext *controllerlib.Context
|
||||
@@ -308,11 +311,13 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
port int,
|
||||
dynamicCertProvider dynamiccert.Private,
|
||||
impersonationProxySignerCAProvider dynamiccert.Public,
|
||||
expiringSingletonTokenCacheGet tokenclient.ExpiringSingletonTokenCacheGet,
|
||||
) (func(stopCh <-chan struct{}) error, error) {
|
||||
impersonatorFuncWasCalled++
|
||||
r.Equal(8444, port)
|
||||
r.NotNil(dynamicCertProvider)
|
||||
r.NotNil(impersonationProxySignerCAProvider)
|
||||
r.Equal(fakeExpiringSingletonTokenCacheGet, expiringSingletonTokenCacheGet)
|
||||
|
||||
if impersonatorFuncError != nil {
|
||||
return nil, impersonatorFuncError
|
||||
@@ -580,7 +585,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
impersonatorFunc,
|
||||
mTLSClientCertCASecretName,
|
||||
mTLSClientCertProvider,
|
||||
plog.Logr(), //nolint:staticcheck // old test with no log assertions
|
||||
plog.Logr(), //nolint:staticcheck // old test with no log assertions,
|
||||
fakeExpiringSingletonTokenCacheGet,
|
||||
)
|
||||
controllerlib.TestWrap(t, subject, func(syncer controllerlib.Syncer) controllerlib.Syncer {
|
||||
tlsServingCertDynamicCertProvider = syncer.(*impersonatorConfigController).tlsServingCertDynamicCertProvider
|
||||
@@ -1121,8 +1127,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
pinnipedInformers = pinnipedinformers.NewSharedInformerFactoryWithOptions(pinnipedInformerClient, 0)
|
||||
|
||||
kubeInformerClient = kubernetesfake.NewSimpleClientset()
|
||||
kubeInformers = kubeinformers.NewSharedInformerFactoryWithOptions(kubeInformerClient, 0,
|
||||
kubeinformers.WithNamespace(installedInNamespace),
|
||||
kubeInformers = k8sinformers.NewSharedInformerFactoryWithOptions(kubeInformerClient, 0,
|
||||
k8sinformers.WithNamespace(installedInNamespace),
|
||||
)
|
||||
kubeAPIClient = kubernetesfake.NewSimpleClientset()
|
||||
pinnipedAPIClient = pinnipedfake.NewSimpleClientset()
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
@@ -41,7 +41,7 @@ func (s *kubeClientPodCommandExecutor) Exec(ctx context.Context, podNamespace st
|
||||
Resource("pods").
|
||||
Name(podName).
|
||||
SubResource("exec").
|
||||
VersionedParams(&v1.PodExecOptions{
|
||||
VersionedParams(&corev1.PodExecOptions{
|
||||
Stdin: false,
|
||||
Stdout: true,
|
||||
Stderr: false,
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package serviceaccounttokencleanup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
)
|
||||
|
||||
// NewLegacyServiceAccountTokenCleanupController creates a controller whose purpose is to delete a legacy Secret
|
||||
// that was created by installation of older versions of the Pinniped Concierge which is no longer needed.
|
||||
// This Secret was used to request and to hold a long-lived service account token which was used by the Concierge
|
||||
// impersonation proxy. It has been replaced by a goroutine which requests short-lived service account tokens
|
||||
// by making calls to the Kubernetes API server, without any need to read or write the tokens to a Secret.
|
||||
// Since the old Secret contains a long-lived token, we try to delete it here. That Secret may not exist if the user
|
||||
// never installed an old version of the Concierge, in which case this controller should do pretty much nothing.
|
||||
func NewLegacyServiceAccountTokenCleanupController(
|
||||
namespace string,
|
||||
legacySecretName string,
|
||||
k8sClient kubernetes.Interface,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
logger plog.Logger,
|
||||
) controllerlib.Controller {
|
||||
name := "legacy-service-account-token-cleanup-controller"
|
||||
return controllerlib.New(controllerlib.Config{
|
||||
Name: name,
|
||||
Syncer: &serviceAccountTokenCleanupController{
|
||||
name: name,
|
||||
namespace: namespace,
|
||||
legacySecretName: legacySecretName,
|
||||
k8sClient: k8sClient,
|
||||
secretInformer: secretInformer,
|
||||
logger: logger.WithName(name),
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
secretInformer,
|
||||
pinnipedcontroller.SimpleFilterWithSingletonQueue(func(obj metav1.Object) bool {
|
||||
secret, ok := obj.(*corev1.Secret)
|
||||
|
||||
return obj.GetNamespace() == namespace &&
|
||||
obj.GetName() == legacySecretName &&
|
||||
ok &&
|
||||
secret.Type == corev1.SecretTypeServiceAccountToken
|
||||
}),
|
||||
controllerlib.InformerOption{},
|
||||
))
|
||||
}
|
||||
|
||||
type serviceAccountTokenCleanupController struct {
|
||||
name string
|
||||
namespace string
|
||||
legacySecretName string
|
||||
k8sClient kubernetes.Interface
|
||||
secretInformer corev1informers.SecretInformer
|
||||
logger plog.Logger
|
||||
}
|
||||
|
||||
func (c serviceAccountTokenCleanupController) Sync(syncCtx controllerlib.Context) error {
|
||||
secrets, err := c.secretInformer.Lister().Secrets(c.namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to list all secrets in namespace %s: %w", c.namespace, err)
|
||||
}
|
||||
|
||||
foundSecret := false
|
||||
for _, secret := range secrets {
|
||||
if secret.Name == c.legacySecretName && secret.Type == corev1.SecretTypeServiceAccountToken {
|
||||
foundSecret = true
|
||||
}
|
||||
}
|
||||
|
||||
c.logger.Debug(
|
||||
fmt.Sprintf("%s controller checked for legacy secret", c.name),
|
||||
"secretName", c.legacySecretName,
|
||||
"secretNamespace", c.namespace,
|
||||
"secretType", corev1.SecretTypeServiceAccountToken,
|
||||
"foundSecret", foundSecret,
|
||||
)
|
||||
|
||||
if foundSecret {
|
||||
err = c.k8sClient.CoreV1().Secrets(c.namespace).Delete(syncCtx.Context, c.legacySecretName, metav1.DeleteOptions{})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to delete secret %s in namespace %s: %w", c.legacySecretName, c.namespace, err)
|
||||
}
|
||||
|
||||
c.logger.Debug(
|
||||
fmt.Sprintf("%s controller succcessfully deleted legacy secret", c.name),
|
||||
"secretName", c.legacySecretName,
|
||||
"secretNamespace", c.namespace,
|
||||
"secretType", corev1.SecretTypeServiceAccountToken,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// Copyright 2023 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package serviceaccounttokencleanup
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
kubeinformers "k8s.io/client-go/informers"
|
||||
kubernetesfake "k8s.io/client-go/kubernetes/fake"
|
||||
kubetesting "k8s.io/client-go/testing"
|
||||
|
||||
"go.pinniped.dev/internal/controllerlib"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
)
|
||||
|
||||
func TestNewServiceAccountTokenCleanupController(t *testing.T) {
|
||||
namespace := "a-namespace"
|
||||
legacySecretName := "a-secret"
|
||||
observableWithInformerOption := testutil.NewObservableWithInformerOption()
|
||||
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
|
||||
|
||||
var log bytes.Buffer
|
||||
_ = NewLegacyServiceAccountTokenCleanupController(
|
||||
namespace,
|
||||
legacySecretName,
|
||||
nil, // not needed for this test
|
||||
secretsInformer,
|
||||
observableWithInformerOption.WithInformer,
|
||||
plog.TestLogger(t, &log),
|
||||
)
|
||||
|
||||
secretsInformerFilter := observableWithInformerOption.GetFilterForInformer(secretsInformer)
|
||||
|
||||
legacySecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: legacySecretName, Namespace: namespace}, Type: corev1.SecretTypeServiceAccountToken}
|
||||
wrongName := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrongName", Namespace: namespace}, Type: corev1.SecretTypeServiceAccountToken}
|
||||
wrongType := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrongType", Namespace: namespace}, Type: "other-type"}
|
||||
wrongNamespace := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "wrongNamespace", Namespace: "wrong-namespace"}, Type: corev1.SecretTypeServiceAccountToken}
|
||||
wrongObject := &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "config-map", Namespace: namespace}}
|
||||
|
||||
require.False(t, secretsInformerFilter.Add(wrongName))
|
||||
require.False(t, secretsInformerFilter.Update(wrongName, wrongNamespace))
|
||||
require.False(t, secretsInformerFilter.Update(wrongNamespace, wrongName))
|
||||
require.False(t, secretsInformerFilter.Delete(wrongName))
|
||||
|
||||
require.False(t, secretsInformerFilter.Add(wrongObject))
|
||||
require.False(t, secretsInformerFilter.Update(wrongObject, wrongNamespace))
|
||||
require.False(t, secretsInformerFilter.Update(wrongNamespace, wrongObject))
|
||||
require.False(t, secretsInformerFilter.Delete(wrongObject))
|
||||
|
||||
require.False(t, secretsInformerFilter.Add(wrongNamespace))
|
||||
require.False(t, secretsInformerFilter.Update(wrongNamespace, wrongObject))
|
||||
require.False(t, secretsInformerFilter.Update(wrongObject, wrongNamespace))
|
||||
require.False(t, secretsInformerFilter.Delete(wrongNamespace))
|
||||
|
||||
require.False(t, secretsInformerFilter.Add(wrongType))
|
||||
require.False(t, secretsInformerFilter.Update(wrongType, wrongNamespace))
|
||||
require.False(t, secretsInformerFilter.Update(wrongNamespace, wrongType))
|
||||
require.False(t, secretsInformerFilter.Delete(wrongType))
|
||||
|
||||
require.True(t, secretsInformerFilter.Add(legacySecret))
|
||||
require.True(t, secretsInformerFilter.Update(legacySecret, wrongNamespace))
|
||||
require.True(t, secretsInformerFilter.Update(wrongNamespace, legacySecret))
|
||||
require.True(t, secretsInformerFilter.Delete(legacySecret))
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
secretNameToDelete string
|
||||
namespace string
|
||||
addReactors func(*kubernetesfake.Clientset)
|
||||
expectedErrMessage string
|
||||
expectedActions []kubetesting.Action
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
secretNameToDelete: "secret-to-delete",
|
||||
namespace: "some-namespace",
|
||||
expectedActions: []kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(
|
||||
schema.GroupVersionResource{
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "secrets",
|
||||
},
|
||||
"some-namespace",
|
||||
"secret-to-delete",
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no secret to delete",
|
||||
secretNameToDelete: "not-an-existing-secret",
|
||||
expectedActions: []kubetesting.Action{},
|
||||
},
|
||||
{
|
||||
name: "returns API errors",
|
||||
secretNameToDelete: "secret-to-delete",
|
||||
namespace: "other-namespace",
|
||||
addReactors: func(clientset *kubernetesfake.Clientset) {
|
||||
clientset.PrependReactor(
|
||||
"delete",
|
||||
"secrets",
|
||||
func(a kubetesting.Action) (bool, runtime.Object, error) {
|
||||
return true, nil, errors.New("error from API client")
|
||||
},
|
||||
)
|
||||
},
|
||||
expectedErrMessage: "unable to delete secret secret-to-delete in namespace other-namespace: error from API client",
|
||||
expectedActions: []kubetesting.Action{
|
||||
kubetesting.NewDeleteAction(
|
||||
schema.GroupVersionResource{
|
||||
Group: "",
|
||||
Version: "v1",
|
||||
Resource: "secrets",
|
||||
},
|
||||
"other-namespace",
|
||||
"secret-to-delete",
|
||||
),
|
||||
},
|
||||
},
|
||||
} {
|
||||
tt := tt
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
kubeAPIClient, kubeInformers := setupKubernetes(t, tt.namespace)
|
||||
if tt.addReactors != nil {
|
||||
tt.addReactors(kubeAPIClient)
|
||||
}
|
||||
|
||||
var log bytes.Buffer
|
||||
controller := NewLegacyServiceAccountTokenCleanupController(
|
||||
tt.namespace,
|
||||
tt.secretNameToDelete,
|
||||
kubeAPIClient,
|
||||
kubeInformers.Core().V1().Secrets(),
|
||||
controllerlib.WithInformer,
|
||||
plog.TestLogger(t, &log),
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Must start informers before calling TestRunSynchronously().
|
||||
kubeInformers.Start(ctx.Done())
|
||||
|
||||
controllerlib.TestRunSynchronously(t, controller)
|
||||
|
||||
err := controllerlib.TestSync(t, controller, controllerlib.Context{
|
||||
Context: ctx,
|
||||
})
|
||||
if tt.expectedErrMessage == "" {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.ErrorContains(t, err, tt.expectedErrMessage)
|
||||
}
|
||||
|
||||
actualActions := kubeAPIClient.Actions()
|
||||
require.Equal(t, tt.expectedActions, actualActions)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setupKubernetes(t *testing.T, namespace string) (*kubernetesfake.Clientset, kubeinformers.SharedInformerFactory) {
|
||||
t.Helper()
|
||||
|
||||
kubeAPIClient := kubernetesfake.NewSimpleClientset()
|
||||
kubeInformerClient := kubernetesfake.NewSimpleClientset()
|
||||
|
||||
kubeInformers := kubeinformers.NewSharedInformerFactory(
|
||||
kubeInformerClient,
|
||||
0,
|
||||
)
|
||||
|
||||
secretToDelete := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secret-to-delete",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Type: corev1.SecretTypeServiceAccountToken,
|
||||
}
|
||||
secretWithWrongName := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "wrong-name",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Type: corev1.SecretTypeServiceAccountToken,
|
||||
}
|
||||
secretWithWrongType := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secret-to-leave-alone",
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
secretWithWrongNamespace := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "secret-to-delete",
|
||||
Namespace: "other",
|
||||
},
|
||||
Type: corev1.SecretTypeServiceAccountToken,
|
||||
}
|
||||
|
||||
require.NoError(t, kubeAPIClient.Tracker().Add(secretToDelete))
|
||||
require.NoError(t, kubeInformerClient.Tracker().Add(secretToDelete))
|
||||
require.NoError(t, kubeAPIClient.Tracker().Add(secretWithWrongName))
|
||||
require.NoError(t, kubeInformerClient.Tracker().Add(secretWithWrongName))
|
||||
require.NoError(t, kubeAPIClient.Tracker().Add(secretWithWrongType))
|
||||
require.NoError(t, kubeInformerClient.Tracker().Add(secretWithWrongType))
|
||||
require.NoError(t, kubeAPIClient.Tracker().Add(secretWithWrongNamespace))
|
||||
require.NoError(t, kubeInformerClient.Tracker().Add(secretWithWrongNamespace))
|
||||
return kubeAPIClient, kubeInformers
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
|
||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
|
||||
supervisorclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
|
||||
idpinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions/idp/v1alpha1"
|
||||
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
||||
"go.pinniped.dev/internal/controller/conditionsutil"
|
||||
@@ -232,7 +232,7 @@ type activeDirectoryWatcherController struct {
|
||||
cache UpstreamActiveDirectoryIdentityProviderICache
|
||||
validatedSettingsCache upstreamwatchers.ValidatedSettingsCacheI
|
||||
ldapDialer upstreamldap.LDAPDialer
|
||||
client pinnipedclientset.Interface
|
||||
client supervisorclientset.Interface
|
||||
activeDirectoryIdentityProviderInformer idpinformers.ActiveDirectoryIdentityProviderInformer
|
||||
secretInformer corev1informers.SecretInformer
|
||||
}
|
||||
@@ -240,7 +240,7 @@ type activeDirectoryWatcherController struct {
|
||||
// New instantiates a new controllerlib.Controller which will populate the provided UpstreamActiveDirectoryIdentityProviderICache.
|
||||
func New(
|
||||
idpCache UpstreamActiveDirectoryIdentityProviderICache,
|
||||
client pinnipedclientset.Interface,
|
||||
client supervisorclientset.Interface,
|
||||
activeDirectoryIdentityProviderInformer idpinformers.ActiveDirectoryIdentityProviderInformer,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
@@ -263,7 +263,7 @@ func newInternal(
|
||||
idpCache UpstreamActiveDirectoryIdentityProviderICache,
|
||||
validatedSettingsCache upstreamwatchers.ValidatedSettingsCacheI,
|
||||
ldapDialer upstreamldap.LDAPDialer,
|
||||
client pinnipedclientset.Interface,
|
||||
client supervisorclientset.Interface,
|
||||
activeDirectoryIdentityProviderInformer idpinformers.ActiveDirectoryIdentityProviderInformer,
|
||||
secretInformer corev1informers.SecretInformer,
|
||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user