Merge pull request #148 from vmware-tanzu/supervisor-with-discovery

Beginning of a Pinniped Supervisor Server, starting with an OIDC Discovery Endpoint
This commit is contained in:
Ryan Richard 2020-10-09 18:58:15 -07:00 committed by GitHub
commit ff545db869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 5714 additions and 171 deletions

View File

@ -109,7 +109,7 @@ docker build .
1. Create a local Kubernetes cluster using `kind`:
```bash
kind create cluster --image kindest/node:v1.18.8
./hack/kind-up.sh
```
1. Install Pinniped and supporting dependencies using `tilt`:
@ -123,11 +123,11 @@ docker build .
1. Run the Pinniped integration tests:
```bash
source ./hack/lib/tilt/integration-test.env && go test -v -count 1 ./test/integration
source /tmp/integration-test-env && go test -v -count 1 ./test/integration
```
To uninstall the test environment, run `./hack/tilt-down.sh`.
To destroy the local Kubernetes cluster, run `kind delete cluster`.
To destroy the local Kubernetes cluster, run `./hack/kind-down.sh`.
### Observing Tests on the Continuous Integration Environment

View File

@ -20,18 +20,20 @@ COPY hack ./hack
# Build the executable binary (CGO_ENABLED=0 means static linking)
RUN mkdir out \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(hack/get-ldflags.sh)" -o out ./cmd/pinniped-server/... \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(hack/get-ldflags.sh)" -o out ./cmd/pinniped-concierge/... \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "$(hack/get-ldflags.sh)" -o out ./cmd/pinniped-supervisor/... \
&& CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o out ./cmd/local-user-authenticator/...
# Use a runtime image based on Debian slim
FROM debian:10.5-slim
# Copy the binaries from the build-env stage
COPY --from=build-env /work/out/pinniped-server /usr/local/bin/pinniped-server
COPY --from=build-env /work/out/pinniped-concierge /usr/local/bin/pinniped-concierge
COPY --from=build-env /work/out/pinniped-supervisor /usr/local/bin/pinniped-supervisor
COPY --from=build-env /work/out/local-user-authenticator /usr/local/bin/local-user-authenticator
# Document the port
EXPOSE 443
# Set the entrypoint
ENTRYPOINT ["/usr/local/bin/pinniped-server"]
ENTRYPOINT ["/usr/local/bin/pinniped-concierge"]

View File

@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CredentialIssuerConfig{},
&CredentialIssuerConfigList{},
&OIDCProviderConfig{},
&OIDCProviderConfigList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -0,0 +1,72 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid
type OIDCProviderStatus string
const (
SuccessOIDCProviderStatus = OIDCProviderStatus("Success")
DuplicateOIDCProviderStatus = OIDCProviderStatus("Duplicate")
InvalidOIDCProviderStatus = OIDCProviderStatus("Invalid")
)
// OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
type OIDCProviderConfigSpec struct {
// 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.
// +kubebuilder:validation:MinLength=1
Issuer string `json:"issuer"`
}
// OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
type OIDCProviderConfigStatus struct {
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
// represent success or failure.
// +optional
Status OIDCProviderStatus `json:"status,omitempty"`
// Message provides human-readable details about the Status.
// +optional
Message string `json:"message,omitempty"`
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
// around some undesirable behavior with respect to the empty metav1.Time value (see
// https://github.com/kubernetes/kubernetes/issues/86811).
// +optional
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
}
// OIDCProviderConfig describes the configuration of an OIDC provider.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:shortName=opc
type OIDCProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec of the OIDC provider.
Spec OIDCProviderConfigSpec `json:"spec"`
// Status of the OIDC provider.
Status OIDCProviderConfigStatus `json:"status,omitempty"`
}
// List of OIDCProviderConfig objects.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type OIDCProviderConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OIDCProviderConfig `json:"items"`
}

View File

@ -13,7 +13,7 @@ import (
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
"go.pinniped.dev/internal/server"
"go.pinniped.dev/internal/concierge/server"
)
func main() {

View File

@ -0,0 +1,152 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"time"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/client-go/pkg/version"
"k8s.io/client-go/rest"
restclient "k8s.io/client-go/rest"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
pinnipedclientset "go.pinniped.dev/generated/1.19/client/clientset/versioned"
pinnipedinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions"
"go.pinniped.dev/internal/controller/supervisorconfig"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/downward"
"go.pinniped.dev/internal/oidc/provider/manager"
)
const (
singletonWorker = 1
defaultResyncInterval = 3 * time.Minute
)
func start(ctx context.Context, l net.Listener, handler http.Handler) {
server := http.Server{Handler: handler}
errCh := make(chan error)
go func() {
errCh <- server.Serve(l)
}()
go func() {
select {
case err := <-errCh:
klog.InfoS("server exited", "err", err)
case <-ctx.Done():
klog.InfoS("server context cancelled", "err", ctx.Err())
if err := server.Shutdown(context.Background()); err != nil {
klog.InfoS("server shutdown failed", "err", err)
}
}
}()
}
func waitForSignal() os.Signal {
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt)
return <-signalCh
}
func startControllers(
ctx context.Context,
issuerProvider *manager.Manager,
pinnipedClient pinnipedclientset.Interface,
pinnipedInformers pinnipedinformers.SharedInformerFactory,
) {
// Create controller manager.
controllerManager := controllerlib.
NewManager().
WithController(
supervisorconfig.NewOIDCProviderConfigWatcherController(
issuerProvider,
clock.RealClock{},
pinnipedClient,
pinnipedInformers.Config().V1alpha1().OIDCProviderConfigs(),
controllerlib.WithInformer,
),
singletonWorker,
)
pinnipedInformers.Start(ctx.Done())
go controllerManager.Start(ctx)
}
func newPinnipedClient() (pinnipedclientset.Interface, error) {
kubeConfig, err := restclient.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("could not load in-cluster configuration: %w", err)
}
// Connect to the core Kubernetes API.
pinnipedClient, err := pinnipedclientset.NewForConfig(kubeConfig)
if err != nil {
return nil, fmt.Errorf("could not load in-cluster configuration: %w", err)
}
return pinnipedClient, nil
}
func run(serverInstallationNamespace string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
pinnipedClient, err := newPinnipedClient()
if err != nil {
return fmt.Errorf("cannot create k8s client: %w", err)
}
pinnipedInformers := pinnipedinformers.NewSharedInformerFactoryWithOptions(
pinnipedClient,
defaultResyncInterval,
pinnipedinformers.WithNamespace(serverInstallationNamespace),
)
oidProvidersManager := manager.NewManager(http.NotFoundHandler())
startControllers(ctx, oidProvidersManager, pinnipedClient, pinnipedInformers)
//nolint: gosec // Intentionally binding to all network interfaces.
l, err := net.Listen("tcp", ":80")
if err != nil {
return fmt.Errorf("cannot create listener: %w", err)
}
defer l.Close()
start(ctx, l, oidProvidersManager)
klog.InfoS("supervisor is ready", "address", l.Addr().String())
gotSignal := waitForSignal()
klog.InfoS("supervisor exiting", "signal", gotSignal)
return nil
}
func main() {
logs.InitLogs()
defer logs.FlushLogs()
klog.Infof("Running %s at %#v", rest.DefaultKubernetesUserAgent(), version.Get())
klog.Infof("Command-line arguments were: %s %s %s", os.Args[0], os.Args[1], os.Args[2])
// Discover in which namespace we are installed.
podInfo, err := downward.Load(os.Args[1])
if err != nil {
klog.Fatal(fmt.Errorf("could not read pod metadata: %w", err))
}
if err := run(podInfo.Namespace); err != nil {
klog.Fatal(err)
}
}

View File

@ -4,7 +4,7 @@
If you would like to try Pinniped, but you don't have a compatible identity provider,
you can use Pinniped's test identity provider.
See [deploy-local-user-authenticator/README.md](../deploy-local-user-authenticator/README.md)
See [deploy/local-user-authenticator/README.md](../../deploy/local-user-authenticator/README.md)
for details.
## Installing the Latest Version with Default Options
@ -26,14 +26,14 @@ kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/download/v0.2
## Installing with Custom Options
Creating your own deployment YAML file requires `ytt` from [Carvel](https://carvel.dev/) to template the YAML files
in the [deploy](../deploy) directory.
in the `deploy/concierge` directory.
Either [install `ytt`](https://get-ytt.io/) or use the [container image from Dockerhub](https://hub.docker.com/r/k14s/image/tags).
1. `git clone` this repo and `git checkout` the release version tag of the release that you would like to deploy.
1. The configuration options are in [deploy/values.yml](values.yaml).
1. The configuration options are in [deploy/concierge/values.yml](values.yaml).
Fill in the values in that file, or override those values using additional `ytt` command-line options in
the command below. Use the release version tag as the `image_tag` value.
2. In a terminal, cd to this `deploy` directory
2. In a terminal, cd to this `deploy/concierge` directory
3. To generate the final YAML files, run `ytt --file .`
4. Deploy the generated YAML using your preferred deployment tool, such as `kubectl` or [`kapp`](https://get-kapp.io/).
For example: `ytt --file . | kapp deploy --yes --app pinniped --diff-changes --file -`

View File

@ -4,8 +4,8 @@
#@data/values
---
app_name: pinniped
namespace: pinniped
app_name: pinniped-concierge
namespace: pinniped-concierge
#! Specify how many replicas of the Pinniped server to run.
replicas: 2

View File

@ -31,14 +31,14 @@ kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/download/v0.2
## Installing with Custom Options
Creating your own deployment YAML file requires `ytt` from [Carvel](https://carvel.dev/) to template the YAML files
in the [deploy-local-user-authenticator](../deploy-local-user-authenticator) directory.
in the `deploy/local-user-authenticator` directory.
Either [install `ytt`](https://get-ytt.io/) or use the [container image from Dockerhub](https://hub.docker.com/r/k14s/image/tags).
1. `git clone` this repo and `git checkout` the release version tag of the release that you would like to deploy.
1. The configuration options are in [deploy-local-user-authenticator/values.yml](values.yaml).
1. The configuration options are in [deploy/local-user-authenticator/values.yml](values.yaml).
Fill in the values in that file, or override those values using additional `ytt` command-line options in
the command below. Use the release version tag as the `image_tag` value.
2. In a terminal, cd to this `deploy-local-user-authenticator` directory
2. In a terminal, cd to this `deploy/local-user-authenticator` directory
3. To generate the final YAML files, run `ytt --file .`
4. Deploy the generated YAML using your preferred deployment tool, such as `kubectl` or [`kapp`](https://get-kapp.io/).
For example: `ytt --file . | kapp deploy --yes --app local-user-authenticator --diff-changes --file -`
@ -79,7 +79,7 @@ kubectl get secret local-user-authenticator-tls-serving-certificate --namespace
When installing Pinniped on the same cluster, configure local-user-authenticator as an Identity Provider for Pinniped
using the webhook URL `https://local-user-authenticator.local-user-authenticator.svc/authenticate`
along with the CA bundle fetched by the above command. See [doc/demo.md](../doc/demo.md) for an example.
along with the CA bundle fetched by the above command. See [doc/demo.md](../../doc/demo.md) for an example.
## Optional: Manually Testing the Webhook Endpoint After Installing

110
deploy/supervisor/README.md Normal file
View File

@ -0,0 +1,110 @@
# Deploying the Pinniped Supervisor
## What is the Pinniped Supervisor?
The Pinniped Supervisor app is a component of the Pinniped OIDC and Cluster Federation solutions.
It can be deployed when those features are needed.
## Installing the Latest Version with Default Options
```bash
kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/latest/download/install-supervisor.yaml
```
## Installing an Older Version with Default Options
Choose your preferred [release](https://github.com/vmware-tanzu/pinniped/releases) version number
and use it to replace the version number in the URL below.
```bash
# Replace v0.3.0 with your preferred version in the URL below
kubectl apply -f https://github.com/vmware-tanzu/pinniped/releases/download/v0.3.0/install-supervisor.yaml
```
## Installing with Custom Options
Creating your own deployment YAML file requires `ytt` from [Carvel](https://carvel.dev/) to template the YAML files
in the `deploy/supervisor` directory.
Either [install `ytt`](https://get-ytt.io/) or use the [container image from Dockerhub](https://hub.docker.com/r/k14s/image/tags).
1. `git clone` this repo and `git checkout` the release version tag of the release that you would like to deploy.
1. The configuration options are in [deploy/supervisor/values.yml](values.yaml).
Fill in the values in that file, or override those values using additional `ytt` command-line options in
the command below. Use the release version tag as the `image_tag` value.
2. In a terminal, cd to this `deploy/supervisor` directory
3. To generate the final YAML files, run `ytt --file .`
4. Deploy the generated YAML using your preferred deployment tool, such as `kubectl` or [`kapp`](https://get-kapp.io/).
For example: `ytt --file . | kapp deploy --yes --app pinniped-supervisor --diff-changes --file -`
## Configuring After Installing
### Exposing the Supervisor App as a Service
Create a Service to make the app available outside of the cluster. If you installed using `ytt` then you can use
the related `service_*_port` options from [deploy/supervisor/values.yml](values.yaml) to create a Service, instead
of creating them manually as shown below.
#### Using a LoadBalancer Service
Using a LoadBalancer Service is probably the easiest way to expose the Supervisor app, if your cluster supports
LoadBalancer Services. For example:
```yaml
apiVersion: v1
kind: Service
metadata:
name: pinniped-supervisor-loadbalancer
namespace: pinniped-supervisor
labels:
app: pinniped-supervisor
spec:
type: LoadBalancer
selector:
app: pinniped-supervisor
ports:
- protocol: TCP
port: 80
targetPort: 80
```
#### Using a NodePort Service
A NodePort Service exposes the app as a port on the nodes of the cluster.
This is convenient for use with kind clusters, because kind can
[expose node ports as localhost ports on the host machine](https://kind.sigs.k8s.io/docs/user/configuration/#extra-port-mappings).
For example:
```yaml
apiVersion: v1
kind: Service
metadata:
name: pinniped-supervisor-nodeport
namespace: pinniped-supervisor
labels:
app: pinniped-supervisor
spec:
type: NodePort
selector:
app: pinniped-supervisor
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 31234
```
### Configuring the Supervisor to Act as an OIDC Provider
The Supervisor can be configured as an OIDC provider by creating `OIDCProviderConfig` resources
in the same namespace where the Supervisor app was installed. For example:
```yaml
apiVersion: config.pinniped.dev/v1alpha1
kind: OIDCProviderConfig
metadata:
name: my-provider
namespace: pinniped-supervisor
spec:
issuer: https://my-issuer.eaxmple.com
```

View File

@ -0,0 +1,86 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
creationTimestamp: null
name: oidcproviderconfigs.config.pinniped.dev
spec:
group: config.pinniped.dev
names:
kind: OIDCProviderConfig
listKind: OIDCProviderConfigList
plural: oidcproviderconfigs
shortNames:
- opc
singular: oidcproviderconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: OIDCProviderConfig describes the configuration of an OIDC provider.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec of the OIDC provider.
properties:
issuer:
description: "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).
\n See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
for more information."
minLength: 1
type: string
required:
- issuer
type: object
status:
description: Status of the OIDC provider.
properties:
lastUpdateTime:
description: LastUpdateTime holds the time at which the Status was
last updated. It is a pointer to get around some undesirable behavior
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
format: date-time
type: string
message:
description: Message provides human-readable details about the Status.
type: string
status:
description: Status holds an enum that describes the state of this
OIDC Provider. Note that this Status can represent success or failure.
enum:
- Success
- Duplicate
- Invalid
type: string
type: object
required:
- spec
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -0,0 +1,112 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data")
---
apiVersion: v1
kind: Namespace
metadata:
name: #@ data.values.namespace
labels:
name: #@ data.values.namespace
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: #@ data.values.app_name
namespace: #@ data.values.namespace
---
apiVersion: v1
kind: ConfigMap
metadata:
name: #@ data.values.app_name + "-static-config"
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
data:
#@yaml/text-templated-strings
pinniped.yaml: |
names:
dynamicConfigMap: (@= data.values.app_name + "-dynamic-config" @)
---
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
apiVersion: v1
kind: Secret
metadata:
name: image-pull-secret
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: #@ data.values.image_pull_dockerconfigjson
#@ end
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: #@ data.values.app_name
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
spec:
replicas: #@ data.values.replicas
selector:
matchLabels:
app: #@ data.values.app_name
template:
metadata:
labels:
app: #@ data.values.app_name
spec:
serviceAccountName: #@ data.values.app_name
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":
imagePullSecrets:
- name: image-pull-secret
#@ end
containers:
- name: pinniped-supervisor
#@ if data.values.image_digest:
image: #@ data.values.image_repo + "@" + data.values.image_digest
#@ else:
image: #@ data.values.image_repo + ":" + data.values.image_tag
#@ end
imagePullPolicy: IfNotPresent
command: #! override the default entrypoint
- /usr/local/bin/pinniped-supervisor
args:
- /etc/podinfo
- /etc/config/pinniped.yaml
resources:
requests:
memory: "128Mi"
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: config-volume
configMap:
name: #@ data.values.app_name + "-static-config"
- name: podinfo
downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "namespace"
fieldRef:
fieldPath: metadata.namespace
#! This will help make sure our multiple pods run on different nodes, making
#! our deployment "more" "HA".
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
podAffinityTerm:
labelSelector:
matchLabels:
app: #@ data.values.app_name
topologyKey: kubernetes.io/hostname

View File

@ -0,0 +1,34 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data")
#! Give permission to various objects within the app's own namespace
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: #@ data.values.app_name
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
rules:
- apiGroups: [config.pinniped.dev]
resources: [oidcproviderconfigs]
verbs: [update, get, list, watch]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: #@ data.values.app_name
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
subjects:
- kind: ServiceAccount
name: #@ data.values.app_name
namespace: #@ data.values.namespace
roleRef:
kind: Role
name: #@ data.values.app_name
apiGroup: rbac.authorization.k8s.io

View File

@ -0,0 +1,59 @@
#@ load("@ytt:data", "data")
#@ if data.values.service_nodeport_port:
---
apiVersion: v1
kind: Service
metadata:
name: #@ data.values.app_name + "-nodeport"
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
spec:
type: NodePort
selector:
app: #@ data.values.app_name
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: #@ data.values.service_nodeport_port
#@ end
#@ if data.values.service_clusterip_port:
---
apiVersion: v1
kind: Service
metadata:
name: #@ data.values.app_name + "-clusterip"
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
spec:
type: ClusterIP
selector:
app: #@ data.values.app_name
ports:
- protocol: TCP
port: #@ data.values.service_clusterip_port
targetPort: 80
#@ end
#@ if data.values.service_loadbalancer_port:
---
apiVersion: v1
kind: Service
metadata:
name: #@ data.values.app_name + "-loadbalancer"
namespace: #@ data.values.namespace
labels:
app: #@ data.values.app_name
spec:
type: LoadBalancer
selector:
app: #@ data.values.app_name
ports:
- protocol: TCP
port: #@ data.values.service_loadbalancer_port
targetPort: 80
#@ end

View File

@ -0,0 +1,29 @@
#! Copyright 2020 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@data/values
---
app_name: pinniped-supervisor
namespace: pinniped-supervisor
#! 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.
image_repo: docker.io/getpinniped/pinniped-server
image_digest: #! e.g. sha256:f3c4fdfd3ef865d4b97a1fd295d94acc3f0c654c46b6f27ffad5cf80216903c8
image_tag: latest
#! Specifies a secret to be used when pulling the above 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"}}}
#! Specify how to expose the Supervisor app as a Service.
#! Typically you would set a value for only one of the following.
#! Setting any of these values means that a Service of that type will be created.
service_nodeport_port: #! e.g. 31234
service_loadbalancer_port: #! e.g. 443
service_clusterip_port: #! e.g. 443

View File

@ -11,7 +11,7 @@
Don't have an identity provider of a type supported by Pinniped handy? No problem, there is a demo identity provider
available. Start by installing local-user-authenticator on the same cluster where you would like to try Pinniped
by following the directions in [deploy-local-user-authenticator/README.md](../deploy-local-user-authenticator/README.md).
by following the directions in [deploy/local-user-authenticator/README.md](../deploy/local-user-authenticator/README.md).
See below for an example of deploying this on kind.
1. A kubeconfig where the current context points to the cluster and has admin-like
@ -22,7 +22,7 @@
Installing and trying Pinniped on any cluster will consist of the following general steps. See the next section below
for a more specific example of installing onto a local kind cluster, including the exact commands to use for that case.
1. Install Pinniped. See [deploy/README.md](../deploy/README.md).
1. Install Pinniped. See [deploy/concierge/README.md](../deploy/concierge/README.md).
1. Download the Pinniped CLI from [Pinniped's github Releases page](https://github.com/vmware-tanzu/pinniped/releases/latest).
1. Generate a kubeconfig using the Pinniped CLI. Run `pinniped get-kubeconfig --help` for more information.
1. Run `kubectl` commands using the generated kubeconfig. Pinniped will automatically be used for authentication during those commands.
@ -88,7 +88,7 @@ as the identity provider.
The `install-local-user-authenticator.yaml` file includes the default deployment options.
If you would prefer to customize the available options, please
see [deploy-local-user-authenticator/README.md](../deploy-local-user-authenticator/README.md)
see [deploy/local-user-authenticator/README.md](../deploy/local-user-authenticator/README.md)
for instructions on how to deploy using `ytt`.
1. Create a test user named `pinny-the-seal` in the local-user-authenticator identity provider.
@ -115,7 +115,7 @@ as the identity provider.
```
The `install-pinniped.yaml` file includes the default deployment options.
If you would prefer to customize the available options, please see [deploy/README.md](../deploy/README.md)
If you would prefer to customize the available options, please see [deploy/concierge/README.md](../deploy/concierge/README.md)
for instructions on how to deploy using `ytt`.
1. Create a `WebhookIdentityProvider` object to configure Pinniped to authenticate using local-user-authenticator.

View File

@ -95,6 +95,65 @@ Status of a credential issuer.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfig"]
==== OIDCProviderConfig
OIDCProviderConfig describes the configuration of an OIDC provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfiglist[$$OIDCProviderConfigList$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfigspec[$$OIDCProviderConfigSpec$$]__ | Spec of the OIDC provider.
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfigstatus[$$OIDCProviderConfigStatus$$]__ | Status of the OIDC provider.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfigspec"]
==== OIDCProviderConfigSpec
OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[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.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfigstatus"]
==== OIDCProviderConfigStatus
OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`status`* __OIDCProviderStatus__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
| *`message`* __string__ | Message provides human-readable details about the Status.
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|===
[id="{anchor_prefix}-idp-pinniped-dev-v1alpha1"]
=== idp.pinniped.dev/v1alpha1

View File

@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CredentialIssuerConfig{},
&CredentialIssuerConfigList{},
&OIDCProviderConfig{},
&OIDCProviderConfigList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -0,0 +1,72 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid
type OIDCProviderStatus string
const (
SuccessOIDCProviderStatus = OIDCProviderStatus("Success")
DuplicateOIDCProviderStatus = OIDCProviderStatus("Duplicate")
InvalidOIDCProviderStatus = OIDCProviderStatus("Invalid")
)
// OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
type OIDCProviderConfigSpec struct {
// 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.
// +kubebuilder:validation:MinLength=1
Issuer string `json:"issuer"`
}
// OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
type OIDCProviderConfigStatus struct {
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
// represent success or failure.
// +optional
Status OIDCProviderStatus `json:"status,omitempty"`
// Message provides human-readable details about the Status.
// +optional
Message string `json:"message,omitempty"`
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
// around some undesirable behavior with respect to the empty metav1.Time value (see
// https://github.com/kubernetes/kubernetes/issues/86811).
// +optional
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
}
// OIDCProviderConfig describes the configuration of an OIDC provider.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:shortName=opc
type OIDCProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec of the OIDC provider.
Spec OIDCProviderConfigSpec `json:"spec"`
// Status of the OIDC provider.
Status OIDCProviderConfigStatus `json:"status,omitempty"`
}
// List of OIDCProviderConfig objects.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type OIDCProviderConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OIDCProviderConfig `json:"items"`
}

View File

@ -131,3 +131,100 @@ func (in *CredentialIssuerConfigStrategy) DeepCopy() *CredentialIssuerConfigStra
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfig) DeepCopyInto(out *OIDCProviderConfig) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfig.
func (in *OIDCProviderConfig) DeepCopy() *OIDCProviderConfig {
if in == nil {
return nil
}
out := new(OIDCProviderConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfig) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigList) DeepCopyInto(out *OIDCProviderConfigList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]OIDCProviderConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigList.
func (in *OIDCProviderConfigList) DeepCopy() *OIDCProviderConfigList {
if in == nil {
return nil
}
out := new(OIDCProviderConfigList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfigList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigSpec) DeepCopyInto(out *OIDCProviderConfigSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigSpec.
func (in *OIDCProviderConfigSpec) DeepCopy() *OIDCProviderConfigSpec {
if in == nil {
return nil
}
out := new(OIDCProviderConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigStatus) DeepCopyInto(out *OIDCProviderConfigStatus) {
*out = *in
if in.LastUpdateTime != nil {
in, out := &in.LastUpdateTime, &out.LastUpdateTime
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigStatus.
func (in *OIDCProviderConfigStatus) DeepCopy() *OIDCProviderConfigStatus {
if in == nil {
return nil
}
out := new(OIDCProviderConfigStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -14,6 +14,7 @@ import (
type ConfigV1alpha1Interface interface {
RESTClient() rest.Interface
CredentialIssuerConfigsGetter
OIDCProviderConfigsGetter
}
// ConfigV1alpha1Client is used to interact with features provided by the config.pinniped.dev group.
@ -25,6 +26,10 @@ func (c *ConfigV1alpha1Client) CredentialIssuerConfigs(namespace string) Credent
return newCredentialIssuerConfigs(c, namespace)
}
func (c *ConfigV1alpha1Client) OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface {
return newOIDCProviderConfigs(c, namespace)
}
// NewForConfig creates a new ConfigV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*ConfigV1alpha1Client, error) {
config := *c

View File

@ -19,6 +19,10 @@ func (c *FakeConfigV1alpha1) CredentialIssuerConfigs(namespace string) v1alpha1.
return &FakeCredentialIssuerConfigs{c, namespace}
}
func (c *FakeConfigV1alpha1) OIDCProviderConfigs(namespace string) v1alpha1.OIDCProviderConfigInterface {
return &FakeOIDCProviderConfigs{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeConfigV1alpha1) RESTClient() rest.Interface {

View File

@ -0,0 +1,127 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "go.pinniped.dev/generated/1.17/apis/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeOIDCProviderConfigs implements OIDCProviderConfigInterface
type FakeOIDCProviderConfigs struct {
Fake *FakeConfigV1alpha1
ns string
}
var oidcproviderconfigsResource = schema.GroupVersionResource{Group: "config.pinniped.dev", Version: "v1alpha1", Resource: "oidcproviderconfigs"}
var oidcproviderconfigsKind = schema.GroupVersionKind{Group: "config.pinniped.dev", Version: "v1alpha1", Kind: "OIDCProviderConfig"}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *FakeOIDCProviderConfigs) Get(name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *FakeOIDCProviderConfigs) List(opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(oidcproviderconfigsResource, oidcproviderconfigsKind, c.ns, opts), &v1alpha1.OIDCProviderConfigList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.OIDCProviderConfigList{ListMeta: obj.(*v1alpha1.OIDCProviderConfigList).ListMeta}
for _, item := range obj.(*v1alpha1.OIDCProviderConfigList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *FakeOIDCProviderConfigs) Watch(opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(oidcproviderconfigsResource, c.ns, opts))
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Create(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Update(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeOIDCProviderConfigs) UpdateStatus(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (*v1alpha1.OIDCProviderConfig, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(oidcproviderconfigsResource, "status", c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *FakeOIDCProviderConfigs) Delete(name string, options *v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeOIDCProviderConfigs) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(oidcproviderconfigsResource, c.ns, listOptions)
_, err := c.Fake.Invokes(action, &v1alpha1.OIDCProviderConfigList{})
return err
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *FakeOIDCProviderConfigs) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(oidcproviderconfigsResource, c.ns, name, pt, data, subresources...), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}

View File

@ -6,3 +6,5 @@
package v1alpha1
type CredentialIssuerConfigExpansion interface{}
type OIDCProviderConfigExpansion interface{}

View File

@ -0,0 +1,178 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"time"
v1alpha1 "go.pinniped.dev/generated/1.17/apis/config/v1alpha1"
scheme "go.pinniped.dev/generated/1.17/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// OIDCProviderConfigsGetter has a method to return a OIDCProviderConfigInterface.
// A group's client should implement this interface.
type OIDCProviderConfigsGetter interface {
OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface
}
// OIDCProviderConfigInterface has methods to work with OIDCProviderConfig resources.
type OIDCProviderConfigInterface interface {
Create(*v1alpha1.OIDCProviderConfig) (*v1alpha1.OIDCProviderConfig, error)
Update(*v1alpha1.OIDCProviderConfig) (*v1alpha1.OIDCProviderConfig, error)
UpdateStatus(*v1alpha1.OIDCProviderConfig) (*v1alpha1.OIDCProviderConfig, error)
Delete(name string, options *v1.DeleteOptions) error
DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error
Get(name string, options v1.GetOptions) (*v1alpha1.OIDCProviderConfig, error)
List(opts v1.ListOptions) (*v1alpha1.OIDCProviderConfigList, error)
Watch(opts v1.ListOptions) (watch.Interface, error)
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error)
OIDCProviderConfigExpansion
}
// oIDCProviderConfigs implements OIDCProviderConfigInterface
type oIDCProviderConfigs struct {
client rest.Interface
ns string
}
// newOIDCProviderConfigs returns a OIDCProviderConfigs
func newOIDCProviderConfigs(c *ConfigV1alpha1Client, namespace string) *oIDCProviderConfigs {
return &oIDCProviderConfigs{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *oIDCProviderConfigs) Get(name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do().
Into(result)
return
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *oIDCProviderConfigs) List(opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.OIDCProviderConfigList{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do().
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *oIDCProviderConfigs) Watch(opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch()
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Create(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Post().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Body(oIDCProviderConfig).
Do().
Into(result)
return
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Update(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
Body(oIDCProviderConfig).
Do().
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *oIDCProviderConfigs) UpdateStatus(oIDCProviderConfig *v1alpha1.OIDCProviderConfig) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
SubResource("status").
Body(oIDCProviderConfig).
Do().
Into(result)
return
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *oIDCProviderConfigs) Delete(name string, options *v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
Body(options).
Do().
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *oIDCProviderConfigs) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error {
var timeout time.Duration
if listOptions.TimeoutSeconds != nil {
timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&listOptions, scheme.ParameterCodec).
Timeout(timeout).
Body(options).
Do().
Error()
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *oIDCProviderConfigs) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("oidcproviderconfigs").
SubResource(subresources...).
Name(name).
Body(data).
Do().
Into(result)
return
}

View File

@ -13,6 +13,8 @@ import (
type Interface interface {
// CredentialIssuerConfigs returns a CredentialIssuerConfigInformer.
CredentialIssuerConfigs() CredentialIssuerConfigInformer
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
OIDCProviderConfigs() OIDCProviderConfigInformer
}
type version struct {
@ -30,3 +32,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (v *version) CredentialIssuerConfigs() CredentialIssuerConfigInformer {
return &credentialIssuerConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
func (v *version) OIDCProviderConfigs() OIDCProviderConfigInformer {
return &oIDCProviderConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@ -0,0 +1,76 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
time "time"
configv1alpha1 "go.pinniped.dev/generated/1.17/apis/config/v1alpha1"
versioned "go.pinniped.dev/generated/1.17/client/clientset/versioned"
internalinterfaces "go.pinniped.dev/generated/1.17/client/informers/externalversions/internalinterfaces"
v1alpha1 "go.pinniped.dev/generated/1.17/client/listers/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigInformer provides access to a shared informer and lister for
// OIDCProviderConfigs.
type OIDCProviderConfigInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.OIDCProviderConfigLister
}
type oIDCProviderConfigInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).List(options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).Watch(options)
},
},
&configv1alpha1.OIDCProviderConfig{},
resyncPeriod,
indexers,
)
}
func (f *oIDCProviderConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *oIDCProviderConfigInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&configv1alpha1.OIDCProviderConfig{}, f.defaultInformer)
}
func (f *oIDCProviderConfigInformer) Lister() v1alpha1.OIDCProviderConfigLister {
return v1alpha1.NewOIDCProviderConfigLister(f.Informer().GetIndexer())
}

View File

@ -44,6 +44,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
// Group=config.pinniped.dev, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("credentialissuerconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().CredentialIssuerConfigs().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("oidcproviderconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().OIDCProviderConfigs().Informer()}, nil
// Group=idp.pinniped.dev, Version=v1alpha1
case idpv1alpha1.SchemeGroupVersion.WithResource("webhookidentityproviders"):

View File

@ -12,3 +12,11 @@ type CredentialIssuerConfigListerExpansion interface{}
// CredentialIssuerConfigNamespaceListerExpansion allows custom methods to be added to
// CredentialIssuerConfigNamespaceLister.
type CredentialIssuerConfigNamespaceListerExpansion interface{}
// OIDCProviderConfigListerExpansion allows custom methods to be added to
// OIDCProviderConfigLister.
type OIDCProviderConfigListerExpansion interface{}
// OIDCProviderConfigNamespaceListerExpansion allows custom methods to be added to
// OIDCProviderConfigNamespaceLister.
type OIDCProviderConfigNamespaceListerExpansion interface{}

View File

@ -0,0 +1,81 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "go.pinniped.dev/generated/1.17/apis/config/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigLister helps list OIDCProviderConfigs.
type OIDCProviderConfigLister interface {
// List lists all OIDCProviderConfigs in the indexer.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister
OIDCProviderConfigListerExpansion
}
// oIDCProviderConfigLister implements the OIDCProviderConfigLister interface.
type oIDCProviderConfigLister struct {
indexer cache.Indexer
}
// NewOIDCProviderConfigLister returns a new OIDCProviderConfigLister.
func NewOIDCProviderConfigLister(indexer cache.Indexer) OIDCProviderConfigLister {
return &oIDCProviderConfigLister{indexer: indexer}
}
// List lists all OIDCProviderConfigs in the indexer.
func (s *oIDCProviderConfigLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
func (s *oIDCProviderConfigLister) OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister {
return oIDCProviderConfigNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// OIDCProviderConfigNamespaceLister helps list and get OIDCProviderConfigs.
type OIDCProviderConfigNamespaceLister interface {
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
Get(name string) (*v1alpha1.OIDCProviderConfig, error)
OIDCProviderConfigNamespaceListerExpansion
}
// oIDCProviderConfigNamespaceLister implements the OIDCProviderConfigNamespaceLister
// interface.
type oIDCProviderConfigNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
func (s oIDCProviderConfigNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
func (s oIDCProviderConfigNamespaceLister) Get(name string) (*v1alpha1.OIDCProviderConfig, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("oidcproviderconfig"), name)
}
return obj.(*v1alpha1.OIDCProviderConfig), nil
}

View File

@ -22,6 +22,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.CredentialIssuerConfigList": schema_117_apis_config_v1alpha1_CredentialIssuerConfigList(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.CredentialIssuerConfigStatus": schema_117_apis_config_v1alpha1_CredentialIssuerConfigStatus(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.CredentialIssuerConfigStrategy": schema_117_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfig": schema_117_apis_config_v1alpha1_OIDCProviderConfig(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigList": schema_117_apis_config_v1alpha1_OIDCProviderConfigList(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigSpec": schema_117_apis_config_v1alpha1_OIDCProviderConfigSpec(ref),
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigStatus": schema_117_apis_config_v1alpha1_OIDCProviderConfigStatus(ref),
"go.pinniped.dev/generated/1.17/apis/idp/v1alpha1.Condition": schema_117_apis_idp_v1alpha1_Condition(ref),
"go.pinniped.dev/generated/1.17/apis/idp/v1alpha1.TLSSpec": schema_117_apis_idp_v1alpha1_TLSSpec(ref),
"go.pinniped.dev/generated/1.17/apis/idp/v1alpha1.WebhookIdentityProvider": schema_117_apis_idp_v1alpha1_WebhookIdentityProvider(ref),
@ -286,6 +290,155 @@ func schema_117_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref common.R
}
}
func schema_117_apis_config_v1alpha1_OIDCProviderConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfig describes the configuration of an OIDC provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Description: "Spec of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigStatus"),
},
},
},
Required: []string{"spec"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigSpec", "go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfigStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_117_apis_config_v1alpha1_OIDCProviderConfigList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: ref("go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfig"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.17/apis/config/v1alpha1.OIDCProviderConfig", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_117_apis_config_v1alpha1_OIDCProviderConfigSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigSpec is a struct that describes an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"issuer": {
SchemaProps: spec.SchemaProps{
Description: "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).\n\nSee https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"issuer"},
},
},
}
}
func schema_117_apis_config_v1alpha1_OIDCProviderConfigStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.",
Type: []string{"string"},
Format: "",
},
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "Message provides human-readable details about the Status.",
Type: []string{"string"},
Format: "",
},
},
"lastUpdateTime": {
SchemaProps: spec.SchemaProps{
Description: "LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
}
}
func schema_117_apis_idp_v1alpha1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@ -0,0 +1,86 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
creationTimestamp: null
name: oidcproviderconfigs.config.pinniped.dev
spec:
group: config.pinniped.dev
names:
kind: OIDCProviderConfig
listKind: OIDCProviderConfigList
plural: oidcproviderconfigs
shortNames:
- opc
singular: oidcproviderconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: OIDCProviderConfig describes the configuration of an OIDC provider.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec of the OIDC provider.
properties:
issuer:
description: "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).
\n See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
for more information."
minLength: 1
type: string
required:
- issuer
type: object
status:
description: Status of the OIDC provider.
properties:
lastUpdateTime:
description: LastUpdateTime holds the time at which the Status was
last updated. It is a pointer to get around some undesirable behavior
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
format: date-time
type: string
message:
description: Message provides human-readable details about the Status.
type: string
status:
description: Status holds an enum that describes the state of this
OIDC Provider. Note that this Status can represent success or failure.
enum:
- Success
- Duplicate
- Invalid
type: string
type: object
required:
- spec
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -95,6 +95,65 @@ Status of a credential issuer.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfig"]
==== OIDCProviderConfig
OIDCProviderConfig describes the configuration of an OIDC provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfiglist[$$OIDCProviderConfigList$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfigspec[$$OIDCProviderConfigSpec$$]__ | Spec of the OIDC provider.
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfigstatus[$$OIDCProviderConfigStatus$$]__ | Status of the OIDC provider.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfigspec"]
==== OIDCProviderConfigSpec
OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[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.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfigstatus"]
==== OIDCProviderConfigStatus
OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`status`* __OIDCProviderStatus__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
| *`message`* __string__ | Message provides human-readable details about the Status.
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|===
[id="{anchor_prefix}-idp-pinniped-dev-v1alpha1"]
=== idp.pinniped.dev/v1alpha1

View File

@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CredentialIssuerConfig{},
&CredentialIssuerConfigList{},
&OIDCProviderConfig{},
&OIDCProviderConfigList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -0,0 +1,72 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid
type OIDCProviderStatus string
const (
SuccessOIDCProviderStatus = OIDCProviderStatus("Success")
DuplicateOIDCProviderStatus = OIDCProviderStatus("Duplicate")
InvalidOIDCProviderStatus = OIDCProviderStatus("Invalid")
)
// OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
type OIDCProviderConfigSpec struct {
// 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.
// +kubebuilder:validation:MinLength=1
Issuer string `json:"issuer"`
}
// OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
type OIDCProviderConfigStatus struct {
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
// represent success or failure.
// +optional
Status OIDCProviderStatus `json:"status,omitempty"`
// Message provides human-readable details about the Status.
// +optional
Message string `json:"message,omitempty"`
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
// around some undesirable behavior with respect to the empty metav1.Time value (see
// https://github.com/kubernetes/kubernetes/issues/86811).
// +optional
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
}
// OIDCProviderConfig describes the configuration of an OIDC provider.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:shortName=opc
type OIDCProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec of the OIDC provider.
Spec OIDCProviderConfigSpec `json:"spec"`
// Status of the OIDC provider.
Status OIDCProviderConfigStatus `json:"status,omitempty"`
}
// List of OIDCProviderConfig objects.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type OIDCProviderConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OIDCProviderConfig `json:"items"`
}

View File

@ -131,3 +131,100 @@ func (in *CredentialIssuerConfigStrategy) DeepCopy() *CredentialIssuerConfigStra
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfig) DeepCopyInto(out *OIDCProviderConfig) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfig.
func (in *OIDCProviderConfig) DeepCopy() *OIDCProviderConfig {
if in == nil {
return nil
}
out := new(OIDCProviderConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfig) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigList) DeepCopyInto(out *OIDCProviderConfigList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]OIDCProviderConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigList.
func (in *OIDCProviderConfigList) DeepCopy() *OIDCProviderConfigList {
if in == nil {
return nil
}
out := new(OIDCProviderConfigList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfigList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigSpec) DeepCopyInto(out *OIDCProviderConfigSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigSpec.
func (in *OIDCProviderConfigSpec) DeepCopy() *OIDCProviderConfigSpec {
if in == nil {
return nil
}
out := new(OIDCProviderConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigStatus) DeepCopyInto(out *OIDCProviderConfigStatus) {
*out = *in
if in.LastUpdateTime != nil {
in, out := &in.LastUpdateTime, &out.LastUpdateTime
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigStatus.
func (in *OIDCProviderConfigStatus) DeepCopy() *OIDCProviderConfigStatus {
if in == nil {
return nil
}
out := new(OIDCProviderConfigStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -14,6 +14,7 @@ import (
type ConfigV1alpha1Interface interface {
RESTClient() rest.Interface
CredentialIssuerConfigsGetter
OIDCProviderConfigsGetter
}
// ConfigV1alpha1Client is used to interact with features provided by the config.pinniped.dev group.
@ -25,6 +26,10 @@ func (c *ConfigV1alpha1Client) CredentialIssuerConfigs(namespace string) Credent
return newCredentialIssuerConfigs(c, namespace)
}
func (c *ConfigV1alpha1Client) OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface {
return newOIDCProviderConfigs(c, namespace)
}
// NewForConfig creates a new ConfigV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*ConfigV1alpha1Client, error) {
config := *c

View File

@ -19,6 +19,10 @@ func (c *FakeConfigV1alpha1) CredentialIssuerConfigs(namespace string) v1alpha1.
return &FakeCredentialIssuerConfigs{c, namespace}
}
func (c *FakeConfigV1alpha1) OIDCProviderConfigs(namespace string) v1alpha1.OIDCProviderConfigInterface {
return &FakeOIDCProviderConfigs{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeConfigV1alpha1) RESTClient() rest.Interface {

View File

@ -0,0 +1,129 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1alpha1 "go.pinniped.dev/generated/1.18/apis/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeOIDCProviderConfigs implements OIDCProviderConfigInterface
type FakeOIDCProviderConfigs struct {
Fake *FakeConfigV1alpha1
ns string
}
var oidcproviderconfigsResource = schema.GroupVersionResource{Group: "config.pinniped.dev", Version: "v1alpha1", Resource: "oidcproviderconfigs"}
var oidcproviderconfigsKind = schema.GroupVersionKind{Group: "config.pinniped.dev", Version: "v1alpha1", Kind: "OIDCProviderConfig"}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *FakeOIDCProviderConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *FakeOIDCProviderConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(oidcproviderconfigsResource, oidcproviderconfigsKind, c.ns, opts), &v1alpha1.OIDCProviderConfigList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.OIDCProviderConfigList{ListMeta: obj.(*v1alpha1.OIDCProviderConfigList).ListMeta}
for _, item := range obj.(*v1alpha1.OIDCProviderConfigList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *FakeOIDCProviderConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(oidcproviderconfigsResource, c.ns, opts))
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeOIDCProviderConfigs) UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(oidcproviderconfigsResource, "status", c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *FakeOIDCProviderConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeOIDCProviderConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(oidcproviderconfigsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.OIDCProviderConfigList{})
return err
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *FakeOIDCProviderConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(oidcproviderconfigsResource, c.ns, name, pt, data, subresources...), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}

View File

@ -6,3 +6,5 @@
package v1alpha1
type CredentialIssuerConfigExpansion interface{}
type OIDCProviderConfigExpansion interface{}

View File

@ -0,0 +1,182 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
"time"
v1alpha1 "go.pinniped.dev/generated/1.18/apis/config/v1alpha1"
scheme "go.pinniped.dev/generated/1.18/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// OIDCProviderConfigsGetter has a method to return a OIDCProviderConfigInterface.
// A group's client should implement this interface.
type OIDCProviderConfigsGetter interface {
OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface
}
// OIDCProviderConfigInterface has methods to work with OIDCProviderConfig resources.
type OIDCProviderConfigInterface interface {
Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (*v1alpha1.OIDCProviderConfig, error)
Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error)
UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.OIDCProviderConfig, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.OIDCProviderConfigList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error)
OIDCProviderConfigExpansion
}
// oIDCProviderConfigs implements OIDCProviderConfigInterface
type oIDCProviderConfigs struct {
client rest.Interface
ns string
}
// newOIDCProviderConfigs returns a OIDCProviderConfigs
func newOIDCProviderConfigs(c *ConfigV1alpha1Client, namespace string) *oIDCProviderConfigs {
return &oIDCProviderConfigs{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *oIDCProviderConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *oIDCProviderConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.OIDCProviderConfigList{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *oIDCProviderConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Post().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *oIDCProviderConfigs) UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *oIDCProviderConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *oIDCProviderConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *oIDCProviderConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -13,6 +13,8 @@ import (
type Interface interface {
// CredentialIssuerConfigs returns a CredentialIssuerConfigInformer.
CredentialIssuerConfigs() CredentialIssuerConfigInformer
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
OIDCProviderConfigs() OIDCProviderConfigInformer
}
type version struct {
@ -30,3 +32,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (v *version) CredentialIssuerConfigs() CredentialIssuerConfigInformer {
return &credentialIssuerConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
func (v *version) OIDCProviderConfigs() OIDCProviderConfigInformer {
return &oIDCProviderConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@ -0,0 +1,77 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
configv1alpha1 "go.pinniped.dev/generated/1.18/apis/config/v1alpha1"
versioned "go.pinniped.dev/generated/1.18/client/clientset/versioned"
internalinterfaces "go.pinniped.dev/generated/1.18/client/informers/externalversions/internalinterfaces"
v1alpha1 "go.pinniped.dev/generated/1.18/client/listers/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigInformer provides access to a shared informer and lister for
// OIDCProviderConfigs.
type OIDCProviderConfigInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.OIDCProviderConfigLister
}
type oIDCProviderConfigInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).Watch(context.TODO(), options)
},
},
&configv1alpha1.OIDCProviderConfig{},
resyncPeriod,
indexers,
)
}
func (f *oIDCProviderConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *oIDCProviderConfigInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&configv1alpha1.OIDCProviderConfig{}, f.defaultInformer)
}
func (f *oIDCProviderConfigInformer) Lister() v1alpha1.OIDCProviderConfigLister {
return v1alpha1.NewOIDCProviderConfigLister(f.Informer().GetIndexer())
}

View File

@ -44,6 +44,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
// Group=config.pinniped.dev, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("credentialissuerconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().CredentialIssuerConfigs().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("oidcproviderconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().OIDCProviderConfigs().Informer()}, nil
// Group=idp.pinniped.dev, Version=v1alpha1
case idpv1alpha1.SchemeGroupVersion.WithResource("webhookidentityproviders"):

View File

@ -12,3 +12,11 @@ type CredentialIssuerConfigListerExpansion interface{}
// CredentialIssuerConfigNamespaceListerExpansion allows custom methods to be added to
// CredentialIssuerConfigNamespaceLister.
type CredentialIssuerConfigNamespaceListerExpansion interface{}
// OIDCProviderConfigListerExpansion allows custom methods to be added to
// OIDCProviderConfigLister.
type OIDCProviderConfigListerExpansion interface{}
// OIDCProviderConfigNamespaceListerExpansion allows custom methods to be added to
// OIDCProviderConfigNamespaceLister.
type OIDCProviderConfigNamespaceListerExpansion interface{}

View File

@ -0,0 +1,81 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "go.pinniped.dev/generated/1.18/apis/config/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigLister helps list OIDCProviderConfigs.
type OIDCProviderConfigLister interface {
// List lists all OIDCProviderConfigs in the indexer.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister
OIDCProviderConfigListerExpansion
}
// oIDCProviderConfigLister implements the OIDCProviderConfigLister interface.
type oIDCProviderConfigLister struct {
indexer cache.Indexer
}
// NewOIDCProviderConfigLister returns a new OIDCProviderConfigLister.
func NewOIDCProviderConfigLister(indexer cache.Indexer) OIDCProviderConfigLister {
return &oIDCProviderConfigLister{indexer: indexer}
}
// List lists all OIDCProviderConfigs in the indexer.
func (s *oIDCProviderConfigLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
func (s *oIDCProviderConfigLister) OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister {
return oIDCProviderConfigNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// OIDCProviderConfigNamespaceLister helps list and get OIDCProviderConfigs.
type OIDCProviderConfigNamespaceLister interface {
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
Get(name string) (*v1alpha1.OIDCProviderConfig, error)
OIDCProviderConfigNamespaceListerExpansion
}
// oIDCProviderConfigNamespaceLister implements the OIDCProviderConfigNamespaceLister
// interface.
type oIDCProviderConfigNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
func (s oIDCProviderConfigNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
func (s oIDCProviderConfigNamespaceLister) Get(name string) (*v1alpha1.OIDCProviderConfig, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("oidcproviderconfig"), name)
}
return obj.(*v1alpha1.OIDCProviderConfig), nil
}

View File

@ -22,6 +22,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.CredentialIssuerConfigList": schema_118_apis_config_v1alpha1_CredentialIssuerConfigList(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.CredentialIssuerConfigStatus": schema_118_apis_config_v1alpha1_CredentialIssuerConfigStatus(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.CredentialIssuerConfigStrategy": schema_118_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfig": schema_118_apis_config_v1alpha1_OIDCProviderConfig(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigList": schema_118_apis_config_v1alpha1_OIDCProviderConfigList(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigSpec": schema_118_apis_config_v1alpha1_OIDCProviderConfigSpec(ref),
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigStatus": schema_118_apis_config_v1alpha1_OIDCProviderConfigStatus(ref),
"go.pinniped.dev/generated/1.18/apis/idp/v1alpha1.Condition": schema_118_apis_idp_v1alpha1_Condition(ref),
"go.pinniped.dev/generated/1.18/apis/idp/v1alpha1.TLSSpec": schema_118_apis_idp_v1alpha1_TLSSpec(ref),
"go.pinniped.dev/generated/1.18/apis/idp/v1alpha1.WebhookIdentityProvider": schema_118_apis_idp_v1alpha1_WebhookIdentityProvider(ref),
@ -286,6 +290,155 @@ func schema_118_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref common.R
}
}
func schema_118_apis_config_v1alpha1_OIDCProviderConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfig describes the configuration of an OIDC provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Description: "Spec of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigStatus"),
},
},
},
Required: []string{"spec"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigSpec", "go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfigStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_118_apis_config_v1alpha1_OIDCProviderConfigList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: ref("go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfig"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.18/apis/config/v1alpha1.OIDCProviderConfig", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_118_apis_config_v1alpha1_OIDCProviderConfigSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigSpec is a struct that describes an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"issuer": {
SchemaProps: spec.SchemaProps{
Description: "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).\n\nSee https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"issuer"},
},
},
}
}
func schema_118_apis_config_v1alpha1_OIDCProviderConfigStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.",
Type: []string{"string"},
Format: "",
},
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "Message provides human-readable details about the Status.",
Type: []string{"string"},
Format: "",
},
},
"lastUpdateTime": {
SchemaProps: spec.SchemaProps{
Description: "LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
}
}
func schema_118_apis_idp_v1alpha1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@ -0,0 +1,86 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
creationTimestamp: null
name: oidcproviderconfigs.config.pinniped.dev
spec:
group: config.pinniped.dev
names:
kind: OIDCProviderConfig
listKind: OIDCProviderConfigList
plural: oidcproviderconfigs
shortNames:
- opc
singular: oidcproviderconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: OIDCProviderConfig describes the configuration of an OIDC provider.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec of the OIDC provider.
properties:
issuer:
description: "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).
\n See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
for more information."
minLength: 1
type: string
required:
- issuer
type: object
status:
description: Status of the OIDC provider.
properties:
lastUpdateTime:
description: LastUpdateTime holds the time at which the Status was
last updated. It is a pointer to get around some undesirable behavior
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
format: date-time
type: string
message:
description: Message provides human-readable details about the Status.
type: string
status:
description: Status holds an enum that describes the state of this
OIDC Provider. Note that this Status can represent success or failure.
enum:
- Success
- Duplicate
- Invalid
type: string
type: object
required:
- spec
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -95,6 +95,65 @@ Status of a credential issuer.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfig"]
==== OIDCProviderConfig
OIDCProviderConfig describes the configuration of an OIDC provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfiglist[$$OIDCProviderConfigList$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfigspec[$$OIDCProviderConfigSpec$$]__ | Spec of the OIDC provider.
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfigstatus[$$OIDCProviderConfigStatus$$]__ | Status of the OIDC provider.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfigspec"]
==== OIDCProviderConfigSpec
OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[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.
|===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfigstatus"]
==== OIDCProviderConfigStatus
OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
.Appears In:
****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-config-v1alpha1-oidcproviderconfig[$$OIDCProviderConfig$$]
****
[cols="25a,75a", options="header"]
|===
| Field | Description
| *`status`* __OIDCProviderStatus__ | Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.
| *`message`* __string__ | Message provides human-readable details about the Status.
| *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#time-v1-meta[$$Time$$]__ | LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
|===
[id="{anchor_prefix}-idp-pinniped-dev-v1alpha1"]
=== idp.pinniped.dev/v1alpha1

View File

@ -32,6 +32,8 @@ func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&CredentialIssuerConfig{},
&CredentialIssuerConfigList{},
&OIDCProviderConfig{},
&OIDCProviderConfigList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil

View File

@ -0,0 +1,72 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package v1alpha1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=Success;Duplicate;Invalid
type OIDCProviderStatus string
const (
SuccessOIDCProviderStatus = OIDCProviderStatus("Success")
DuplicateOIDCProviderStatus = OIDCProviderStatus("Duplicate")
InvalidOIDCProviderStatus = OIDCProviderStatus("Invalid")
)
// OIDCProviderConfigSpec is a struct that describes an OIDC Provider.
type OIDCProviderConfigSpec struct {
// 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.
// +kubebuilder:validation:MinLength=1
Issuer string `json:"issuer"`
}
// OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.
type OIDCProviderConfigStatus struct {
// Status holds an enum that describes the state of this OIDC Provider. Note that this Status can
// represent success or failure.
// +optional
Status OIDCProviderStatus `json:"status,omitempty"`
// Message provides human-readable details about the Status.
// +optional
Message string `json:"message,omitempty"`
// LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get
// around some undesirable behavior with respect to the empty metav1.Time value (see
// https://github.com/kubernetes/kubernetes/issues/86811).
// +optional
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
}
// OIDCProviderConfig describes the configuration of an OIDC provider.
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:shortName=opc
type OIDCProviderConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec of the OIDC provider.
Spec OIDCProviderConfigSpec `json:"spec"`
// Status of the OIDC provider.
Status OIDCProviderConfigStatus `json:"status,omitempty"`
}
// List of OIDCProviderConfig objects.
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type OIDCProviderConfigList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []OIDCProviderConfig `json:"items"`
}

View File

@ -131,3 +131,100 @@ func (in *CredentialIssuerConfigStrategy) DeepCopy() *CredentialIssuerConfigStra
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfig) DeepCopyInto(out *OIDCProviderConfig) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfig.
func (in *OIDCProviderConfig) DeepCopy() *OIDCProviderConfig {
if in == nil {
return nil
}
out := new(OIDCProviderConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfig) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigList) DeepCopyInto(out *OIDCProviderConfigList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]OIDCProviderConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigList.
func (in *OIDCProviderConfigList) DeepCopy() *OIDCProviderConfigList {
if in == nil {
return nil
}
out := new(OIDCProviderConfigList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *OIDCProviderConfigList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigSpec) DeepCopyInto(out *OIDCProviderConfigSpec) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigSpec.
func (in *OIDCProviderConfigSpec) DeepCopy() *OIDCProviderConfigSpec {
if in == nil {
return nil
}
out := new(OIDCProviderConfigSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OIDCProviderConfigStatus) DeepCopyInto(out *OIDCProviderConfigStatus) {
*out = *in
if in.LastUpdateTime != nil {
in, out := &in.LastUpdateTime, &out.LastUpdateTime
*out = (*in).DeepCopy()
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCProviderConfigStatus.
func (in *OIDCProviderConfigStatus) DeepCopy() *OIDCProviderConfigStatus {
if in == nil {
return nil
}
out := new(OIDCProviderConfigStatus)
in.DeepCopyInto(out)
return out
}

View File

@ -14,6 +14,7 @@ import (
type ConfigV1alpha1Interface interface {
RESTClient() rest.Interface
CredentialIssuerConfigsGetter
OIDCProviderConfigsGetter
}
// ConfigV1alpha1Client is used to interact with features provided by the config.pinniped.dev group.
@ -25,6 +26,10 @@ func (c *ConfigV1alpha1Client) CredentialIssuerConfigs(namespace string) Credent
return newCredentialIssuerConfigs(c, namespace)
}
func (c *ConfigV1alpha1Client) OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface {
return newOIDCProviderConfigs(c, namespace)
}
// NewForConfig creates a new ConfigV1alpha1Client for the given config.
func NewForConfig(c *rest.Config) (*ConfigV1alpha1Client, error) {
config := *c

View File

@ -19,6 +19,10 @@ func (c *FakeConfigV1alpha1) CredentialIssuerConfigs(namespace string) v1alpha1.
return &FakeCredentialIssuerConfigs{c, namespace}
}
func (c *FakeConfigV1alpha1) OIDCProviderConfigs(namespace string) v1alpha1.OIDCProviderConfigInterface {
return &FakeOIDCProviderConfigs{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeConfigV1alpha1) RESTClient() rest.Interface {

View File

@ -0,0 +1,129 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeOIDCProviderConfigs implements OIDCProviderConfigInterface
type FakeOIDCProviderConfigs struct {
Fake *FakeConfigV1alpha1
ns string
}
var oidcproviderconfigsResource = schema.GroupVersionResource{Group: "config.pinniped.dev", Version: "v1alpha1", Resource: "oidcproviderconfigs"}
var oidcproviderconfigsKind = schema.GroupVersionKind{Group: "config.pinniped.dev", Version: "v1alpha1", Kind: "OIDCProviderConfig"}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *FakeOIDCProviderConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *FakeOIDCProviderConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(oidcproviderconfigsResource, oidcproviderconfigsKind, c.ns, opts), &v1alpha1.OIDCProviderConfigList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.OIDCProviderConfigList{ListMeta: obj.(*v1alpha1.OIDCProviderConfigList).ListMeta}
for _, item := range obj.(*v1alpha1.OIDCProviderConfigList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *FakeOIDCProviderConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(oidcproviderconfigsResource, c.ns, opts))
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *FakeOIDCProviderConfigs) Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(oidcproviderconfigsResource, c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeOIDCProviderConfigs) UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(oidcproviderconfigsResource, "status", c.ns, oIDCProviderConfig), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *FakeOIDCProviderConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteAction(oidcproviderconfigsResource, c.ns, name), &v1alpha1.OIDCProviderConfig{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeOIDCProviderConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(oidcproviderconfigsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.OIDCProviderConfigList{})
return err
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *FakeOIDCProviderConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(oidcproviderconfigsResource, c.ns, name, pt, data, subresources...), &v1alpha1.OIDCProviderConfig{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.OIDCProviderConfig), err
}

View File

@ -6,3 +6,5 @@
package v1alpha1
type CredentialIssuerConfigExpansion interface{}
type OIDCProviderConfigExpansion interface{}

View File

@ -0,0 +1,182 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
"time"
v1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
scheme "go.pinniped.dev/generated/1.19/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// OIDCProviderConfigsGetter has a method to return a OIDCProviderConfigInterface.
// A group's client should implement this interface.
type OIDCProviderConfigsGetter interface {
OIDCProviderConfigs(namespace string) OIDCProviderConfigInterface
}
// OIDCProviderConfigInterface has methods to work with OIDCProviderConfig resources.
type OIDCProviderConfigInterface interface {
Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (*v1alpha1.OIDCProviderConfig, error)
Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error)
UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (*v1alpha1.OIDCProviderConfig, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.OIDCProviderConfig, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.OIDCProviderConfigList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error)
OIDCProviderConfigExpansion
}
// oIDCProviderConfigs implements OIDCProviderConfigInterface
type oIDCProviderConfigs struct {
client rest.Interface
ns string
}
// newOIDCProviderConfigs returns a OIDCProviderConfigs
func newOIDCProviderConfigs(c *ConfigV1alpha1Client, namespace string) *oIDCProviderConfigs {
return &oIDCProviderConfigs{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the oIDCProviderConfig, and returns the corresponding oIDCProviderConfig object, and an error if there is any.
func (c *oIDCProviderConfigs) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of OIDCProviderConfigs that match those selectors.
func (c *oIDCProviderConfigs) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OIDCProviderConfigList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.OIDCProviderConfigList{}
err = c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested oIDCProviderConfigs.
func (c *oIDCProviderConfigs) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a oIDCProviderConfig and creates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Create(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.CreateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Post().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a oIDCProviderConfig and updates it. Returns the server's representation of the oIDCProviderConfig, and an error, if there is any.
func (c *oIDCProviderConfigs) Update(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *oIDCProviderConfigs) UpdateStatus(ctx context.Context, oIDCProviderConfig *v1alpha1.OIDCProviderConfig, opts v1.UpdateOptions) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Put().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(oIDCProviderConfig.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(oIDCProviderConfig).
Do(ctx).
Into(result)
return
}
// Delete takes name of the oIDCProviderConfig and deletes it. Returns an error if one occurs.
func (c *oIDCProviderConfigs) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *oIDCProviderConfigs) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("oidcproviderconfigs").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched oIDCProviderConfig.
func (c *oIDCProviderConfigs) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OIDCProviderConfig, err error) {
result = &v1alpha1.OIDCProviderConfig{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("oidcproviderconfigs").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -13,6 +13,8 @@ import (
type Interface interface {
// CredentialIssuerConfigs returns a CredentialIssuerConfigInformer.
CredentialIssuerConfigs() CredentialIssuerConfigInformer
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
OIDCProviderConfigs() OIDCProviderConfigInformer
}
type version struct {
@ -30,3 +32,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
func (v *version) CredentialIssuerConfigs() CredentialIssuerConfigInformer {
return &credentialIssuerConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// OIDCProviderConfigs returns a OIDCProviderConfigInformer.
func (v *version) OIDCProviderConfigs() OIDCProviderConfigInformer {
return &oIDCProviderConfigInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@ -0,0 +1,77 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
configv1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
versioned "go.pinniped.dev/generated/1.19/client/clientset/versioned"
internalinterfaces "go.pinniped.dev/generated/1.19/client/informers/externalversions/internalinterfaces"
v1alpha1 "go.pinniped.dev/generated/1.19/client/listers/config/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigInformer provides access to a shared informer and lister for
// OIDCProviderConfigs.
type OIDCProviderConfigInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.OIDCProviderConfigLister
}
type oIDCProviderConfigInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredOIDCProviderConfigInformer constructs a new informer for OIDCProviderConfig type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredOIDCProviderConfigInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.ConfigV1alpha1().OIDCProviderConfigs(namespace).Watch(context.TODO(), options)
},
},
&configv1alpha1.OIDCProviderConfig{},
resyncPeriod,
indexers,
)
}
func (f *oIDCProviderConfigInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredOIDCProviderConfigInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *oIDCProviderConfigInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&configv1alpha1.OIDCProviderConfig{}, f.defaultInformer)
}
func (f *oIDCProviderConfigInformer) Lister() v1alpha1.OIDCProviderConfigLister {
return v1alpha1.NewOIDCProviderConfigLister(f.Informer().GetIndexer())
}

View File

@ -44,6 +44,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
// Group=config.pinniped.dev, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("credentialissuerconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().CredentialIssuerConfigs().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("oidcproviderconfigs"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Config().V1alpha1().OIDCProviderConfigs().Informer()}, nil
// Group=idp.pinniped.dev, Version=v1alpha1
case idpv1alpha1.SchemeGroupVersion.WithResource("webhookidentityproviders"):

View File

@ -12,3 +12,11 @@ type CredentialIssuerConfigListerExpansion interface{}
// CredentialIssuerConfigNamespaceListerExpansion allows custom methods to be added to
// CredentialIssuerConfigNamespaceLister.
type CredentialIssuerConfigNamespaceListerExpansion interface{}
// OIDCProviderConfigListerExpansion allows custom methods to be added to
// OIDCProviderConfigLister.
type OIDCProviderConfigListerExpansion interface{}
// OIDCProviderConfigNamespaceListerExpansion allows custom methods to be added to
// OIDCProviderConfigNamespaceLister.
type OIDCProviderConfigNamespaceListerExpansion interface{}

View File

@ -0,0 +1,86 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// OIDCProviderConfigLister helps list OIDCProviderConfigs.
// All objects returned here must be treated as read-only.
type OIDCProviderConfigLister interface {
// List lists all OIDCProviderConfigs in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister
OIDCProviderConfigListerExpansion
}
// oIDCProviderConfigLister implements the OIDCProviderConfigLister interface.
type oIDCProviderConfigLister struct {
indexer cache.Indexer
}
// NewOIDCProviderConfigLister returns a new OIDCProviderConfigLister.
func NewOIDCProviderConfigLister(indexer cache.Indexer) OIDCProviderConfigLister {
return &oIDCProviderConfigLister{indexer: indexer}
}
// List lists all OIDCProviderConfigs in the indexer.
func (s *oIDCProviderConfigLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// OIDCProviderConfigs returns an object that can list and get OIDCProviderConfigs.
func (s *oIDCProviderConfigLister) OIDCProviderConfigs(namespace string) OIDCProviderConfigNamespaceLister {
return oIDCProviderConfigNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// OIDCProviderConfigNamespaceLister helps list and get OIDCProviderConfigs.
// All objects returned here must be treated as read-only.
type OIDCProviderConfigNamespaceLister interface {
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error)
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1alpha1.OIDCProviderConfig, error)
OIDCProviderConfigNamespaceListerExpansion
}
// oIDCProviderConfigNamespaceLister implements the OIDCProviderConfigNamespaceLister
// interface.
type oIDCProviderConfigNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all OIDCProviderConfigs in the indexer for a given namespace.
func (s oIDCProviderConfigNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.OIDCProviderConfig, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.OIDCProviderConfig))
})
return ret, err
}
// Get retrieves the OIDCProviderConfig from the indexer for a given namespace and name.
func (s oIDCProviderConfigNamespaceLister) Get(name string) (*v1alpha1.OIDCProviderConfig, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("oidcproviderconfig"), name)
}
return obj.(*v1alpha1.OIDCProviderConfig), nil
}

View File

@ -22,6 +22,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.CredentialIssuerConfigList": schema_119_apis_config_v1alpha1_CredentialIssuerConfigList(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.CredentialIssuerConfigStatus": schema_119_apis_config_v1alpha1_CredentialIssuerConfigStatus(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.CredentialIssuerConfigStrategy": schema_119_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfig": schema_119_apis_config_v1alpha1_OIDCProviderConfig(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigList": schema_119_apis_config_v1alpha1_OIDCProviderConfigList(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigSpec": schema_119_apis_config_v1alpha1_OIDCProviderConfigSpec(ref),
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigStatus": schema_119_apis_config_v1alpha1_OIDCProviderConfigStatus(ref),
"go.pinniped.dev/generated/1.19/apis/idp/v1alpha1.Condition": schema_119_apis_idp_v1alpha1_Condition(ref),
"go.pinniped.dev/generated/1.19/apis/idp/v1alpha1.TLSSpec": schema_119_apis_idp_v1alpha1_TLSSpec(ref),
"go.pinniped.dev/generated/1.19/apis/idp/v1alpha1.WebhookIdentityProvider": schema_119_apis_idp_v1alpha1_WebhookIdentityProvider(ref),
@ -287,6 +291,155 @@ func schema_119_apis_config_v1alpha1_CredentialIssuerConfigStrategy(ref common.R
}
}
func schema_119_apis_config_v1alpha1_OIDCProviderConfig(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfig describes the configuration of an OIDC provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"),
},
},
"spec": {
SchemaProps: spec.SchemaProps{
Description: "Spec of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigSpec"),
},
},
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status of the OIDC provider.",
Ref: ref("go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigStatus"),
},
},
},
Required: []string{"spec"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigSpec", "go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfigStatus", "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"},
}
}
func schema_119_apis_config_v1alpha1_OIDCProviderConfigList(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: map[string]spec.Schema{
"kind": {
SchemaProps: spec.SchemaProps{
Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
Type: []string{"string"},
Format: "",
},
},
"apiVersion": {
SchemaProps: spec.SchemaProps{
Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
Type: []string{"string"},
Format: "",
},
},
"metadata": {
SchemaProps: spec.SchemaProps{
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"),
},
},
"items": {
SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: ref("go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfig"),
},
},
},
},
},
},
Required: []string{"items"},
},
},
Dependencies: []string{
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1.OIDCProviderConfig", "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"},
}
}
func schema_119_apis_config_v1alpha1_OIDCProviderConfigSpec(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigSpec is a struct that describes an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"issuer": {
SchemaProps: spec.SchemaProps{
Description: "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).\n\nSee https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3 for more information.",
Type: []string{"string"},
Format: "",
},
},
},
Required: []string{"issuer"},
},
},
}
}
func schema_119_apis_config_v1alpha1_OIDCProviderConfigStatus(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{
SchemaProps: spec.SchemaProps{
Description: "OIDCProviderConfigStatus is a struct that describes the actual state of an OIDC Provider.",
Type: []string{"object"},
Properties: map[string]spec.Schema{
"status": {
SchemaProps: spec.SchemaProps{
Description: "Status holds an enum that describes the state of this OIDC Provider. Note that this Status can represent success or failure.",
Type: []string{"string"},
Format: "",
},
},
"message": {
SchemaProps: spec.SchemaProps{
Description: "Message provides human-readable details about the Status.",
Type: []string{"string"},
Format: "",
},
},
"lastUpdateTime": {
SchemaProps: spec.SchemaProps{
Description: "LastUpdateTime holds the time at which the Status was last updated. It is a pointer to get around some undesirable behavior with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).",
Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"),
},
},
},
},
},
Dependencies: []string{
"k8s.io/apimachinery/pkg/apis/meta/v1.Time"},
}
}
func schema_119_apis_idp_v1alpha1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition {
return common.OpenAPIDefinition{
Schema: spec.Schema{

View File

@ -0,0 +1,86 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.0
creationTimestamp: null
name: oidcproviderconfigs.config.pinniped.dev
spec:
group: config.pinniped.dev
names:
kind: OIDCProviderConfig
listKind: OIDCProviderConfigList
plural: oidcproviderconfigs
shortNames:
- opc
singular: oidcproviderconfig
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: OIDCProviderConfig describes the configuration of an OIDC provider.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: Spec of the OIDC provider.
properties:
issuer:
description: "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).
\n See https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3
for more information."
minLength: 1
type: string
required:
- issuer
type: object
status:
description: Status of the OIDC provider.
properties:
lastUpdateTime:
description: LastUpdateTime holds the time at which the Status was
last updated. It is a pointer to get around some undesirable behavior
with respect to the empty metav1.Time value (see https://github.com/kubernetes/kubernetes/issues/86811).
format: date-time
type: string
message:
description: Message provides human-readable details about the Status.
type: string
status:
description: Status holds an enum that describes the state of this
OIDC Provider. Note that this Status can represent success or failure.
enum:
- Success
- Duplicate
- Invalid
type: string
type: object
required:
- spec
type: object
served: true
storage: true
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

11
hack/kind-down.sh Executable file
View File

@ -0,0 +1,11 @@
#!/usr/bin/env bash
# Copyright 2020 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${ROOT}"
kind delete cluster --name pinniped

12
hack/kind-up.sh Executable file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Copyright 2020 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${ROOT}"
# To choose a specific version of kube, add this option to the command below: `--image kindest/node:v1.18.8`
kind create cluster --config "hack/lib/kind-config/single-node.yaml" --name pinniped

View File

@ -0,0 +1,7 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
extraPortMappings: [{containerPort: 31234, hostPort: 12345, protocol: TCP}]

View File

@ -0,0 +1,5 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings: [{containerPort: 31234, hostPort: 12345, protocol: TCP}]

View File

@ -8,13 +8,20 @@ os.putenv('GOARCH', 'amd64')
os.putenv('CGO_ENABLED', '0')
os.putenv('KUBE_GIT_VERSION', 'v0.0.0')
#####################################################################################################
# Compile all of our ./cmd/... binaries.
#
local_resource(
'compile',
'cd ../../../ && mkdir -p ./hack/lib/tilt/build && go build -v -ldflags "$(hack/get-ldflags.sh)" -o ./hack/lib/tilt/build ./cmd/...',
deps=['../../../cmd', '../../../internal', '../../../pkg', '../../../generated'],
)
#####################################################################################################
# Local-user-authenticator app
#
# Build a container image for local-user-authenticator, with live-update enabled.
docker_build_with_restart('image/local-user-auth', '.',
dockerfile='local-user-authenticator.Dockerfile',
@ -26,16 +33,17 @@ docker_build_with_restart('image/local-user-auth', '.',
# Render the local-user-authenticator installation manifest using ytt.
k8s_yaml(local([
'ytt',
'--file', '../../../deploy-local-user-authenticator',
'--file', '../../../deploy/local-user-authenticator',
'--data-value', 'image_repo=image/local-user-auth',
'--data-value', 'image_tag=tilt-dev',
]))
# Collect all the deployed local-user-authenticator resources under a "local-user-auth" resource tab.
k8s_resource(
workload='local-user-authenticator',
new_name='local-user-auth',
workload='local-user-authenticator', # this is the deployment name
new_name='local-user-auth', # this is the name that will appear in the tilt UI
objects=[
# these are the objects that would otherwise appear in the "uncategorized" tab in the tilt UI
'local-user-authenticator:namespace',
'local-user-authenticator:serviceaccount',
'local-user-authenticator:role',
@ -43,55 +51,105 @@ k8s_resource(
],
)
# Build a container image for the Pinniped server, with live-update enabled.
docker_build_with_restart('image/pinniped', '.',
dockerfile='pinniped.Dockerfile',
entrypoint=['/usr/local/bin/pinniped-server'],
live_update=[sync('./build/pinniped-server', '/usr/local/bin/pinniped-server')],
only=['./build/pinniped-server'],
#####################################################################################################
# Supervisor app
#
# Build a container image for supervisor, with live-update enabled.
docker_build_with_restart('image/supervisor', '.',
dockerfile='supervisor.Dockerfile',
entrypoint=['/usr/local/bin/pinniped-supervisor'],
live_update=[sync('./build/pinniped-supervisor', '/usr/local/bin/pinniped-supervisor')],
only=['./build/pinniped-supervisor'],
)
# Render the Pinniped server installation manifest using ytt.
# Render the supervisor installation manifest using ytt.
k8s_yaml(local([
'ytt',
'--file', '../../../deploy/supervisor',
'--data-value', 'app_name=pinniped-supervisor',
'--data-value', 'namespace=supervisor',
'--data-value', 'image_repo=image/supervisor',
'--data-value', 'image_tag=tilt-dev',
'--data-value-yaml', 'replicas=1',
'--data-value-yaml', 'service_nodeport_port=31234',
]))
# Collect all the deployed supervisor resources under a "supervisor" resource tab.
k8s_resource(
workload='pinniped-supervisor', # this is the deployment name
new_name='supervisor', # this is the name that will appear in the tilt UI
objects=[
# these are the objects that would otherwise appear in the "uncategorized" tab in the tilt UI
'oidcproviderconfigs.config.pinniped.dev:customresourcedefinition',
'pinniped-supervisor-static-config:configmap',
'supervisor:namespace',
'pinniped-supervisor:role',
'pinniped-supervisor:rolebinding',
'pinniped-supervisor:serviceaccount',
],
)
# Build a container image for the Concierge server, with live-update enabled.
docker_build_with_restart('image/concierge', '.',
dockerfile='concierge.Dockerfile',
entrypoint=['/usr/local/bin/pinniped-concierge'],
live_update=[sync('./build/pinniped-concierge', '/usr/local/bin/pinniped-concierge')],
only=['./build/pinniped-concierge'],
)
#####################################################################################################
# Concierge app
#
# Render the Concierge server installation manifest using ytt.
k8s_yaml(local([
'sh', '-c',
'ytt --file ../../../deploy ' +
'--data-value namespace=integration ' +
'--data-value image_repo=image/pinniped ' +
'ytt --file ../../../deploy/concierge ' +
'--data-value app_name=pinniped-concierge ' +
'--data-value namespace=concierge ' +
'--data-value image_repo=image/concierge ' +
'--data-value image_tag=tilt-dev ' +
'--data-value kube_cert_agent_image=debian:10.5-slim ' +
'--data-value discovery_url=$(TERM=dumb kubectl cluster-info | awk \'/Kubernetes master/ {print $NF}\') ' +
'--data-value-yaml replicas=1'
'--data-value-yaml replicas=1',
]))
# Collect all the deployed local-user-authenticator resources under a "deploy/pinniped" resource tab.
# Collect all the deployed local-user-authenticator resources under a "concierge" resource tab.
k8s_resource(
workload='pinniped',
workload='pinniped-concierge', # this is the deployment name
new_name='concierge', # this is the name that will appear in the tilt UI
objects=[
'integration:namespace',
# these are the objects that would otherwise appear in the "uncategorized" tab in the tilt UI
'concierge:namespace',
'pinniped-concierge-aggregated-api-server:clusterrole',
'pinniped-concierge-aggregated-api-server:clusterrolebinding',
'pinniped-concierge-aggregated-api-server:role',
'pinniped-concierge-aggregated-api-server:rolebinding',
'pinniped-concierge-cluster-info-lister-watcher:role',
'pinniped-concierge-cluster-info-lister-watcher:rolebinding',
'pinniped-concierge-config:configmap',
'pinniped-concierge-create-token-credential-requests:clusterrole',
'pinniped-concierge-create-token-credential-requests:clusterrolebinding',
'pinniped-concierge-extension-apiserver-authentication-reader:rolebinding',
'pinniped-concierge-kube-system-pod-read:role',
'pinniped-concierge-kube-system-pod-read:rolebinding',
'pinniped-concierge:clusterrolebinding',
'pinniped-concierge:serviceaccount',
'credentialissuerconfigs.config.pinniped.dev:customresourcedefinition',
'webhookidentityproviders.idp.pinniped.dev:customresourcedefinition',
'pinniped:serviceaccount',
'pinniped-aggregated-api-server:role',
'pinniped-kube-system-pod-read:role',
'pinniped-cluster-info-lister-watcher:role',
'pinniped-aggregated-api-server:clusterrole',
'pinniped-create-token-credential-requests:clusterrole',
'pinniped-aggregated-api-server:rolebinding',
'pinniped-kube-system-pod-read:rolebinding',
'pinniped-extension-apiserver-authentication-reader:rolebinding',
'pinniped-cluster-info-lister-watcher:rolebinding',
'pinniped-aggregated-api-server:clusterrolebinding',
'pinniped-create-token-credential-requests:clusterrolebinding',
'pinniped:clusterrolebinding',
'pinniped-config:configmap',
'v1alpha1.login.pinniped.dev:apiservice',
],
)
#####################################################################################################
# Finish setting up cluster and creating integration test env file
#
# Collect environment variables needed to run our integration test suite.
local_resource(
'test-env',
'TILT_MODE=yes ../../prepare-for-integration-tests.sh',
resource_deps=['local-user-auth', 'pinniped'],
resource_deps=['local-user-auth', 'concierge', 'supervisor'],
deps=['../../prepare-for-integration-tests.sh'],
)

View File

@ -5,10 +5,10 @@
FROM debian:10.5-slim
# Copy the binary which was built outside the container.
COPY build/pinniped-server /usr/local/bin/pinniped-server
COPY build/pinniped-concierge /usr/local/bin/pinniped-concierge
# Document the port
EXPOSE 443
# Set the entrypoint
ENTRYPOINT ["/usr/local/bin/pinniped-server"]
ENTRYPOINT ["/usr/local/bin/pinniped-concierge"]

View File

@ -0,0 +1,14 @@
# Copyright 2020 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
# Use a runtime image based on Debian slim
FROM debian:10.5-slim
# Copy the binary which was built outside the container.
COPY build/pinniped-supervisor /usr/local/bin/pinniped-supervisor
# Document the port
EXPOSE 443
# Set the entrypoint
ENTRYPOINT ["/usr/local/bin/pinniped-supervisor"]

View File

@ -50,6 +50,7 @@ function check_dependency() {
#
help=no
skip_build=no
clean_kind=no
while (("$#")); do
case "$1" in
@ -61,6 +62,10 @@ while (("$#")); do
skip_build=yes
shift
;;
-c | --clean)
clean_kind=yes
shift
;;
-*)
log_error "Unsupported flag $1" >&2
exit 1
@ -98,18 +103,24 @@ check_dependency htpasswd "Please install htpasswd. Should be pre-installed on M
# Require kubectl >= 1.18.x
if [ "$(kubectl version --client=true --short | cut -d '.' -f 2)" -lt 18 ]; then
echo "kubectl >= 1.18.x is required, you have $(kubectl version --client=true --short | cut -d ':' -f2)"
log_error "kubectl >= 1.18.x is required, you have $(kubectl version --client=true --short | cut -d ':' -f2)"
exit 1
fi
if ! tilt_mode; then
if [[ "$clean_kind" == "yes" ]]; then
log_note "Deleting running kind clusters to prepare from a clean slate..."
kind delete cluster --name pinniped
fi
#
# Setup kind and build the app
#
log_note "Checking for running kind clusters..."
if ! kind get clusters | grep -q -e '^kind$'; then
if ! kind get clusters | grep -q -e '^pinniped$'; then
log_note "Creating a kind cluster..."
kind create cluster
# single-node.yaml exposes node port 31234 as 127.0.0.1:12345
kind create cluster --config "$pinniped_path/hack/lib/kind-config/single-node.yaml" --name pinniped
else
if ! kubectl cluster-info | grep master | grep -q 127.0.0.1; then
log_error "Seems like your kubeconfig is not targeting a local cluster."
@ -146,14 +157,14 @@ if ! tilt_mode; then
# Load it into the cluster
log_note "Loading the app's container image into the kind cluster..."
kind load docker-image "$registry_repo_tag"
kind load docker-image "$registry_repo_tag" --name pinniped
manifest=/tmp/manifest.yaml
#
# Deploy local-user-authenticator
#
pushd deploy-local-user-authenticator >/dev/null
pushd deploy/local-user-authenticator >/dev/null
log_note "Deploying the local-user-authenticator app to the cluster..."
ytt --file . \
@ -167,7 +178,6 @@ if ! tilt_mode; then
fi
test_username="test-username"
test_groups="test-group-0,test-group-1"
set +o pipefail
@ -186,27 +196,49 @@ kubectl create secret generic "$test_username" \
--output yaml |
kubectl apply -f -
app_name="pinniped"
namespace="integration"
#
# Deploy the Pinniped Supervisor
#
supervisor_app_name="pinniped-supervisor"
supervisor_namespace="supervisor"
if ! tilt_mode; then
pushd deploy/supervisor >/dev/null
log_note "Deploying the Pinniped Supervisor app to the cluster..."
ytt --file . \
--data-value "app_name=$supervisor_app_name" \
--data-value "namespace=$supervisor_namespace" \
--data-value "image_repo=$registry_repo" \
--data-value "image_tag=$tag" \
--data-value-yaml 'service_nodeport_port=31234' >"$manifest"
kapp deploy --yes --app "$supervisor_app_name" --diff-changes --file "$manifest"
popd >/dev/null
fi
#
# Deploy Pinniped
#
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 '/Kubernetes master/ {print $NF}')"
if ! tilt_mode; then
#
# Deploy Pinniped
#
pushd deploy >/dev/null
pushd deploy/concierge >/dev/null
log_note "Deploying the Pinniped app to the cluster..."
ytt --file . \
--data-value "app_name=$app_name" \
--data-value "namespace=$namespace" \
--data-value "app_name=$concierge_app_name" \
--data-value "namespace=$concierge_namespace" \
--data-value "image_repo=$registry_repo" \
--data-value "image_tag=$tag" \
--data-value "discovery_url=$discovery_url" >"$manifest"
kapp deploy --yes --app "$app_name" --diff-changes --file "$manifest"
kapp deploy --yes --app "$concierge_app_name" --diff-changes --file "$manifest"
popd >/dev/null
fi
@ -218,20 +250,23 @@ kind_capabilities_file="$pinniped_path/test/cluster_capabilities/kind.yaml"
pinniped_cluster_capability_file_content=$(cat "$kind_capabilities_file")
cat <<EOF >/tmp/integration-test-env
# The following env vars should be set before running 'go test -v -count 1 ./test/...'
export PINNIPED_NAMESPACE=${namespace}
export PINNIPED_APP_NAME=${app_name}
# The following env vars should be set before running 'go test -v -count 1 ./test/integration'
export PINNIPED_TEST_CONCIERGE_NAMESPACE=${concierge_namespace}
export PINNIPED_TEST_CONCIERGE_APP_NAME=${concierge_app_name}
export PINNIPED_TEST_USER_USERNAME=${test_username}
export PINNIPED_TEST_USER_GROUPS=${test_groups}
export PINNIPED_TEST_USER_TOKEN=${test_username}:${test_password}
export PINNIPED_TEST_WEBHOOK_ENDPOINT=${webhook_url}
export PINNIPED_TEST_WEBHOOK_CA_BUNDLE=${webhook_ca_bundle}
export PINNIPED_TEST_SUPERVISOR_NAMESPACE=${supervisor_namespace}
export PINNIPED_TEST_SUPERVISOR_APP_NAME=${supervisor_app_name}
export PINNIPED_TEST_SUPERVISOR_ADDRESS="127.0.0.1:12345"
read -r -d '' PINNIPED_CLUSTER_CAPABILITY_YAML << PINNIPED_CLUSTER_CAPABILITY_YAML_EOF || true
read -r -d '' PINNIPED_TEST_CLUSTER_CAPABILITY_YAML << PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF || true
${pinniped_cluster_capability_file_content}
PINNIPED_CLUSTER_CAPABILITY_YAML_EOF
PINNIPED_TEST_CLUSTER_CAPABILITY_YAML_EOF
export PINNIPED_CLUSTER_CAPABILITY_YAML
export PINNIPED_TEST_CLUSTER_CAPABILITY_YAML
EOF
#
@ -242,15 +277,16 @@ goland_vars=$(grep -v '^#' /tmp/integration-test-env | grep -E '^export .+=' | s
log_note
log_note "🚀 Ready to run integration tests! For example..."
log_note " cd $pinniped_path"
log_note ' source /tmp/integration-test-env && go test -v -count 1 ./test/...'
log_note ' source /tmp/integration-test-env && go test -v -count 1 ./test/integration'
log_note
log_note 'Want to run integration tests in GoLand? Copy/paste this "Environment" value for GoLand run configurations:'
log_note " ${goland_vars}PINNIPED_CLUSTER_CAPABILITY_FILE=${kind_capabilities_file}"
log_note " ${goland_vars}PINNIPED_TEST_CLUSTER_CAPABILITY_FILE=${kind_capabilities_file}"
log_note
if ! tilt_mode; then
log_note "You can rerun this script to redeploy local production code changes while you are working."
log_note
log_note "To delete the deployments, run 'kapp delete -a local-user-authenticator -y && kapp delete -a pinniped -y'."
log_note "When you're finished, use 'kind delete cluster' to tear down the cluster."
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 'kind delete cluster --name pinniped' to tear down the cluster."
fi

View File

@ -5,5 +5,7 @@
set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "${ROOT}"
exec tilt up -f ./hack/lib/tilt/Tiltfile --stream
exec tilt up -f ./hack/lib/tilt/Tiltfile

View File

@ -7,6 +7,20 @@ set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
# Generate code.
xargs "$ROOT/hack/lib/update-codegen.sh" < "${ROOT}/hack/lib/kube-versions.txt"
cp "$ROOT/generated/1.19/crds/"*.yaml "$ROOT/deploy/"
# Copy each CRD yaml to the app which should cause it to be installed.
cp "$ROOT"/generated/1.19/crds/*oidcproviderconfigs.yaml "$ROOT/deploy/supervisor"
cp "$ROOT"/generated/1.19/crds/*credentialissuerconfigs.yaml "$ROOT/deploy/concierge"
cp "$ROOT"/generated/1.19/crds/*webhookidentityproviders.yaml "$ROOT/deploy/concierge"
# Make sure we didn't miss any new CRDs.
crdCount=$(find "$ROOT"/generated/1.19/crds/ -maxdepth 1 -type f -name '*.yaml' | wc -l | tr -d ' ')
if [[ "$crdCount" != "3" ]]; then
echo "Looks like you added a new CRD. Please update this update.sh script to decide where to copy it and then run it again."
exit 1
fi
# Tidy.
"$ROOT/hack/module.sh" tidy

View File

@ -87,7 +87,7 @@ func (c *Config) Complete() CompletedConfig {
// New returns a new instance of AdmissionServer from the given config.
func (c completedConfig) New() (*PinnipedServer, error) {
genericServer, err := c.GenericConfig.New("pinniped-server", genericapiserver.NewEmptyDelegate()) // completion is done in Complete, no need for a second time
genericServer, err := c.GenericConfig.New("pinniped-concierge", genericapiserver.NewEmptyDelegate()) // completion is done in Complete, no need for a second time
if err != nil {
return nil, fmt.Errorf("completion error: %w", err)
}

View File

@ -1,7 +1,7 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package server is the command line entry point for pinniped-server.
// Package server is the command line entry point for pinniped-concierge.
package server
import (
@ -15,8 +15,8 @@ import (
genericoptions "k8s.io/apiserver/pkg/server/options"
loginv1alpha1 "go.pinniped.dev/generated/1.19/apis/login/v1alpha1"
"go.pinniped.dev/internal/apiserver"
"go.pinniped.dev/internal/certauthority/dynamiccertauthority"
"go.pinniped.dev/internal/concierge/apiserver"
"go.pinniped.dev/internal/controller/identityprovider/idpcache"
"go.pinniped.dev/internal/controllermanager"
"go.pinniped.dev/internal/downward"
@ -26,7 +26,7 @@ import (
"go.pinniped.dev/pkg/config"
)
// App is an object that represents the pinniped-server application.
// App is an object that represents the pinniped-concierge application.
type App struct {
cmd *cobra.Command
@ -54,9 +54,9 @@ func (a *App) Run() error {
// Create the server command and save it into the App.
func (a *App) addServerCommand(ctx context.Context, args []string, stdout, stderr io.Writer) {
cmd := &cobra.Command{
Use: "pinniped-server",
Use: "pinniped-concierge",
Long: here.Doc(`
pinniped-server provides a generic API for mapping an external
pinniped-concierge provides a generic API for mapping an external
credential from somewhere to an internal credential to be used for
authenticating to the Kubernetes API.`),
RunE: func(cmd *cobra.Command, args []string) error { return a.runServer(ctx) },

View File

@ -15,17 +15,17 @@ import (
)
const knownGoodUsage = `
pinniped-server provides a generic API for mapping an external
pinniped-concierge provides a generic API for mapping an external
credential from somewhere to an internal credential to be used for
authenticating to the Kubernetes API.
Usage:
pinniped-server [flags]
pinniped-concierge [flags]
Flags:
-c, --config string path to configuration file (default "pinniped.yaml")
--downward-api-path string path to Downward API volume mount (default "/etc/podinfo")
-h, --help help for pinniped-server
-h, --help help for pinniped-concierge
--log-flush-frequency duration Maximum number of seconds between log flushes (default 5s)
`
@ -48,7 +48,7 @@ func TestCommand(t *testing.T) {
{
name: "OneArgFails",
args: []string{"tuna"},
wantErr: `unknown command "tuna" for "pinniped-server"`,
wantErr: `unknown command "tuna" for "pinniped-concierge"`,
},
{
name: "ShortConfigFlagSucceeds",
@ -64,7 +64,7 @@ func TestCommand(t *testing.T) {
"--config", "some/path/to/config.yaml",
"tuna",
},
wantErr: `unknown command "tuna" for "pinniped-server"`,
wantErr: `unknown command "tuna" for "pinniped-concierge"`,
},
}
for _, test := range tests {

View File

@ -0,0 +1,161 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package supervisorconfig
import (
"context"
"fmt"
"go.pinniped.dev/internal/multierror"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/clock"
"k8s.io/client-go/util/retry"
"k8s.io/klog/v2"
configv1alpha1 "go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
pinnipedclientset "go.pinniped.dev/generated/1.19/client/clientset/versioned"
configinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions/config/v1alpha1"
pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/oidc/provider"
)
// ProvidersSetter can be notified of all known valid providers with its SetIssuer function.
// If there are no longer any valid issuers, then it can be called with no arguments.
// Implementations of this type should be thread-safe to support calls from multiple goroutines.
type ProvidersSetter interface {
SetProviders(oidcProviders ...*provider.OIDCProvider)
}
type oidcProviderConfigWatcherController struct {
providerSetter ProvidersSetter
clock clock.Clock
client pinnipedclientset.Interface
opcInformer configinformers.OIDCProviderConfigInformer
}
// NewOIDCProviderConfigWatcherController creates a controllerlib.Controller that watches
// OIDCProviderConfig objects and notifies a callback object of the collection of provider configs.
func NewOIDCProviderConfigWatcherController(
providerSetter ProvidersSetter,
clock clock.Clock,
client pinnipedclientset.Interface,
opcInformer configinformers.OIDCProviderConfigInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc,
) controllerlib.Controller {
return controllerlib.New(
controllerlib.Config{
Name: "OIDCProviderConfigWatcherController",
Syncer: &oidcProviderConfigWatcherController{
providerSetter: providerSetter,
clock: clock,
client: client,
opcInformer: opcInformer,
},
},
withInformer(
opcInformer,
pinnipedcontroller.NoOpFilter(),
controllerlib.InformerOption{},
),
)
}
// Sync implements controllerlib.Syncer.
func (c *oidcProviderConfigWatcherController) Sync(ctx controllerlib.Context) error {
all, err := c.opcInformer.Lister().List(labels.Everything())
if err != nil {
return err
}
issuerCounts := make(map[string]int)
for _, opc := range all {
issuerCounts[opc.Spec.Issuer]++
}
errs := multierror.New()
oidcProviders := make([]*provider.OIDCProvider, 0)
for _, opc := range all {
if issuerCount := issuerCounts[opc.Spec.Issuer]; issuerCount > 1 {
if err := c.updateStatus(
ctx.Context,
opc.Namespace,
opc.Name,
configv1alpha1.DuplicateOIDCProviderStatus,
"Duplicate issuer: "+opc.Spec.Issuer,
); err != nil {
errs.Add(fmt.Errorf("could not update status: %w", err))
}
continue
}
oidcProvider, err := provider.NewOIDCProvider(opc.Spec.Issuer)
if err != nil {
if err := c.updateStatus(
ctx.Context,
opc.Namespace,
opc.Name,
configv1alpha1.InvalidOIDCProviderStatus,
"Invalid: "+err.Error(),
); err != nil {
errs.Add(fmt.Errorf("could not update status: %w", err))
}
continue
}
if err := c.updateStatus(
ctx.Context,
opc.Namespace,
opc.Name,
configv1alpha1.SuccessOIDCProviderStatus,
"Provider successfully created",
); err != nil {
errs.Add(fmt.Errorf("could not update status: %w", err))
continue
}
oidcProviders = append(oidcProviders, oidcProvider)
}
c.providerSetter.SetProviders(oidcProviders...)
return errs.ErrOrNil()
}
func (c *oidcProviderConfigWatcherController) updateStatus(
ctx context.Context,
namespace, name string,
status configv1alpha1.OIDCProviderStatus,
message string,
) error {
return retry.RetryOnConflict(retry.DefaultRetry, func() error {
opc, err := c.client.ConfigV1alpha1().OIDCProviderConfigs(namespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("get failed: %w", err)
}
if opc.Status.Status == status && opc.Status.Message == message {
return nil
}
klog.InfoS(
"attempting status update",
"openidproviderconfig",
klog.KRef(namespace, name),
"status",
status,
"message",
message,
)
opc.Status.Status = status
opc.Status.Message = message
opc.Status.LastUpdateTime = timePtr(metav1.NewTime(c.clock.Now()))
_, err = c.client.ConfigV1alpha1().OIDCProviderConfigs(namespace).Update(ctx, opc, metav1.UpdateOptions{})
return err
})
}
func timePtr(t metav1.Time) *metav1.Time { return &t }

View File

@ -0,0 +1,818 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package supervisorconfig
import (
"context"
"errors"
"reflect"
"sync"
"testing"
"time"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
"github.com/stretchr/testify/require"
k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/clock"
coretesting "k8s.io/client-go/testing"
"go.pinniped.dev/generated/1.19/apis/config/v1alpha1"
pinnipedfake "go.pinniped.dev/generated/1.19/client/clientset/versioned/fake"
pinnipedinformers "go.pinniped.dev/generated/1.19/client/informers/externalversions"
"go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/oidc/provider"
"go.pinniped.dev/internal/testutil"
)
func TestInformerFilters(t *testing.T) {
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
var r *require.Assertions
var observableWithInformerOption *testutil.ObservableWithInformerOption
var configMapInformerFilter controllerlib.Filter
it.Before(func() {
r = require.New(t)
observableWithInformerOption = testutil.NewObservableWithInformerOption()
opcInformer := pinnipedinformers.NewSharedInformerFactoryWithOptions(nil, 0).Config().V1alpha1().OIDCProviderConfigs()
_ = NewOIDCProviderConfigWatcherController(
nil,
nil,
nil,
opcInformer,
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
)
configMapInformerFilter = observableWithInformerOption.GetFilterForInformer(opcInformer)
})
when("watching OIDCProviderConfig objects", func() {
var subject controllerlib.Filter
var target, otherNamespace, otherName *v1alpha1.OIDCProviderConfig
it.Before(func() {
subject = configMapInformerFilter
target = &v1alpha1.OIDCProviderConfig{ObjectMeta: metav1.ObjectMeta{Name: "some-name", Namespace: "some-namespace"}}
otherNamespace = &v1alpha1.OIDCProviderConfig{ObjectMeta: metav1.ObjectMeta{Name: "some-name", Namespace: "other-namespace"}}
otherName = &v1alpha1.OIDCProviderConfig{ObjectMeta: metav1.ObjectMeta{Name: "other-name", Namespace: "some-namespace"}}
})
when("any OIDCProviderConfig changes", func() {
it("returns true to trigger the sync method", func() {
r.True(subject.Add(target))
r.True(subject.Add(otherName))
r.True(subject.Add(otherNamespace))
r.True(subject.Update(target, otherName))
r.True(subject.Update(otherName, otherName))
r.True(subject.Update(otherNamespace, otherName))
r.True(subject.Update(otherName, target))
r.True(subject.Update(otherName, otherName))
r.True(subject.Update(otherName, otherNamespace))
r.True(subject.Delete(target))
r.True(subject.Delete(otherName))
r.True(subject.Delete(otherNamespace))
})
})
})
}, spec.Parallel(), spec.Report(report.Terminal{}))
}
type fakeProvidersSetter struct {
SetProvidersWasCalled bool
OIDCProvidersReceived []*provider.OIDCProvider
}
func (f *fakeProvidersSetter) SetProviders(oidcProviders ...*provider.OIDCProvider) {
f.SetProvidersWasCalled = true
f.OIDCProvidersReceived = oidcProviders
}
func TestSync(t *testing.T) {
spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) {
const namespace = "some-namespace"
var r *require.Assertions
var subject controllerlib.Controller
var opcInformerClient *pinnipedfake.Clientset
var opcInformers pinnipedinformers.SharedInformerFactory
var pinnipedAPIClient *pinnipedfake.Clientset
var timeoutContext context.Context
var timeoutContextCancel context.CancelFunc
var syncContext *controllerlib.Context
var frozenNow time.Time
var providersSetter *fakeProvidersSetter
var oidcProviderConfigGVR schema.GroupVersionResource
// Defer starting the informers until the last possible moment so that the
// nested Before's can keep adding things to the informer caches.
var startInformersAndController = func() {
// Set this at the last second to allow for injection of server override.
subject = NewOIDCProviderConfigWatcherController(
providersSetter,
clock.NewFakeClock(frozenNow),
pinnipedAPIClient,
opcInformers.Config().V1alpha1().OIDCProviderConfigs(),
controllerlib.WithInformer,
)
// Set this at the last second to support calling subject.Name().
syncContext = &controllerlib.Context{
Context: timeoutContext,
Name: subject.Name(),
Key: controllerlib.Key{
Namespace: namespace,
Name: "config-name",
},
}
// Must start informers before calling TestRunSynchronously()
opcInformers.Start(timeoutContext.Done())
controllerlib.TestRunSynchronously(t, subject)
}
it.Before(func() {
r = require.New(t)
providersSetter = &fakeProvidersSetter{}
frozenNow = time.Date(2020, time.September, 23, 7, 42, 0, 0, time.Local)
timeoutContext, timeoutContextCancel = context.WithTimeout(context.Background(), time.Second*3)
opcInformerClient = pinnipedfake.NewSimpleClientset()
opcInformers = pinnipedinformers.NewSharedInformerFactory(opcInformerClient, 0)
pinnipedAPIClient = pinnipedfake.NewSimpleClientset()
oidcProviderConfigGVR = schema.GroupVersionResource{
Group: v1alpha1.SchemeGroupVersion.Group,
Version: v1alpha1.SchemeGroupVersion.Version,
Resource: "oidcproviderconfigs",
}
})
it.After(func() {
timeoutContextCancel()
})
when("there are some valid OIDCProviderConfigs in the informer", func() {
var (
oidcProviderConfig1 *v1alpha1.OIDCProviderConfig
oidcProviderConfig2 *v1alpha1.OIDCProviderConfig
)
it.Before(func() {
oidcProviderConfig1 = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "config1", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer1.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfig1))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfig1))
oidcProviderConfig2 = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "config2", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer2.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfig2))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfig2))
})
it("calls the ProvidersSetter", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
provider1, err := provider.NewOIDCProvider(oidcProviderConfig1.Spec.Issuer)
r.NoError(err)
provider2, err := provider.NewOIDCProvider(oidcProviderConfig2.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.ElementsMatch(
[]*provider.OIDCProvider{
provider1,
provider2,
},
providersSetter.OIDCProvidersReceived,
)
})
it("updates the status to success in the OIDCProviderConfigs", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
oidcProviderConfig1.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig1.Status.Message = "Provider successfully created"
oidcProviderConfig1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
oidcProviderConfig2.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig2.Status.Message = "Provider successfully created"
oidcProviderConfig2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig1.Namespace,
oidcProviderConfig1.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig1.Namespace,
oidcProviderConfig1,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
when("one OIDCProviderConfig is already up to date", func() {
it.Before(func() {
oidcProviderConfig1.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig1.Status.Message = "Provider successfully created"
oidcProviderConfig1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
r.NoError(pinnipedAPIClient.Tracker().Update(oidcProviderConfigGVR, oidcProviderConfig1, oidcProviderConfig1.Namespace))
r.NoError(opcInformerClient.Tracker().Update(oidcProviderConfigGVR, oidcProviderConfig1, oidcProviderConfig1.Namespace))
})
it("only updates the out-of-date OIDCProviderConfig", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
oidcProviderConfig2.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig2.Status.Message = "Provider successfully created"
oidcProviderConfig2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig1.Namespace,
oidcProviderConfig1.Name,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
it("calls the ProvidersSetter with both OIDCProviderConfig's", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
provider1, err := provider.NewOIDCProvider(oidcProviderConfig1.Spec.Issuer)
r.NoError(err)
provider2, err := provider.NewOIDCProvider(oidcProviderConfig2.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.ElementsMatch(
[]*provider.OIDCProvider{
provider1,
provider2,
},
providersSetter.OIDCProvidersReceived,
)
})
})
when("updating only one OIDCProviderConfig fails for a reason other than conflict", func() {
it.Before(func() {
once := sync.Once{}
pinnipedAPIClient.PrependReactor(
"update",
"oidcproviderconfigs",
func(_ coretesting.Action) (bool, runtime.Object, error) {
var err error
once.Do(func() {
err = errors.New("some update error")
})
return true, nil, err
},
)
})
it("sets the provider that it could actually update in the API", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: some update error")
provider1, err := provider.NewOIDCProvider(oidcProviderConfig1.Spec.Issuer)
r.NoError(err)
provider2, err := provider.NewOIDCProvider(oidcProviderConfig2.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.Len(providersSetter.OIDCProvidersReceived, 1)
r.True(
reflect.DeepEqual(providersSetter.OIDCProvidersReceived[0], provider1) ||
reflect.DeepEqual(providersSetter.OIDCProvidersReceived[0], provider2),
)
})
it("returns an error", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: some update error")
oidcProviderConfig1.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig1.Status.Message = "Provider successfully created"
oidcProviderConfig1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
oidcProviderConfig2.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig2.Status.Message = "Provider successfully created"
oidcProviderConfig2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig1.Namespace,
oidcProviderConfig1.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig1.Namespace,
oidcProviderConfig1,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig2.Namespace,
oidcProviderConfig2,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
})
})
when("there are errors updating the OIDCProviderConfigs", func() {
var (
oidcProviderConfig *v1alpha1.OIDCProviderConfig
)
it.Before(func() {
oidcProviderConfig = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "config", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfig))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfig))
})
when("there is a conflict while updating an OIDCProviderConfig", func() {
it.Before(func() {
once := sync.Once{}
pinnipedAPIClient.PrependReactor(
"update",
"oidcproviderconfigs",
func(_ coretesting.Action) (bool, runtime.Object, error) {
var err error
once.Do(func() {
err = k8serrors.NewConflict(schema.GroupResource{}, "", nil)
})
return true, nil, err
},
)
})
it("retries updating the OIDCProviderConfig", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
oidcProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig.Status.Message = "Provider successfully created"
oidcProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig,
),
}
r.Equal(expectedActions, pinnipedAPIClient.Actions())
})
})
when("updating the OIDCProviderConfig fails for a reason other than conflict", func() {
it.Before(func() {
pinnipedAPIClient.PrependReactor(
"update",
"oidcproviderconfigs",
func(_ coretesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("some update error")
},
)
})
it("returns an error", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: some update error")
oidcProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig.Status.Message = "Provider successfully created"
oidcProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig,
),
}
r.Equal(expectedActions, pinnipedAPIClient.Actions())
})
})
when("there is an error when getting the OIDCProviderConfig", func() {
it.Before(func() {
pinnipedAPIClient.PrependReactor(
"get",
"oidcproviderconfigs",
func(_ coretesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("some get error")
},
)
})
it("returns the get error", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: get failed: some get error")
oidcProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig.Status.Message = "Provider successfully created"
oidcProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
}
r.Equal(expectedActions, pinnipedAPIClient.Actions())
})
})
})
when("there are both valid and invalid OIDCProviderConfigs in the informer", func() {
var (
validOIDCProviderConfig *v1alpha1.OIDCProviderConfig
invalidOIDCProviderConfig *v1alpha1.OIDCProviderConfig
)
it.Before(func() {
validOIDCProviderConfig = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "valid-config", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://valid-issuer.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(validOIDCProviderConfig))
r.NoError(opcInformerClient.Tracker().Add(validOIDCProviderConfig))
invalidOIDCProviderConfig = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "invalid-config", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://invalid-issuer.com?some=query"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(invalidOIDCProviderConfig))
r.NoError(opcInformerClient.Tracker().Add(invalidOIDCProviderConfig))
})
it("calls the ProvidersSetter with the valid provider", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
validProvider, err := provider.NewOIDCProvider(validOIDCProviderConfig.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.Equal(
[]*provider.OIDCProvider{
validProvider,
},
providersSetter.OIDCProvidersReceived,
)
})
it("updates the status to success/invalid in the OIDCProviderConfigs", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
validOIDCProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
validOIDCProviderConfig.Status.Message = "Provider successfully created"
validOIDCProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
invalidOIDCProviderConfig.Status.Status = v1alpha1.InvalidOIDCProviderStatus
invalidOIDCProviderConfig.Status.Message = "Invalid: issuer must not have query"
invalidOIDCProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
invalidOIDCProviderConfig.Namespace,
invalidOIDCProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
invalidOIDCProviderConfig.Namespace,
invalidOIDCProviderConfig,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
validOIDCProviderConfig.Namespace,
validOIDCProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
validOIDCProviderConfig.Namespace,
validOIDCProviderConfig,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
when("updating only the invalid OIDCProviderConfig fails for a reason other than conflict", func() {
it.Before(func() {
pinnipedAPIClient.PrependReactor(
"update",
"oidcproviderconfigs",
func(action coretesting.Action) (bool, runtime.Object, error) {
updateAction := action.(coretesting.UpdateActionImpl)
opc := updateAction.Object.(*v1alpha1.OIDCProviderConfig)
if opc.Name == validOIDCProviderConfig.Name {
return true, nil, nil
}
return true, nil, errors.New("some update error")
},
)
})
it("sets the provider that it could actually update in the API", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: some update error")
validProvider, err := provider.NewOIDCProvider(validOIDCProviderConfig.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.Equal(
[]*provider.OIDCProvider{
validProvider,
},
providersSetter.OIDCProvidersReceived,
)
})
it("returns an error", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, "1 error(s):\n- could not update status: some update error")
validOIDCProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
validOIDCProviderConfig.Status.Message = "Provider successfully created"
validOIDCProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
invalidOIDCProviderConfig.Status.Status = v1alpha1.InvalidOIDCProviderStatus
invalidOIDCProviderConfig.Status.Message = "Invalid: issuer must not have query"
invalidOIDCProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
invalidOIDCProviderConfig.Namespace,
invalidOIDCProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
invalidOIDCProviderConfig.Namespace,
invalidOIDCProviderConfig,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
validOIDCProviderConfig.Namespace,
validOIDCProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
validOIDCProviderConfig.Namespace,
validOIDCProviderConfig,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
})
})
when("there are OIDCProviderConfigs with duplicate issuer names in the informer", func() {
var (
oidcProviderConfigDuplicate1 *v1alpha1.OIDCProviderConfig
oidcProviderConfigDuplicate2 *v1alpha1.OIDCProviderConfig
oidcProviderConfig *v1alpha1.OIDCProviderConfig
)
it.Before(func() {
oidcProviderConfigDuplicate1 = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "duplicate1", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer-duplicate.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfigDuplicate1))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfigDuplicate1))
oidcProviderConfigDuplicate2 = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "duplicate2", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer-duplicate.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfigDuplicate2))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfigDuplicate2))
oidcProviderConfig = &v1alpha1.OIDCProviderConfig{
ObjectMeta: metav1.ObjectMeta{Name: "not-duplicate", Namespace: namespace},
Spec: v1alpha1.OIDCProviderConfigSpec{Issuer: "https://issuer-not-duplicate.com"},
}
r.NoError(pinnipedAPIClient.Tracker().Add(oidcProviderConfig))
r.NoError(opcInformerClient.Tracker().Add(oidcProviderConfig))
})
it("calls the ProvidersSetter with the non-duplicate", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
nonDuplicateProvider, err := provider.NewOIDCProvider(oidcProviderConfig.Spec.Issuer)
r.NoError(err)
r.True(providersSetter.SetProvidersWasCalled)
r.Equal(
[]*provider.OIDCProvider{
nonDuplicateProvider,
},
providersSetter.OIDCProvidersReceived,
)
})
it("updates the statuses", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
oidcProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig.Status.Message = "Provider successfully created"
oidcProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
oidcProviderConfigDuplicate1.Status.Status = v1alpha1.DuplicateOIDCProviderStatus
oidcProviderConfigDuplicate1.Status.Message = "Duplicate issuer: https://issuer-duplicate.com"
oidcProviderConfigDuplicate1.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
oidcProviderConfigDuplicate2.Status.Status = v1alpha1.DuplicateOIDCProviderStatus
oidcProviderConfigDuplicate2.Status.Message = "Duplicate issuer: https://issuer-duplicate.com"
oidcProviderConfigDuplicate2.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate1.Namespace,
oidcProviderConfigDuplicate1.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate1.Namespace,
oidcProviderConfigDuplicate1,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate2.Namespace,
oidcProviderConfigDuplicate2.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate2.Namespace,
oidcProviderConfigDuplicate2,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
coretesting.NewUpdateAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
when("we cannot talk to the API", func() {
it.Before(func() {
pinnipedAPIClient.PrependReactor(
"get",
"oidcproviderconfigs",
func(_ coretesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("some get error")
},
)
})
it("returns the get errors", func() {
expectedError := here.Doc(`
3 error(s):
- could not update status: get failed: some get error
- could not update status: get failed: some get error
- could not update status: get failed: some get error`)
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.EqualError(err, expectedError)
oidcProviderConfig.Status.Status = v1alpha1.SuccessOIDCProviderStatus
oidcProviderConfig.Status.Message = "Provider successfully created"
oidcProviderConfig.Status.LastUpdateTime = timePtr(metav1.NewTime(frozenNow))
expectedActions := []coretesting.Action{
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate1.Namespace,
oidcProviderConfigDuplicate1.Name,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfigDuplicate2.Namespace,
oidcProviderConfigDuplicate2.Name,
),
coretesting.NewGetAction(
oidcProviderConfigGVR,
oidcProviderConfig.Namespace,
oidcProviderConfig.Name,
),
}
r.ElementsMatch(expectedActions, pinnipedAPIClient.Actions())
})
})
})
when("there are no OIDCProviderConfigs in the informer", func() {
it("keeps waiting for one", func() {
startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext)
r.NoError(err)
r.Empty(pinnipedAPIClient.Actions())
r.True(providersSetter.SetProvidersWasCalled)
r.Empty(providersSetter.OIDCProvidersReceived)
})
})
}, spec.Parallel(), spec.Report(report.Terminal{}))
}

View File

@ -0,0 +1,63 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package multierror provides a type that can translate multiple errors into a Go error interface.
//
// A common use of this package is as follows.
// errs := multierror.New()
// for i := range stuff {
// err := doThing(i)
// errs.Add(err)
// }
// return errs.ErrOrNil()
package multierror
import (
"fmt"
"strings"
)
// formatFunc is a function used to format the string representing of a MultiError. It is used in the
// Error() function.
//
// It is marked out here to indicate how we could potentially extend MultiError in the future to
// support more styles of converting from a list of error's to a string.
//nolint: gochecknoglobals
var formatFunc func(errs MultiError, sb *strings.Builder) = defaultFormat
// MultiError holds a list of error's, that could potentially be empty.
//
// Use New() to create a MultiError.
type MultiError []error
// New returns an empty MultiError.
func New() MultiError {
return make([]error, 0)
}
// Add adds an error to the MultiError. The provided err must not be nil.
func (m *MultiError) Add(err error) {
*m = append(*m, err)
}
// Error implements the error.Error() interface method.
func (m MultiError) Error() string {
sb := strings.Builder{}
formatFunc(m, &sb)
return sb.String()
}
// ErrOrNil returns either nil, if there are no errors in this MultiError, or an error, otherwise.
func (m MultiError) ErrOrNil() error {
if len(m) > 0 {
return m
}
return nil
}
func defaultFormat(errs MultiError, sb *strings.Builder) {
_, _ = fmt.Fprintf(sb, "%d error(s):", len(errs))
for _, err := range errs {
_, _ = fmt.Fprintf(sb, "\n- %s", err.Error())
}
}

View File

@ -0,0 +1,24 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package multierror
import (
"errors"
"testing"
"github.com/stretchr/testify/require"
)
func TestMultierror(t *testing.T) {
errs := New()
require.Nil(t, errs.ErrOrNil())
errs.Add(errors.New("some error 1"))
require.EqualError(t, errs.ErrOrNil(), "1 error(s):\n- some error 1")
errs.Add(errors.New("some error 2"))
errs.Add(errors.New("some error 3"))
require.EqualError(t, errs.ErrOrNil(), "3 error(s):\n- some error 1\n- some error 2\n- some error 3")
}

View File

@ -0,0 +1,69 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package discovery provides a handler for the OIDC discovery endpoint.
package discovery
import (
"encoding/json"
"net/http"
"go.pinniped.dev/internal/oidc"
)
// Metadata holds all fields (that we care about) from the OpenID Provider Metadata section in the
// OpenID Connect Discovery specification:
// https://openid.net/specs/openid-connect-discovery-1_0.html#rfc.section.3.
type Metadata struct {
// vvv Required vvv
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
TokenEndpoint string `json:"token_endpoint"`
JWKSURI string `json:"jwks_uri"`
ResponseTypesSupported []string `json:"response_types_supported"`
SubjectTypesSupported []string `json:"subject_types_supported"`
IDTokenSigningAlgValuesSupported []string `json:"id_token_signing_alg_values_supported"`
// ^^^ Required ^^^
// vvv Optional vvv
TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported"`
TokenEndpointAuthSigningAlgoValuesSupported []string `json:"token_endpoint_auth_signing_alg_values_supported"`
ScopesSupported []string `json:"scopes_supported"`
ClaimsSupported []string `json:"claims_supported"`
// ^^^ Optional ^^^
}
// New returns an http.Handler that serves an OIDC discovery endpoint.
func New(issuerURL string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method != http.MethodGet {
http.Error(w, `{"error": "Method not allowed (try GET)"}`, http.StatusMethodNotAllowed)
return
}
oidcConfig := Metadata{
Issuer: issuerURL,
AuthorizationEndpoint: issuerURL + oidc.AuthorizationEndpointPath,
TokenEndpoint: issuerURL + oidc.TokenEndpointPath,
JWKSURI: issuerURL + oidc.JWKSEndpointPath,
ResponseTypesSupported: []string{"code"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"},
TokenEndpointAuthSigningAlgoValuesSupported: []string{"RS256"},
ScopesSupported: []string{"openid", "offline"},
ClaimsSupported: []string{"groups"},
}
if err := json.NewEncoder(w).Encode(&oidcConfig); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
})
}

View File

@ -0,0 +1,82 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package discovery
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/oidc"
)
func TestDiscovery(t *testing.T) {
tests := []struct {
name string
issuer string
method string
path string
wantStatus int
wantContentType string
wantBody interface{}
}{
{
name: "happy path",
issuer: "https://some-issuer.com/some/path",
method: http.MethodGet,
path: "/some/path" + oidc.WellKnownEndpointPath,
wantStatus: http.StatusOK,
wantContentType: "application/json",
wantBody: &Metadata{
Issuer: "https://some-issuer.com/some/path",
AuthorizationEndpoint: "https://some-issuer.com/some/path/oauth2/authorize",
TokenEndpoint: "https://some-issuer.com/some/path/oauth2/token",
JWKSURI: "https://some-issuer.com/some/path/jwks.json",
ResponseTypesSupported: []string{"code"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_basic"},
TokenEndpointAuthSigningAlgoValuesSupported: []string{"RS256"},
ScopesSupported: []string{"openid", "offline"},
ClaimsSupported: []string{"groups"},
},
},
{
name: "bad method",
issuer: "https://some-issuer.com",
method: http.MethodPost,
path: oidc.WellKnownEndpointPath,
wantStatus: http.StatusMethodNotAllowed,
wantBody: map[string]string{
"error": "Method not allowed (try GET)",
},
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
handler := New(test.issuer)
req := httptest.NewRequest(test.method, test.path, nil)
rsp := httptest.NewRecorder()
handler.ServeHTTP(rsp, req)
require.Equal(t, test.wantStatus, rsp.Code)
if test.wantContentType != "" {
require.Equal(t, test.wantContentType, rsp.Header().Get("Content-Type"))
}
if test.wantBody != nil {
wantJSON, err := json.Marshal(test.wantBody)
require.NoError(t, err)
require.JSONEq(t, string(wantJSON), rsp.Body.String())
}
})
}
}

12
internal/oidc/oidc.go Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package oidc contains common OIDC functionality needed by Pinniped.
package oidc
const (
WellKnownEndpointPath = "/.well-known/openid-configuration"
AuthorizationEndpointPath = "/oauth2/authorize"
TokenEndpointPath = "/oauth2/token" //nolint:gosec // ignore lint warning that this is a credential
JWKSEndpointPath = "/jwks.json"
)

View File

@ -0,0 +1,77 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package manager
import (
"net/http"
"sync"
"k8s.io/klog/v2"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/discovery"
"go.pinniped.dev/internal/oidc/provider"
)
// Manager can manage multiple active OIDC providers. It acts as a request router for them.
//
// It is thread-safe.
type Manager struct {
mu sync.RWMutex
providers []*provider.OIDCProvider
providerHandlers map[string]http.Handler // map of all routes for all providers
nextHandler http.Handler // the next handler in a chain, called when this manager didn't know how to handle a request
}
// NewManager returns an empty Manager.
// nextHandler will be invoked for any requests that could not be handled by this manager's providers.
func NewManager(nextHandler http.Handler) *Manager {
return &Manager{providerHandlers: make(map[string]http.Handler), nextHandler: nextHandler}
}
// SetProviders adds or updates all the given providerHandlers using each provider's issuer string
// as the name of the provider to decide if it is an add or update operation.
//
// It also removes any providerHandlers that were previously added but were not passed in to
// the current invocation.
//
// This method assumes that all of the OIDCProvider arguments have already been validated
// by someone else before they are passed to this method.
func (m *Manager) SetProviders(oidcProviders ...*provider.OIDCProvider) {
m.mu.Lock()
defer m.mu.Unlock()
m.providers = oidcProviders
m.providerHandlers = make(map[string]http.Handler)
for _, incomingProvider := range oidcProviders {
m.providerHandlers[incomingProvider.IssuerHost()+"/"+incomingProvider.IssuerPath()+oidc.WellKnownEndpointPath] = discovery.New(incomingProvider.Issuer())
klog.InfoS("oidc provider manager added or updated issuer", "issuer", incomingProvider.Issuer())
}
}
// ServeHTTP implements the http.Handler interface.
func (m *Manager) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
requestHandler := m.findHandler(req)
klog.InfoS(
"oidc provider manager examining request",
"method", req.Method,
"host", req.Host,
"path", req.URL.Path,
"foundMatchingIssuer", requestHandler != nil,
)
if requestHandler == nil {
requestHandler = m.nextHandler // couldn't find an issuer to handle the request
}
requestHandler.ServeHTTP(resp, req)
}
func (m *Manager) findHandler(req *http.Request) http.Handler {
m.mu.RLock()
defer m.mu.RUnlock()
return m.providerHandlers[req.Host+"/"+req.URL.Path]
}

View File

@ -0,0 +1,123 @@
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package manager
import (
"encoding/json"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/sclevine/spec"
"github.com/stretchr/testify/require"
"go.pinniped.dev/internal/oidc"
"go.pinniped.dev/internal/oidc/discovery"
"go.pinniped.dev/internal/oidc/provider"
)
func TestManager(t *testing.T) {
spec.Run(t, "ServeHTTP", func(t *testing.T, when spec.G, it spec.S) {
var r *require.Assertions
var subject *Manager
var nextHandler http.HandlerFunc
var fallbackHandlerWasCalled bool
newGetRequest := func(url string) *http.Request {
return httptest.NewRequest(http.MethodGet, url, nil)
}
requireDiscoveryRequestToBeHandled := func(issuer, requestURLSuffix string) {
recorder := httptest.NewRecorder()
subject.ServeHTTP(recorder, newGetRequest(issuer+oidc.WellKnownEndpointPath+requestURLSuffix))
r.Equal(http.StatusOK, recorder.Code)
responseBody, err := ioutil.ReadAll(recorder.Body)
r.NoError(err)
parsedDiscoveryResult := discovery.Metadata{}
err = json.Unmarshal(responseBody, &parsedDiscoveryResult)
r.NoError(err)
r.Equal(issuer, parsedDiscoveryResult.Issuer)
}
it.Before(func() {
r = require.New(t)
nextHandler = func(http.ResponseWriter, *http.Request) {
fallbackHandlerWasCalled = true
}
subject = NewManager(nextHandler)
})
when("given no providers", func() {
it("sends all requests to the nextHandler", func() {
r.False(fallbackHandlerWasCalled)
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest("/anything"))
r.True(fallbackHandlerWasCalled)
})
})
when("given some valid providers", func() {
issuer1 := "https://example.com/some/path"
issuer2 := "https://example.com/some/path/more/deeply/nested/path" // note that this is a sub-path of the other issuer url
it.Before(func() {
p1, err := provider.NewOIDCProvider(issuer1)
r.NoError(err)
p2, err := provider.NewOIDCProvider(issuer2)
r.NoError(err)
subject.SetProviders(p1, p2)
})
it("sends all non-matching host requests to the nextHandler", func() {
r.False(fallbackHandlerWasCalled)
url := strings.ReplaceAll(issuer1+oidc.WellKnownEndpointPath, "example.com", "wrong-host.com")
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(url))
r.True(fallbackHandlerWasCalled)
})
it("sends all non-matching path requests to the nextHandler", func() {
r.False(fallbackHandlerWasCalled)
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest("https://example.com/path-does-not-match-any-provider"))
r.True(fallbackHandlerWasCalled)
})
it("sends requests which match the issuer prefix but do not match any of that provider's known paths to the nextHandler", func() {
r.False(fallbackHandlerWasCalled)
subject.ServeHTTP(httptest.NewRecorder(), newGetRequest(issuer1+"/unhandled-sub-path"))
r.True(fallbackHandlerWasCalled)
})
it("routes matching requests to the appropriate provider", func() {
requireDiscoveryRequestToBeHandled(issuer1, "")
requireDiscoveryRequestToBeHandled(issuer2, "")
requireDiscoveryRequestToBeHandled(issuer2, "?some=query")
r.False(fallbackHandlerWasCalled)
})
})
when("given the same valid providers in reverse order", func() {
issuer1 := "https://example.com/some/path"
issuer2 := "https://example.com/some/path/more/deeply/nested/path"
it.Before(func() {
p1, err := provider.NewOIDCProvider(issuer1)
r.NoError(err)
p2, err := provider.NewOIDCProvider(issuer2)
r.NoError(err)
subject.SetProviders(p2, p1)
})
it("still routes matching requests to the appropriate provider", func() {
requireDiscoveryRequestToBeHandled(issuer1, "")
requireDiscoveryRequestToBeHandled(issuer2, "")
requireDiscoveryRequestToBeHandled(issuer2, "?some=query")
r.False(fallbackHandlerWasCalled)
})
})
})
}

Some files were not shown because too many files have changed in this diff Show More