Merge pull request #626 from vmware-tanzu/credentialissuer-spec-api
Add spec fields to Credentialissuer API to configure impersonation proxy behavior
This commit is contained in:
commit
a39b328778
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -21,7 +21,8 @@ spec:
|
|||||||
- name: v1alpha1
|
- name: v1alpha1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Describes the configuration status of a Pinniped credential issuer.
|
description: CredentialIssuer describes the configuration and status of the
|
||||||
|
Pinniped Concierge credential issuer.
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
@ -35,8 +36,73 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Spec describes the intended configuration of the Concierge.
|
||||||
|
properties:
|
||||||
|
impersonationProxy:
|
||||||
|
description: ImpersonationProxy describes the intended configuration
|
||||||
|
of the Concierge impersonation proxy.
|
||||||
|
properties:
|
||||||
|
externalEndpoint:
|
||||||
|
description: "ExternalEndpoint describes the HTTPS endpoint where
|
||||||
|
the proxy will be exposed. If not set, the proxy will be served
|
||||||
|
using the external name of the LoadBalancer service or the cluster
|
||||||
|
service DNS name. \n This field must be non-empty when spec.impersonationProxy.service.mode
|
||||||
|
is \"None\"."
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
description: 'Mode configures whether the impersonation proxy
|
||||||
|
should be started: - "disabled" explicitly disables the impersonation
|
||||||
|
proxy. This is the default. - "enabled" explicitly enables the
|
||||||
|
impersonation proxy. - "auto" enables or disables the impersonation
|
||||||
|
proxy based upon the cluster in which it is running.'
|
||||||
|
enum:
|
||||||
|
- auto
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
type: string
|
||||||
|
service:
|
||||||
|
default:
|
||||||
|
type: LoadBalancer
|
||||||
|
description: Service describes the configuration of the Service
|
||||||
|
provisioned to expose the impersonation proxy to clients.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Annotations specifies zero or more key/value
|
||||||
|
pairs to set as annotations on the provisioned Service.
|
||||||
|
type: object
|
||||||
|
loadBalancerIP:
|
||||||
|
description: LoadBalancerIP specifies the IP address to set
|
||||||
|
in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
This is not supported on all cloud providers.
|
||||||
|
maxLength: 255
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
default: LoadBalancer
|
||||||
|
description: "Type specifies the type of Service to provision
|
||||||
|
for the impersonation proxy. \n If the type is \"None\",
|
||||||
|
then the \"spec.impersonationProxy.externalEndpoint\" field
|
||||||
|
must be set to a non-empty value so that the Concierge can
|
||||||
|
properly advertise the endpoint in the CredentialIssuer's
|
||||||
|
status."
|
||||||
|
enum:
|
||||||
|
- LoadBalancer
|
||||||
|
- ClusterIP
|
||||||
|
- None
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- mode
|
||||||
|
- service
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- impersonationProxy
|
||||||
|
type: object
|
||||||
status:
|
status:
|
||||||
description: Status of the credential issuer.
|
description: CredentialIssuerStatus describes the status of the Concierge.
|
||||||
properties:
|
properties:
|
||||||
kubeConfigInfo:
|
kubeConfigInfo:
|
||||||
description: Information needed to form a valid Pinniped-based kubeconfig
|
description: Information needed to form a valid Pinniped-based kubeconfig
|
||||||
@ -60,8 +126,8 @@ spec:
|
|||||||
description: List of integration strategies that were attempted by
|
description: List of integration strategies that were attempted by
|
||||||
Pinniped.
|
Pinniped.
|
||||||
items:
|
items:
|
||||||
description: Status of an integration strategy that was attempted
|
description: CredentialIssuerStrategy describes the status of an
|
||||||
by Pinniped.
|
integration strategy that was attempted by Pinniped.
|
||||||
properties:
|
properties:
|
||||||
frontend:
|
frontend:
|
||||||
description: Frontend describes how clients can connect using
|
description: Frontend describes how clients can connect using
|
||||||
|
@ -49,8 +49,8 @@ data:
|
|||||||
servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @)
|
servingCertificateSecret: (@= defaultResourceNameWithSuffix("api-tls-serving-certificate") @)
|
||||||
credentialIssuer: (@= defaultResourceNameWithSuffix("config") @)
|
credentialIssuer: (@= defaultResourceNameWithSuffix("config") @)
|
||||||
apiService: (@= defaultResourceNameWithSuffix("api") @)
|
apiService: (@= defaultResourceNameWithSuffix("api") @)
|
||||||
impersonationConfigMap: (@= defaultResourceNameWithSuffix("impersonation-proxy-config") @)
|
|
||||||
impersonationLoadBalancerService: (@= defaultResourceNameWithSuffix("impersonation-proxy-load-balancer") @)
|
impersonationLoadBalancerService: (@= defaultResourceNameWithSuffix("impersonation-proxy-load-balancer") @)
|
||||||
|
impersonationClusterIPService: (@= defaultResourceNameWithSuffix("impersonation-proxy-cluster-ip") @)
|
||||||
impersonationTLSCertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-tls-serving-certificate") @)
|
impersonationTLSCertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-tls-serving-certificate") @)
|
||||||
impersonationCACertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-ca-certificate") @)
|
impersonationCACertificateSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-ca-certificate") @)
|
||||||
impersonationSignerSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-signer-ca-certificate") @)
|
impersonationSignerSecret: (@= defaultResourceNameWithSuffix("impersonation-proxy-signer-ca-certificate") @)
|
||||||
@ -253,3 +253,15 @@ kind: CredentialIssuer
|
|||||||
metadata:
|
metadata:
|
||||||
name: #@ defaultResourceNameWithSuffix("config")
|
name: #@ defaultResourceNameWithSuffix("config")
|
||||||
labels: #@ labels()
|
labels: #@ labels()
|
||||||
|
spec:
|
||||||
|
impersonationProxy:
|
||||||
|
mode: #@ data.values.impersonation_proxy_spec.mode
|
||||||
|
#@ if data.values.impersonation_proxy_spec.external_endpoint:
|
||||||
|
externalEndpoint: #@ data.values.impersonation_proxy_spec.external_endpoint
|
||||||
|
#@ end
|
||||||
|
service:
|
||||||
|
mode: #@ data.values.impersonation_proxy_spec.service.mode
|
||||||
|
#@ if data.values.impersonation_proxy_spec.service.load_balancer_ip:
|
||||||
|
loadBalancerIP: #@ data.values.impersonation_proxy_spec.service.load_balancer_ip
|
||||||
|
#@ end
|
||||||
|
annotations: #@ data.values.impersonation_proxy_spec.service.annotations
|
||||||
|
@ -63,3 +63,33 @@ run_as_group: 1001 #! run_as_group specifies the group ID that will own the proc
|
|||||||
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
|
#! authentication.concierge.pinniped.dev, etc. As an example, if this is set to tuna.io, then
|
||||||
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
|
#! Pinniped API groups will look like foo.tuna.io. authentication.concierge.tuna.io, etc.
|
||||||
api_group_suffix: pinniped.dev
|
api_group_suffix: pinniped.dev
|
||||||
|
|
||||||
|
#! Customize CredentialIssuer.spec.impersonationProxy to change how the concierge
|
||||||
|
#! handles impersonation.
|
||||||
|
impersonation_proxy_spec:
|
||||||
|
#! options are "auto", "disabled" or "enabled".
|
||||||
|
#! If auto, the impersonation proxy will run only if the cluster signing key is not available
|
||||||
|
#! and the other strategy does not work.
|
||||||
|
#! If disabled, the impersonation proxy will never run, which could mean that the concierge
|
||||||
|
#! doesn't work at all.
|
||||||
|
#! If enabled, the impersonation proxy will always run regardless of other strategies available.
|
||||||
|
mode: auto
|
||||||
|
#! The endpoint which the client should use to connect to the impersonation proxy.
|
||||||
|
#! If left unset, the client will default to connecting based on the ClusterIP or LoadBalancer
|
||||||
|
#! endpoint.
|
||||||
|
external_endpoint:
|
||||||
|
service:
|
||||||
|
#! Options are "LoadBalancer", "ClusterIP" and "None".
|
||||||
|
#! LoadBalancer automatically provisions a Service of type LoadBalancer pointing at
|
||||||
|
#! the impersonation proxy. Some cloud providers will allocate
|
||||||
|
#! a public IP address by default even on private clusters.
|
||||||
|
#! ClusterIP automatically provisions a Service of type ClusterIP pointing at the
|
||||||
|
#! impersonation proxy.
|
||||||
|
#! None does not provision either and assumes that you have set the external_endpoint
|
||||||
|
#! and set up your own ingress to connect to the impersonation proxy.
|
||||||
|
mode: LoadBalancer
|
||||||
|
#! The annotations that should be set on the ClusterIP or LoadBalancer Service.
|
||||||
|
annotations:
|
||||||
|
{service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "4000"}
|
||||||
|
#! When mode LoadBalancer is set, this will set the LoadBalancer Service's Spec.LoadBalancerIP.
|
||||||
|
load_balancer_ip:
|
||||||
|
88
generated/1.17/README.adoc
generated
88
generated/1.17/README.adoc
generated
@ -220,7 +220,7 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge configuration
|
|||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuer"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuer"]
|
||||||
==== CredentialIssuer
|
==== CredentialIssuer
|
||||||
|
|
||||||
Describes the configuration status of a Pinniped credential issuer.
|
CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -232,7 +232,8 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
| Field | Description
|
| 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`.
|
| *`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`.
|
||||||
|
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | Status of the credential issuer.
|
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]__ | Spec describes the intended configuration of the Concierge.
|
||||||
|
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -275,10 +276,27 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerspec"]
|
||||||
|
==== CredentialIssuerSpec
|
||||||
|
|
||||||
|
CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuer[$$CredentialIssuer$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`impersonationProxy`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]__ | ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
||||||
==== CredentialIssuerStatus
|
==== CredentialIssuerStatus
|
||||||
|
|
||||||
Status of a credential issuer.
|
CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -333,6 +351,70 @@ Status of a credential issuer.
|
|||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxymode"]
|
||||||
|
==== ImpersonationProxyMode (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyservicespec"]
|
||||||
|
==== ImpersonationProxyServiceSpec
|
||||||
|
|
||||||
|
ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`type`* __ImpersonationProxyServiceType__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||||
|
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyservicetype"]
|
||||||
|
==== ImpersonationProxyServiceType (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyspec"]
|
||||||
|
==== ImpersonationProxySpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`mode`* __ImpersonationProxyMode__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
||||||
==== TokenCredentialRequestAPIInfo
|
==== TokenCredentialRequestAPIInfo
|
||||||
|
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -16,6 +16,7 @@ func (in *CredentialIssuer) DeepCopyInto(out *CredentialIssuer) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,6 +114,27 @@ func (in *CredentialIssuerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopyInto(out *CredentialIssuerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImpersonationProxy != nil {
|
||||||
|
in, out := &in.ImpersonationProxy, &out.ImpersonationProxy
|
||||||
|
*out = new(ImpersonationProxySpec)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerSpec.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopy() *CredentialIssuerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialIssuerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -179,6 +201,46 @@ func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxyServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyServiceSpec.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopy() *ImpersonationProxyServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxyServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopyInto(out *ImpersonationProxySpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Service.DeepCopyInto(&out.Service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxySpec.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopy() *ImpersonationProxySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -21,7 +21,8 @@ spec:
|
|||||||
- name: v1alpha1
|
- name: v1alpha1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Describes the configuration status of a Pinniped credential issuer.
|
description: CredentialIssuer describes the configuration and status of the
|
||||||
|
Pinniped Concierge credential issuer.
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
@ -35,8 +36,73 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Spec describes the intended configuration of the Concierge.
|
||||||
|
properties:
|
||||||
|
impersonationProxy:
|
||||||
|
description: ImpersonationProxy describes the intended configuration
|
||||||
|
of the Concierge impersonation proxy.
|
||||||
|
properties:
|
||||||
|
externalEndpoint:
|
||||||
|
description: "ExternalEndpoint describes the HTTPS endpoint where
|
||||||
|
the proxy will be exposed. If not set, the proxy will be served
|
||||||
|
using the external name of the LoadBalancer service or the cluster
|
||||||
|
service DNS name. \n This field must be non-empty when spec.impersonationProxy.service.mode
|
||||||
|
is \"None\"."
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
description: 'Mode configures whether the impersonation proxy
|
||||||
|
should be started: - "disabled" explicitly disables the impersonation
|
||||||
|
proxy. This is the default. - "enabled" explicitly enables the
|
||||||
|
impersonation proxy. - "auto" enables or disables the impersonation
|
||||||
|
proxy based upon the cluster in which it is running.'
|
||||||
|
enum:
|
||||||
|
- auto
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
type: string
|
||||||
|
service:
|
||||||
|
default:
|
||||||
|
type: LoadBalancer
|
||||||
|
description: Service describes the configuration of the Service
|
||||||
|
provisioned to expose the impersonation proxy to clients.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Annotations specifies zero or more key/value
|
||||||
|
pairs to set as annotations on the provisioned Service.
|
||||||
|
type: object
|
||||||
|
loadBalancerIP:
|
||||||
|
description: LoadBalancerIP specifies the IP address to set
|
||||||
|
in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
This is not supported on all cloud providers.
|
||||||
|
maxLength: 255
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
default: LoadBalancer
|
||||||
|
description: "Type specifies the type of Service to provision
|
||||||
|
for the impersonation proxy. \n If the type is \"None\",
|
||||||
|
then the \"spec.impersonationProxy.externalEndpoint\" field
|
||||||
|
must be set to a non-empty value so that the Concierge can
|
||||||
|
properly advertise the endpoint in the CredentialIssuer's
|
||||||
|
status."
|
||||||
|
enum:
|
||||||
|
- LoadBalancer
|
||||||
|
- ClusterIP
|
||||||
|
- None
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- mode
|
||||||
|
- service
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- impersonationProxy
|
||||||
|
type: object
|
||||||
status:
|
status:
|
||||||
description: Status of the credential issuer.
|
description: CredentialIssuerStatus describes the status of the Concierge.
|
||||||
properties:
|
properties:
|
||||||
kubeConfigInfo:
|
kubeConfigInfo:
|
||||||
description: Information needed to form a valid Pinniped-based kubeconfig
|
description: Information needed to form a valid Pinniped-based kubeconfig
|
||||||
@ -60,8 +126,8 @@ spec:
|
|||||||
description: List of integration strategies that were attempted by
|
description: List of integration strategies that were attempted by
|
||||||
Pinniped.
|
Pinniped.
|
||||||
items:
|
items:
|
||||||
description: Status of an integration strategy that was attempted
|
description: CredentialIssuerStrategy describes the status of an
|
||||||
by Pinniped.
|
integration strategy that was attempted by Pinniped.
|
||||||
properties:
|
properties:
|
||||||
frontend:
|
frontend:
|
||||||
description: Frontend describes how clients can connect using
|
description: Frontend describes how clients can connect using
|
||||||
|
88
generated/1.18/README.adoc
generated
88
generated/1.18/README.adoc
generated
@ -220,7 +220,7 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge configuration
|
|||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuer"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuer"]
|
||||||
==== CredentialIssuer
|
==== CredentialIssuer
|
||||||
|
|
||||||
Describes the configuration status of a Pinniped credential issuer.
|
CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -232,7 +232,8 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
| Field | Description
|
| 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`.
|
| *`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`.
|
||||||
|
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | Status of the credential issuer.
|
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]__ | Spec describes the intended configuration of the Concierge.
|
||||||
|
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -275,10 +276,27 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerspec"]
|
||||||
|
==== CredentialIssuerSpec
|
||||||
|
|
||||||
|
CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuer[$$CredentialIssuer$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`impersonationProxy`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]__ | ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
||||||
==== CredentialIssuerStatus
|
==== CredentialIssuerStatus
|
||||||
|
|
||||||
Status of a credential issuer.
|
CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -333,6 +351,70 @@ Status of a credential issuer.
|
|||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxymode"]
|
||||||
|
==== ImpersonationProxyMode (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyservicespec"]
|
||||||
|
==== ImpersonationProxyServiceSpec
|
||||||
|
|
||||||
|
ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`type`* __ImpersonationProxyServiceType__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||||
|
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyservicetype"]
|
||||||
|
==== ImpersonationProxyServiceType (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyspec"]
|
||||||
|
==== ImpersonationProxySpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`mode`* __ImpersonationProxyMode__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
||||||
==== TokenCredentialRequestAPIInfo
|
==== TokenCredentialRequestAPIInfo
|
||||||
|
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -16,6 +16,7 @@ func (in *CredentialIssuer) DeepCopyInto(out *CredentialIssuer) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,6 +114,27 @@ func (in *CredentialIssuerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopyInto(out *CredentialIssuerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImpersonationProxy != nil {
|
||||||
|
in, out := &in.ImpersonationProxy, &out.ImpersonationProxy
|
||||||
|
*out = new(ImpersonationProxySpec)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerSpec.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopy() *CredentialIssuerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialIssuerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -179,6 +201,46 @@ func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxyServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyServiceSpec.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopy() *ImpersonationProxyServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxyServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopyInto(out *ImpersonationProxySpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Service.DeepCopyInto(&out.Service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxySpec.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopy() *ImpersonationProxySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -21,7 +21,8 @@ spec:
|
|||||||
- name: v1alpha1
|
- name: v1alpha1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Describes the configuration status of a Pinniped credential issuer.
|
description: CredentialIssuer describes the configuration and status of the
|
||||||
|
Pinniped Concierge credential issuer.
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
@ -35,8 +36,73 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Spec describes the intended configuration of the Concierge.
|
||||||
|
properties:
|
||||||
|
impersonationProxy:
|
||||||
|
description: ImpersonationProxy describes the intended configuration
|
||||||
|
of the Concierge impersonation proxy.
|
||||||
|
properties:
|
||||||
|
externalEndpoint:
|
||||||
|
description: "ExternalEndpoint describes the HTTPS endpoint where
|
||||||
|
the proxy will be exposed. If not set, the proxy will be served
|
||||||
|
using the external name of the LoadBalancer service or the cluster
|
||||||
|
service DNS name. \n This field must be non-empty when spec.impersonationProxy.service.mode
|
||||||
|
is \"None\"."
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
description: 'Mode configures whether the impersonation proxy
|
||||||
|
should be started: - "disabled" explicitly disables the impersonation
|
||||||
|
proxy. This is the default. - "enabled" explicitly enables the
|
||||||
|
impersonation proxy. - "auto" enables or disables the impersonation
|
||||||
|
proxy based upon the cluster in which it is running.'
|
||||||
|
enum:
|
||||||
|
- auto
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
type: string
|
||||||
|
service:
|
||||||
|
default:
|
||||||
|
type: LoadBalancer
|
||||||
|
description: Service describes the configuration of the Service
|
||||||
|
provisioned to expose the impersonation proxy to clients.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Annotations specifies zero or more key/value
|
||||||
|
pairs to set as annotations on the provisioned Service.
|
||||||
|
type: object
|
||||||
|
loadBalancerIP:
|
||||||
|
description: LoadBalancerIP specifies the IP address to set
|
||||||
|
in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
This is not supported on all cloud providers.
|
||||||
|
maxLength: 255
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
default: LoadBalancer
|
||||||
|
description: "Type specifies the type of Service to provision
|
||||||
|
for the impersonation proxy. \n If the type is \"None\",
|
||||||
|
then the \"spec.impersonationProxy.externalEndpoint\" field
|
||||||
|
must be set to a non-empty value so that the Concierge can
|
||||||
|
properly advertise the endpoint in the CredentialIssuer's
|
||||||
|
status."
|
||||||
|
enum:
|
||||||
|
- LoadBalancer
|
||||||
|
- ClusterIP
|
||||||
|
- None
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- mode
|
||||||
|
- service
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- impersonationProxy
|
||||||
|
type: object
|
||||||
status:
|
status:
|
||||||
description: Status of the credential issuer.
|
description: CredentialIssuerStatus describes the status of the Concierge.
|
||||||
properties:
|
properties:
|
||||||
kubeConfigInfo:
|
kubeConfigInfo:
|
||||||
description: Information needed to form a valid Pinniped-based kubeconfig
|
description: Information needed to form a valid Pinniped-based kubeconfig
|
||||||
@ -60,8 +126,8 @@ spec:
|
|||||||
description: List of integration strategies that were attempted by
|
description: List of integration strategies that were attempted by
|
||||||
Pinniped.
|
Pinniped.
|
||||||
items:
|
items:
|
||||||
description: Status of an integration strategy that was attempted
|
description: CredentialIssuerStrategy describes the status of an
|
||||||
by Pinniped.
|
integration strategy that was attempted by Pinniped.
|
||||||
properties:
|
properties:
|
||||||
frontend:
|
frontend:
|
||||||
description: Frontend describes how clients can connect using
|
description: Frontend describes how clients can connect using
|
||||||
|
88
generated/1.19/README.adoc
generated
88
generated/1.19/README.adoc
generated
@ -220,7 +220,7 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge configuration
|
|||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuer"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuer"]
|
||||||
==== CredentialIssuer
|
==== CredentialIssuer
|
||||||
|
|
||||||
Describes the configuration status of a Pinniped credential issuer.
|
CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -232,7 +232,8 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
| Field | Description
|
| 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`.
|
| *`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`.
|
||||||
|
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | Status of the credential issuer.
|
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]__ | Spec describes the intended configuration of the Concierge.
|
||||||
|
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -275,10 +276,27 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerspec"]
|
||||||
|
==== CredentialIssuerSpec
|
||||||
|
|
||||||
|
CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuer[$$CredentialIssuer$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`impersonationProxy`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]__ | ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
||||||
==== CredentialIssuerStatus
|
==== CredentialIssuerStatus
|
||||||
|
|
||||||
Status of a credential issuer.
|
CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -333,6 +351,70 @@ Status of a credential issuer.
|
|||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxymode"]
|
||||||
|
==== ImpersonationProxyMode (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyservicespec"]
|
||||||
|
==== ImpersonationProxyServiceSpec
|
||||||
|
|
||||||
|
ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`type`* __ImpersonationProxyServiceType__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||||
|
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyservicetype"]
|
||||||
|
==== ImpersonationProxyServiceType (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyspec"]
|
||||||
|
==== ImpersonationProxySpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`mode`* __ImpersonationProxyMode__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
||||||
==== TokenCredentialRequestAPIInfo
|
==== TokenCredentialRequestAPIInfo
|
||||||
|
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -16,6 +16,7 @@ func (in *CredentialIssuer) DeepCopyInto(out *CredentialIssuer) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,6 +114,27 @@ func (in *CredentialIssuerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopyInto(out *CredentialIssuerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImpersonationProxy != nil {
|
||||||
|
in, out := &in.ImpersonationProxy, &out.ImpersonationProxy
|
||||||
|
*out = new(ImpersonationProxySpec)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerSpec.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopy() *CredentialIssuerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialIssuerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -179,6 +201,46 @@ func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxyServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyServiceSpec.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopy() *ImpersonationProxyServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxyServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopyInto(out *ImpersonationProxySpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Service.DeepCopyInto(&out.Service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxySpec.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopy() *ImpersonationProxySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -21,7 +21,8 @@ spec:
|
|||||||
- name: v1alpha1
|
- name: v1alpha1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Describes the configuration status of a Pinniped credential issuer.
|
description: CredentialIssuer describes the configuration and status of the
|
||||||
|
Pinniped Concierge credential issuer.
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
@ -35,8 +36,73 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Spec describes the intended configuration of the Concierge.
|
||||||
|
properties:
|
||||||
|
impersonationProxy:
|
||||||
|
description: ImpersonationProxy describes the intended configuration
|
||||||
|
of the Concierge impersonation proxy.
|
||||||
|
properties:
|
||||||
|
externalEndpoint:
|
||||||
|
description: "ExternalEndpoint describes the HTTPS endpoint where
|
||||||
|
the proxy will be exposed. If not set, the proxy will be served
|
||||||
|
using the external name of the LoadBalancer service or the cluster
|
||||||
|
service DNS name. \n This field must be non-empty when spec.impersonationProxy.service.mode
|
||||||
|
is \"None\"."
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
description: 'Mode configures whether the impersonation proxy
|
||||||
|
should be started: - "disabled" explicitly disables the impersonation
|
||||||
|
proxy. This is the default. - "enabled" explicitly enables the
|
||||||
|
impersonation proxy. - "auto" enables or disables the impersonation
|
||||||
|
proxy based upon the cluster in which it is running.'
|
||||||
|
enum:
|
||||||
|
- auto
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
type: string
|
||||||
|
service:
|
||||||
|
default:
|
||||||
|
type: LoadBalancer
|
||||||
|
description: Service describes the configuration of the Service
|
||||||
|
provisioned to expose the impersonation proxy to clients.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Annotations specifies zero or more key/value
|
||||||
|
pairs to set as annotations on the provisioned Service.
|
||||||
|
type: object
|
||||||
|
loadBalancerIP:
|
||||||
|
description: LoadBalancerIP specifies the IP address to set
|
||||||
|
in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
This is not supported on all cloud providers.
|
||||||
|
maxLength: 255
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
default: LoadBalancer
|
||||||
|
description: "Type specifies the type of Service to provision
|
||||||
|
for the impersonation proxy. \n If the type is \"None\",
|
||||||
|
then the \"spec.impersonationProxy.externalEndpoint\" field
|
||||||
|
must be set to a non-empty value so that the Concierge can
|
||||||
|
properly advertise the endpoint in the CredentialIssuer's
|
||||||
|
status."
|
||||||
|
enum:
|
||||||
|
- LoadBalancer
|
||||||
|
- ClusterIP
|
||||||
|
- None
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- mode
|
||||||
|
- service
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- impersonationProxy
|
||||||
|
type: object
|
||||||
status:
|
status:
|
||||||
description: Status of the credential issuer.
|
description: CredentialIssuerStatus describes the status of the Concierge.
|
||||||
properties:
|
properties:
|
||||||
kubeConfigInfo:
|
kubeConfigInfo:
|
||||||
description: Information needed to form a valid Pinniped-based kubeconfig
|
description: Information needed to form a valid Pinniped-based kubeconfig
|
||||||
@ -60,8 +126,8 @@ spec:
|
|||||||
description: List of integration strategies that were attempted by
|
description: List of integration strategies that were attempted by
|
||||||
Pinniped.
|
Pinniped.
|
||||||
items:
|
items:
|
||||||
description: Status of an integration strategy that was attempted
|
description: CredentialIssuerStrategy describes the status of an
|
||||||
by Pinniped.
|
integration strategy that was attempted by Pinniped.
|
||||||
properties:
|
properties:
|
||||||
frontend:
|
frontend:
|
||||||
description: Frontend describes how clients can connect using
|
description: Frontend describes how clients can connect using
|
||||||
|
88
generated/1.20/README.adoc
generated
88
generated/1.20/README.adoc
generated
@ -220,7 +220,7 @@ Package v1alpha1 is the v1alpha1 version of the Pinniped concierge configuration
|
|||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuer"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuer"]
|
||||||
==== CredentialIssuer
|
==== CredentialIssuer
|
||||||
|
|
||||||
Describes the configuration status of a Pinniped credential issuer.
|
CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -232,7 +232,8 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
| Field | Description
|
| Field | Description
|
||||||
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.2/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
| *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.2/#objectmeta-v1-meta[$$ObjectMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`.
|
||||||
|
|
||||||
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | Status of the credential issuer.
|
| *`spec`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]__ | Spec describes the intended configuration of the Concierge.
|
||||||
|
| *`status`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$]__ | CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
@ -275,10 +276,27 @@ Describes the configuration status of a Pinniped credential issuer.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerspec"]
|
||||||
|
==== CredentialIssuerSpec
|
||||||
|
|
||||||
|
CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuer[$$CredentialIssuer$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`impersonationProxy`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]__ | ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstatus"]
|
||||||
==== CredentialIssuerStatus
|
==== CredentialIssuerStatus
|
||||||
|
|
||||||
Status of a credential issuer.
|
CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
|
||||||
.Appears In:
|
.Appears In:
|
||||||
****
|
****
|
||||||
@ -333,6 +351,70 @@ Status of a credential issuer.
|
|||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxymode"]
|
||||||
|
==== ImpersonationProxyMode (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyservicespec"]
|
||||||
|
==== ImpersonationProxyServiceSpec
|
||||||
|
|
||||||
|
ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyspec[$$ImpersonationProxySpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`type`* __ImpersonationProxyServiceType__ | Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
| *`loadBalancerIP`* __string__ | LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service. This is not supported on all cloud providers.
|
||||||
|
| *`annotations`* __object (keys:string, values:string)__ | Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyservicetype"]
|
||||||
|
==== ImpersonationProxyServiceType (string)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyspec"]
|
||||||
|
==== ImpersonationProxySpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.Appears In:
|
||||||
|
****
|
||||||
|
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerspec[$$CredentialIssuerSpec$$]
|
||||||
|
****
|
||||||
|
|
||||||
|
[cols="25a,75a", options="header"]
|
||||||
|
|===
|
||||||
|
| Field | Description
|
||||||
|
| *`mode`* __ImpersonationProxyMode__ | Mode configures whether the impersonation proxy should be started: - "disabled" explicitly disables the impersonation proxy. This is the default. - "enabled" explicitly enables the impersonation proxy. - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
| *`service`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyservicespec[$$ImpersonationProxyServiceSpec$$]__ | Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
| *`externalEndpoint`* __string__ | ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
|===
|
||||||
|
|
||||||
|
|
||||||
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"]
|
||||||
==== TokenCredentialRequestAPIInfo
|
==== TokenCredentialRequestAPIInfo
|
||||||
|
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -16,6 +16,7 @@ func (in *CredentialIssuer) DeepCopyInto(out *CredentialIssuer) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,6 +114,27 @@ func (in *CredentialIssuerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopyInto(out *CredentialIssuerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImpersonationProxy != nil {
|
||||||
|
in, out := &in.ImpersonationProxy, &out.ImpersonationProxy
|
||||||
|
*out = new(ImpersonationProxySpec)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerSpec.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopy() *CredentialIssuerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialIssuerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -179,6 +201,46 @@ func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxyServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyServiceSpec.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopy() *ImpersonationProxyServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxyServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopyInto(out *ImpersonationProxySpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Service.DeepCopyInto(&out.Service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxySpec.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopy() *ImpersonationProxySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -21,7 +21,8 @@ spec:
|
|||||||
- name: v1alpha1
|
- name: v1alpha1
|
||||||
schema:
|
schema:
|
||||||
openAPIV3Schema:
|
openAPIV3Schema:
|
||||||
description: Describes the configuration status of a Pinniped credential issuer.
|
description: CredentialIssuer describes the configuration and status of the
|
||||||
|
Pinniped Concierge credential issuer.
|
||||||
properties:
|
properties:
|
||||||
apiVersion:
|
apiVersion:
|
||||||
description: 'APIVersion defines the versioned schema of this representation
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
@ -35,8 +36,73 @@ spec:
|
|||||||
type: string
|
type: string
|
||||||
metadata:
|
metadata:
|
||||||
type: object
|
type: object
|
||||||
|
spec:
|
||||||
|
description: Spec describes the intended configuration of the Concierge.
|
||||||
|
properties:
|
||||||
|
impersonationProxy:
|
||||||
|
description: ImpersonationProxy describes the intended configuration
|
||||||
|
of the Concierge impersonation proxy.
|
||||||
|
properties:
|
||||||
|
externalEndpoint:
|
||||||
|
description: "ExternalEndpoint describes the HTTPS endpoint where
|
||||||
|
the proxy will be exposed. If not set, the proxy will be served
|
||||||
|
using the external name of the LoadBalancer service or the cluster
|
||||||
|
service DNS name. \n This field must be non-empty when spec.impersonationProxy.service.mode
|
||||||
|
is \"None\"."
|
||||||
|
type: string
|
||||||
|
mode:
|
||||||
|
description: 'Mode configures whether the impersonation proxy
|
||||||
|
should be started: - "disabled" explicitly disables the impersonation
|
||||||
|
proxy. This is the default. - "enabled" explicitly enables the
|
||||||
|
impersonation proxy. - "auto" enables or disables the impersonation
|
||||||
|
proxy based upon the cluster in which it is running.'
|
||||||
|
enum:
|
||||||
|
- auto
|
||||||
|
- enabled
|
||||||
|
- disabled
|
||||||
|
type: string
|
||||||
|
service:
|
||||||
|
default:
|
||||||
|
type: LoadBalancer
|
||||||
|
description: Service describes the configuration of the Service
|
||||||
|
provisioned to expose the impersonation proxy to clients.
|
||||||
|
properties:
|
||||||
|
annotations:
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
description: Annotations specifies zero or more key/value
|
||||||
|
pairs to set as annotations on the provisioned Service.
|
||||||
|
type: object
|
||||||
|
loadBalancerIP:
|
||||||
|
description: LoadBalancerIP specifies the IP address to set
|
||||||
|
in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
This is not supported on all cloud providers.
|
||||||
|
maxLength: 255
|
||||||
|
minLength: 1
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
default: LoadBalancer
|
||||||
|
description: "Type specifies the type of Service to provision
|
||||||
|
for the impersonation proxy. \n If the type is \"None\",
|
||||||
|
then the \"spec.impersonationProxy.externalEndpoint\" field
|
||||||
|
must be set to a non-empty value so that the Concierge can
|
||||||
|
properly advertise the endpoint in the CredentialIssuer's
|
||||||
|
status."
|
||||||
|
enum:
|
||||||
|
- LoadBalancer
|
||||||
|
- ClusterIP
|
||||||
|
- None
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- mode
|
||||||
|
- service
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- impersonationProxy
|
||||||
|
type: object
|
||||||
status:
|
status:
|
||||||
description: Status of the credential issuer.
|
description: CredentialIssuerStatus describes the status of the Concierge.
|
||||||
properties:
|
properties:
|
||||||
kubeConfigInfo:
|
kubeConfigInfo:
|
||||||
description: Information needed to form a valid Pinniped-based kubeconfig
|
description: Information needed to form a valid Pinniped-based kubeconfig
|
||||||
@ -60,8 +126,8 @@ spec:
|
|||||||
description: List of integration strategies that were attempted by
|
description: List of integration strategies that were attempted by
|
||||||
Pinniped.
|
Pinniped.
|
||||||
items:
|
items:
|
||||||
description: Status of an integration strategy that was attempted
|
description: CredentialIssuerStrategy describes the status of an
|
||||||
by Pinniped.
|
integration strategy that was attempted by Pinniped.
|
||||||
properties:
|
properties:
|
||||||
frontend:
|
frontend:
|
||||||
description: Frontend describes how clients can connect using
|
description: Frontend describes how clients can connect using
|
||||||
|
@ -3,17 +3,23 @@
|
|||||||
|
|
||||||
package v1alpha1
|
package v1alpha1
|
||||||
|
|
||||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StrategyType enumerates a type of "strategy" used to implement credential access on a cluster.
|
||||||
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate;ImpersonationProxy
|
||||||
type StrategyType string
|
type StrategyType string
|
||||||
|
|
||||||
|
// FrontendType enumerates a type of "frontend" used to provide access to users of a cluster.
|
||||||
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI;ImpersonationProxy
|
||||||
type FrontendType string
|
type FrontendType string
|
||||||
|
|
||||||
|
// StrategyStatus enumerates whether a strategy is working on a cluster.
|
||||||
// +kubebuilder:validation:Enum=Success;Error
|
// +kubebuilder:validation:Enum=Success;Error
|
||||||
type StrategyStatus string
|
type StrategyStatus string
|
||||||
|
|
||||||
|
// StrategyReason enumerates the detailed reason why a strategy is in a particular status.
|
||||||
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
// +kubebuilder:validation:Enum=Listening;Pending;Disabled;ErrorDuringSetup;CouldNotFetchKey;CouldNotGetClusterInfo;FetchedKey
|
||||||
type StrategyReason string
|
type StrategyReason string
|
||||||
|
|
||||||
@ -36,7 +42,91 @@ const (
|
|||||||
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
FetchedKeyStrategyReason = StrategyReason("FetchedKey")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Status of a credential issuer.
|
// CredentialIssuerSpec describes the intended configuration of the Concierge.
|
||||||
|
type CredentialIssuerSpec struct {
|
||||||
|
// ImpersonationProxy describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
ImpersonationProxy *ImpersonationProxySpec `json:"impersonationProxy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyMode enumerates the configuration modes for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=auto;enabled;disabled
|
||||||
|
type ImpersonationProxyMode string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyModeDisabled explicitly disables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeDisabled = ImpersonationProxyMode("disabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeEnabled explicitly enables the impersonation proxy.
|
||||||
|
ImpersonationProxyModeEnabled = ImpersonationProxyMode("enabled")
|
||||||
|
|
||||||
|
// ImpersonationProxyModeAuto enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
ImpersonationProxyModeAuto = ImpersonationProxyMode("auto")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceType enumerates the types of service that can be provisioned for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:Enum=LoadBalancer;ClusterIP;None
|
||||||
|
type ImpersonationProxyServiceType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ImpersonationProxyServiceTypeLoadBalancer provisions a service of type LoadBalancer.
|
||||||
|
ImpersonationProxyServiceTypeLoadBalancer = ImpersonationProxyServiceType("LoadBalancer")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeClusterIP provisions a service of type ClusterIP.
|
||||||
|
ImpersonationProxyServiceTypeClusterIP = ImpersonationProxyServiceType("ClusterIP")
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceTypeNone does not automatically provision any service.
|
||||||
|
ImpersonationProxyServiceTypeNone = ImpersonationProxyServiceType("None")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ImpersonationProxySpec describes the intended configuration of the Concierge impersonation proxy.
|
||||||
|
type ImpersonationProxySpec struct {
|
||||||
|
// Mode configures whether the impersonation proxy should be started:
|
||||||
|
// - "disabled" explicitly disables the impersonation proxy. This is the default.
|
||||||
|
// - "enabled" explicitly enables the impersonation proxy.
|
||||||
|
// - "auto" enables or disables the impersonation proxy based upon the cluster in which it is running.
|
||||||
|
Mode ImpersonationProxyMode `json:"mode"`
|
||||||
|
|
||||||
|
// Service describes the configuration of the Service provisioned to expose the impersonation proxy to clients.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:={"type": "LoadBalancer"}
|
||||||
|
Service ImpersonationProxyServiceSpec `json:"service"`
|
||||||
|
|
||||||
|
// ExternalEndpoint describes the HTTPS endpoint where the proxy will be exposed. If not set, the proxy will
|
||||||
|
// be served using the external name of the LoadBalancer service or the cluster service DNS name.
|
||||||
|
//
|
||||||
|
// This field must be non-empty when spec.impersonationProxy.service.mode is "None".
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
ExternalEndpoint string `json:"externalEndpoint,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonationProxyServiceSpec describes how the Concierge should provision a Service to expose the impersonation proxy.
|
||||||
|
type ImpersonationProxyServiceSpec struct {
|
||||||
|
// Type specifies the type of Service to provision for the impersonation proxy.
|
||||||
|
//
|
||||||
|
// If the type is "None", then the "spec.impersonationProxy.externalEndpoint" field must be set to a non-empty
|
||||||
|
// value so that the Concierge can properly advertise the endpoint in the CredentialIssuer's status.
|
||||||
|
//
|
||||||
|
// +kubebuilder:default:="LoadBalancer"
|
||||||
|
Type ImpersonationProxyServiceType `json:"type,omitempty"`
|
||||||
|
|
||||||
|
// LoadBalancerIP specifies the IP address to set in the spec.loadBalancerIP field of the provisioned Service.
|
||||||
|
// This is not supported on all cloud providers.
|
||||||
|
//
|
||||||
|
// +kubebuilder:validation:MinLength=1
|
||||||
|
// +kubebuilder:validation:MaxLength=255
|
||||||
|
// +optional
|
||||||
|
LoadBalancerIP string `json:"loadBalancerIP,omitempty"`
|
||||||
|
|
||||||
|
// Annotations specifies zero or more key/value pairs to set as annotations on the provisioned Service.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
type CredentialIssuerStatus struct {
|
type CredentialIssuerStatus struct {
|
||||||
// List of integration strategies that were attempted by Pinniped.
|
// List of integration strategies that were attempted by Pinniped.
|
||||||
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
Strategies []CredentialIssuerStrategy `json:"strategies"`
|
||||||
@ -47,7 +137,8 @@ type CredentialIssuerStatus struct {
|
|||||||
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
// CredentialIssuerKubeConfigInfo provides the information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
|
||||||
|
// This type is deprecated and will be removed in a future version.
|
||||||
type CredentialIssuerKubeConfigInfo struct {
|
type CredentialIssuerKubeConfigInfo struct {
|
||||||
// The K8s API server URL.
|
// The K8s API server URL.
|
||||||
// +kubebuilder:validation:MinLength=1
|
// +kubebuilder:validation:MinLength=1
|
||||||
@ -59,7 +150,7 @@ type CredentialIssuerKubeConfigInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status of an integration strategy that was attempted by Pinniped.
|
// CredentialIssuerStrategy describes the status of an integration strategy that was attempted by Pinniped.
|
||||||
type CredentialIssuerStrategy struct {
|
type CredentialIssuerStrategy struct {
|
||||||
// Type of integration attempted.
|
// Type of integration attempted.
|
||||||
Type StrategyType `json:"type"`
|
Type StrategyType `json:"type"`
|
||||||
@ -81,6 +172,7 @@ type CredentialIssuerStrategy struct {
|
|||||||
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CredentialIssuerFrontend describes how to connect using a particular integration strategy.
|
||||||
type CredentialIssuerFrontend struct {
|
type CredentialIssuerFrontend struct {
|
||||||
// Type describes which frontend mechanism clients can use with a strategy.
|
// Type describes which frontend mechanism clients can use with a strategy.
|
||||||
Type FrontendType `json:"type"`
|
Type FrontendType `json:"type"`
|
||||||
@ -118,7 +210,7 @@ type ImpersonationProxyInfo struct {
|
|||||||
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
CertificateAuthorityData string `json:"certificateAuthorityData"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describes the configuration status of a Pinniped credential issuer.
|
// CredentialIssuer describes the configuration and status of the Pinniped Concierge credential issuer.
|
||||||
// +genclient
|
// +genclient
|
||||||
// +genclient:nonNamespaced
|
// +genclient:nonNamespaced
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
@ -128,12 +220,18 @@ type CredentialIssuer struct {
|
|||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||||
|
|
||||||
// Status of the credential issuer.
|
// Spec describes the intended configuration of the Concierge.
|
||||||
|
//
|
||||||
|
// +optional
|
||||||
|
Spec CredentialIssuerSpec `json:"spec"`
|
||||||
|
|
||||||
|
// CredentialIssuerStatus describes the status of the Concierge.
|
||||||
|
//
|
||||||
// +optional
|
// +optional
|
||||||
Status CredentialIssuerStatus `json:"status"`
|
Status CredentialIssuerStatus `json:"status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of CredentialIssuer objects.
|
// CredentialIssuerList is a list of CredentialIssuer objects.
|
||||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||||
type CredentialIssuerList struct {
|
type CredentialIssuerList struct {
|
||||||
metav1.TypeMeta `json:",inline"`
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
@ -16,6 +16,7 @@ func (in *CredentialIssuer) DeepCopyInto(out *CredentialIssuer) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
|
in.Spec.DeepCopyInto(&out.Spec)
|
||||||
in.Status.DeepCopyInto(&out.Status)
|
in.Status.DeepCopyInto(&out.Status)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -113,6 +114,27 @@ func (in *CredentialIssuerList) DeepCopyObject() runtime.Object {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopyInto(out *CredentialIssuerSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.ImpersonationProxy != nil {
|
||||||
|
in, out := &in.ImpersonationProxy, &out.ImpersonationProxy
|
||||||
|
*out = new(ImpersonationProxySpec)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerSpec.
|
||||||
|
func (in *CredentialIssuerSpec) DeepCopy() *CredentialIssuerSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(CredentialIssuerSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -179,6 +201,46 @@ func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopyInto(out *ImpersonationProxyServiceSpec) {
|
||||||
|
*out = *in
|
||||||
|
if in.Annotations != nil {
|
||||||
|
in, out := &in.Annotations, &out.Annotations
|
||||||
|
*out = make(map[string]string, len(*in))
|
||||||
|
for key, val := range *in {
|
||||||
|
(*out)[key] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyServiceSpec.
|
||||||
|
func (in *ImpersonationProxyServiceSpec) DeepCopy() *ImpersonationProxyServiceSpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxyServiceSpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopyInto(out *ImpersonationProxySpec) {
|
||||||
|
*out = *in
|
||||||
|
in.Service.DeepCopyInto(&out.Service)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxySpec.
|
||||||
|
func (in *ImpersonationProxySpec) DeepCopy() *ImpersonationProxySpec {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(ImpersonationProxySpec)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package impersonator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"sigs.k8s.io/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Mode string
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Explicitly enable the impersonation proxy.
|
|
||||||
ModeEnabled Mode = "enabled"
|
|
||||||
|
|
||||||
// Explicitly disable the impersonation proxy.
|
|
||||||
ModeDisabled Mode = "disabled"
|
|
||||||
|
|
||||||
// Allow the proxy to decide if it should be enabled or disabled based upon the cluster in which it is running.
|
|
||||||
ModeAuto Mode = "auto"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ConfigMapDataKey = "config.yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
// Enable or disable the impersonation proxy. Optional. Defaults to ModeAuto.
|
|
||||||
Mode Mode `json:"mode,omitempty"`
|
|
||||||
|
|
||||||
// Used when creating TLS certificates and for clients to discover the endpoint. Optional. When not specified, if the
|
|
||||||
// impersonation proxy is started, then it will automatically create a LoadBalancer Service and use its ingress as the
|
|
||||||
// endpoint.
|
|
||||||
//
|
|
||||||
// When specified, it may be a hostname or IP address, optionally with a port number, of the impersonation proxy
|
|
||||||
// for clients to use from outside the cluster. E.g. myhost.mycompany.com:8443. Clients should assume that they should
|
|
||||||
// connect via HTTPS to this service.
|
|
||||||
Endpoint string `json:"endpoint,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) HasEndpoint() bool {
|
|
||||||
return c.Endpoint != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewConfig() *Config {
|
|
||||||
return &Config{Mode: ModeAuto}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConfigFromConfigMap(configMap *v1.ConfigMap) (*Config, error) {
|
|
||||||
stringConfig, ok := configMap.Data[ConfigMapDataKey]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf(`ConfigMap is missing expected key "%s"`, ConfigMapDataKey)
|
|
||||||
}
|
|
||||||
config := NewConfig()
|
|
||||||
if err := yaml.Unmarshal([]byte(stringConfig), config); err != nil {
|
|
||||||
return nil, fmt.Errorf("decode yaml: %w", err)
|
|
||||||
}
|
|
||||||
if config.Mode != ModeAuto && config.Mode != ModeEnabled && config.Mode != ModeDisabled {
|
|
||||||
return nil, fmt.Errorf(`illegal value for "mode": %s`, config.Mode)
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
@ -1,155 +0,0 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package impersonator
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
|
|
||||||
"go.pinniped.dev/internal/here"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestNewConfig(t *testing.T) {
|
|
||||||
// It defaults the mode.
|
|
||||||
require.Equal(t, &Config{Mode: ModeAuto}, NewConfig())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHasEndpoint(t *testing.T) {
|
|
||||||
configWithoutEndpoint := Config{}
|
|
||||||
configWithEndpoint := Config{Endpoint: "something"}
|
|
||||||
require.False(t, configWithoutEndpoint.HasEndpoint())
|
|
||||||
require.True(t, configWithEndpoint.HasEndpoint())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestConfigFromConfigMap(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
configMap *v1.ConfigMap
|
|
||||||
wantConfig *Config
|
|
||||||
wantError string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "fully configured, valid config",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": here.Doc(`
|
|
||||||
mode: enabled
|
|
||||||
endpoint: proxy.example.com:8443
|
|
||||||
`),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantConfig: &Config{
|
|
||||||
Mode: "enabled",
|
|
||||||
Endpoint: "proxy.example.com:8443",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty, valid config",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantConfig: &Config{
|
|
||||||
Mode: "auto",
|
|
||||||
Endpoint: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with mode enabled",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "mode: enabled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantConfig: &Config{
|
|
||||||
Mode: "enabled",
|
|
||||||
Endpoint: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with mode disabled",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "mode: disabled",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantConfig: &Config{
|
|
||||||
Mode: "disabled",
|
|
||||||
Endpoint: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "valid config with mode auto",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "mode: auto",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantConfig: &Config{
|
|
||||||
Mode: "auto",
|
|
||||||
Endpoint: "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "wrong key in configmap",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"wrong-key": "",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantError: `ConfigMap is missing expected key "config.yaml"`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "illegal yaml in configmap",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "this is not yaml",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type impersonator.Config",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "illegal value for mode in configmap",
|
|
||||||
configMap: &v1.ConfigMap{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": "mode: unexpected-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantError: `illegal value for "mode": unexpected-value`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
test := tt
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
config, err := ConfigFromConfigMap(test.configMap)
|
|
||||||
require.Equal(t, test.wantConfig, config)
|
|
||||||
if test.wantError != "" {
|
|
||||||
require.EqualError(t, err, test.wantError)
|
|
||||||
} else {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -195,7 +195,6 @@ func newInternal( //nolint:funlen // yeah, it's kind of long.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wire up a fake audit backend at the metadata level so we can preserve the original user during nested impersonation
|
// wire up a fake audit backend at the metadata level so we can preserve the original user during nested impersonation
|
||||||
// TODO: wire up the real std out logging audit backend based on plog log level
|
|
||||||
serverConfig.AuditPolicyChecker = policy.FakeChecker(auditinternal.LevelMetadata, nil)
|
serverConfig.AuditPolicyChecker = policy.FakeChecker(auditinternal.LevelMetadata, nil)
|
||||||
serverConfig.AuditBackend = &auditfake.Backend{}
|
serverConfig.AuditBackend = &auditfake.Backend{}
|
||||||
|
|
||||||
|
@ -108,12 +108,12 @@ func validateNames(names *NamesConfigSpec) error {
|
|||||||
if names.APIService == "" {
|
if names.APIService == "" {
|
||||||
missingNames = append(missingNames, "apiService")
|
missingNames = append(missingNames, "apiService")
|
||||||
}
|
}
|
||||||
if names.ImpersonationConfigMap == "" {
|
|
||||||
missingNames = append(missingNames, "impersonationConfigMap")
|
|
||||||
}
|
|
||||||
if names.ImpersonationLoadBalancerService == "" {
|
if names.ImpersonationLoadBalancerService == "" {
|
||||||
missingNames = append(missingNames, "impersonationLoadBalancerService")
|
missingNames = append(missingNames, "impersonationLoadBalancerService")
|
||||||
}
|
}
|
||||||
|
if names.ImpersonationClusterIPService == "" {
|
||||||
|
missingNames = append(missingNames, "impersonationClusterIPService")
|
||||||
|
}
|
||||||
if names.ImpersonationTLSCertificateSecret == "" {
|
if names.ImpersonationTLSCertificateSecret == "" {
|
||||||
missingNames = append(missingNames, "impersonationTLSCertificateSecret")
|
missingNames = append(missingNames, "impersonationTLSCertificateSecret")
|
||||||
}
|
}
|
||||||
|
@ -38,13 +38,14 @@ func TestFromPath(t *testing.T) {
|
|||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
kubeCertAgentPrefix: kube-cert-agent-prefix
|
kubeCertAgentPrefix: kube-cert-agent-prefix
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
agentServiceAccount: agentServiceAccount-value
|
agentServiceAccount: agentServiceAccount-value
|
||||||
|
extraName: extraName-value
|
||||||
labels:
|
labels:
|
||||||
myLabelKey1: myLabelValue1
|
myLabelKey1: myLabelValue1
|
||||||
myLabelKey2: myLabelValue2
|
myLabelKey2: myLabelValue2
|
||||||
@ -69,8 +70,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
||||||
CredentialIssuer: "pinniped-config",
|
CredentialIssuer: "pinniped-config",
|
||||||
APIService: "pinniped-api",
|
APIService: "pinniped-api",
|
||||||
ImpersonationConfigMap: "impersonationConfigMap-value",
|
|
||||||
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
||||||
|
ImpersonationClusterIPService: "impersonationClusterIPService-value",
|
||||||
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
||||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||||
@ -96,8 +97,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
@ -118,8 +119,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
|
||||||
CredentialIssuer: "pinniped-config",
|
CredentialIssuer: "pinniped-config",
|
||||||
APIService: "pinniped-api",
|
APIService: "pinniped-api",
|
||||||
ImpersonationConfigMap: "impersonationConfigMap-value",
|
|
||||||
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
|
||||||
|
ImpersonationClusterIPService: "impersonationClusterIPService-value",
|
||||||
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
|
||||||
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
|
||||||
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
ImpersonationSignerSecret: "impersonationSignerSecret-value",
|
||||||
@ -136,8 +137,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
name: "Empty",
|
name: "Empty",
|
||||||
yaml: here.Doc(``),
|
yaml: here.Doc(``),
|
||||||
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuer, " +
|
wantError: "validate names: missing required names: servingCertificateSecret, credentialIssuer, " +
|
||||||
"apiService, impersonationConfigMap, impersonationLoadBalancerService, " +
|
"apiService, impersonationLoadBalancerService, " +
|
||||||
"impersonationTLSCertificateSecret, impersonationCACertificateSecret, " +
|
"impersonationClusterIPService, impersonationTLSCertificateSecret, impersonationCACertificateSecret, " +
|
||||||
"impersonationSignerSecret, agentServiceAccount",
|
"impersonationSignerSecret, agentServiceAccount",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -147,8 +148,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
@ -163,8 +164,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
@ -179,8 +180,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
names:
|
names:
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
@ -188,22 +189,6 @@ func TestFromPath(t *testing.T) {
|
|||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: servingCertificateSecret",
|
wantError: "validate names: missing required names: servingCertificateSecret",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "Missing impersonationConfigMap name",
|
|
||||||
yaml: here.Doc(`
|
|
||||||
---
|
|
||||||
names:
|
|
||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
|
||||||
credentialIssuer: pinniped-config
|
|
||||||
apiService: pinniped-api
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
|
||||||
agentServiceAccount: agentServiceAccount-value
|
|
||||||
`),
|
|
||||||
wantError: "validate names: missing required names: impersonationConfigMap",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "Missing impersonationLoadBalancerService name",
|
name: "Missing impersonationLoadBalancerService name",
|
||||||
yaml: here.Doc(`
|
yaml: here.Doc(`
|
||||||
@ -212,7 +197,7 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
@ -220,6 +205,22 @@ func TestFromPath(t *testing.T) {
|
|||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: impersonationLoadBalancerService",
|
wantError: "validate names: missing required names: impersonationLoadBalancerService",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "Missing impersonationClusterIPService name",
|
||||||
|
yaml: here.Doc(`
|
||||||
|
---
|
||||||
|
names:
|
||||||
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
|
credentialIssuer: pinniped-config
|
||||||
|
apiService: pinniped-api
|
||||||
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
|
agentServiceAccount: agentServiceAccount-value
|
||||||
|
`),
|
||||||
|
wantError: "validate names: missing required names: impersonationClusterIPService",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "Missing impersonationTLSCertificateSecret name",
|
name: "Missing impersonationTLSCertificateSecret name",
|
||||||
yaml: here.Doc(`
|
yaml: here.Doc(`
|
||||||
@ -228,8 +229,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
agentServiceAccount: agentServiceAccount-value
|
agentServiceAccount: agentServiceAccount-value
|
||||||
@ -244,8 +245,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
agentServiceAccount: agentServiceAccount-value
|
agentServiceAccount: agentServiceAccount-value
|
||||||
@ -260,8 +261,8 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
agentServiceAccount: agentServiceAccount-value
|
agentServiceAccount: agentServiceAccount-value
|
||||||
@ -277,10 +278,11 @@ func TestFromPath(t *testing.T) {
|
|||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
|
impersonationClusterIPService: impersonationClusterIPService-value
|
||||||
impersonationSignerSecret: impersonationSignerSecret-value
|
impersonationSignerSecret: impersonationSignerSecret-value
|
||||||
agentServiceAccount: agentServiceAccount-value
|
agentServiceAccount: agentServiceAccount-value
|
||||||
`),
|
`),
|
||||||
wantError: "validate names: missing required names: impersonationConfigMap, " +
|
wantError: "validate names: missing required names: " +
|
||||||
"impersonationTLSCertificateSecret, impersonationCACertificateSecret",
|
"impersonationTLSCertificateSecret, impersonationCACertificateSecret",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -295,7 +297,6 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
@ -315,7 +316,6 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
@ -335,7 +335,6 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
@ -356,7 +355,6 @@ func TestFromPath(t *testing.T) {
|
|||||||
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
|
||||||
credentialIssuer: pinniped-config
|
credentialIssuer: pinniped-config
|
||||||
apiService: pinniped-api
|
apiService: pinniped-api
|
||||||
impersonationConfigMap: impersonationConfigMap-value
|
|
||||||
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
impersonationLoadBalancerService: impersonationLoadBalancerService-value
|
||||||
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
|
||||||
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
impersonationCACertificateSecret: impersonationCACertificateSecret-value
|
||||||
|
@ -36,8 +36,8 @@ type NamesConfigSpec struct {
|
|||||||
ServingCertificateSecret string `json:"servingCertificateSecret"`
|
ServingCertificateSecret string `json:"servingCertificateSecret"`
|
||||||
CredentialIssuer string `json:"credentialIssuer"`
|
CredentialIssuer string `json:"credentialIssuer"`
|
||||||
APIService string `json:"apiService"`
|
APIService string `json:"apiService"`
|
||||||
ImpersonationConfigMap string `json:"impersonationConfigMap"`
|
|
||||||
ImpersonationLoadBalancerService string `json:"impersonationLoadBalancerService"`
|
ImpersonationLoadBalancerService string `json:"impersonationLoadBalancerService"`
|
||||||
|
ImpersonationClusterIPService string `json:"impersonationClusterIPService"`
|
||||||
ImpersonationTLSCertificateSecret string `json:"impersonationTLSCertificateSecret"`
|
ImpersonationTLSCertificateSecret string `json:"impersonationTLSCertificateSecret"`
|
||||||
ImpersonationCACertificateSecret string `json:"impersonationCACertificateSecret"`
|
ImpersonationCACertificateSecret string `json:"impersonationCACertificateSecret"`
|
||||||
ImpersonationSignerSecret string `json:"impersonationSignerSecret"`
|
ImpersonationSignerSecret string `json:"impersonationSignerSecret"`
|
||||||
|
@ -14,19 +14,25 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/go-logr/logr"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/equality"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/clock"
|
"k8s.io/apimachinery/pkg/util/clock"
|
||||||
"k8s.io/apimachinery/pkg/util/errors"
|
"k8s.io/apimachinery/pkg/util/errors"
|
||||||
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
corev1informers "k8s.io/client-go/informers/core/v1"
|
corev1informers "k8s.io/client-go/informers/core/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/klog/v2"
|
||||||
|
|
||||||
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||||
|
conciergeconfiginformers "go.pinniped.dev/generated/latest/client/concierge/informers/externalversions/config/v1alpha1"
|
||||||
"go.pinniped.dev/internal/certauthority"
|
"go.pinniped.dev/internal/certauthority"
|
||||||
"go.pinniped.dev/internal/clusterhost"
|
"go.pinniped.dev/internal/clusterhost"
|
||||||
"go.pinniped.dev/internal/concierge/impersonator"
|
"go.pinniped.dev/internal/concierge/impersonator"
|
||||||
@ -36,7 +42,7 @@ import (
|
|||||||
"go.pinniped.dev/internal/controller/issuerconfig"
|
"go.pinniped.dev/internal/controller/issuerconfig"
|
||||||
"go.pinniped.dev/internal/controllerlib"
|
"go.pinniped.dev/internal/controllerlib"
|
||||||
"go.pinniped.dev/internal/dynamiccert"
|
"go.pinniped.dev/internal/dynamiccert"
|
||||||
"go.pinniped.dev/internal/plog"
|
"go.pinniped.dev/internal/endpointaddr"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -51,9 +57,9 @@ const (
|
|||||||
|
|
||||||
type impersonatorConfigController struct {
|
type impersonatorConfigController struct {
|
||||||
namespace string
|
namespace string
|
||||||
configMapResourceName string
|
|
||||||
credentialIssuerResourceName string
|
credentialIssuerResourceName string
|
||||||
generatedLoadBalancerServiceName string
|
generatedLoadBalancerServiceName string
|
||||||
|
generatedClusterIPServiceName string
|
||||||
tlsSecretName string
|
tlsSecretName string
|
||||||
caSecretName string
|
caSecretName string
|
||||||
impersonationSignerSecretName string
|
impersonationSignerSecretName string
|
||||||
@ -61,7 +67,7 @@ type impersonatorConfigController struct {
|
|||||||
k8sClient kubernetes.Interface
|
k8sClient kubernetes.Interface
|
||||||
pinnipedAPIClient pinnipedclientset.Interface
|
pinnipedAPIClient pinnipedclientset.Interface
|
||||||
|
|
||||||
configMapsInformer corev1informers.ConfigMapInformer
|
credIssuerInformer conciergeconfiginformers.CredentialIssuerInformer
|
||||||
servicesInformer corev1informers.ServiceInformer
|
servicesInformer corev1informers.ServiceInformer
|
||||||
secretsInformer corev1informers.SecretInformer
|
secretsInformer corev1informers.SecretInformer
|
||||||
|
|
||||||
@ -74,20 +80,21 @@ type impersonatorConfigController struct {
|
|||||||
serverStopCh chan struct{}
|
serverStopCh chan struct{}
|
||||||
errorCh chan error
|
errorCh chan error
|
||||||
tlsServingCertDynamicCertProvider dynamiccert.Private
|
tlsServingCertDynamicCertProvider dynamiccert.Private
|
||||||
|
infoLog logr.Logger
|
||||||
|
debugLog logr.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewImpersonatorConfigController(
|
func NewImpersonatorConfigController(
|
||||||
namespace string,
|
namespace string,
|
||||||
configMapResourceName string,
|
|
||||||
credentialIssuerResourceName string,
|
credentialIssuerResourceName string,
|
||||||
k8sClient kubernetes.Interface,
|
k8sClient kubernetes.Interface,
|
||||||
pinnipedAPIClient pinnipedclientset.Interface,
|
pinnipedAPIClient pinnipedclientset.Interface,
|
||||||
configMapsInformer corev1informers.ConfigMapInformer,
|
credentialIssuerInformer conciergeconfiginformers.CredentialIssuerInformer,
|
||||||
servicesInformer corev1informers.ServiceInformer,
|
servicesInformer corev1informers.ServiceInformer,
|
||||||
secretsInformer corev1informers.SecretInformer,
|
secretsInformer corev1informers.SecretInformer,
|
||||||
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
||||||
withInitialEvent pinnipedcontroller.WithInitialEventOptionFunc,
|
|
||||||
generatedLoadBalancerServiceName string,
|
generatedLoadBalancerServiceName string,
|
||||||
|
generatedClusterIPServiceName string,
|
||||||
tlsSecretName string,
|
tlsSecretName string,
|
||||||
caSecretName string,
|
caSecretName string,
|
||||||
labels map[string]string,
|
labels map[string]string,
|
||||||
@ -95,22 +102,24 @@ func NewImpersonatorConfigController(
|
|||||||
impersonatorFunc impersonator.FactoryFunc,
|
impersonatorFunc impersonator.FactoryFunc,
|
||||||
impersonationSignerSecretName string,
|
impersonationSignerSecretName string,
|
||||||
impersonationSigningCertProvider dynamiccert.Provider,
|
impersonationSigningCertProvider dynamiccert.Provider,
|
||||||
|
log logr.Logger,
|
||||||
) controllerlib.Controller {
|
) controllerlib.Controller {
|
||||||
secretNames := sets.NewString(tlsSecretName, caSecretName, impersonationSignerSecretName)
|
secretNames := sets.NewString(tlsSecretName, caSecretName, impersonationSignerSecretName)
|
||||||
|
log = log.WithName("impersonator-config-controller")
|
||||||
return controllerlib.New(
|
return controllerlib.New(
|
||||||
controllerlib.Config{
|
controllerlib.Config{
|
||||||
Name: "impersonator-config-controller",
|
Name: "impersonator-config-controller",
|
||||||
Syncer: &impersonatorConfigController{
|
Syncer: &impersonatorConfigController{
|
||||||
namespace: namespace,
|
namespace: namespace,
|
||||||
configMapResourceName: configMapResourceName,
|
|
||||||
credentialIssuerResourceName: credentialIssuerResourceName,
|
credentialIssuerResourceName: credentialIssuerResourceName,
|
||||||
generatedLoadBalancerServiceName: generatedLoadBalancerServiceName,
|
generatedLoadBalancerServiceName: generatedLoadBalancerServiceName,
|
||||||
|
generatedClusterIPServiceName: generatedClusterIPServiceName,
|
||||||
tlsSecretName: tlsSecretName,
|
tlsSecretName: tlsSecretName,
|
||||||
caSecretName: caSecretName,
|
caSecretName: caSecretName,
|
||||||
impersonationSignerSecretName: impersonationSignerSecretName,
|
impersonationSignerSecretName: impersonationSignerSecretName,
|
||||||
k8sClient: k8sClient,
|
k8sClient: k8sClient,
|
||||||
pinnipedAPIClient: pinnipedAPIClient,
|
pinnipedAPIClient: pinnipedAPIClient,
|
||||||
configMapsInformer: configMapsInformer,
|
credIssuerInformer: credentialIssuerInformer,
|
||||||
servicesInformer: servicesInformer,
|
servicesInformer: servicesInformer,
|
||||||
secretsInformer: secretsInformer,
|
secretsInformer: secretsInformer,
|
||||||
labels: labels,
|
labels: labels,
|
||||||
@ -118,45 +127,48 @@ func NewImpersonatorConfigController(
|
|||||||
impersonationSigningCertProvider: impersonationSigningCertProvider,
|
impersonationSigningCertProvider: impersonationSigningCertProvider,
|
||||||
impersonatorFunc: impersonatorFunc,
|
impersonatorFunc: impersonatorFunc,
|
||||||
tlsServingCertDynamicCertProvider: dynamiccert.NewServingCert("impersonation-proxy-serving-cert"),
|
tlsServingCertDynamicCertProvider: dynamiccert.NewServingCert("impersonation-proxy-serving-cert"),
|
||||||
|
infoLog: log.V(2),
|
||||||
|
debugLog: log.V(4),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
withInformer(
|
withInformer(credentialIssuerInformer,
|
||||||
configMapsInformer,
|
pinnipedcontroller.SimpleFilterWithSingletonQueue(func(obj metav1.Object) bool {
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(configMapResourceName, namespace),
|
return obj.GetName() == credentialIssuerResourceName
|
||||||
|
}),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
withInformer(
|
withInformer(
|
||||||
servicesInformer,
|
servicesInformer,
|
||||||
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(generatedLoadBalancerServiceName, namespace),
|
pinnipedcontroller.SimpleFilterWithSingletonQueue(func(obj metav1.Object) bool {
|
||||||
|
return obj.GetNamespace() == namespace && obj.GetName() == generatedLoadBalancerServiceName
|
||||||
|
}),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
withInformer(
|
withInformer(
|
||||||
secretsInformer,
|
secretsInformer,
|
||||||
pinnipedcontroller.SimpleFilter(func(obj metav1.Object) bool {
|
pinnipedcontroller.SimpleFilterWithSingletonQueue(func(obj metav1.Object) bool {
|
||||||
return obj.GetNamespace() == namespace && secretNames.Has(obj.GetName())
|
return obj.GetNamespace() == namespace && secretNames.Has(obj.GetName())
|
||||||
}, nil),
|
}),
|
||||||
controllerlib.InformerOption{},
|
controllerlib.InformerOption{},
|
||||||
),
|
),
|
||||||
// Be sure to run once even if the ConfigMap that the informer is watching doesn't exist so we can implement
|
|
||||||
// the default configuration behavior.
|
|
||||||
withInitialEvent(controllerlib.Key{
|
|
||||||
Namespace: namespace,
|
|
||||||
Name: configMapResourceName,
|
|
||||||
}),
|
|
||||||
// TODO fix these controller options to make this a singleton queue
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) Sync(syncCtx controllerlib.Context) error {
|
func (c *impersonatorConfigController) Sync(syncCtx controllerlib.Context) error {
|
||||||
plog.Debug("Starting impersonatorConfigController Sync")
|
c.debugLog.Info("starting impersonatorConfigController Sync")
|
||||||
|
|
||||||
strategy, err := c.doSync(syncCtx)
|
// Load the CredentialIssuer that we'll update with status.
|
||||||
|
credIssuer, err := c.credIssuerInformer.Lister().Get(c.credentialIssuerResourceName)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get CredentialIssuer to update: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
strategy, err := c.doSync(syncCtx, credIssuer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
strategy = &v1alpha1.CredentialIssuerStrategy{
|
strategy = &v1alpha1.CredentialIssuerStrategy{
|
||||||
Type: v1alpha1.ImpersonationProxyStrategyType,
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
||||||
Status: v1alpha1.ErrorStrategyStatus,
|
Status: v1alpha1.ErrorStrategyStatus,
|
||||||
Reason: v1alpha1.ErrorDuringSetupStrategyReason,
|
Reason: strategyReasonForError(err),
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
||||||
}
|
}
|
||||||
@ -164,20 +176,31 @@ func (c *impersonatorConfigController) Sync(syncCtx controllerlib.Context) error
|
|||||||
c.clearSignerCA()
|
c.clearSignerCA()
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStrategyErr := c.updateStrategy(syncCtx.Context, strategy)
|
err = utilerrors.NewAggregate([]error{err, issuerconfig.Update(
|
||||||
if updateStrategyErr != nil {
|
syncCtx.Context,
|
||||||
plog.Error("error while updating the CredentialIssuer status", err)
|
c.pinnipedAPIClient,
|
||||||
if err == nil {
|
credIssuer,
|
||||||
err = updateStrategyErr
|
*strategy,
|
||||||
}
|
)})
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
plog.Debug("Successfully finished impersonatorConfigController Sync")
|
c.debugLog.Info("successfully finished impersonatorConfigController Sync")
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// strategyReasonForError returns the proper v1alpha1.StrategyReason for a sync error. Some errors are occasionally
|
||||||
|
// expected because there are multiple pods running, in these cases we should report a Pending reason and we'll
|
||||||
|
// recover on a following sync.
|
||||||
|
func strategyReasonForError(err error) v1alpha1.StrategyReason {
|
||||||
|
switch {
|
||||||
|
case k8serrors.IsConflict(err), k8serrors.IsAlreadyExists(err):
|
||||||
|
return v1alpha1.PendingStrategyReason
|
||||||
|
default:
|
||||||
|
return v1alpha1.ErrorDuringSetupStrategyReason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type certNameInfo struct {
|
type certNameInfo struct {
|
||||||
// ready will be true when the certificate name information is known.
|
// ready will be true when the certificate name information is known.
|
||||||
// ready will be false when it is pending because we are waiting for a load balancer to get assigned an ip/hostname.
|
// ready will be false when it is pending because we are waiting for a load balancer to get assigned an ip/hostname.
|
||||||
@ -186,7 +209,7 @@ type certNameInfo struct {
|
|||||||
|
|
||||||
// The IP address or hostname which was selected to be used as the name in the cert.
|
// The IP address or hostname which was selected to be used as the name in the cert.
|
||||||
// Either selectedIP or selectedHostname will be set, but not both.
|
// Either selectedIP or selectedHostname will be set, but not both.
|
||||||
selectedIP net.IP
|
selectedIPs []net.IP
|
||||||
selectedHostname string
|
selectedHostname string
|
||||||
|
|
||||||
// The name of the endpoint to which a client should connect to talk to the impersonator.
|
// The name of the endpoint to which a client should connect to talk to the impersonator.
|
||||||
@ -194,10 +217,10 @@ type certNameInfo struct {
|
|||||||
clientEndpoint string
|
clientEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v1alpha1.CredentialIssuerStrategy, error) {
|
func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context, credIssuer *v1alpha1.CredentialIssuer) (*v1alpha1.CredentialIssuerStrategy, error) {
|
||||||
ctx := syncCtx.Context
|
ctx := syncCtx.Context
|
||||||
|
|
||||||
config, err := c.loadImpersonationProxyConfiguration()
|
impersonationSpec, err := c.loadImpersonationProxyConfiguration(credIssuer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -212,21 +235,21 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c.hasControlPlaneNodes = &hasControlPlaneNodes
|
c.hasControlPlaneNodes = &hasControlPlaneNodes
|
||||||
plog.Debug("Queried for control plane nodes", "foundControlPlaneNodes", hasControlPlaneNodes)
|
c.debugLog.Info("queried for control plane nodes", "foundControlPlaneNodes", hasControlPlaneNodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.shouldHaveImpersonator(config) {
|
if c.shouldHaveImpersonator(impersonationSpec) {
|
||||||
if err = c.ensureImpersonatorIsStarted(syncCtx); err != nil {
|
if err = c.ensureImpersonatorIsStarted(syncCtx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = c.ensureImpersonatorIsStopped(true); err != nil {
|
if err = c.ensureImpersonatorIsStopped(true); err != nil {
|
||||||
return nil, err // TODO write unit test that errors during stopping the server are returned by sync
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.shouldHaveLoadBalancer(config) {
|
if c.shouldHaveLoadBalancer(impersonationSpec) {
|
||||||
if err = c.ensureLoadBalancerIsStarted(ctx); err != nil {
|
if err = c.ensureLoadBalancerIsStarted(ctx, impersonationSpec); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -235,7 +258,17 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nameInfo, err := c.findDesiredTLSCertificateName(config)
|
if c.shouldHaveClusterIPService(impersonationSpec) {
|
||||||
|
if err = c.ensureClusterIPServiceIsStarted(ctx, impersonationSpec); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err = c.ensureClusterIPServiceIsStopped(ctx); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nameInfo, err := c.findDesiredTLSCertificateName(impersonationSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Unexpected error while determining the name that should go into the certs, so clear any existing certs.
|
// Unexpected error while determining the name that should go into the certs, so clear any existing certs.
|
||||||
c.tlsServingCertDynamicCertProvider.UnsetCertKeyContent()
|
c.tlsServingCertDynamicCertProvider.UnsetCertKeyContent()
|
||||||
@ -243,7 +276,7 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
|||||||
}
|
}
|
||||||
|
|
||||||
var impersonationCA *certauthority.CA
|
var impersonationCA *certauthority.CA
|
||||||
if c.shouldHaveTLSSecret(config) {
|
if c.shouldHaveTLSSecret(impersonationSpec) {
|
||||||
if impersonationCA, err = c.ensureCASecretIsCreated(ctx); err != nil {
|
if impersonationCA, err = c.ensureCASecretIsCreated(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -254,7 +287,7 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
credentialIssuerStrategyResult := c.doSyncResult(nameInfo, config, impersonationCA)
|
credentialIssuerStrategyResult := c.doSyncResult(nameInfo, impersonationSpec, impersonationCA)
|
||||||
|
|
||||||
if err = c.loadSignerCA(credentialIssuerStrategyResult.Status); err != nil {
|
if err = c.loadSignerCA(credentialIssuerStrategyResult.Status); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -263,64 +296,55 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
|||||||
return credentialIssuerStrategyResult, nil
|
return credentialIssuerStrategyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) loadImpersonationProxyConfiguration() (*impersonator.Config, error) {
|
func (c *impersonatorConfigController) loadImpersonationProxyConfiguration(credIssuer *v1alpha1.CredentialIssuer) (*v1alpha1.ImpersonationProxySpec, error) {
|
||||||
configMap, err := c.configMapsInformer.Lister().ConfigMaps(c.namespace).Get(c.configMapResourceName)
|
// Make a copy of the spec since we got this object from informer cache.
|
||||||
notFound := k8serrors.IsNotFound(err)
|
spec := credIssuer.Spec.DeepCopy().ImpersonationProxy
|
||||||
if err != nil && !notFound {
|
if spec == nil {
|
||||||
return nil, fmt.Errorf("failed to get %s/%s configmap: %w", c.namespace, c.configMapResourceName, err)
|
return nil, fmt.Errorf("could not load CredentialIssuer: spec.impersonationProxy is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
var config *impersonator.Config
|
// Default service type to LoadBalancer (this is normally already done via CRD defaulting).
|
||||||
if notFound {
|
if spec.Service.Type == "" {
|
||||||
plog.Info("Did not find impersonation proxy config: using default config values",
|
spec.Service.Type = v1alpha1.ImpersonationProxyServiceTypeLoadBalancer
|
||||||
"configmap", c.configMapResourceName,
|
|
||||||
"namespace", c.namespace,
|
|
||||||
)
|
|
||||||
config = impersonator.NewConfig() // use default configuration options
|
|
||||||
} else {
|
|
||||||
config, err = impersonator.ConfigFromConfigMap(configMap)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid impersonator configuration: %v", err)
|
|
||||||
}
|
|
||||||
plog.Info("Read impersonation proxy config",
|
|
||||||
"configmap", c.configMapResourceName,
|
|
||||||
"namespace", c.namespace,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
if err := validateCredentialIssuerSpec(spec); err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load CredentialIssuer spec.impersonationProxy: %w", err)
|
||||||
|
}
|
||||||
|
c.debugLog.Info("read impersonation proxy config", "credentialIssuer", c.credentialIssuerResourceName)
|
||||||
|
return spec, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) shouldHaveImpersonator(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) shouldHaveImpersonator(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return c.enabledByAutoMode(config) || config.Mode == impersonator.ModeEnabled
|
return c.enabledByAutoMode(config) || config.Mode == v1alpha1.ImpersonationProxyModeEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) enabledByAutoMode(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) enabledByAutoMode(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return config.Mode == impersonator.ModeAuto && !*c.hasControlPlaneNodes
|
return config.Mode == v1alpha1.ImpersonationProxyModeAuto && !*c.hasControlPlaneNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) disabledByAutoMode(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) disabledByAutoMode(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return config.Mode == impersonator.ModeAuto && *c.hasControlPlaneNodes
|
return config.Mode == v1alpha1.ImpersonationProxyModeAuto && *c.hasControlPlaneNodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) disabledExplicitly(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) disabledExplicitly(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return config.Mode == impersonator.ModeDisabled
|
return config.Mode == v1alpha1.ImpersonationProxyModeDisabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) shouldHaveLoadBalancer(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) shouldHaveLoadBalancer(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return c.shouldHaveImpersonator(config) && !config.HasEndpoint()
|
return c.shouldHaveImpersonator(config) && config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeLoadBalancer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) shouldHaveTLSSecret(config *impersonator.Config) bool {
|
func (c *impersonatorConfigController) shouldHaveClusterIPService(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
|
return c.shouldHaveImpersonator(config) && config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeClusterIP
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *impersonatorConfigController) shouldHaveTLSSecret(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||||
return c.shouldHaveImpersonator(config)
|
return c.shouldHaveImpersonator(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) updateStrategy(ctx context.Context, strategy *v1alpha1.CredentialIssuerStrategy) error {
|
func (c *impersonatorConfigController) serviceExists(serviceName string) (bool, error) {
|
||||||
return issuerconfig.UpdateStrategy(ctx, c.credentialIssuerResourceName, c.labels, c.pinnipedAPIClient, *strategy)
|
_, err := c.servicesInformer.Lister().Services(c.namespace).Get(serviceName)
|
||||||
}
|
|
||||||
|
|
||||||
func (c *impersonatorConfigController) loadBalancerExists() (bool, error) {
|
|
||||||
_, err := c.servicesInformer.Lister().Services(c.namespace).Get(c.generatedLoadBalancerServiceName)
|
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if notFound {
|
if notFound {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -367,7 +391,7 @@ func (c *impersonatorConfigController) ensureImpersonatorIsStarted(syncCtx contr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Starting impersonation proxy", "port", impersonationProxyPort)
|
c.infoLog.Info("starting impersonation proxy", "port", impersonationProxyPort)
|
||||||
startImpersonatorFunc, err := c.impersonatorFunc(
|
startImpersonatorFunc, err := c.impersonatorFunc(
|
||||||
impersonationProxyPort,
|
impersonationProxyPort,
|
||||||
c.tlsServingCertDynamicCertProvider,
|
c.tlsServingCertDynamicCertProvider,
|
||||||
@ -402,7 +426,7 @@ func (c *impersonatorConfigController) ensureImpersonatorIsStopped(shouldCloseEr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Stopping impersonation proxy", "port", impersonationProxyPort)
|
c.infoLog.Info("stopping impersonation proxy", "port", impersonationProxyPort)
|
||||||
close(c.serverStopCh)
|
close(c.serverStopCh)
|
||||||
stopErr := <-c.errorCh
|
stopErr := <-c.errorCh
|
||||||
|
|
||||||
@ -416,14 +440,7 @@ func (c *impersonatorConfigController) ensureImpersonatorIsStopped(shouldCloseEr
|
|||||||
return stopErr
|
return stopErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.Context) error {
|
func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.Context, config *v1alpha1.ImpersonationProxySpec) error {
|
||||||
running, err := c.loadBalancerExists()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if running {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
appNameLabel := c.labels[appLabelKey]
|
appNameLabel := c.labels[appLabelKey]
|
||||||
loadBalancer := v1.Service{
|
loadBalancer := v1.Service{
|
||||||
Spec: v1.ServiceSpec{
|
Spec: v1.ServiceSpec{
|
||||||
@ -435,26 +452,21 @@ func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.C
|
|||||||
Protocol: v1.ProtocolTCP,
|
Protocol: v1.ProtocolTCP,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Selector: map[string]string{appLabelKey: appNameLabel},
|
LoadBalancerIP: config.Service.LoadBalancerIP,
|
||||||
|
Selector: map[string]string{appLabelKey: appNameLabel},
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: c.generatedLoadBalancerServiceName,
|
Name: c.generatedLoadBalancerServiceName,
|
||||||
Namespace: c.namespace,
|
Namespace: c.namespace,
|
||||||
Labels: c.labels,
|
Labels: c.labels,
|
||||||
Annotations: map[string]string{
|
Annotations: config.Service.Annotations,
|
||||||
"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "4000", // AWS' default is to time out after 60 seconds idle. Prevent that.
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
plog.Info("creating load balancer for impersonation proxy",
|
return c.createOrUpdateService(ctx, &loadBalancer)
|
||||||
"service", c.generatedLoadBalancerServiceName,
|
|
||||||
"namespace", c.namespace)
|
|
||||||
_, err = c.k8sClient.CoreV1().Services(c.namespace).Create(ctx, &loadBalancer, metav1.CreateOptions{})
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.Context) error {
|
func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.Context) error {
|
||||||
running, err := c.loadBalancerExists()
|
running, err := c.serviceExists(c.generatedLoadBalancerServiceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -462,12 +474,82 @@ func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.C
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Deleting load balancer for impersonation proxy",
|
c.infoLog.Info("deleting load balancer for impersonation proxy",
|
||||||
"service", c.generatedLoadBalancerServiceName,
|
"service", klog.KRef(c.namespace, c.generatedLoadBalancerServiceName),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
return c.k8sClient.CoreV1().Services(c.namespace).Delete(ctx, c.generatedLoadBalancerServiceName, metav1.DeleteOptions{})
|
return c.k8sClient.CoreV1().Services(c.namespace).Delete(ctx, c.generatedLoadBalancerServiceName, metav1.DeleteOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *impersonatorConfigController) ensureClusterIPServiceIsStarted(ctx context.Context, config *v1alpha1.ImpersonationProxySpec) error {
|
||||||
|
appNameLabel := c.labels[appLabelKey]
|
||||||
|
clusterIP := v1.Service{
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
Type: v1.ServiceTypeClusterIP,
|
||||||
|
Ports: []v1.ServicePort{
|
||||||
|
{
|
||||||
|
TargetPort: intstr.FromInt(impersonationProxyPort),
|
||||||
|
Port: defaultHTTPSPort,
|
||||||
|
Protocol: v1.ProtocolTCP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Selector: map[string]string{appLabelKey: appNameLabel},
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: c.generatedClusterIPServiceName,
|
||||||
|
Namespace: c.namespace,
|
||||||
|
Labels: c.labels,
|
||||||
|
Annotations: config.Service.Annotations,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return c.createOrUpdateService(ctx, &clusterIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *impersonatorConfigController) ensureClusterIPServiceIsStopped(ctx context.Context) error {
|
||||||
|
running, err := c.serviceExists(c.generatedClusterIPServiceName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !running {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c.infoLog.Info("deleting cluster ip for impersonation proxy",
|
||||||
|
"service", klog.KRef(c.namespace, c.generatedClusterIPServiceName),
|
||||||
|
)
|
||||||
|
return c.k8sClient.CoreV1().Services(c.namespace).Delete(ctx, c.generatedClusterIPServiceName, metav1.DeleteOptions{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *impersonatorConfigController) createOrUpdateService(ctx context.Context, service *v1.Service) error {
|
||||||
|
log := c.infoLog.WithValues("serviceType", service.Spec.Type, "service", klog.KObj(service))
|
||||||
|
existing, err := c.servicesInformer.Lister().Services(c.namespace).Get(service.Name)
|
||||||
|
if k8serrors.IsNotFound(err) {
|
||||||
|
log.Info("creating service for impersonation proxy")
|
||||||
|
_, err := c.k8sClient.CoreV1().Services(c.namespace).Create(ctx, service, metav1.CreateOptions{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update only the specific fields that are meaningfully part of our desired state.
|
||||||
|
updated := existing.DeepCopy()
|
||||||
|
updated.ObjectMeta.Labels = service.ObjectMeta.Labels
|
||||||
|
updated.ObjectMeta.Annotations = service.ObjectMeta.Annotations
|
||||||
|
updated.Spec.LoadBalancerIP = service.Spec.LoadBalancerIP
|
||||||
|
updated.Spec.Type = service.Spec.Type
|
||||||
|
updated.Spec.Selector = service.Spec.Selector
|
||||||
|
|
||||||
|
// If our updates didn't change anything, we're done.
|
||||||
|
if equality.Semantic.DeepEqual(existing, updated) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise apply the updates.
|
||||||
|
c.infoLog.Info("updating service for impersonation proxy")
|
||||||
|
_, err = c.k8sClient.CoreV1().Services(c.namespace).Update(ctx, updated, metav1.UpdateOptions{})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) ensureTLSSecret(ctx context.Context, nameInfo *certNameInfo, ca *certauthority.CA) error {
|
func (c *impersonatorConfigController) ensureTLSSecret(ctx context.Context, nameInfo *certNameInfo, ca *certauthority.CA) error {
|
||||||
secretFromInformer, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.tlsSecretName)
|
secretFromInformer, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.tlsSecretName)
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
@ -494,10 +576,10 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
|||||||
certPEM := secret.Data[v1.TLSCertKey]
|
certPEM := secret.Data[v1.TLSCertKey]
|
||||||
block, _ := pem.Decode(certPEM)
|
block, _ := pem.Decode(certPEM)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
plog.Warning("Found missing or not PEM-encoded data in TLS Secret",
|
c.infoLog.Info("found missing or not PEM-encoded data in TLS Secret",
|
||||||
"invalidCertPEM", string(certPEM),
|
"invalidCertPEM", string(certPEM),
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KObj(secret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
deleteErr := c.ensureTLSSecretIsRemoved(ctx)
|
deleteErr := c.ensureTLSSecretIsRemoved(ctx)
|
||||||
if deleteErr != nil {
|
if deleteErr != nil {
|
||||||
return false, fmt.Errorf("found missing or not PEM-encoded data in TLS Secret, but got error while deleting it: %w", deleteErr)
|
return false, fmt.Errorf("found missing or not PEM-encoded data in TLS Secret, but got error while deleting it: %w", deleteErr)
|
||||||
@ -507,10 +589,10 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
|||||||
|
|
||||||
actualCertFromSecret, err := x509.ParseCertificate(block.Bytes)
|
actualCertFromSecret, err := x509.ParseCertificate(block.Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.Error("Found invalid PEM data in TLS Secret", err,
|
c.infoLog.Error(err, "found missing or not PEM-encoded data in TLS Secret",
|
||||||
"invalidCertPEM", string(certPEM),
|
"invalidCertPEM", string(certPEM),
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KObj(secret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
||||||
return false, fmt.Errorf("PEM data represented an invalid cert, but got error while deleting it: %w", err)
|
return false, fmt.Errorf("PEM data represented an invalid cert, but got error while deleting it: %w", err)
|
||||||
}
|
}
|
||||||
@ -520,9 +602,10 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
|||||||
keyPEM := secret.Data[v1.TLSPrivateKeyKey]
|
keyPEM := secret.Data[v1.TLSPrivateKeyKey]
|
||||||
_, err = tls.X509KeyPair(certPEM, keyPEM)
|
_, err = tls.X509KeyPair(certPEM, keyPEM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
plog.Error("Found invalid private key PEM data in TLS Secret", err,
|
c.infoLog.Error(err, "found invalid private key PEM data in TLS Secret",
|
||||||
"secret", c.tlsSecretName,
|
"invalidCertPEM", string(certPEM),
|
||||||
"namespace", c.namespace)
|
"secret", klog.KObj(secret),
|
||||||
|
)
|
||||||
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
||||||
return false, fmt.Errorf("cert had an invalid private key, but got error while deleting it: %w", err)
|
return false, fmt.Errorf("cert had an invalid private key, but got error while deleting it: %w", err)
|
||||||
}
|
}
|
||||||
@ -550,15 +633,15 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
|||||||
|
|
||||||
actualIPs := actualCertFromSecret.IPAddresses
|
actualIPs := actualCertFromSecret.IPAddresses
|
||||||
actualHostnames := actualCertFromSecret.DNSNames
|
actualHostnames := actualCertFromSecret.DNSNames
|
||||||
plog.Info("Checking TLS certificate names",
|
c.infoLog.Info("checking TLS certificate names",
|
||||||
"desiredIP", nameInfo.selectedIP,
|
"desiredIPs", nameInfo.selectedIPs,
|
||||||
"desiredHostname", nameInfo.selectedHostname,
|
"desiredHostname", nameInfo.selectedHostname,
|
||||||
"actualIPs", actualIPs,
|
"actualIPs", actualIPs,
|
||||||
"actualHostnames", actualHostnames,
|
"actualHostnames", actualHostnames,
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KObj(secret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
|
|
||||||
if certHostnameAndIPMatchDesiredState(nameInfo.selectedIP, actualIPs, nameInfo.selectedHostname, actualHostnames) {
|
if certHostnameAndIPMatchDesiredState(nameInfo.selectedIPs, actualIPs, nameInfo.selectedHostname, actualHostnames) {
|
||||||
// The cert already matches the desired state, so there is no need to delete/recreate it.
|
// The cert already matches the desired state, so there is no need to delete/recreate it.
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@ -569,8 +652,13 @@ func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatc
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func certHostnameAndIPMatchDesiredState(desiredIP net.IP, actualIPs []net.IP, desiredHostname string, actualHostnames []string) bool {
|
func certHostnameAndIPMatchDesiredState(desiredIPs []net.IP, actualIPs []net.IP, desiredHostname string, actualHostnames []string) bool {
|
||||||
if desiredIP != nil && len(actualIPs) == 1 && desiredIP.Equal(actualIPs[0]) && len(actualHostnames) == 0 {
|
if len(desiredIPs) > 0 && len(actualIPs) > 0 && len(actualIPs) == len(desiredIPs) && len(actualHostnames) == 0 {
|
||||||
|
for i := range desiredIPs {
|
||||||
|
if !actualIPs[i].Equal(desiredIPs[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if desiredHostname != "" && len(actualHostnames) == 1 && desiredHostname == actualHostnames[0] && len(actualIPs) == 0 {
|
if desiredHostname != "" && len(actualHostnames) == 1 && desiredHostname == actualHostnames[0] && len(actualIPs) == 0 {
|
||||||
@ -592,7 +680,7 @@ func (c *impersonatorConfigController) ensureTLSSecretIsCreatedAndLoaded(ctx con
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
newTLSSecret, err := c.createNewTLSSecret(ctx, ca, nameInfo.selectedIP, nameInfo.selectedHostname)
|
newTLSSecret, err := c.createNewTLSSecret(ctx, ca, nameInfo.selectedIPs, nameInfo.selectedHostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -650,9 +738,9 @@ func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*cer
|
|||||||
Type: v1.SecretTypeOpaque,
|
Type: v1.SecretTypeOpaque,
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Creating CA certificates for impersonation proxy",
|
c.infoLog.Info("creating CA certificates for impersonation proxy",
|
||||||
"secret", c.caSecretName,
|
"secret", klog.KObj(&secret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
if _, err = c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, &secret, metav1.CreateOptions{}); err != nil {
|
if _, err = c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, &secret, metav1.CreateOptions{}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -660,21 +748,23 @@ func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*cer
|
|||||||
return impersonationCA, nil
|
return impersonationCA, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) findDesiredTLSCertificateName(config *impersonator.Config) (*certNameInfo, error) {
|
func (c *impersonatorConfigController) findDesiredTLSCertificateName(config *v1alpha1.ImpersonationProxySpec) (*certNameInfo, error) {
|
||||||
if config.HasEndpoint() {
|
if config.ExternalEndpoint != "" {
|
||||||
return c.findTLSCertificateNameFromEndpointConfig(config), nil
|
return c.findTLSCertificateNameFromEndpointConfig(config), nil
|
||||||
|
} else if config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeClusterIP {
|
||||||
|
return c.findTLSCertificateNameFromClusterIPService()
|
||||||
}
|
}
|
||||||
return c.findTLSCertificateNameFromLoadBalancer()
|
return c.findTLSCertificateNameFromLoadBalancer()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) findTLSCertificateNameFromEndpointConfig(config *impersonator.Config) *certNameInfo {
|
func (c *impersonatorConfigController) findTLSCertificateNameFromEndpointConfig(config *v1alpha1.ImpersonationProxySpec) *certNameInfo {
|
||||||
endpointMaybeWithPort := config.Endpoint
|
addr, _ := endpointaddr.Parse(config.ExternalEndpoint, 443)
|
||||||
endpointWithoutPort := strings.Split(endpointMaybeWithPort, ":")[0]
|
endpoint := strings.TrimSuffix(addr.Endpoint(), ":443")
|
||||||
parsedAsIP := net.ParseIP(endpointWithoutPort)
|
|
||||||
if parsedAsIP != nil {
|
if ip := net.ParseIP(addr.Host); ip != nil {
|
||||||
return &certNameInfo{ready: true, selectedIP: parsedAsIP, clientEndpoint: endpointMaybeWithPort}
|
return &certNameInfo{ready: true, selectedIPs: []net.IP{ip}, clientEndpoint: endpoint}
|
||||||
}
|
}
|
||||||
return &certNameInfo{ready: true, selectedHostname: endpointWithoutPort, clientEndpoint: endpointMaybeWithPort}
|
return &certNameInfo{ready: true, selectedHostname: addr.Host, clientEndpoint: endpoint}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer() (*certNameInfo, error) {
|
func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer() (*certNameInfo, error) {
|
||||||
@ -689,9 +779,9 @@ func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer()
|
|||||||
}
|
}
|
||||||
ingresses := lb.Status.LoadBalancer.Ingress
|
ingresses := lb.Status.LoadBalancer.Ingress
|
||||||
if len(ingresses) == 0 || (ingresses[0].Hostname == "" && ingresses[0].IP == "") {
|
if len(ingresses) == 0 || (ingresses[0].Hostname == "" && ingresses[0].IP == "") {
|
||||||
plog.Info("load balancer for impersonation proxy does not have an ingress yet, so skipping tls cert generation while we wait",
|
c.infoLog.Info("load balancer for impersonation proxy does not have an ingress yet, so skipping tls cert generation while we wait",
|
||||||
"service", c.generatedLoadBalancerServiceName,
|
"service", klog.KObj(lb),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
return &certNameInfo{ready: false}, nil
|
return &certNameInfo{ready: false}, nil
|
||||||
}
|
}
|
||||||
for _, ingress := range ingresses {
|
for _, ingress := range ingresses {
|
||||||
@ -704,22 +794,45 @@ func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer()
|
|||||||
ip := ingress.IP
|
ip := ingress.IP
|
||||||
parsedIP := net.ParseIP(ip)
|
parsedIP := net.ParseIP(ip)
|
||||||
if parsedIP != nil {
|
if parsedIP != nil {
|
||||||
return &certNameInfo{ready: true, selectedIP: parsedIP, clientEndpoint: ip}, nil
|
return &certNameInfo{ready: true, selectedIPs: []net.IP{parsedIP}, clientEndpoint: ip}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("could not find valid IP addresses or hostnames from load balancer %s/%s", c.namespace, lb.Name)
|
return nil, fmt.Errorf("could not find valid IP addresses or hostnames from load balancer %s/%s", c.namespace, lb.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, ca *certauthority.CA, ip net.IP, hostname string) (*v1.Secret, error) {
|
func (c *impersonatorConfigController) findTLSCertificateNameFromClusterIPService() (*certNameInfo, error) {
|
||||||
|
clusterIP, err := c.servicesInformer.Lister().Services(c.namespace).Get(c.generatedClusterIPServiceName)
|
||||||
|
notFound := k8serrors.IsNotFound(err)
|
||||||
|
if notFound {
|
||||||
|
// We aren't ready and will try again later in this case.
|
||||||
|
return &certNameInfo{ready: false}, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ip := clusterIP.Spec.ClusterIP
|
||||||
|
ips := clusterIP.Spec.ClusterIPs
|
||||||
|
if ip != "" {
|
||||||
|
// clusterIP will always exist when clusterIPs does, but not vice versa
|
||||||
|
var parsedIPs []net.IP
|
||||||
|
if len(ips) > 0 {
|
||||||
|
for _, ipFromIPs := range ips {
|
||||||
|
parsedIPs = append(parsedIPs, net.ParseIP(ipFromIPs))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parsedIPs = []net.IP{net.ParseIP(ip)}
|
||||||
|
}
|
||||||
|
return &certNameInfo{ready: true, selectedIPs: parsedIPs, clientEndpoint: ip}, nil
|
||||||
|
}
|
||||||
|
return &certNameInfo{ready: false}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, ca *certauthority.CA, ips []net.IP, hostname string) (*v1.Secret, error) {
|
||||||
var hostnames []string
|
var hostnames []string
|
||||||
var ips []net.IP
|
|
||||||
if hostname != "" {
|
if hostname != "" {
|
||||||
hostnames = []string{hostname}
|
hostnames = []string{hostname}
|
||||||
}
|
}
|
||||||
if ip != nil {
|
|
||||||
ips = []net.IP{ip}
|
|
||||||
}
|
|
||||||
|
|
||||||
impersonationCert, err := ca.IssueServerCert(hostnames, ips, approximatelyOneHundredYears)
|
impersonationCert, err := ca.IssueServerCert(hostnames, ips, approximatelyOneHundredYears)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -744,11 +857,11 @@ func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, c
|
|||||||
Type: v1.SecretTypeTLS,
|
Type: v1.SecretTypeTLS,
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Creating TLS certificates for impersonation proxy",
|
c.infoLog.Info("creating TLS certificates for impersonation proxy",
|
||||||
"ips", ips,
|
"ips", ips,
|
||||||
"hostnames", hostnames,
|
"hostnames", hostnames,
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KObj(newTLSSecret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
return c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, newTLSSecret, metav1.CreateOptions{})
|
return c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, newTLSSecret, metav1.CreateOptions{})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -761,10 +874,10 @@ func (c *impersonatorConfigController) loadTLSCertFromSecret(tlsSecret *v1.Secre
|
|||||||
return fmt.Errorf("could not parse TLS cert PEM data from Secret: %w", err)
|
return fmt.Errorf("could not parse TLS cert PEM data from Secret: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Loading TLS certificates for impersonation proxy",
|
c.infoLog.Info("loading TLS certificates for impersonation proxy",
|
||||||
"certPEM", string(certPEM),
|
"certPEM", string(certPEM),
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KObj(tlsSecret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -777,9 +890,9 @@ func (c *impersonatorConfigController) ensureTLSSecretIsRemoved(ctx context.Cont
|
|||||||
if !tlsSecretExists {
|
if !tlsSecretExists {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
plog.Info("Deleting TLS certificates for impersonation proxy",
|
c.infoLog.Info("deleting TLS certificates for impersonation proxy",
|
||||||
"secret", c.tlsSecretName,
|
"secret", klog.KRef(c.namespace, c.tlsSecretName),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
err = c.k8sClient.CoreV1().Secrets(c.namespace).Delete(ctx, c.tlsSecretName, metav1.DeleteOptions{})
|
err = c.k8sClient.CoreV1().Secrets(c.namespace).Delete(ctx, c.tlsSecretName, metav1.DeleteOptions{})
|
||||||
notFound := k8serrors.IsNotFound(err)
|
notFound := k8serrors.IsNotFound(err)
|
||||||
if notFound {
|
if notFound {
|
||||||
@ -815,20 +928,20 @@ func (c *impersonatorConfigController) loadSignerCA(status v1alpha1.StrategyStat
|
|||||||
return fmt.Errorf("could not load the impersonator's credential signing secret: %w", err)
|
return fmt.Errorf("could not load the impersonator's credential signing secret: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
plog.Info("Loading credential signing certificate for impersonation proxy",
|
c.infoLog.Info("loading credential signing certificate for impersonation proxy",
|
||||||
"certPEM", string(certPEM),
|
"certPEM", string(certPEM),
|
||||||
"fromSecret", c.impersonationSignerSecretName,
|
"secret", klog.KObj(signingCertSecret),
|
||||||
"namespace", c.namespace)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) clearSignerCA() {
|
func (c *impersonatorConfigController) clearSignerCA() {
|
||||||
plog.Info("Clearing credential signing certificate for impersonation proxy")
|
c.debugLog.Info("clearing credential signing certificate for impersonation proxy")
|
||||||
c.impersonationSigningCertProvider.UnsetCertKeyContent()
|
c.impersonationSigningCertProvider.UnsetCertKeyContent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, config *impersonator.Config, ca *certauthority.CA) *v1alpha1.CredentialIssuerStrategy {
|
func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, config *v1alpha1.ImpersonationProxySpec, ca *certauthority.CA) *v1alpha1.CredentialIssuerStrategy {
|
||||||
switch {
|
switch {
|
||||||
case c.disabledExplicitly(config):
|
case c.disabledExplicitly(config):
|
||||||
return &v1alpha1.CredentialIssuerStrategy{
|
return &v1alpha1.CredentialIssuerStrategy{
|
||||||
@ -871,3 +984,46 @@ func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, conf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateCredentialIssuerSpec(spec *v1alpha1.ImpersonationProxySpec) error {
|
||||||
|
// Validate that the mode is one of our known values.
|
||||||
|
switch spec.Mode {
|
||||||
|
case v1alpha1.ImpersonationProxyModeDisabled:
|
||||||
|
case v1alpha1.ImpersonationProxyModeAuto:
|
||||||
|
case v1alpha1.ImpersonationProxyModeEnabled:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid proxy mode %q (expected auto, disabled, or enabled)", spec.Mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If disabled, ignore all other fields and consider the configuration valid.
|
||||||
|
if spec.Mode == v1alpha1.ImpersonationProxyModeDisabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the service type is one of our known values.
|
||||||
|
switch spec.Service.Type {
|
||||||
|
case v1alpha1.ImpersonationProxyServiceTypeNone:
|
||||||
|
case v1alpha1.ImpersonationProxyServiceTypeLoadBalancer:
|
||||||
|
case v1alpha1.ImpersonationProxyServiceTypeClusterIP:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid service type %q (expected None, LoadBalancer, or ClusterIP)", spec.Service.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If specified, validate that the LoadBalancerIP is a valid IPv4 or IPv6 address.
|
||||||
|
if ip := spec.Service.LoadBalancerIP; ip != "" && len(validation.IsValidIP(ip)) > 0 {
|
||||||
|
return fmt.Errorf("invalid LoadBalancerIP %q", spec.Service.LoadBalancerIP)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If service is type "None", a non-empty external endpoint must be specified.
|
||||||
|
if spec.ExternalEndpoint == "" && spec.Service.Type == v1alpha1.ImpersonationProxyServiceTypeNone {
|
||||||
|
return fmt.Errorf("externalEndpoint must be set when service.type is None")
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.ExternalEndpoint != "" {
|
||||||
|
if _, err := endpointaddr.Parse(spec.ExternalEndpoint, 443); err != nil {
|
||||||
|
return fmt.Errorf("invalid ExternalEndpoint %q: %w", spec.ExternalEndpoint, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,85 +0,0 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package issuerconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/equality"
|
|
||||||
|
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/client-go/util/retry"
|
|
||||||
|
|
||||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
|
||||||
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx context.Context,
|
|
||||||
credentialIssuerResourceName string,
|
|
||||||
credentialIssuerLabels map[string]string,
|
|
||||||
pinnipedClient pinnipedclientset.Interface,
|
|
||||||
applyUpdatesToCredentialIssuerFunc func(configToUpdate *configv1alpha1.CredentialIssuerStatus),
|
|
||||||
) error {
|
|
||||||
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
|
||||||
existingCredentialIssuer, err := pinnipedClient.
|
|
||||||
ConfigV1alpha1().
|
|
||||||
CredentialIssuers().
|
|
||||||
Get(ctx, credentialIssuerResourceName, metav1.GetOptions{})
|
|
||||||
|
|
||||||
notFound := k8serrors.IsNotFound(err)
|
|
||||||
if err != nil && !notFound {
|
|
||||||
return fmt.Errorf("get failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
credentialIssuersClient := pinnipedClient.ConfigV1alpha1().CredentialIssuers()
|
|
||||||
|
|
||||||
if notFound {
|
|
||||||
// create an empty credential issuer
|
|
||||||
minCredentialIssuer := minimalValidCredentialIssuer(credentialIssuerResourceName, credentialIssuerLabels)
|
|
||||||
|
|
||||||
newCredentialIssuer, err := credentialIssuersClient.Create(ctx, minCredentialIssuer, metav1.CreateOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("create failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
existingCredentialIssuer = newCredentialIssuer
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if we need to update the status
|
|
||||||
credentialIssuer := existingCredentialIssuer.DeepCopy()
|
|
||||||
applyUpdatesToCredentialIssuerFunc(&credentialIssuer.Status)
|
|
||||||
|
|
||||||
if equality.Semantic.DeepEqual(existingCredentialIssuer, credentialIssuer) {
|
|
||||||
// Nothing interesting would change as a result of this update, so skip it
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := credentialIssuersClient.UpdateStatus(ctx, credentialIssuer, metav1.UpdateOptions{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not create or update credentialissuer: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func minimalValidCredentialIssuer(
|
|
||||||
credentialIssuerName string,
|
|
||||||
credentialIssuerLabels map[string]string,
|
|
||||||
) *configv1alpha1.CredentialIssuer {
|
|
||||||
return &configv1alpha1.CredentialIssuer{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: credentialIssuerName,
|
|
||||||
Labels: credentialIssuerLabels,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,301 +0,0 @@
|
|||||||
// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package issuerconfig
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/sclevine/spec"
|
|
||||||
"github.com/sclevine/spec/report"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
apierrors "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"
|
|
||||||
coretesting "k8s.io/client-go/testing"
|
|
||||||
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
|
||||||
|
|
||||||
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
|
||||||
pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreateOrUpdateCredentialIssuerStatus(t *testing.T) {
|
|
||||||
spec.Run(t, "specs", func(t *testing.T, when spec.G, it spec.S) {
|
|
||||||
var r *require.Assertions
|
|
||||||
var ctx context.Context
|
|
||||||
var pinnipedAPIClient *pinnipedfake.Clientset
|
|
||||||
var credentialIssuerGVR schema.GroupVersionResource
|
|
||||||
const credentialIssuerResourceName = "some-resource-name"
|
|
||||||
|
|
||||||
it.Before(func() {
|
|
||||||
r = require.New(t)
|
|
||||||
ctx = context.Background()
|
|
||||||
pinnipedAPIClient = pinnipedfake.NewSimpleClientset()
|
|
||||||
credentialIssuerGVR = schema.GroupVersionResource{
|
|
||||||
Group: configv1alpha1.GroupName,
|
|
||||||
Version: configv1alpha1.SchemeGroupVersion.Version,
|
|
||||||
Resource: "credentialissuers",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
when("the config does not exist", func() {
|
|
||||||
it("creates a new config and then updates it with the func parameter", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
"myLabelKey2": "myLabelValue2",
|
|
||||||
},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {
|
|
||||||
configToUpdate.KubeConfigInfo = &configv1alpha1.CredentialIssuerKubeConfigInfo{
|
|
||||||
CertificateAuthorityData: "some-ca-value",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
|
|
||||||
|
|
||||||
expectedCreateAction := coretesting.NewRootCreateAction(
|
|
||||||
credentialIssuerGVR,
|
|
||||||
&configv1alpha1.CredentialIssuer{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: credentialIssuerResourceName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
"myLabelKey2": "myLabelValue2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
expectedUpdateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status",
|
|
||||||
&configv1alpha1.CredentialIssuer{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: credentialIssuerResourceName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
"myLabelKey2": "myLabelValue2",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Status: configv1alpha1.CredentialIssuerStatus{
|
|
||||||
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
|
|
||||||
Server: "",
|
|
||||||
CertificateAuthorityData: "some-ca-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
r.Equal([]coretesting.Action{expectedGetAction, expectedCreateAction, expectedUpdateAction}, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
|
|
||||||
when("there is an unexpected error while creating the existing object", func() {
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor("create", "credentialissuers", func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, nil, fmt.Errorf("error on create")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns an error", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {},
|
|
||||||
)
|
|
||||||
r.EqualError(err, "could not create or update credentialissuer: create failed: error on create")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
when("the config already exists", func() {
|
|
||||||
var existingConfig *configv1alpha1.CredentialIssuer
|
|
||||||
|
|
||||||
it.Before(func() {
|
|
||||||
existingConfig = &configv1alpha1.CredentialIssuer{
|
|
||||||
TypeMeta: metav1.TypeMeta{},
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: credentialIssuerResourceName,
|
|
||||||
Labels: map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Status: configv1alpha1.CredentialIssuerStatus{
|
|
||||||
Strategies: []configv1alpha1.CredentialIssuerStrategy{
|
|
||||||
{
|
|
||||||
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,
|
|
||||||
Status: configv1alpha1.SuccessStrategyStatus,
|
|
||||||
Reason: configv1alpha1.FetchedKeyStrategyReason,
|
|
||||||
Message: "initial-message",
|
|
||||||
LastUpdateTime: metav1.Now(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
|
|
||||||
Server: "initial-server-value",
|
|
||||||
CertificateAuthorityData: "initial-ca-value",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Add(existingConfig))
|
|
||||||
})
|
|
||||||
|
|
||||||
it("updates the existing config to only apply the updates made by the func parameter", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
"myLabelKey2": "myLabelValue2",
|
|
||||||
},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {
|
|
||||||
configToUpdate.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
|
|
||||||
|
|
||||||
// Only the edited field should be changed.
|
|
||||||
expectedUpdatedConfig := existingConfig.DeepCopy()
|
|
||||||
expectedUpdatedConfig.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
expectedUpdateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedUpdatedConfig)
|
|
||||||
|
|
||||||
r.Equal([]coretesting.Action{expectedGetAction, expectedUpdateAction}, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
|
|
||||||
it("avoids the cost of an update if the local updates made by the func parameter did not actually change anything", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {
|
|
||||||
configToUpdate.KubeConfigInfo.CertificateAuthorityData = "initial-ca-value"
|
|
||||||
|
|
||||||
t := configToUpdate.Strategies[0].LastUpdateTime
|
|
||||||
loc, err := time.LoadLocation("Asia/Shanghai")
|
|
||||||
r.NoError(err)
|
|
||||||
configToUpdate.Strategies[0].LastUpdateTime = metav1.NewTime(t.In(loc))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
|
|
||||||
r.Equal([]coretesting.Action{expectedGetAction}, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
|
|
||||||
when("there is an unexpected error while getting the existing object", func() {
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor("get", "credentialissuers", func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, nil, fmt.Errorf("error on get")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns an error", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {},
|
|
||||||
)
|
|
||||||
r.EqualError(err, "could not create or update credentialissuer: get failed: error on get")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
when("there is an unexpected error while updating the existing object", func() {
|
|
||||||
it.Before(func() {
|
|
||||||
pinnipedAPIClient.PrependReactor("update", "credentialissuers", func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
return true, nil, fmt.Errorf("error on update")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("returns an error", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {
|
|
||||||
configToUpdate.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
r.EqualError(err, "could not create or update credentialissuer: error on update")
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
when("there is a conflict error while updating the existing object on the first try and the next try succeeds", func() {
|
|
||||||
var slightlyDifferentExistingConfig *configv1alpha1.CredentialIssuer
|
|
||||||
|
|
||||||
it.Before(func() {
|
|
||||||
hit := false
|
|
||||||
slightlyDifferentExistingConfig = existingConfig.DeepCopy()
|
|
||||||
slightlyDifferentExistingConfig.Status.KubeConfigInfo.Server = "some-other-server-value-from-conflicting-update"
|
|
||||||
|
|
||||||
pinnipedAPIClient.PrependReactor("update", "credentialissuers", func(_ coretesting.Action) (bool, runtime.Object, error) {
|
|
||||||
// Return an error on the first call, then fall through to the default (successful) response.
|
|
||||||
if !hit {
|
|
||||||
// Before the update fails, also change the object that will be returned by the next Get(),
|
|
||||||
// to make sure that the production code does a fresh Get() after detecting a conflict.
|
|
||||||
r.NoError(pinnipedAPIClient.Tracker().Update(credentialIssuerGVR, slightlyDifferentExistingConfig, ""))
|
|
||||||
hit = true
|
|
||||||
return true, nil, apierrors.NewConflict(schema.GroupResource{
|
|
||||||
Group: apiregistrationv1.GroupName,
|
|
||||||
Resource: "credentialissuers",
|
|
||||||
}, "alphav1.pinniped.dev", fmt.Errorf("there was a conflict"))
|
|
||||||
}
|
|
||||||
return false, nil, nil
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it("retries updates on conflict", func() {
|
|
||||||
err := CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
credentialIssuerResourceName,
|
|
||||||
map[string]string{
|
|
||||||
"myLabelKey1": "myLabelValue1",
|
|
||||||
"myLabelKey2": "myLabelValue2",
|
|
||||||
},
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *configv1alpha1.CredentialIssuerStatus) {
|
|
||||||
configToUpdate.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
},
|
|
||||||
)
|
|
||||||
r.NoError(err)
|
|
||||||
|
|
||||||
expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
|
|
||||||
|
|
||||||
// The first attempted update only includes its own edits.
|
|
||||||
firstExpectedUpdatedConfig := existingConfig.DeepCopy()
|
|
||||||
firstExpectedUpdatedConfig.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
firstExpectedUpdateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", firstExpectedUpdatedConfig)
|
|
||||||
|
|
||||||
// Both the edits made by this update and the edits made by the conflicting update should be included.
|
|
||||||
secondExpectedUpdatedConfig := existingConfig.DeepCopy()
|
|
||||||
secondExpectedUpdatedConfig.Status.KubeConfigInfo.Server = "some-other-server-value-from-conflicting-update"
|
|
||||||
secondExpectedUpdatedConfig.Status.KubeConfigInfo.CertificateAuthorityData = "new-ca-value"
|
|
||||||
secondExpectedUpdateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", secondExpectedUpdatedConfig)
|
|
||||||
|
|
||||||
expectedActions := []coretesting.Action{
|
|
||||||
expectedGetAction,
|
|
||||||
firstExpectedUpdateAction,
|
|
||||||
expectedGetAction,
|
|
||||||
secondExpectedUpdateAction,
|
|
||||||
}
|
|
||||||
r.Equal(expectedActions, pinnipedAPIClient.Actions())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}, spec.Parallel(), spec.Report(report.Terminal{}))
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
// Package issuerconfig contains controller(s) for reconciling CredentialIssuer's.
|
|
||||||
package issuerconfig
|
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package issuerconfig contains helpers for updating CredentialIssuer status entries.
|
||||||
package issuerconfig
|
package issuerconfig
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -15,23 +16,6 @@ import (
|
|||||||
"go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
"go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UpdateStrategy creates or updates the desired strategy in the CredentialIssuer status.strategies field.
|
|
||||||
// The CredentialIssuer will be created if it does not already exist.
|
|
||||||
func UpdateStrategy(ctx context.Context,
|
|
||||||
name string,
|
|
||||||
credentialIssuerLabels map[string]string,
|
|
||||||
pinnipedAPIClient versioned.Interface,
|
|
||||||
strategy v1alpha1.CredentialIssuerStrategy,
|
|
||||||
) error {
|
|
||||||
return CreateOrUpdateCredentialIssuerStatus(
|
|
||||||
ctx,
|
|
||||||
name,
|
|
||||||
credentialIssuerLabels,
|
|
||||||
pinnipedAPIClient,
|
|
||||||
func(configToUpdate *v1alpha1.CredentialIssuerStatus) { mergeStrategy(configToUpdate, strategy) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update a strategy on an existing CredentialIssuer, merging into any existing strategy entries.
|
// Update a strategy on an existing CredentialIssuer, merging into any existing strategy entries.
|
||||||
func Update(ctx context.Context, client versioned.Interface, issuer *v1alpha1.CredentialIssuer, strategy v1alpha1.CredentialIssuerStrategy) error {
|
func Update(ctx context.Context, client versioned.Interface, issuer *v1alpha1.CredentialIssuer, strategy v1alpha1.CredentialIssuerStrategy) error {
|
||||||
// Update the existing object to merge in the new strategy.
|
// Update the existing object to merge in the new strategy.
|
||||||
@ -58,7 +42,9 @@ func mergeStrategy(configToUpdate *v1alpha1.CredentialIssuerStatus, strategy v1a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
strategy.DeepCopyInto(existing)
|
if !equalExceptLastUpdated(existing, &strategy) {
|
||||||
|
strategy.DeepCopyInto(existing)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
configToUpdate.Strategies = append(configToUpdate.Strategies, strategy)
|
configToUpdate.Strategies = append(configToUpdate.Strategies, strategy)
|
||||||
}
|
}
|
||||||
@ -91,3 +77,11 @@ func (s sortableStrategies) Less(i, j int) bool {
|
|||||||
return s[i].Type < s[j].Type
|
return s[i].Type < s[j].Type
|
||||||
}
|
}
|
||||||
func (s sortableStrategies) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s sortableStrategies) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
|
func equalExceptLastUpdated(s1, s2 *v1alpha1.CredentialIssuerStrategy) bool {
|
||||||
|
s1 = s1.DeepCopy()
|
||||||
|
s2 = s2.DeepCopy()
|
||||||
|
s1.LastUpdateTime = metav1.Time{}
|
||||||
|
s2.LastUpdateTime = metav1.Time{}
|
||||||
|
return apiequality.Semantic.DeepEqual(s1, s2)
|
||||||
|
}
|
@ -125,6 +125,38 @@ func TestMergeStrategy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "existing entry matches except for LastUpdated time",
|
||||||
|
configToUpdate: v1alpha1.CredentialIssuerStatus{
|
||||||
|
Strategies: []v1alpha1.CredentialIssuerStrategy{
|
||||||
|
{
|
||||||
|
Type: "Type1",
|
||||||
|
Status: v1alpha1.ErrorStrategyStatus,
|
||||||
|
Reason: "some starting reason",
|
||||||
|
Message: "some starting message",
|
||||||
|
LastUpdateTime: t1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
strategy: v1alpha1.CredentialIssuerStrategy{
|
||||||
|
Type: "Type1",
|
||||||
|
Status: v1alpha1.ErrorStrategyStatus,
|
||||||
|
Reason: "some starting reason",
|
||||||
|
Message: "some starting message",
|
||||||
|
LastUpdateTime: t2,
|
||||||
|
},
|
||||||
|
expected: v1alpha1.CredentialIssuerStatus{
|
||||||
|
Strategies: []v1alpha1.CredentialIssuerStrategy{
|
||||||
|
{
|
||||||
|
Type: "Type1",
|
||||||
|
Status: v1alpha1.ErrorStrategyStatus,
|
||||||
|
Reason: "some starting reason",
|
||||||
|
Message: "some starting message",
|
||||||
|
LastUpdateTime: t1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "new entry among others",
|
name: "new entry among others",
|
||||||
configToUpdate: v1alpha1.CredentialIssuerStatus{
|
configToUpdate: v1alpha1.CredentialIssuerStatus{
|
@ -252,16 +252,15 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
|||||||
WithController(
|
WithController(
|
||||||
impersonatorconfig.NewImpersonatorConfigController(
|
impersonatorconfig.NewImpersonatorConfigController(
|
||||||
c.ServerInstallationInfo.Namespace,
|
c.ServerInstallationInfo.Namespace,
|
||||||
c.NamesConfig.ImpersonationConfigMap,
|
|
||||||
c.NamesConfig.CredentialIssuer,
|
c.NamesConfig.CredentialIssuer,
|
||||||
client.Kubernetes,
|
client.Kubernetes,
|
||||||
client.PinnipedConcierge,
|
client.PinnipedConcierge,
|
||||||
informers.installationNamespaceK8s.Core().V1().ConfigMaps(),
|
informers.pinniped.Config().V1alpha1().CredentialIssuers(),
|
||||||
informers.installationNamespaceK8s.Core().V1().Services(),
|
informers.installationNamespaceK8s.Core().V1().Services(),
|
||||||
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
informers.installationNamespaceK8s.Core().V1().Secrets(),
|
||||||
controllerlib.WithInformer,
|
controllerlib.WithInformer,
|
||||||
controllerlib.WithInitialEvent,
|
|
||||||
c.NamesConfig.ImpersonationLoadBalancerService,
|
c.NamesConfig.ImpersonationLoadBalancerService,
|
||||||
|
c.NamesConfig.ImpersonationClusterIPService,
|
||||||
c.NamesConfig.ImpersonationTLSCertificateSecret,
|
c.NamesConfig.ImpersonationTLSCertificateSecret,
|
||||||
c.NamesConfig.ImpersonationCACertificateSecret,
|
c.NamesConfig.ImpersonationCACertificateSecret,
|
||||||
c.Labels,
|
c.Labels,
|
||||||
@ -269,6 +268,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
|
|||||||
impersonator.New,
|
impersonator.New,
|
||||||
c.NamesConfig.ImpersonationSignerSecret,
|
c.NamesConfig.ImpersonationSignerSecret,
|
||||||
c.ImpersonationSigningCertProvider,
|
c.ImpersonationSigningCertProvider,
|
||||||
|
klogr.New(),
|
||||||
),
|
),
|
||||||
singletonWorker,
|
singletonWorker,
|
||||||
).
|
).
|
||||||
|
@ -17,6 +17,8 @@ You should have a [supported Kubernetes cluster]({{< ref "../reference/supported
|
|||||||
1. Install the latest version of the Concierge into the `pinniped-concierge` namespace with default options:
|
1. Install the latest version of the Concierge into the `pinniped-concierge` namespace with default options:
|
||||||
|
|
||||||
- `kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-concierge.yaml`
|
- `kubectl apply -f https://get.pinniped.dev/latest/install-pinniped-concierge.yaml`
|
||||||
|
|
||||||
|
Warning: the default configuration may create a public LoadBalancer Service on your cluster.
|
||||||
|
|
||||||
## With specific version and default options
|
## With specific version and default options
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@ -51,13 +52,12 @@ import (
|
|||||||
"k8s.io/client-go/util/cert"
|
"k8s.io/client-go/util/cert"
|
||||||
"k8s.io/client-go/util/certificate/csr"
|
"k8s.io/client-go/util/certificate/csr"
|
||||||
"k8s.io/client-go/util/keyutil"
|
"k8s.io/client-go/util/keyutil"
|
||||||
"sigs.k8s.io/yaml"
|
"k8s.io/client-go/util/retry"
|
||||||
|
|
||||||
conciergev1alpha "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
conciergev1alpha "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||||
identityv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/identity/v1alpha1"
|
identityv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/identity/v1alpha1"
|
||||||
loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1"
|
loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1"
|
||||||
pinnipedconciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
pinnipedconciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
||||||
"go.pinniped.dev/internal/concierge/impersonator"
|
|
||||||
"go.pinniped.dev/internal/httputil/roundtripper"
|
"go.pinniped.dev/internal/httputil/roundtripper"
|
||||||
"go.pinniped.dev/internal/kubeclient"
|
"go.pinniped.dev/internal/kubeclient"
|
||||||
"go.pinniped.dev/internal/testutil"
|
"go.pinniped.dev/internal/testutil"
|
||||||
@ -121,7 +121,10 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
mostRecentTokenCredentialRequestResponse *loginv1alpha1.TokenCredentialRequest
|
mostRecentTokenCredentialRequestResponse *loginv1alpha1.TokenCredentialRequest
|
||||||
mostRecentTokenCredentialRequestResponseLock sync.Mutex
|
mostRecentTokenCredentialRequestResponseLock sync.Mutex
|
||||||
)
|
)
|
||||||
refreshCredential := func(t *testing.T, impersonationProxyURL string, impersonationProxyCACertPEM []byte) *loginv1alpha1.ClusterCredential {
|
|
||||||
|
refreshCredentialHelper := func(t *testing.T, client pinnipedconciergeclientset.Interface) *loginv1alpha1.ClusterCredential {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
mostRecentTokenCredentialRequestResponseLock.Lock()
|
mostRecentTokenCredentialRequestResponseLock.Lock()
|
||||||
defer mostRecentTokenCredentialRequestResponseLock.Unlock()
|
defer mostRecentTokenCredentialRequestResponseLock.Unlock()
|
||||||
if mostRecentTokenCredentialRequestResponse == nil || credentialAlmostExpired(t, mostRecentTokenCredentialRequestResponse) {
|
if mostRecentTokenCredentialRequestResponse == nil || credentialAlmostExpired(t, mostRecentTokenCredentialRequestResponse) {
|
||||||
@ -133,18 +136,13 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
// However, we issue short-lived certs, so this cert will only be valid for a few minutes.
|
// However, we issue short-lived certs, so this cert will only be valid for a few minutes.
|
||||||
// Cache it until it is almost expired and then refresh it whenever it is close to expired.
|
// Cache it until it is almost expired and then refresh it whenever it is close to expired.
|
||||||
//
|
//
|
||||||
// Also, use an anonymous client which goes through the impersonation proxy to make the request because that's
|
|
||||||
// what would normally happen when a user is using a kubeconfig where the server is the impersonation proxy,
|
|
||||||
// so it more closely simulates the normal use case, and also because we want this to work on AKS clusters
|
|
||||||
// which do not allow anonymous requests.
|
|
||||||
client := newAnonymousImpersonationProxyClient(t, impersonationProxyURL, impersonationProxyCACertPEM, nil).PinnipedConcierge
|
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
mostRecentTokenCredentialRequestResponse, err = createTokenCredentialRequest(credentialRequestSpecWithWorkingCredentials, client)
|
mostRecentTokenCredentialRequestResponse, err = createTokenCredentialRequest(credentialRequestSpecWithWorkingCredentials, client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("failed to make TokenCredentialRequest: %s", library.Sdump(err))
|
t.Logf("failed to make TokenCredentialRequest: %s", library.Sdump(err))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return mostRecentTokenCredentialRequestResponse.Status.Credential != nil
|
||||||
}, 5*time.Minute, 5*time.Second)
|
}, 5*time.Minute, 5*time.Second)
|
||||||
|
|
||||||
require.Nil(t, mostRecentTokenCredentialRequestResponse.Status.Message,
|
require.Nil(t, mostRecentTokenCredentialRequestResponse.Status.Message,
|
||||||
@ -156,36 +154,38 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
// tokens, we should revisit this test's rest config below.
|
// tokens, we should revisit this test's rest config below.
|
||||||
require.Empty(t, mostRecentTokenCredentialRequestResponse.Status.Credential.Token)
|
require.Empty(t, mostRecentTokenCredentialRequestResponse.Status.Credential.Token)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mostRecentTokenCredentialRequestResponse.Status.Credential
|
return mostRecentTokenCredentialRequestResponse.Status.Credential
|
||||||
}
|
}
|
||||||
|
|
||||||
oldConfigMap, err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Get(ctx, impersonationProxyConfigMapName(env), metav1.GetOptions{})
|
refreshCredential := func(t *testing.T, impersonationProxyURL string, impersonationProxyCACertPEM []byte) *loginv1alpha1.ClusterCredential {
|
||||||
if !k8serrors.IsNotFound(err) {
|
// Use an anonymous client which goes through the impersonation proxy to make the request because that's
|
||||||
require.NoError(t, err) // other errors aside from NotFound are unexpected
|
// what would normally happen when a user is using a kubeconfig where the server is the impersonation proxy,
|
||||||
t.Logf("stashing a pre-existing configmap %s", oldConfigMap.Name)
|
// so it more closely simulates the normal use case, and also because we want this to work on AKS clusters
|
||||||
require.NoError(t, adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName(env), metav1.DeleteOptions{}))
|
// which do not allow anonymous requests.
|
||||||
|
client := newAnonymousImpersonationProxyClient(t, impersonationProxyURL, impersonationProxyCACertPEM, nil).PinnipedConcierge
|
||||||
|
return refreshCredentialHelper(t, client)
|
||||||
}
|
}
|
||||||
// At the end of the test, clean up the ConfigMap.
|
|
||||||
|
oldCredentialIssuer, err := adminConciergeClient.ConfigV1alpha1().CredentialIssuers().Get(ctx, credentialIssuerName(env), metav1.GetOptions{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
// At the end of the test, clean up the CredentialIssuer
|
||||||
t.Cleanup(func() {
|
t.Cleanup(func() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Delete any version that was created by this test.
|
// Delete any version that was created by this test.
|
||||||
t.Logf("cleaning up configmap at end of test %s", impersonationProxyConfigMapName(env))
|
t.Logf("cleaning up credentialissuer at end of test %s", credentialIssuerName(env))
|
||||||
err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Delete(ctx, impersonationProxyConfigMapName(env), metav1.DeleteOptions{})
|
err = retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
if !k8serrors.IsNotFound(err) {
|
newCredentialIssuer, err := adminConciergeClient.ConfigV1alpha1().CredentialIssuers().Get(ctx, credentialIssuerName(env), metav1.GetOptions{})
|
||||||
require.NoError(t, err) // only not found errors are acceptable
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
// Only recreate it if it already existed at the start of this test.
|
oldCredentialIssuer.Spec.DeepCopyInto(&newCredentialIssuer.Spec)
|
||||||
if len(oldConfigMap.Data) != 0 {
|
_, err = adminConciergeClient.ConfigV1alpha1().CredentialIssuers().Update(ctx, newCredentialIssuer, metav1.UpdateOptions{})
|
||||||
t.Log(oldConfigMap)
|
return err
|
||||||
oldConfigMap.UID = "" // cant have a UID yet
|
})
|
||||||
oldConfigMap.ResourceVersion = ""
|
require.NoError(t, err)
|
||||||
t.Logf("restoring a pre-existing configmap %s", oldConfigMap.Name)
|
|
||||||
_, err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, oldConfigMap, metav1.CreateOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are running on an environment that has a load balancer, expect that the
|
// If we are running on an environment that has a load balancer, expect that the
|
||||||
// CredentialIssuer will be updated eventually with a successful impersonation proxy frontend.
|
// CredentialIssuer will be updated eventually with a successful impersonation proxy frontend.
|
||||||
@ -200,6 +200,15 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
// this point depending on the capabilities of the cluster under test. We handle each possible case here.
|
// this point depending on the capabilities of the cluster under test. We handle each possible case here.
|
||||||
switch {
|
switch {
|
||||||
case impersonatorShouldHaveStartedAutomaticallyByDefault && clusterSupportsLoadBalancers:
|
case impersonatorShouldHaveStartedAutomaticallyByDefault && clusterSupportsLoadBalancers:
|
||||||
|
// configure the credential issuer spec to have the impersonation proxy in auto mode
|
||||||
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
|
Mode: conciergev1alpha.ImpersonationProxyModeAuto,
|
||||||
|
Service: conciergev1alpha.ImpersonationProxyServiceSpec{
|
||||||
|
Type: conciergev1alpha.ImpersonationProxyServiceTypeLoadBalancer,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
// Auto mode should have decided that the impersonator will run and should have started a load balancer,
|
// Auto mode should have decided that the impersonator will run and should have started a load balancer,
|
||||||
// and we will be able to use the load balancer to access the impersonator. (e.g. GKE, AKS, EKS)
|
// and we will be able to use the load balancer to access the impersonator. (e.g. GKE, AKS, EKS)
|
||||||
// Check that load balancer has been automatically created by the impersonator's "auto" mode.
|
// Check that load balancer has been automatically created by the impersonator's "auto" mode.
|
||||||
@ -221,10 +230,11 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
requireDisabledStrategy(ctx, t, env, adminConciergeClient)
|
requireDisabledStrategy(ctx, t, env, adminConciergeClient)
|
||||||
|
|
||||||
// Create configuration to make the impersonation proxy turn on with no endpoint (i.e. automatically create a load balancer).
|
// Create configuration to make the impersonation proxy turn on with no endpoint (i.e. automatically create a load balancer).
|
||||||
configMap := impersonationProxyConfigMapForConfig(t, env, impersonator.Config{Mode: impersonator.ModeEnabled})
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
t.Logf("creating configmap %s", configMap.Name)
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
_, err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
Mode: conciergev1alpha.ImpersonationProxyModeEnabled,
|
||||||
require.NoError(t, err)
|
},
|
||||||
|
})
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Auto mode should have decided that the impersonator will be disabled. We need to manually enable it.
|
// Auto mode should have decided that the impersonator will be disabled. We need to manually enable it.
|
||||||
@ -246,13 +256,12 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
require.Truef(t, isErr, "wanted error %q to be service unavailable via squid error, but: %s", err, message)
|
require.Truef(t, isErr, "wanted error %q to be service unavailable via squid error, but: %s", err, message)
|
||||||
|
|
||||||
// Create configuration to make the impersonation proxy turn on with a hard coded endpoint (without a load balancer).
|
// Create configuration to make the impersonation proxy turn on with a hard coded endpoint (without a load balancer).
|
||||||
configMap := impersonationProxyConfigMapForConfig(t, env, impersonator.Config{
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
Mode: impersonator.ModeEnabled,
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
Endpoint: proxyServiceEndpoint,
|
Mode: conciergev1alpha.ImpersonationProxyModeEnabled,
|
||||||
|
ExternalEndpoint: proxyServiceEndpoint,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
t.Logf("creating configmap %s", configMap.Name)
|
|
||||||
_, err = adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point the impersonator should be starting/running. When it is ready, the CredentialIssuer's
|
// At this point the impersonator should be starting/running. When it is ready, the CredentialIssuer's
|
||||||
@ -376,6 +385,24 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
kubeconfigPath, envVarsWithProxy, _ := getImpersonationKubeconfig(t, env, impersonationProxyURL, impersonationProxyCACertPEM, credentialRequestSpecWithWorkingCredentials.Authenticator)
|
kubeconfigPath, envVarsWithProxy, _ := getImpersonationKubeconfig(t, env, impersonationProxyURL, impersonationProxyCACertPEM, credentialRequestSpecWithWorkingCredentials.Authenticator)
|
||||||
|
|
||||||
|
// set credential issuer to have new annotation to ensure the idle timeout is long enough on AWS.
|
||||||
|
// this also ensures that updates to the credential issuer impersonation proxy spec go through
|
||||||
|
if impersonatorShouldHaveStartedAutomaticallyByDefault && clusterSupportsLoadBalancers {
|
||||||
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
|
Mode: conciergev1alpha.ImpersonationProxyModeAuto,
|
||||||
|
Service: conciergev1alpha.ImpersonationProxyServiceSpec{
|
||||||
|
Type: conciergev1alpha.ImpersonationProxyServiceTypeLoadBalancer,
|
||||||
|
Annotations: map[string]string{"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "4000"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// Wait until the annotation shows up on the load balancer
|
||||||
|
library.RequireEventuallyWithoutError(t, func() (bool, error) {
|
||||||
|
return loadBalancerHasAnnotations(ctx, env, adminClient, map[string]string{"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "4000"})
|
||||||
|
}, 30*time.Second, 500*time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
// Run the kubectl port-forward command.
|
// Run the kubectl port-forward command.
|
||||||
timeout, cancelFunc := context.WithTimeout(ctx, 2*time.Minute)
|
timeout, cancelFunc := context.WithTimeout(ctx, 2*time.Minute)
|
||||||
defer cancelFunc()
|
defer cancelFunc()
|
||||||
@ -1181,18 +1208,47 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("running impersonation proxy with ClusterIP service", func(t *testing.T) {
|
||||||
|
if env.Proxy == "" {
|
||||||
|
t.Skip("Skipping ClusterIP test because squid proxy is not present")
|
||||||
|
}
|
||||||
|
clusterIPServiceURL := fmt.Sprintf("%s.%s.svc.cluster.local", impersonationProxyClusterIPName(env), env.ConciergeNamespace)
|
||||||
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
|
Mode: conciergev1alpha.ImpersonationProxyModeEnabled,
|
||||||
|
ExternalEndpoint: clusterIPServiceURL,
|
||||||
|
Service: conciergev1alpha.ImpersonationProxyServiceSpec{
|
||||||
|
Type: conciergev1alpha.ImpersonationProxyServiceTypeClusterIP,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// wait until the credential issuer is updated with the new url
|
||||||
|
require.Eventually(t, func() bool {
|
||||||
|
newImpersonationProxyURL, _ := performImpersonatorDiscovery(ctx, t, env, adminConciergeClient)
|
||||||
|
return newImpersonationProxyURL == "https://"+clusterIPServiceURL
|
||||||
|
}, 30*time.Second, 500*time.Millisecond)
|
||||||
|
newImpersonationProxyURL, newImpersonationProxyCACertPEM := performImpersonatorDiscovery(ctx, t, env, adminConciergeClient)
|
||||||
|
|
||||||
|
anonymousClient := newAnonymousImpersonationProxyClientWithProxy(t, newImpersonationProxyURL, newImpersonationProxyCACertPEM, nil).PinnipedConcierge
|
||||||
|
refreshedCredentials := refreshCredentialHelper(t, anonymousClient)
|
||||||
|
|
||||||
|
client := newImpersonationProxyClientWithCredentialsAndProxy(t, refreshedCredentials, newImpersonationProxyURL, newImpersonationProxyCACertPEM, nil).Kubernetes
|
||||||
|
|
||||||
|
// everything should work properly through the cluster ip service
|
||||||
|
t.Run(
|
||||||
|
"access as user",
|
||||||
|
library.AccessAsUserTest(ctx, env.TestUser.ExpectedUsername, client),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("manually disabling the impersonation proxy feature", func(t *testing.T) {
|
t.Run("manually disabling the impersonation proxy feature", func(t *testing.T) {
|
||||||
// Update configuration to force the proxy to disabled mode
|
// Update configuration to force the proxy to disabled mode
|
||||||
configMap := impersonationProxyConfigMapForConfig(t, env, impersonator.Config{Mode: impersonator.ModeDisabled})
|
updateCredentialIssuer(ctx, t, env, adminConciergeClient, conciergev1alpha.CredentialIssuerSpec{
|
||||||
if clusterSupportsLoadBalancers {
|
ImpersonationProxy: &conciergev1alpha.ImpersonationProxySpec{
|
||||||
t.Logf("creating configmap %s", configMap.Name)
|
Mode: conciergev1alpha.ImpersonationProxyModeDisabled,
|
||||||
_, err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Create(ctx, &configMap, metav1.CreateOptions{})
|
},
|
||||||
require.NoError(t, err)
|
})
|
||||||
} else {
|
|
||||||
t.Logf("updating configmap %s", configMap.Name)
|
|
||||||
_, err := adminClient.CoreV1().ConfigMaps(env.ConciergeNamespace).Update(ctx, &configMap, metav1.UpdateOptions{})
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if clusterSupportsLoadBalancers {
|
if clusterSupportsLoadBalancers {
|
||||||
// The load balancer should have been deleted when we disabled the impersonation proxy.
|
// The load balancer should have been deleted when we disabled the impersonation proxy.
|
||||||
@ -1450,19 +1506,19 @@ func kubeconfigProxyFunc(t *testing.T, squidProxyURL string) func(req *http.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func impersonationProxyConfigMapForConfig(t *testing.T, env *library.TestEnv, config impersonator.Config) corev1.ConfigMap {
|
func updateCredentialIssuer(ctx context.Context, t *testing.T, env *library.TestEnv, adminConciergeClient pinnipedconciergeclientset.Interface, spec conciergev1alpha.CredentialIssuerSpec) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
configString, err := yaml.Marshal(config)
|
err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
|
||||||
|
newCredentialIssuer, err := adminConciergeClient.ConfigV1alpha1().CredentialIssuers().Get(ctx, credentialIssuerName(env), metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
spec.DeepCopyInto(&newCredentialIssuer.Spec)
|
||||||
|
_, err = adminConciergeClient.ConfigV1alpha1().CredentialIssuers().Update(ctx, newCredentialIssuer, metav1.UpdateOptions{})
|
||||||
|
return err
|
||||||
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
configMap := corev1.ConfigMap{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: impersonationProxyConfigMapName(env),
|
|
||||||
},
|
|
||||||
Data: map[string]string{
|
|
||||||
"config.yaml": string(configString),
|
|
||||||
}}
|
|
||||||
return configMap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func hasImpersonationProxyLoadBalancerService(ctx context.Context, env *library.TestEnv, client kubernetes.Interface) (bool, error) {
|
func hasImpersonationProxyLoadBalancerService(ctx context.Context, env *library.TestEnv, client kubernetes.Interface) (bool, error) {
|
||||||
@ -1476,8 +1532,16 @@ func hasImpersonationProxyLoadBalancerService(ctx context.Context, env *library.
|
|||||||
return service.Spec.Type == corev1.ServiceTypeLoadBalancer, nil
|
return service.Spec.Type == corev1.ServiceTypeLoadBalancer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func impersonationProxyConfigMapName(env *library.TestEnv) string {
|
func loadBalancerHasAnnotations(ctx context.Context, env *library.TestEnv, client kubernetes.Interface, annotations map[string]string) (bool, error) {
|
||||||
return env.ConciergeAppName + "-impersonation-proxy-config"
|
service, err := client.CoreV1().Services(env.ConciergeNamespace).Get(ctx, impersonationProxyLoadBalancerName(env), metav1.GetOptions{})
|
||||||
|
if k8serrors.IsNotFound(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
hasExactAnnotations := reflect.DeepEqual(annotations, service.Annotations)
|
||||||
|
return service.Spec.Type == corev1.ServiceTypeLoadBalancer && hasExactAnnotations, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func impersonationProxyTLSSecretName(env *library.TestEnv) string {
|
func impersonationProxyTLSSecretName(env *library.TestEnv) string {
|
||||||
@ -1492,6 +1556,10 @@ func impersonationProxyLoadBalancerName(env *library.TestEnv) string {
|
|||||||
return env.ConciergeAppName + "-impersonation-proxy-load-balancer"
|
return env.ConciergeAppName + "-impersonation-proxy-load-balancer"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func impersonationProxyClusterIPName(env *library.TestEnv) string {
|
||||||
|
return env.ConciergeAppName + "-impersonation-proxy-cluster-ip"
|
||||||
|
}
|
||||||
|
|
||||||
func credentialIssuerName(env *library.TestEnv) string {
|
func credentialIssuerName(env *library.TestEnv) string {
|
||||||
return env.ConciergeAppName + "-config"
|
return env.ConciergeAppName + "-config"
|
||||||
}
|
}
|
||||||
@ -1643,6 +1711,29 @@ func newAnonymousImpersonationProxyClient(t *testing.T, impersonationProxyURL st
|
|||||||
return newImpersonationProxyClientWithCredentials(t, emptyCredentials, impersonationProxyURL, impersonationProxyCACertPEM, nestedImpersonationConfig)
|
return newImpersonationProxyClientWithCredentials(t, emptyCredentials, impersonationProxyURL, impersonationProxyCACertPEM, nestedImpersonationConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newImpersonationProxyClientWithCredentialsAndProxy(t *testing.T, credentials *loginv1alpha1.ClusterCredential, impersonationProxyURL string, impersonationProxyCACertPEM []byte, nestedImpersonationConfig *rest.ImpersonationConfig) *kubeclient.Client {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
env := library.IntegrationEnv(t)
|
||||||
|
|
||||||
|
kubeconfig := impersonationProxyRestConfig(credentials, impersonationProxyURL, impersonationProxyCACertPEM, nestedImpersonationConfig)
|
||||||
|
kubeconfig.Proxy = kubeconfigProxyFunc(t, env.Proxy)
|
||||||
|
return library.NewKubeclient(t, kubeconfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this uses a proxy in all cases, the other will only use it if you don't have load balancer capabilities.
|
||||||
|
func newAnonymousImpersonationProxyClientWithProxy(t *testing.T, impersonationProxyURL string, impersonationProxyCACertPEM []byte, nestedImpersonationConfig *rest.ImpersonationConfig) *kubeclient.Client {
|
||||||
|
t.Helper()
|
||||||
|
env := library.IntegrationEnv(t)
|
||||||
|
|
||||||
|
emptyCredentials := &loginv1alpha1.ClusterCredential{}
|
||||||
|
kubeconfig := impersonationProxyRestConfig(emptyCredentials, impersonationProxyURL, impersonationProxyCACertPEM, nestedImpersonationConfig)
|
||||||
|
|
||||||
|
kubeconfig.Proxy = kubeconfigProxyFunc(t, env.Proxy)
|
||||||
|
|
||||||
|
return library.NewKubeclient(t, kubeconfig)
|
||||||
|
}
|
||||||
|
|
||||||
func impersonationProxyViaSquidKubeClientWithoutCredential(t *testing.T, proxyServiceEndpoint string) kubernetes.Interface {
|
func impersonationProxyViaSquidKubeClientWithoutCredential(t *testing.T, proxyServiceEndpoint string) kubernetes.Interface {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
|
@ -228,6 +228,11 @@ func TestKubeClientOwnerRef(t *testing.T) {
|
|||||||
GenerateName: "owner-ref-test-",
|
GenerateName: "owner-ref-test-",
|
||||||
OwnerReferences: nil, // no owner refs set
|
OwnerReferences: nil, // no owner refs set
|
||||||
},
|
},
|
||||||
|
Spec: conciergeconfigv1alpha1.CredentialIssuerSpec{
|
||||||
|
ImpersonationProxy: &conciergeconfigv1alpha1.ImpersonationProxySpec{
|
||||||
|
Mode: conciergeconfigv1alpha1.ImpersonationProxyModeDisabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
metav1.CreateOptions{},
|
metav1.CreateOptions{},
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user