diff --git a/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl b/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl index 63d59446..39989501 100644 --- a/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl +++ b/apis/concierge/config/v1alpha1/types_credentialissuer.go.tmpl @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml b/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml index 900db6cb..d61a7835 100644 --- a/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/deploy/concierge/config.concierge.pinniped.dev_credentialissuers.yaml @@ -40,7 +40,8 @@ spec: properties: kubeConfigInfo: description: Information needed to form a valid Pinniped-based kubeconfig - using this credential issuer. + using this credential issuer. This field is deprecated and will + be removed in a future version. properties: certificateAuthorityData: description: The K8s API server CA bundle. @@ -62,6 +63,38 @@ spec: description: Status of an integration strategy that was attempted by Pinniped. properties: + frontend: + description: Frontend describes how clients can connect using + this strategy. + properties: + tokenCredentialRequestInfo: + description: TokenCredentialRequestAPIInfo describes the + parameters for the TokenCredentialRequest API on this + Concierge. This field is only set when Type is "TokenCredentialRequestAPI". + properties: + certificateAuthorityData: + description: CertificateAuthorityData is the Kubernetes + API server CA bundle. + minLength: 1 + type: string + server: + description: Server is the Kubernetes API server URL. + minLength: 1 + pattern: ^https://|^http:// + type: string + required: + - certificateAuthorityData + - server + type: object + type: + description: Type describes which frontend mechanism clients + can use with a strategy. + enum: + - TokenCredentialRequestAPI + type: string + required: + - type + type: object lastUpdateTime: description: When the status was last checked. format: date-time diff --git a/generated/1.17/README.adoc b/generated/1.17/README.adoc index d909c9de..c2848d45 100644 --- a/generated/1.17/README.adoc +++ b/generated/1.17/README.adoc @@ -236,6 +236,24 @@ Describes the configuration status of a Pinniped credential issuer. |=== +[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerfrontend"] +==== CredentialIssuerFrontend + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy. +| *`tokenCredentialRequestInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo[$$TokenCredentialRequestAPIInfo$$]__ | TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. This field is only set when Type is "TokenCredentialRequestAPI". +|=== + + [id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo"] ==== CredentialIssuerKubeConfigInfo @@ -270,7 +288,7 @@ Status of a credential issuer. |=== | Field | Description | *`strategies`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] array__ | List of integration strategies that were attempted by Pinniped. -| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. +| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. This field is deprecated and will be removed in a future version. |=== @@ -292,6 +310,25 @@ Status of a credential issuer. | *`reason`* __StrategyReason__ | Reason for the current status. | *`message`* __string__ | Human-readable description of the current status. | *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#time-v1-meta[$$Time$$]__ | When the status was last checked. +| *`frontend`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$]__ | Frontend describes how clients can connect using this strategy. +|=== + + +[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"] +==== TokenCredentialRequestAPIInfo + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`server`* __string__ | Server is the Kubernetes API server URL. +| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the Kubernetes API server CA bundle. |=== diff --git a/generated/1.17/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.17/apis/concierge/config/v1alpha1/types_credentialissuer.go index 63d59446..39989501 100644 --- a/generated/1.17/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.17/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/generated/1.17/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.17/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index eebbe7af..ad9a9f66 100644 --- a/generated/1.17/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.17/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -38,6 +38,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) { + *out = *in + if in.TokenCredentialRequestAPIInfo != nil { + in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo + *out = new(TokenCredentialRequestAPIInfo) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend. +func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend { + if in == nil { + return nil + } + out := new(CredentialIssuerFrontend) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialIssuerKubeConfigInfo) DeepCopyInto(out *CredentialIssuerKubeConfigInfo) { *out = *in @@ -119,6 +140,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(CredentialIssuerFrontend) + (*in).DeepCopyInto(*out) + } return } @@ -131,3 +157,19 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenCredentialRequestAPIInfo. +func (in *TokenCredentialRequestAPIInfo) DeepCopy() *TokenCredentialRequestAPIInfo { + if in == nil { + return nil + } + out := new(TokenCredentialRequestAPIInfo) + in.DeepCopyInto(out) + return out +} diff --git a/generated/1.17/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.17/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 900db6cb..d61a7835 100644 --- a/generated/1.17/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.17/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -40,7 +40,8 @@ spec: properties: kubeConfigInfo: description: Information needed to form a valid Pinniped-based kubeconfig - using this credential issuer. + using this credential issuer. This field is deprecated and will + be removed in a future version. properties: certificateAuthorityData: description: The K8s API server CA bundle. @@ -62,6 +63,38 @@ spec: description: Status of an integration strategy that was attempted by Pinniped. properties: + frontend: + description: Frontend describes how clients can connect using + this strategy. + properties: + tokenCredentialRequestInfo: + description: TokenCredentialRequestAPIInfo describes the + parameters for the TokenCredentialRequest API on this + Concierge. This field is only set when Type is "TokenCredentialRequestAPI". + properties: + certificateAuthorityData: + description: CertificateAuthorityData is the Kubernetes + API server CA bundle. + minLength: 1 + type: string + server: + description: Server is the Kubernetes API server URL. + minLength: 1 + pattern: ^https://|^http:// + type: string + required: + - certificateAuthorityData + - server + type: object + type: + description: Type describes which frontend mechanism clients + can use with a strategy. + enum: + - TokenCredentialRequestAPI + type: string + required: + - type + type: object lastUpdateTime: description: When the status was last checked. format: date-time diff --git a/generated/1.18/README.adoc b/generated/1.18/README.adoc index a40e3568..4a1580f2 100644 --- a/generated/1.18/README.adoc +++ b/generated/1.18/README.adoc @@ -236,6 +236,24 @@ Describes the configuration status of a Pinniped credential issuer. |=== +[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerfrontend"] +==== CredentialIssuerFrontend + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy. +| *`tokenCredentialRequestInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo[$$TokenCredentialRequestAPIInfo$$]__ | TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. This field is only set when Type is "TokenCredentialRequestAPI". +|=== + + [id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo"] ==== CredentialIssuerKubeConfigInfo @@ -270,7 +288,7 @@ Status of a credential issuer. |=== | Field | Description | *`strategies`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] array__ | List of integration strategies that were attempted by Pinniped. -| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. +| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. This field is deprecated and will be removed in a future version. |=== @@ -292,6 +310,25 @@ Status of a credential issuer. | *`reason`* __StrategyReason__ | Reason for the current status. | *`message`* __string__ | Human-readable description of the current status. | *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.18/#time-v1-meta[$$Time$$]__ | When the status was last checked. +| *`frontend`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$]__ | Frontend describes how clients can connect using this strategy. +|=== + + +[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"] +==== TokenCredentialRequestAPIInfo + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`server`* __string__ | Server is the Kubernetes API server URL. +| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the Kubernetes API server CA bundle. |=== diff --git a/generated/1.18/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.18/apis/concierge/config/v1alpha1/types_credentialissuer.go index 63d59446..39989501 100644 --- a/generated/1.18/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.18/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/generated/1.18/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.18/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index eebbe7af..ad9a9f66 100644 --- a/generated/1.18/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.18/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -38,6 +38,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) { + *out = *in + if in.TokenCredentialRequestAPIInfo != nil { + in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo + *out = new(TokenCredentialRequestAPIInfo) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend. +func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend { + if in == nil { + return nil + } + out := new(CredentialIssuerFrontend) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialIssuerKubeConfigInfo) DeepCopyInto(out *CredentialIssuerKubeConfigInfo) { *out = *in @@ -119,6 +140,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(CredentialIssuerFrontend) + (*in).DeepCopyInto(*out) + } return } @@ -131,3 +157,19 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenCredentialRequestAPIInfo. +func (in *TokenCredentialRequestAPIInfo) DeepCopy() *TokenCredentialRequestAPIInfo { + if in == nil { + return nil + } + out := new(TokenCredentialRequestAPIInfo) + in.DeepCopyInto(out) + return out +} diff --git a/generated/1.18/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.18/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 900db6cb..d61a7835 100644 --- a/generated/1.18/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.18/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -40,7 +40,8 @@ spec: properties: kubeConfigInfo: description: Information needed to form a valid Pinniped-based kubeconfig - using this credential issuer. + using this credential issuer. This field is deprecated and will + be removed in a future version. properties: certificateAuthorityData: description: The K8s API server CA bundle. @@ -62,6 +63,38 @@ spec: description: Status of an integration strategy that was attempted by Pinniped. properties: + frontend: + description: Frontend describes how clients can connect using + this strategy. + properties: + tokenCredentialRequestInfo: + description: TokenCredentialRequestAPIInfo describes the + parameters for the TokenCredentialRequest API on this + Concierge. This field is only set when Type is "TokenCredentialRequestAPI". + properties: + certificateAuthorityData: + description: CertificateAuthorityData is the Kubernetes + API server CA bundle. + minLength: 1 + type: string + server: + description: Server is the Kubernetes API server URL. + minLength: 1 + pattern: ^https://|^http:// + type: string + required: + - certificateAuthorityData + - server + type: object + type: + description: Type describes which frontend mechanism clients + can use with a strategy. + enum: + - TokenCredentialRequestAPI + type: string + required: + - type + type: object lastUpdateTime: description: When the status was last checked. format: date-time diff --git a/generated/1.19/README.adoc b/generated/1.19/README.adoc index 0b74cef3..a77f3f18 100644 --- a/generated/1.19/README.adoc +++ b/generated/1.19/README.adoc @@ -236,6 +236,24 @@ Describes the configuration status of a Pinniped credential issuer. |=== +[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerfrontend"] +==== CredentialIssuerFrontend + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy. +| *`tokenCredentialRequestInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo[$$TokenCredentialRequestAPIInfo$$]__ | TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. This field is only set when Type is "TokenCredentialRequestAPI". +|=== + + [id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo"] ==== CredentialIssuerKubeConfigInfo @@ -270,7 +288,7 @@ Status of a credential issuer. |=== | Field | Description | *`strategies`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] array__ | List of integration strategies that were attempted by Pinniped. -| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. +| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. This field is deprecated and will be removed in a future version. |=== @@ -292,6 +310,25 @@ Status of a credential issuer. | *`reason`* __StrategyReason__ | Reason for the current status. | *`message`* __string__ | Human-readable description of the current status. | *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#time-v1-meta[$$Time$$]__ | When the status was last checked. +| *`frontend`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$]__ | Frontend describes how clients can connect using this strategy. +|=== + + +[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"] +==== TokenCredentialRequestAPIInfo + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`server`* __string__ | Server is the Kubernetes API server URL. +| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the Kubernetes API server CA bundle. |=== diff --git a/generated/1.19/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.19/apis/concierge/config/v1alpha1/types_credentialissuer.go index 63d59446..39989501 100644 --- a/generated/1.19/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.19/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/generated/1.19/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.19/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index eebbe7af..ad9a9f66 100644 --- a/generated/1.19/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.19/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -38,6 +38,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) { + *out = *in + if in.TokenCredentialRequestAPIInfo != nil { + in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo + *out = new(TokenCredentialRequestAPIInfo) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend. +func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend { + if in == nil { + return nil + } + out := new(CredentialIssuerFrontend) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialIssuerKubeConfigInfo) DeepCopyInto(out *CredentialIssuerKubeConfigInfo) { *out = *in @@ -119,6 +140,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(CredentialIssuerFrontend) + (*in).DeepCopyInto(*out) + } return } @@ -131,3 +157,19 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenCredentialRequestAPIInfo. +func (in *TokenCredentialRequestAPIInfo) DeepCopy() *TokenCredentialRequestAPIInfo { + if in == nil { + return nil + } + out := new(TokenCredentialRequestAPIInfo) + in.DeepCopyInto(out) + return out +} diff --git a/generated/1.19/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.19/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 900db6cb..d61a7835 100644 --- a/generated/1.19/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.19/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -40,7 +40,8 @@ spec: properties: kubeConfigInfo: description: Information needed to form a valid Pinniped-based kubeconfig - using this credential issuer. + using this credential issuer. This field is deprecated and will + be removed in a future version. properties: certificateAuthorityData: description: The K8s API server CA bundle. @@ -62,6 +63,38 @@ spec: description: Status of an integration strategy that was attempted by Pinniped. properties: + frontend: + description: Frontend describes how clients can connect using + this strategy. + properties: + tokenCredentialRequestInfo: + description: TokenCredentialRequestAPIInfo describes the + parameters for the TokenCredentialRequest API on this + Concierge. This field is only set when Type is "TokenCredentialRequestAPI". + properties: + certificateAuthorityData: + description: CertificateAuthorityData is the Kubernetes + API server CA bundle. + minLength: 1 + type: string + server: + description: Server is the Kubernetes API server URL. + minLength: 1 + pattern: ^https://|^http:// + type: string + required: + - certificateAuthorityData + - server + type: object + type: + description: Type describes which frontend mechanism clients + can use with a strategy. + enum: + - TokenCredentialRequestAPI + type: string + required: + - type + type: object lastUpdateTime: description: When the status was last checked. format: date-time diff --git a/generated/1.20/README.adoc b/generated/1.20/README.adoc index 76a678f4..7b35be86 100644 --- a/generated/1.20/README.adoc +++ b/generated/1.20/README.adoc @@ -236,6 +236,24 @@ Describes the configuration status of a Pinniped credential issuer. |=== +[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerfrontend"] +==== CredentialIssuerFrontend + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy. +| *`tokenCredentialRequestInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo[$$TokenCredentialRequestAPIInfo$$]__ | TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. This field is only set when Type is "TokenCredentialRequestAPI". +|=== + + [id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo"] ==== CredentialIssuerKubeConfigInfo @@ -270,7 +288,7 @@ Status of a credential issuer. |=== | Field | Description | *`strategies`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$] array__ | List of integration strategies that were attempted by Pinniped. -| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. +| *`kubeConfigInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerkubeconfiginfo[$$CredentialIssuerKubeConfigInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. This field is deprecated and will be removed in a future version. |=== @@ -292,6 +310,25 @@ Status of a credential issuer. | *`reason`* __StrategyReason__ | Reason for the current status. | *`message`* __string__ | Human-readable description of the current status. | *`lastUpdateTime`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.2/#time-v1-meta[$$Time$$]__ | When the status was last checked. +| *`frontend`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$]__ | Frontend describes how clients can connect using this strategy. +|=== + + +[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-tokencredentialrequestapiinfo"] +==== TokenCredentialRequestAPIInfo + + + +.Appears In: +**** +- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerfrontend[$$CredentialIssuerFrontend$$] +**** + +[cols="25a,75a", options="header"] +|=== +| Field | Description +| *`server`* __string__ | Server is the Kubernetes API server URL. +| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the Kubernetes API server CA bundle. |=== diff --git a/generated/1.20/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/1.20/apis/concierge/config/v1alpha1/types_credentialissuer.go index 63d59446..39989501 100644 --- a/generated/1.20/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/1.20/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/generated/1.20/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/1.20/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index eebbe7af..ad9a9f66 100644 --- a/generated/1.20/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/1.20/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -38,6 +38,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) { + *out = *in + if in.TokenCredentialRequestAPIInfo != nil { + in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo + *out = new(TokenCredentialRequestAPIInfo) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend. +func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend { + if in == nil { + return nil + } + out := new(CredentialIssuerFrontend) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialIssuerKubeConfigInfo) DeepCopyInto(out *CredentialIssuerKubeConfigInfo) { *out = *in @@ -119,6 +140,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(CredentialIssuerFrontend) + (*in).DeepCopyInto(*out) + } return } @@ -131,3 +157,19 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenCredentialRequestAPIInfo. +func (in *TokenCredentialRequestAPIInfo) DeepCopy() *TokenCredentialRequestAPIInfo { + if in == nil { + return nil + } + out := new(TokenCredentialRequestAPIInfo) + in.DeepCopyInto(out) + return out +} diff --git a/generated/1.20/crds/config.concierge.pinniped.dev_credentialissuers.yaml b/generated/1.20/crds/config.concierge.pinniped.dev_credentialissuers.yaml index 900db6cb..d61a7835 100644 --- a/generated/1.20/crds/config.concierge.pinniped.dev_credentialissuers.yaml +++ b/generated/1.20/crds/config.concierge.pinniped.dev_credentialissuers.yaml @@ -40,7 +40,8 @@ spec: properties: kubeConfigInfo: description: Information needed to form a valid Pinniped-based kubeconfig - using this credential issuer. + using this credential issuer. This field is deprecated and will + be removed in a future version. properties: certificateAuthorityData: description: The K8s API server CA bundle. @@ -62,6 +63,38 @@ spec: description: Status of an integration strategy that was attempted by Pinniped. properties: + frontend: + description: Frontend describes how clients can connect using + this strategy. + properties: + tokenCredentialRequestInfo: + description: TokenCredentialRequestAPIInfo describes the + parameters for the TokenCredentialRequest API on this + Concierge. This field is only set when Type is "TokenCredentialRequestAPI". + properties: + certificateAuthorityData: + description: CertificateAuthorityData is the Kubernetes + API server CA bundle. + minLength: 1 + type: string + server: + description: Server is the Kubernetes API server URL. + minLength: 1 + pattern: ^https://|^http:// + type: string + required: + - certificateAuthorityData + - server + type: object + type: + description: Type describes which frontend mechanism clients + can use with a strategy. + enum: + - TokenCredentialRequestAPI + type: string + required: + - type + type: object lastUpdateTime: description: When the status was last checked. format: date-time diff --git a/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go b/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go index 63d59446..39989501 100644 --- a/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go +++ b/generated/latest/apis/concierge/config/v1alpha1/types_credentialissuer.go @@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // +kubebuilder:validation:Enum=KubeClusterSigningCertificate type StrategyType string +// +kubebuilder:validation:Enum=TokenCredentialRequestAPI +type FrontendType string + // +kubebuilder:validation:Enum=Success;Error type StrategyStatus string @@ -17,11 +20,14 @@ type StrategyReason string const ( KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") + TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI") + SuccessStrategyStatus = StrategyStatus("Success") ErrorStrategyStatus = StrategyStatus("Error") - CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") - FetchedKeyStrategyReason = StrategyReason("FetchedKey") + CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") + CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo") + FetchedKeyStrategyReason = StrategyReason("FetchedKey") ) // Status of a credential issuer. @@ -30,6 +36,7 @@ type CredentialIssuerStatus struct { Strategies []CredentialIssuerStrategy `json:"strategies"` // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer. + // This field is deprecated and will be removed in a future version. // +optional KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` } @@ -63,6 +70,30 @@ type CredentialIssuerStrategy struct { // When the status was last checked. LastUpdateTime metav1.Time `json:"lastUpdateTime"` + + // Frontend describes how clients can connect using this strategy. + Frontend *CredentialIssuerFrontend `json:"frontend,omitempty"` +} + +type CredentialIssuerFrontend struct { + // Type describes which frontend mechanism clients can use with a strategy. + Type FrontendType `json:"type"` + + // TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. + // This field is only set when Type is "TokenCredentialRequestAPI". + TokenCredentialRequestAPIInfo *TokenCredentialRequestAPIInfo `json:"tokenCredentialRequestInfo,omitempty"` +} + +// TokenCredentialRequestAPIInfo describes the parameters for the TokenCredentialRequest API on this Concierge. +type TokenCredentialRequestAPIInfo struct { + // Server is the Kubernetes API server URL. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^https://|^http://` + Server string `json:"server"` + + // CertificateAuthorityData is the Kubernetes API server CA bundle. + // +kubebuilder:validation:MinLength=1 + CertificateAuthorityData string `json:"certificateAuthorityData"` } // Describes the configuration status of a Pinniped credential issuer. diff --git a/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go b/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go index eebbe7af..ad9a9f66 100644 --- a/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go +++ b/generated/latest/apis/concierge/config/v1alpha1/zz_generated.deepcopy.go @@ -38,6 +38,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) { + *out = *in + if in.TokenCredentialRequestAPIInfo != nil { + in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo + *out = new(TokenCredentialRequestAPIInfo) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend. +func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend { + if in == nil { + return nil + } + out := new(CredentialIssuerFrontend) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CredentialIssuerKubeConfigInfo) DeepCopyInto(out *CredentialIssuerKubeConfigInfo) { *out = *in @@ -119,6 +140,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(CredentialIssuerFrontend) + (*in).DeepCopyInto(*out) + } return } @@ -131,3 +157,19 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TokenCredentialRequestAPIInfo) DeepCopyInto(out *TokenCredentialRequestAPIInfo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TokenCredentialRequestAPIInfo. +func (in *TokenCredentialRequestAPIInfo) DeepCopy() *TokenCredentialRequestAPIInfo { + if in == nil { + return nil + } + out := new(TokenCredentialRequestAPIInfo) + in.DeepCopyInto(out) + return out +} diff --git a/go.sum b/go.sum index 00df0a18..1d0de09f 100644 --- a/go.sum +++ b/go.sum @@ -214,7 +214,6 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg github.com/go-logr/stdr v0.4.0 h1:ijk9G/xzDRZdMU1QRhLYdHuWvNZWqte+NZMOGsiKWbc= github.com/go-logr/stdr v0.4.0/go.mod h1:NO1vneyJDqKVgJYnxhwXWWmQPOvNM391IG3H8ql3jiA= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -226,7 +225,6 @@ github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8 github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= @@ -693,7 +691,6 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -1178,7 +1175,6 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -1266,11 +1262,9 @@ golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201112073958-5cba982894dd h1:5CtCZbICpIOFdgO940moixOPjc0178IU44m4EjOO5IY= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1279,7 +1273,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/internal/controller/issuerconfig/kube_config_info_publisher.go b/internal/controller/issuerconfig/kube_config_info_publisher.go deleted file mode 100644 index 5a940811..00000000 --- a/internal/controller/issuerconfig/kube_config_info_publisher.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package issuerconfig - -import ( - "encoding/base64" - "fmt" - - k8serrors "k8s.io/apimachinery/pkg/api/errors" - corev1informers "k8s.io/client-go/informers/core/v1" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog/v2" - - configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" - pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned" - pinnipedcontroller "go.pinniped.dev/internal/controller" - "go.pinniped.dev/internal/controllerlib" - "go.pinniped.dev/internal/plog" -) - -const ( - ClusterInfoNamespace = "kube-public" - clusterInfoName = "cluster-info" - clusterInfoConfigMapKey = "kubeconfig" -) - -type kubeConigInfoPublisherController struct { - credentialIssuerResourceName string - credentialIssuerLabels map[string]string - serverOverride *string - pinnipedClient pinnipedclientset.Interface - configMapInformer corev1informers.ConfigMapInformer -} - -// NewKubeConfigInfoPublisherController returns a controller that syncs the -// configv1alpha1.CredentialIssuer.Status.KubeConfigInfo field with the cluster-info ConfigMap -// in the kube-public namespace. -func NewKubeConfigInfoPublisherController( - credentialIssuerResourceName string, - credentialIssuerLabels map[string]string, - serverOverride *string, - pinnipedClient pinnipedclientset.Interface, - configMapInformer corev1informers.ConfigMapInformer, - withInformer pinnipedcontroller.WithInformerOptionFunc, -) controllerlib.Controller { - return controllerlib.New( - controllerlib.Config{ - Name: "publisher-controller", - Syncer: &kubeConigInfoPublisherController{ - credentialIssuerResourceName: credentialIssuerResourceName, - credentialIssuerLabels: credentialIssuerLabels, - serverOverride: serverOverride, - pinnipedClient: pinnipedClient, - configMapInformer: configMapInformer, - }, - }, - withInformer( - configMapInformer, - pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(clusterInfoName, ClusterInfoNamespace), - controllerlib.InformerOption{}, - ), - ) -} - -func (c *kubeConigInfoPublisherController) Sync(ctx controllerlib.Context) error { - configMap, err := c.configMapInformer. - Lister(). - ConfigMaps(ClusterInfoNamespace). - Get(clusterInfoName) - notFound := k8serrors.IsNotFound(err) - if err != nil && !notFound { - return fmt.Errorf("failed to get %s configmap: %w", clusterInfoName, err) - } - if notFound { - plog.Debug( - "could not find config map", - "configmap", - klog.KRef(ClusterInfoNamespace, clusterInfoName), - ) - return nil - } - - kubeConfig, kubeConfigPresent := configMap.Data[clusterInfoConfigMapKey] - if !kubeConfigPresent { - plog.Debug("could not find kubeconfig configmap key") - return nil - } - - config, err := clientcmd.Load([]byte(kubeConfig)) - if err != nil { - plog.Debug("could not load kubeconfig configmap key") - return nil - } - - var certificateAuthorityData, server string - for _, v := range config.Clusters { - certificateAuthorityData = base64.StdEncoding.EncodeToString(v.CertificateAuthorityData) - server = v.Server - break - } - - if c.serverOverride != nil { - server = *c.serverOverride - } - - updateServerAndCAFunc := func(c *configv1alpha1.CredentialIssuerStatus) { - c.KubeConfigInfo = &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: server, - CertificateAuthorityData: certificateAuthorityData, - } - } - - return CreateOrUpdateCredentialIssuerStatus( - ctx.Context, - c.credentialIssuerResourceName, - c.credentialIssuerLabels, - c.pinnipedClient, - updateServerAndCAFunc, - ) -} diff --git a/internal/controller/issuerconfig/kube_config_info_publisher_test.go b/internal/controller/issuerconfig/kube_config_info_publisher_test.go deleted file mode 100644 index c11c8758..00000000 --- a/internal/controller/issuerconfig/kube_config_info_publisher_test.go +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright 2020-2021 the Pinniped contributors. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package issuerconfig - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/sclevine/spec" - "github.com/sclevine/spec/report" - "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - kubeinformers "k8s.io/client-go/informers" - kubernetesfake "k8s.io/client-go/kubernetes/fake" - coretesting "k8s.io/client-go/testing" - - configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" - pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake" - "go.pinniped.dev/internal/controllerlib" - "go.pinniped.dev/internal/here" - "go.pinniped.dev/internal/testutil" -) - -func TestInformerFilters(t *testing.T) { - spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) { - const credentialIssuerResourceName = "some-resource-name" - - var r *require.Assertions - var observableWithInformerOption *testutil.ObservableWithInformerOption - var configMapInformerFilter controllerlib.Filter - - it.Before(func() { - r = require.New(t) - observableWithInformerOption = testutil.NewObservableWithInformerOption() - configMapInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().ConfigMaps() - _ = NewKubeConfigInfoPublisherController( - credentialIssuerResourceName, - map[string]string{}, - nil, - nil, - configMapInformer, - observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters - ) - configMapInformerFilter = observableWithInformerOption.GetFilterForInformer(configMapInformer) - }) - - when("watching ConfigMap objects", func() { - var subject controllerlib.Filter - var target, wrongNamespace, wrongName, unrelated *corev1.ConfigMap - - it.Before(func() { - subject = configMapInformerFilter - target = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "kube-public"}} - wrongNamespace = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "wrong-namespace"}} - wrongName = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "kube-public"}} - unrelated = &corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "wrong-name", Namespace: "wrong-namespace"}} - }) - - when("the target ConfigMap changes", func() { - it("returns true to trigger the sync method", func() { - r.True(subject.Add(target)) - r.True(subject.Update(target, unrelated)) - r.True(subject.Update(unrelated, target)) - r.True(subject.Delete(target)) - }) - }) - - when("a ConfigMap from another namespace changes", func() { - it("returns false to avoid triggering the sync method", func() { - r.False(subject.Add(wrongNamespace)) - r.False(subject.Update(wrongNamespace, unrelated)) - r.False(subject.Update(unrelated, wrongNamespace)) - r.False(subject.Delete(wrongNamespace)) - }) - }) - - when("a ConfigMap with a different name changes", func() { - it("returns false to avoid triggering the sync method", func() { - r.False(subject.Add(wrongName)) - r.False(subject.Update(wrongName, unrelated)) - r.False(subject.Update(unrelated, wrongName)) - r.False(subject.Delete(wrongName)) - }) - }) - - when("a ConfigMap with a different name and a different namespace changes", func() { - it("returns false to avoid triggering the sync method", func() { - r.False(subject.Add(unrelated)) - r.False(subject.Update(unrelated, unrelated)) - r.False(subject.Delete(unrelated)) - }) - }) - }) - }, spec.Parallel(), spec.Report(report.Terminal{})) -} - -func TestSync(t *testing.T) { - spec.Run(t, "Sync", func(t *testing.T, when spec.G, it spec.S) { - const credentialIssuerResourceName = "some-resource-name" - - var r *require.Assertions - - var subject controllerlib.Controller - var serverOverride *string - var kubeInformerClient *kubernetesfake.Clientset - var kubeInformers kubeinformers.SharedInformerFactory - var pinnipedAPIClient *pinnipedfake.Clientset - var timeoutContext context.Context - var timeoutContextCancel context.CancelFunc - var syncContext *controllerlib.Context - - var expectedCredentialIssuer = func(expectedServerURL, expectedCAData string) (schema.GroupVersionResource, *configv1alpha1.CredentialIssuer, *configv1alpha1.CredentialIssuer) { - expectedCredentialIssuerGVR := schema.GroupVersionResource{ - Group: configv1alpha1.GroupName, - Version: "v1alpha1", - Resource: "credentialissuers", - } - - expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{ - ObjectMeta: metav1.ObjectMeta{ - Name: credentialIssuerResourceName, - Labels: map[string]string{ - "myLabelKey1": "myLabelValue1", - "myLabelKey2": "myLabelValue2", - }, - }, - } - - expectedCredentialIssuer := &configv1alpha1.CredentialIssuer{ - ObjectMeta: metav1.ObjectMeta{ - Name: credentialIssuerResourceName, - Labels: map[string]string{ - "myLabelKey1": "myLabelValue1", - "myLabelKey2": "myLabelValue2", - }, - }, - Status: configv1alpha1.CredentialIssuerStatus{ - KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: expectedServerURL, - CertificateAuthorityData: expectedCAData, - }, - }, - } - return expectedCredentialIssuerGVR, expectedCreateCredentialIssuer, expectedCredentialIssuer - } - - // Defer starting the informers until the last possible moment so that the - // nested Before's can keep adding things to the informer caches. - var startInformersAndController = func() { - // Set this at the last second to allow for injection of server override. - subject = NewKubeConfigInfoPublisherController( - credentialIssuerResourceName, - map[string]string{ - "myLabelKey1": "myLabelValue1", - "myLabelKey2": "myLabelValue2", - }, - serverOverride, - pinnipedAPIClient, - kubeInformers.Core().V1().ConfigMaps(), - controllerlib.WithInformer, - ) - - // Set this at the last second to support calling subject.Name(). - syncContext = &controllerlib.Context{ - Context: timeoutContext, - Name: subject.Name(), - Key: controllerlib.Key{ - Namespace: "kube-public", - Name: "cluster-info", - }, - } - - // Must start informers before calling TestRunSynchronously() - kubeInformers.Start(timeoutContext.Done()) - controllerlib.TestRunSynchronously(t, subject) - } - - it.Before(func() { - r = require.New(t) - - timeoutContext, timeoutContextCancel = context.WithTimeout(context.Background(), time.Second*3) - - kubeInformerClient = kubernetesfake.NewSimpleClientset() - kubeInformers = kubeinformers.NewSharedInformerFactory(kubeInformerClient, 0) - pinnipedAPIClient = pinnipedfake.NewSimpleClientset() - }) - - it.After(func() { - timeoutContextCancel() - }) - - when("there is a cluster-info ConfigMap in the kube-public namespace", func() { - const caData = "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=" // "some-certificate-authority-data" base64 encoded - const kubeServerURL = "https://some-server" - - when("the ConfigMap has the expected `kubeconfig` top-level data key", func() { - it.Before(func() { - clusterInfoConfigMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "kube-public"}, - // Note that go fmt puts tabs in our file, which we must remove from our configmap yaml below. - Data: map[string]string{ - "kubeconfig": here.Docf(` - kind: Config - apiVersion: v1 - clusters: - - name: "" - cluster: - certificate-authority-data: "%s" - server: "%s"`, - caData, kubeServerURL), - "uninteresting-key": "uninteresting-value", - }, - } - err := kubeInformerClient.Tracker().Add(clusterInfoConfigMap) - r.NoError(err) - }) - - when("the CredentialIssuer does not already exist", func() { - it("creates a CredentialIssuer", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - - expectedCredentialIssuerGVR, expectedCreateCredentialIssuer, expectedCredentialIssuer := expectedCredentialIssuer( - kubeServerURL, - caData, - ) - - r.Equal( - []coretesting.Action{ - coretesting.NewRootGetAction(expectedCredentialIssuerGVR, expectedCreateCredentialIssuer.Name), - coretesting.NewRootCreateAction( - expectedCredentialIssuerGVR, - expectedCreateCredentialIssuer, - ), - coretesting.NewRootUpdateSubresourceAction( - expectedCredentialIssuerGVR, - "status", - expectedCredentialIssuer, - ), - }, - pinnipedAPIClient.Actions(), - ) - }) - - when("creating the CredentialIssuer fails", func() { - it.Before(func() { - pinnipedAPIClient.PrependReactor( - "create", - "credentialissuers", - func(_ coretesting.Action) (bool, runtime.Object, error) { - return true, nil, errors.New("create failed") - }, - ) - }) - - it("returns the create error", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.EqualError(err, "could not create or update credentialissuer: create failed: create failed") - }) - }) - - when("a server override is passed to the controller", func() { - it("uses the server override field", func() { - serverOverride = new(string) - *serverOverride = "https://some-server-override" - - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - - expectedCredentialIssuerGVR, expectedCreateCredentialIssuer, expectedCredentialIssuer := expectedCredentialIssuer( - kubeServerURL, - caData, - ) - expectedCredentialIssuer.Status.KubeConfigInfo.Server = "https://some-server-override" - - r.Equal( - []coretesting.Action{ - coretesting.NewRootGetAction(expectedCredentialIssuerGVR, expectedCreateCredentialIssuer.Name), - coretesting.NewRootCreateAction( - expectedCredentialIssuerGVR, - expectedCreateCredentialIssuer, - ), - coretesting.NewRootUpdateSubresourceAction( - expectedCredentialIssuerGVR, - "status", - expectedCredentialIssuer, - ), - }, - pinnipedAPIClient.Actions(), - ) - }) - }) - }) - - when("the CredentialIssuer already exists", func() { - when("the CredentialIssuer is already up to date according to the data in the ConfigMap", func() { - var credentialIssuerGVR schema.GroupVersionResource - var credentialIssuer *configv1alpha1.CredentialIssuer - - it.Before(func() { - credentialIssuerGVR, _, credentialIssuer = expectedCredentialIssuer( - kubeServerURL, - caData, - ) - err := pinnipedAPIClient.Tracker().Add(credentialIssuer) - r.NoError(err) - }) - - it("does not update the CredentialIssuer to avoid unnecessary etcd writes/api calls", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - - r.Equal( - []coretesting.Action{ - coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuer.Name), - }, - pinnipedAPIClient.Actions(), - ) - }) - }) - - when("the CredentialIssuer is stale compared to the data in the ConfigMap", func() { - it.Before(func() { - _, _, expectedCredentialIssuer := expectedCredentialIssuer( - kubeServerURL, - caData, - ) - expectedCredentialIssuer.Status.KubeConfigInfo.Server = "https://some-other-server" - r.NoError(pinnipedAPIClient.Tracker().Add(expectedCredentialIssuer)) - }) - - it("updates the existing CredentialIssuer", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - - expectedCredentialIssuerGVR, _, expectedCredentialIssuer := expectedCredentialIssuer( - kubeServerURL, - caData, - ) - expectedActions := []coretesting.Action{ - coretesting.NewRootGetAction(expectedCredentialIssuerGVR, expectedCredentialIssuer.Name), - coretesting.NewRootUpdateSubresourceAction( - expectedCredentialIssuerGVR, - "status", - expectedCredentialIssuer, - ), - } - r.Equal(expectedActions, pinnipedAPIClient.Actions()) - }) - - when("updating the CredentialIssuer fails", func() { - it.Before(func() { - pinnipedAPIClient.PrependReactor( - "update", - "credentialissuers", - func(_ coretesting.Action) (bool, runtime.Object, error) { - return true, nil, errors.New("update failed") - }, - ) - }) - - it("returns the update error", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.EqualError(err, "could not create or update credentialissuer: update failed") - }) - }) - }) - }) - }) - - when("the ConfigMap is missing the expected `kubeconfig` top-level data key", func() { - it.Before(func() { - clusterInfoConfigMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "kube-public"}, - Data: map[string]string{ - "these are not the droids you're looking for": "uninteresting-value", - }, - } - err := kubeInformerClient.Tracker().Add(clusterInfoConfigMap) - r.NoError(err) - }) - - it("keeps waiting for it to exist", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - r.Empty(pinnipedAPIClient.Actions()) - }) - }) - - when("the ConfigMap does not have a valid kubeconfig", func() { - it.Before(func() { - clusterInfoConfigMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{Name: "cluster-info", Namespace: "kube-public"}, - Data: map[string]string{ - "kubeconfig": "this is an invalid kubeconfig", - }, - } - err := kubeInformerClient.Tracker().Add(clusterInfoConfigMap) - r.NoError(err) - }) - - it("keeps waiting for it to be properly formatted", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - r.Empty(pinnipedAPIClient.Actions()) - }) - }) - }) - - when("there is not a cluster-info ConfigMap in the kube-public namespace", func() { - it.Before(func() { - unrelatedConfigMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: "oops this is not the cluster-info ConfigMap", - Namespace: "kube-public", - }, - } - err := kubeInformerClient.Tracker().Add(unrelatedConfigMap) - r.NoError(err) - }) - - it("keeps waiting for one", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.NoError(err) - r.Empty(pinnipedAPIClient.Actions()) - }) - }) - }, spec.Parallel(), spec.Report(report.Terminal{})) -} diff --git a/internal/controller/issuerconfig/update_strategy.go b/internal/controller/issuerconfig/update_strategy.go index 33a5ecd8..669516ff 100644 --- a/internal/controller/issuerconfig/update_strategy.go +++ b/internal/controller/issuerconfig/update_strategy.go @@ -42,6 +42,14 @@ func mergeStrategy(configToUpdate *v1alpha1.CredentialIssuerStatus, strategy v1a configToUpdate.Strategies = append(configToUpdate.Strategies, strategy) } sort.Stable(sortableStrategies(configToUpdate.Strategies)) + + // Special case: the "TokenCredentialRequestAPI" data is mirrored into the deprecated status.kubeConfigInfo field. + if strategy.Frontend != nil && strategy.Frontend.Type == v1alpha1.TokenCredentialRequestAPIFrontendType { + configToUpdate.KubeConfigInfo = &v1alpha1.CredentialIssuerKubeConfigInfo{ + Server: strategy.Frontend.TokenCredentialRequestAPIInfo.Server, + CertificateAuthorityData: strategy.Frontend.TokenCredentialRequestAPIInfo.CertificateAuthorityData, + } + } } // TODO: sort strategies by server preference rather than alphanumerically by type. diff --git a/internal/controller/issuerconfig/update_strategy_test.go b/internal/controller/issuerconfig/update_strategy_test.go index f261c872..b1b90429 100644 --- a/internal/controller/issuerconfig/update_strategy_test.go +++ b/internal/controller/issuerconfig/update_strategy_test.go @@ -47,6 +47,48 @@ func TestMergeStrategy(t *testing.T) { }, }, }, + { + name: "new entry updating deprecated kubeConfigInfo", + configToUpdate: v1alpha1.CredentialIssuerStatus{ + Strategies: nil, + }, + strategy: v1alpha1.CredentialIssuerStrategy{ + Type: "Type1", + Status: v1alpha1.SuccessStrategyStatus, + Reason: "some reason", + Message: "some message", + LastUpdateTime: t1, + Frontend: &v1alpha1.CredentialIssuerFrontend{ + Type: "TokenCredentialRequestAPI", + TokenCredentialRequestAPIInfo: &v1alpha1.TokenCredentialRequestAPIInfo{ + Server: "https://test-server", + CertificateAuthorityData: "test-ca-bundle", + }, + }, + }, + expected: v1alpha1.CredentialIssuerStatus{ + Strategies: []v1alpha1.CredentialIssuerStrategy{ + { + Type: "Type1", + Status: v1alpha1.SuccessStrategyStatus, + Reason: "some reason", + Message: "some message", + LastUpdateTime: t1, + Frontend: &v1alpha1.CredentialIssuerFrontend{ + Type: "TokenCredentialRequestAPI", + TokenCredentialRequestAPIInfo: &v1alpha1.TokenCredentialRequestAPIInfo{ + Server: "https://test-server", + CertificateAuthorityData: "test-ca-bundle", + }, + }, + }, + }, + KubeConfigInfo: &v1alpha1.CredentialIssuerKubeConfigInfo{ + Server: "https://test-server", + CertificateAuthorityData: "test-ca-bundle", + }, + }, + }, { name: "existing entry to update", configToUpdate: v1alpha1.CredentialIssuerStatus{ diff --git a/internal/controller/kubecertagent/annotater.go b/internal/controller/kubecertagent/annotater.go index a18cc732..fa640d21 100644 --- a/internal/controller/kubecertagent/annotater.go +++ b/internal/controller/kubecertagent/annotater.go @@ -33,6 +33,7 @@ const ( type annotaterController struct { agentPodConfig *AgentPodConfig credentialIssuerLocationConfig *CredentialIssuerLocationConfig + credentialIssuerLabels map[string]string clock clock.Clock k8sClient kubernetes.Interface pinnipedAPIClient pinnipedclientset.Interface @@ -51,6 +52,7 @@ type annotaterController struct { func NewAnnotaterController( agentPodConfig *AgentPodConfig, credentialIssuerLocationConfig *CredentialIssuerLocationConfig, + credentialIssuerLabels map[string]string, clock clock.Clock, k8sClient kubernetes.Interface, pinnipedAPIClient pinnipedclientset.Interface, @@ -64,6 +66,7 @@ func NewAnnotaterController( Syncer: &annotaterController{ agentPodConfig: agentPodConfig, credentialIssuerLocationConfig: credentialIssuerLocationConfig, + credentialIssuerLabels: credentialIssuerLabels, clock: clock, k8sClient: k8sClient, pinnipedAPIClient: pinnipedAPIClient, @@ -125,7 +128,7 @@ func (c *annotaterController) Sync(ctx controllerlib.Context) error { strategyResultUpdateErr := issuerconfig.UpdateStrategy( ctx.Context, c.credentialIssuerLocationConfig.Name, - nil, + c.credentialIssuerLabels, c.pinnipedAPIClient, strategyError(c.clock, err), ) diff --git a/internal/controller/kubecertagent/annotater_test.go b/internal/controller/kubecertagent/annotater_test.go index 164cb7b0..bb767a47 100644 --- a/internal/controller/kubecertagent/annotater_test.go +++ b/internal/controller/kubecertagent/annotater_test.go @@ -41,6 +41,7 @@ func TestAnnotaterControllerFilter(t *testing.T) { ) { _ = NewAnnotaterController( agentPodConfig, + nil, // credentialIssuerLabels, shouldn't matter nil, // credentialIssuerLocationConfig, shouldn't matter nil, // clock, shouldn't matter nil, // k8sClient, shouldn't matter @@ -85,6 +86,7 @@ func TestAnnotaterControllerSync(t *testing.T) { var podsGVR schema.GroupVersionResource var credentialIssuerGVR schema.GroupVersionResource var frozenNow time.Time + var credentialIssuerLabels map[string]string // Defer starting the informers until the last possible moment so that the // nested Before's can keep adding things to the informer caches. @@ -103,6 +105,7 @@ func TestAnnotaterControllerSync(t *testing.T) { &CredentialIssuerLocationConfig{ Name: credentialIssuerResourceName, }, + credentialIssuerLabels, clock.NewFakeClock(frozenNow), kubeAPIClient, pinnipedAPIClient, @@ -238,10 +241,6 @@ func TestAnnotaterControllerSync(t *testing.T) { }, Status: configv1alpha1.CredentialIssuerStatus{ Strategies: []configv1alpha1.CredentialIssuerStrategy{}, - KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: "some-server", - CertificateAuthorityData: "some-ca-value", - }, }, } r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) @@ -301,6 +300,10 @@ func TestAnnotaterControllerSync(t *testing.T) { }) when("there is not already a CredentialIssuer", func() { + it.Before(func() { + credentialIssuerLabels = map[string]string{"foo": "bar"} + }) + it("creates the CredentialIssuer status with the error", func() { startInformersAndController() err := controllerlib.TestSync(t, subject, *syncContext) @@ -308,14 +311,16 @@ func TestAnnotaterControllerSync(t *testing.T) { expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ - Name: credentialIssuerResourceName, + Name: credentialIssuerResourceName, + Labels: map[string]string{"foo": "bar"}, }, } expectedCredentialIssuer := &configv1alpha1.CredentialIssuer{ TypeMeta: metav1.TypeMeta{}, ObjectMeta: metav1.ObjectMeta{ - Name: credentialIssuerResourceName, + Name: credentialIssuerResourceName, + Labels: map[string]string{"foo": "bar"}, }, Status: configv1alpha1.CredentialIssuerStatus{ Strategies: []configv1alpha1.CredentialIssuerStrategy{ diff --git a/internal/controller/kubecertagent/creater_test.go b/internal/controller/kubecertagent/creater_test.go index 18df3e1f..eab57997 100644 --- a/internal/controller/kubecertagent/creater_test.go +++ b/internal/controller/kubecertagent/creater_test.go @@ -309,10 +309,6 @@ func TestCreaterControllerSync(t *testing.T) { }, Status: configv1alpha1.CredentialIssuerStatus{ Strategies: []configv1alpha1.CredentialIssuerStrategy{}, - KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: "some-server", - CertificateAuthorityData: "some-ca-value", - }, }, } r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) @@ -449,10 +445,6 @@ func TestCreaterControllerSync(t *testing.T) { }, Status: configv1alpha1.CredentialIssuerStatus{ Strategies: []configv1alpha1.CredentialIssuerStrategy{}, - KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: "some-server", - CertificateAuthorityData: "some-ca-value", - }, }, } r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) diff --git a/internal/controller/kubecertagent/execer.go b/internal/controller/kubecertagent/execer.go index 2322103e..b8ff1c83 100644 --- a/internal/controller/kubecertagent/execer.go +++ b/internal/controller/kubecertagent/execer.go @@ -4,14 +4,18 @@ package kubecertagent import ( + "encoding/base64" "fmt" v1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/clock" corev1informers "k8s.io/client-go/informers/core/v1" + "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" + configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1" pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned" pinnipedcontroller "go.pinniped.dev/internal/controller" "go.pinniped.dev/internal/controller/issuerconfig" @@ -19,13 +23,22 @@ import ( "go.pinniped.dev/internal/dynamiccert" ) +const ( + ClusterInfoNamespace = "kube-public" + clusterInfoName = "cluster-info" + clusterInfoConfigMapKey = "kubeconfig" +) + type execerController struct { credentialIssuerLocationConfig *CredentialIssuerLocationConfig + credentialIssuerLabels map[string]string + discoveryURLOverride *string dynamicCertProvider dynamiccert.Provider podCommandExecutor PodCommandExecutor clock clock.Clock pinnipedAPIClient pinnipedclientset.Interface agentPodInformer corev1informers.PodInformer + configMapInformer corev1informers.ConfigMapInformer } // NewExecerController returns a controllerlib.Controller that listens for agent pods with proper @@ -36,11 +49,14 @@ type execerController struct { // credentialIssuerLocationConfig, with any errors that it encounters. func NewExecerController( credentialIssuerLocationConfig *CredentialIssuerLocationConfig, + credentialIssuerLabels map[string]string, + discoveryURLOverride *string, dynamicCertProvider dynamiccert.Provider, podCommandExecutor PodCommandExecutor, pinnipedAPIClient pinnipedclientset.Interface, clock clock.Clock, agentPodInformer corev1informers.PodInformer, + configMapInformer corev1informers.ConfigMapInformer, withInformer pinnipedcontroller.WithInformerOptionFunc, ) controllerlib.Controller { return controllerlib.New( @@ -48,11 +64,14 @@ func NewExecerController( Name: "kube-cert-agent-execer-controller", Syncer: &execerController{ credentialIssuerLocationConfig: credentialIssuerLocationConfig, + credentialIssuerLabels: credentialIssuerLabels, + discoveryURLOverride: discoveryURLOverride, dynamicCertProvider: dynamicCertProvider, podCommandExecutor: podCommandExecutor, pinnipedAPIClient: pinnipedAPIClient, clock: clock, agentPodInformer: agentPodInformer, + configMapInformer: configMapInformer, }, }, withInformer( @@ -60,6 +79,11 @@ func NewExecerController( pinnipedcontroller.SimpleFilter(isAgentPod, nil), // nil parent func is fine because each event is distinct controllerlib.InformerOption{}, ), + withInformer( + configMapInformer, + pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(clusterInfoName, ClusterInfoNamespace), + controllerlib.InformerOption{}, + ), ) } @@ -91,7 +115,7 @@ func (c *execerController) Sync(ctx controllerlib.Context) error { strategyResultUpdateErr := issuerconfig.UpdateStrategy( ctx.Context, c.credentialIssuerLocationConfig.Name, - nil, + c.credentialIssuerLabels, c.pinnipedAPIClient, strategyError(c.clock, err), ) @@ -104,7 +128,7 @@ func (c *execerController) Sync(ctx controllerlib.Context) error { strategyResultUpdateErr := issuerconfig.UpdateStrategy( ctx.Context, c.credentialIssuerLocationConfig.Name, - nil, + c.credentialIssuerLabels, c.pinnipedAPIClient, strategyError(c.clock, err), ) @@ -114,18 +138,74 @@ func (c *execerController) Sync(ctx controllerlib.Context) error { c.dynamicCertProvider.Set([]byte(certPEM), []byte(keyPEM)) - err = issuerconfig.UpdateStrategy( - ctx.Context, - c.credentialIssuerLocationConfig.Name, - nil, - c.pinnipedAPIClient, - strategySuccess(c.clock), - ) + apiInfo, err := c.getTokenCredentialRequestAPIInfo() if err != nil { + strategyResultUpdateErr := issuerconfig.UpdateStrategy( + ctx.Context, + c.credentialIssuerLocationConfig.Name, + c.credentialIssuerLabels, + c.pinnipedAPIClient, + configv1alpha1.CredentialIssuerStrategy{ + Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, + Status: configv1alpha1.ErrorStrategyStatus, + Reason: configv1alpha1.CouldNotGetClusterInfoStrategyReason, + Message: err.Error(), + LastUpdateTime: metav1.NewTime(c.clock.Now()), + }, + ) + klog.ErrorS(strategyResultUpdateErr, "could not create or update CredentialIssuer with strategy success") return err } - return nil + return issuerconfig.UpdateStrategy( + ctx.Context, + c.credentialIssuerLocationConfig.Name, + c.credentialIssuerLabels, + c.pinnipedAPIClient, + configv1alpha1.CredentialIssuerStrategy{ + Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, + Status: configv1alpha1.SuccessStrategyStatus, + Reason: configv1alpha1.FetchedKeyStrategyReason, + Message: "Key was fetched successfully", + LastUpdateTime: metav1.NewTime(c.clock.Now()), + Frontend: &configv1alpha1.CredentialIssuerFrontend{ + Type: configv1alpha1.TokenCredentialRequestAPIFrontendType, + TokenCredentialRequestAPIInfo: apiInfo, + }, + }, + ) +} + +func (c *execerController) getTokenCredentialRequestAPIInfo() (*configv1alpha1.TokenCredentialRequestAPIInfo, error) { + configMap, err := c.configMapInformer. + Lister(). + ConfigMaps(ClusterInfoNamespace). + Get(clusterInfoName) + if err != nil { + return nil, fmt.Errorf("failed to get %s configmap: %w", clusterInfoName, err) + } + + kubeConfigYAML, kubeConfigPresent := configMap.Data[clusterInfoConfigMapKey] + if !kubeConfigPresent { + return nil, fmt.Errorf("failed to get %s key from %s configmap", clusterInfoConfigMapKey, clusterInfoName) + } + + kubeconfig, err := clientcmd.Load([]byte(kubeConfigYAML)) + if err != nil { + return nil, fmt.Errorf("failed to load data from %s key in %s configmap", clusterInfoConfigMapKey, clusterInfoName) + } + + for _, v := range kubeconfig.Clusters { + result := &configv1alpha1.TokenCredentialRequestAPIInfo{ + Server: v.Server, + CertificateAuthorityData: base64.StdEncoding.EncodeToString(v.CertificateAuthorityData), + } + if c.discoveryURLOverride != nil { + result.Server = *c.discoveryURLOverride + } + return result, nil + } + return nil, fmt.Errorf("kubeconfig in %s key in %s configmap did not contain any clusters", clusterInfoConfigMapKey, clusterInfoName) } func (c *execerController) getKeypairFilePaths(pod *v1.Pod) (string, string) { diff --git a/internal/controller/kubecertagent/execer_test.go b/internal/controller/kubecertagent/execer_test.go index 774e0c92..b3789176 100644 --- a/internal/controller/kubecertagent/execer_test.go +++ b/internal/controller/kubecertagent/execer_test.go @@ -27,6 +27,7 @@ import ( pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake" "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/dynamiccert" + "go.pinniped.dev/internal/here" "go.pinniped.dev/internal/testutil" ) @@ -41,16 +42,21 @@ func TestExecerControllerOptions(t *testing.T) { it.Before(func() { r = require.New(t) observableWithInformerOption = testutil.NewObservableWithInformerOption() - agentPodsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Pods() + informerFactory := kubeinformers.NewSharedInformerFactory(nil, 0) + agentPodsInformer := informerFactory.Core().V1().Pods() + configMapsInformer := informerFactory.Core().V1().ConfigMaps() _ = NewExecerController( &CredentialIssuerLocationConfig{ Name: "ignored by this test", }, + nil, // credentialIssuerLabels, not needed for this test + nil, // discoveryURLOverride, not needed for this test nil, // dynamicCertProvider, not needed for this test nil, // podCommandExecutor, not needed for this test nil, // pinnipedAPIClient, not needed for this test nil, // clock, not needed for this test agentPodsInformer, + configMapsInformer, observableWithInformerOption.WithInformer, ) agentPodInformerFilter = observableWithInformerOption.GetFilterForInformer(agentPodsInformer) @@ -144,9 +150,11 @@ func TestManagerControllerSync(t *testing.T) { var timeoutContextCancel context.CancelFunc var syncContext *controllerlib.Context var pinnipedAPIClient *pinnipedfake.Clientset - var agentPodInformer kubeinformers.SharedInformerFactory - var agentPodInformerClient *kubernetesfake.Clientset + var kubeInformerFactory kubeinformers.SharedInformerFactory + var kubeClientset *kubernetesfake.Clientset var fakeExecutor *fakePodExecutor + var credentialIssuerLabels map[string]string + var discoveryURLOverride *string var dynamicCertProvider dynamiccert.Provider var fakeCertPEM, fakeKeyPEM string var credentialIssuerGVR schema.GroupVersionResource @@ -160,11 +168,14 @@ func TestManagerControllerSync(t *testing.T) { &CredentialIssuerLocationConfig{ Name: credentialIssuerResourceName, }, + credentialIssuerLabels, + discoveryURLOverride, dynamicCertProvider, fakeExecutor, pinnipedAPIClient, clock.NewFakeClock(frozenNow), - agentPodInformer.Core().V1().Pods(), + kubeInformerFactory.Core().V1().Pods(), + kubeInformerFactory.Core().V1().ConfigMaps(), controllerlib.WithInformer, ) @@ -179,7 +190,7 @@ func TestManagerControllerSync(t *testing.T) { } // Must start informers before calling TestRunSynchronously() - agentPodInformer.Start(timeoutContext.Done()) + kubeInformerFactory.Start(timeoutContext.Done()) controllerlib.TestRunSynchronously(t, subject) } @@ -219,8 +230,8 @@ func TestManagerControllerSync(t *testing.T) { timeoutContext, timeoutContextCancel = context.WithTimeout(context.Background(), time.Second*3) pinnipedAPIClient = pinnipedfake.NewSimpleClientset() - agentPodInformerClient = kubernetesfake.NewSimpleClientset() - agentPodInformer = kubeinformers.NewSharedInformerFactory(agentPodInformerClient, 0) + kubeClientset = kubernetesfake.NewSimpleClientset() + kubeInformerFactory = kubeinformers.NewSharedInformerFactory(kubeClientset, 0) fakeExecutor = &fakePodExecutor{r: r} frozenNow = time.Date(2020, time.September, 23, 7, 42, 0, 0, time.Local) dynamicCertProvider = dynamiccert.New() @@ -253,7 +264,7 @@ func TestManagerControllerSync(t *testing.T) { Namespace: agentPodNamespace, }, } - r.NoError(agentPodInformerClient.Tracker().Add(unrelatedPod)) + r.NoError(kubeClientset.Tracker().Add(unrelatedPod)) startInformersAndController() }) @@ -266,7 +277,7 @@ func TestManagerControllerSync(t *testing.T) { when("there is an agent pod, as determined by its labels matching the agent pod template labels, which is not yet annotated by the annotater controller", func() { it.Before(func() { agentPod := newAgentPod(agentPodName, false) - r.NoError(agentPodInformerClient.Tracker().Add(agentPod)) + r.NoError(kubeClientset.Tracker().Add(agentPod)) startInformersAndController() }) @@ -280,7 +291,7 @@ func TestManagerControllerSync(t *testing.T) { it.Before(func() { agentPod := newAgentPod(agentPodName, true) agentPod.Status.Phase = corev1.PodPending // not Running - r.NoError(agentPodInformerClient.Tracker().Add(agentPod)) + r.NoError(kubeClientset.Tracker().Add(agentPod)) startInformersAndController() }) @@ -295,8 +306,8 @@ func TestManagerControllerSync(t *testing.T) { targetAgentPod := newAgentPod(agentPodName, true) targetAgentPod.Status.Phase = corev1.PodRunning anotherAgentPod := newAgentPod("some-other-agent-pod-which-is-not-the-context-of-this-sync", true) - r.NoError(agentPodInformerClient.Tracker().Add(targetAgentPod)) - r.NoError(agentPodInformerClient.Tracker().Add(anotherAgentPod)) + r.NoError(kubeClientset.Tracker().Add(targetAgentPod)) + r.NoError(kubeClientset.Tracker().Add(anotherAgentPod)) }) when("the resulting pod execs will succeed", func() { @@ -304,90 +315,10 @@ func TestManagerControllerSync(t *testing.T) { fakeExecutor.resultsToReturn = []string{fakeCertPEM, fakeKeyPEM} }) - it("execs to the agent pod to get the keys and updates the dynamic certificates provider with the new certs", func() { - startInformersAndController() - r.NoError(controllerlib.TestSync(t, subject, *syncContext)) - - r.Equal(2, fakeExecutor.callCount) - - r.Equal(agentPodNamespace, fakeExecutor.calledWithPodNamespace[0]) - r.Equal(agentPodName, fakeExecutor.calledWithPodName[0]) - r.Equal([]string{"cat", fakeCertPath}, fakeExecutor.calledWithCommandAndArgs[0]) - - r.Equal(agentPodNamespace, fakeExecutor.calledWithPodNamespace[1]) - r.Equal(agentPodName, fakeExecutor.calledWithPodName[1]) - r.Equal([]string{"cat", fakeKeyPath}, fakeExecutor.calledWithCommandAndArgs[1]) - - actualCertPEM, actualKeyPEM := dynamicCertProvider.CurrentCertKeyContent() - r.Equal(fakeCertPEM, string(actualCertPEM)) - r.Equal(fakeKeyPEM, string(actualKeyPEM)) - }) - - when("there is already a CredentialIssuer", func() { - var initialCredentialIssuer *configv1alpha1.CredentialIssuer - - it.Before(func() { - initialCredentialIssuer = &configv1alpha1.CredentialIssuer{ - TypeMeta: metav1.TypeMeta{}, - ObjectMeta: metav1.ObjectMeta{ - Name: credentialIssuerResourceName, - }, - Status: configv1alpha1.CredentialIssuerStatus{ - Strategies: []configv1alpha1.CredentialIssuerStrategy{}, - KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: "some-server", - CertificateAuthorityData: "some-ca-value", - }, - }, - } - r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) - }) - - it("also updates the the existing CredentialIssuer status field", func() { + when("the cluster-info ConfigMap is not found", func() { + it("returns an error and updates the strategy with an error", func() { startInformersAndController() - r.NoError(controllerlib.TestSync(t, subject, *syncContext)) - - expectedCredentialIssuer := initialCredentialIssuer.DeepCopy() - expectedCredentialIssuer.Status.Strategies = []configv1alpha1.CredentialIssuerStrategy{ - { - Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, - Status: configv1alpha1.SuccessStrategyStatus, - Reason: configv1alpha1.FetchedKeyStrategyReason, - Message: "Key was fetched successfully", - LastUpdateTime: metav1.NewTime(frozenNow), - }, - } - expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName) - expectedCreateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedCredentialIssuer) - r.Equal([]coretesting.Action{expectedGetAction, expectedCreateAction}, pinnipedAPIClient.Actions()) - }) - - when("updating the CredentialIssuer fails", func() { - it.Before(func() { - pinnipedAPIClient.PrependReactor( - "update", - "credentialissuers", - func(_ coretesting.Action) (bool, runtime.Object, error) { - return true, nil, errors.New("some update error") - }, - ) - }) - - it("returns an error", func() { - startInformersAndController() - err := controllerlib.TestSync(t, subject, *syncContext) - r.EqualError(err, "could not create or update credentialissuer: some update error") - }) - }) - }) - - when("there is not already a CredentialIssuer", func() { - it.Before(func() { - startInformersAndController() - }) - - it("also creates the the CredentialIssuer with the appropriate status field", func() { - r.NoError(controllerlib.TestSync(t, subject, *syncContext)) + r.EqualError(controllerlib.TestSync(t, subject, *syncContext), `failed to get cluster-info configmap: configmap "cluster-info" not found`) expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{ TypeMeta: metav1.TypeMeta{}, @@ -405,9 +336,9 @@ func TestManagerControllerSync(t *testing.T) { Strategies: []configv1alpha1.CredentialIssuerStrategy{ { Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, - Status: configv1alpha1.SuccessStrategyStatus, - Reason: configv1alpha1.FetchedKeyStrategyReason, - Message: "Key was fetched successfully", + Status: configv1alpha1.ErrorStrategyStatus, + Reason: configv1alpha1.CouldNotGetClusterInfoStrategyReason, + Message: `failed to get cluster-info configmap: configmap "cluster-info" not found`, LastUpdateTime: metav1.NewTime(frozenNow), }, }, @@ -419,6 +350,226 @@ func TestManagerControllerSync(t *testing.T) { r.Equal([]coretesting.Action{expectedGetAction, expectedCreateAction, expectedUpdateAction}, pinnipedAPIClient.Actions()) }) }) + + when("the cluster-info ConfigMap is missing a key", func() { + it.Before(func() { + r.NoError(kubeClientset.Tracker().Add(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ClusterInfoNamespace, + Name: clusterInfoName, + }, + Data: map[string]string{"uninteresting-key": "uninteresting-value"}, + })) + }) + it("returns an error", func() { + startInformersAndController() + r.EqualError(controllerlib.TestSync(t, subject, *syncContext), `failed to get kubeconfig key from cluster-info configmap`) + }) + }) + + when("the cluster-info ConfigMap is contains invalid YAML", func() { + it.Before(func() { + r.NoError(kubeClientset.Tracker().Add(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ClusterInfoNamespace, + Name: clusterInfoName, + }, + Data: map[string]string{"kubeconfig": "invalid-yaml"}, + })) + }) + it("returns an error", func() { + startInformersAndController() + r.EqualError(controllerlib.TestSync(t, subject, *syncContext), `failed to load data from kubeconfig key in cluster-info configmap`) + }) + }) + + when("the cluster-info ConfigMap is contains an empty list of clusters", func() { + it.Before(func() { + r.NoError(kubeClientset.Tracker().Add(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ClusterInfoNamespace, + Name: clusterInfoName, + }, + Data: map[string]string{ + "kubeconfig": here.Doc(` + kind: Config + apiVersion: v1 + clusters: [] + `), + "uninteresting-key": "uninteresting-value", + }, + })) + }) + it("returns an error", func() { + startInformersAndController() + r.EqualError(controllerlib.TestSync(t, subject, *syncContext), `kubeconfig in kubeconfig key in cluster-info configmap did not contain any clusters`) + }) + }) + + when("the cluster-info ConfigMap is valid", func() { + it.Before(func() { + const caData = "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=" // "some-certificate-authority-data" base64 encoded + const kubeServerURL = "https://some-server" + r.NoError(kubeClientset.Tracker().Add(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: ClusterInfoNamespace, + Name: clusterInfoName, + }, + Data: map[string]string{ + "kubeconfig": here.Docf(` + kind: Config + apiVersion: v1 + clusters: + - name: "" + cluster: + certificate-authority-data: "%s" + server: "%s"`, + caData, kubeServerURL), + "uninteresting-key": "uninteresting-value", + }, + })) + }) + + it("execs to the agent pod to get the keys and updates the dynamic certificates provider with the new certs", func() { + startInformersAndController() + r.NoError(controllerlib.TestSync(t, subject, *syncContext)) + + r.Equal(2, fakeExecutor.callCount) + + r.Equal(agentPodNamespace, fakeExecutor.calledWithPodNamespace[0]) + r.Equal(agentPodName, fakeExecutor.calledWithPodName[0]) + r.Equal([]string{"cat", fakeCertPath}, fakeExecutor.calledWithCommandAndArgs[0]) + + r.Equal(agentPodNamespace, fakeExecutor.calledWithPodNamespace[1]) + r.Equal(agentPodName, fakeExecutor.calledWithPodName[1]) + r.Equal([]string{"cat", fakeKeyPath}, fakeExecutor.calledWithCommandAndArgs[1]) + + actualCertPEM, actualKeyPEM := dynamicCertProvider.CurrentCertKeyContent() + r.Equal(fakeCertPEM, string(actualCertPEM)) + r.Equal(fakeKeyPEM, string(actualKeyPEM)) + }) + + when("there is already a CredentialIssuer", func() { + var initialCredentialIssuer *configv1alpha1.CredentialIssuer + + it.Before(func() { + initialCredentialIssuer = &configv1alpha1.CredentialIssuer{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: credentialIssuerResourceName, + }, + Status: configv1alpha1.CredentialIssuerStatus{ + Strategies: []configv1alpha1.CredentialIssuerStrategy{}, + }, + } + r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) + }) + + it("also updates the the existing CredentialIssuer status field", func() { + startInformersAndController() + r.NoError(controllerlib.TestSync(t, subject, *syncContext)) + + // The first update to the CredentialIssuer will set the strategy entry + expectedCredentialIssuer := initialCredentialIssuer.DeepCopy() + expectedCredentialIssuer.Status.Strategies = []configv1alpha1.CredentialIssuerStrategy{ + { + Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, + Status: configv1alpha1.SuccessStrategyStatus, + Reason: configv1alpha1.FetchedKeyStrategyReason, + Message: "Key was fetched successfully", + LastUpdateTime: metav1.NewTime(frozenNow), + Frontend: &configv1alpha1.CredentialIssuerFrontend{ + Type: configv1alpha1.TokenCredentialRequestAPIFrontendType, + TokenCredentialRequestAPIInfo: &configv1alpha1.TokenCredentialRequestAPIInfo{ + Server: "https://some-server", + CertificateAuthorityData: "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=", + }, + }, + }, + } + expectedCredentialIssuer.Status.KubeConfigInfo = &configv1alpha1.CredentialIssuerKubeConfigInfo{ + Server: "https://some-server", + CertificateAuthorityData: "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=", + } + expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName) + expectedCreateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedCredentialIssuer) + r.Equal([]coretesting.Action{expectedGetAction, expectedCreateAction}, pinnipedAPIClient.Actions()) + }) + + when("updating the CredentialIssuer fails", func() { + it.Before(func() { + pinnipedAPIClient.PrependReactor( + "update", + "credentialissuers", + func(_ coretesting.Action) (bool, runtime.Object, error) { + return true, nil, errors.New("some update error") + }, + ) + }) + + it("returns an error", func() { + startInformersAndController() + err := controllerlib.TestSync(t, subject, *syncContext) + r.EqualError(err, "could not create or update credentialissuer: some update error") + }) + }) + }) + + when("there is not already a CredentialIssuer", func() { + it.Before(func() { + server := "https://overridden-server-url.example.com" + discoveryURLOverride = &server + credentialIssuerLabels = map[string]string{"foo": "bar"} + startInformersAndController() + }) + + it("also creates the the CredentialIssuer with the appropriate status field and labels", func() { + r.NoError(controllerlib.TestSync(t, subject, *syncContext)) + + expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: credentialIssuerResourceName, + Labels: map[string]string{"foo": "bar"}, + }, + } + + expectedCredentialIssuer := &configv1alpha1.CredentialIssuer{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: credentialIssuerResourceName, + Labels: map[string]string{"foo": "bar"}, + }, + Status: configv1alpha1.CredentialIssuerStatus{ + Strategies: []configv1alpha1.CredentialIssuerStrategy{ + { + Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, + Status: configv1alpha1.SuccessStrategyStatus, + Reason: configv1alpha1.FetchedKeyStrategyReason, + Message: "Key was fetched successfully", + LastUpdateTime: metav1.NewTime(frozenNow), + Frontend: &configv1alpha1.CredentialIssuerFrontend{ + Type: configv1alpha1.TokenCredentialRequestAPIFrontendType, + TokenCredentialRequestAPIInfo: &configv1alpha1.TokenCredentialRequestAPIInfo{ + Server: "https://overridden-server-url.example.com", + CertificateAuthorityData: "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=", + }, + }, + }, + }, + KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ + Server: "https://overridden-server-url.example.com", + CertificateAuthorityData: "c29tZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YQo=", + }, + }, + } + expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName) + expectedCreateAction := coretesting.NewRootCreateAction(credentialIssuerGVR, expectedCreateCredentialIssuer) + expectedUpdateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedCredentialIssuer) + r.Equal([]coretesting.Action{expectedGetAction, expectedCreateAction, expectedUpdateAction}, pinnipedAPIClient.Actions()) + }) + }) + }) }) when("the first resulting pod exec will fail", func() { diff --git a/internal/controller/kubecertagent/kubecertagent.go b/internal/controller/kubecertagent/kubecertagent.go index dff42f63..553765fc 100644 --- a/internal/controller/kubecertagent/kubecertagent.go +++ b/internal/controller/kubecertagent/kubecertagent.go @@ -277,16 +277,6 @@ func findControllerManagerPodForSpecificAgentPod( return maybeControllerManagerPod, nil } -func strategySuccess(clock clock.Clock) configv1alpha1.CredentialIssuerStrategy { - return configv1alpha1.CredentialIssuerStrategy{ - Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, - Status: configv1alpha1.SuccessStrategyStatus, - Reason: configv1alpha1.FetchedKeyStrategyReason, - Message: "Key was fetched successfully", - LastUpdateTime: metav1.NewTime(clock.Now()), - } -} - func strategyError(clock clock.Clock, err error) configv1alpha1.CredentialIssuerStrategy { return configv1alpha1.CredentialIssuerStrategy{ Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, diff --git a/internal/controllermanager/prepare_controllers.go b/internal/controllermanager/prepare_controllers.go index 902ed43b..61990a39 100644 --- a/internal/controllermanager/prepare_controllers.go +++ b/internal/controllermanager/prepare_controllers.go @@ -24,7 +24,6 @@ import ( "go.pinniped.dev/internal/controller/authenticator/cachecleaner" "go.pinniped.dev/internal/controller/authenticator/jwtcachefiller" "go.pinniped.dev/internal/controller/authenticator/webhookcachefiller" - "go.pinniped.dev/internal/controller/issuerconfig" "go.pinniped.dev/internal/controller/kubecertagent" "go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/deploymentref" @@ -124,20 +123,6 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) { controllerManager := controllerlib. NewManager(). - // KubeConfig info publishing controller is responsible for writing the KubeConfig information to the - // CredentialIssuer resource and keeping that information up to date. - WithController( - issuerconfig.NewKubeConfigInfoPublisherController( - c.NamesConfig.CredentialIssuer, - c.Labels, - c.DiscoveryURLOverride, - client.PinnipedConcierge, - informers.kubePublicNamespaceK8s.Core().V1().ConfigMaps(), - controllerlib.WithInformer, - ), - singletonWorker, - ). - // API certs controllers are responsible for managing the TLS certificates used to serve Pinniped's API. WithController( apicerts.NewCertsManagerController( @@ -219,6 +204,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) { kubecertagent.NewAnnotaterController( agentPodConfig, credentialIssuerLocationConfig, + c.Labels, clock.RealClock{}, client.Kubernetes, client.PinnipedConcierge, @@ -231,11 +217,14 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) { WithController( kubecertagent.NewExecerController( credentialIssuerLocationConfig, + c.Labels, + c.DiscoveryURLOverride, c.DynamicSigningCertProvider, kubecertagent.NewPodCommandExecutor(client.JSONConfig, client.Kubernetes), client.PinnipedConcierge, clock.RealClock{}, informers.installationNamespaceK8s.Core().V1().Pods(), + informers.kubePublicNamespaceK8s.Core().V1().ConfigMaps(), controllerlib.WithInformer, ), singletonWorker, @@ -303,7 +292,7 @@ func createInformers( kubePublicNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions( k8sClient, defaultResyncInterval, - k8sinformers.WithNamespace(issuerconfig.ClusterInfoNamespace), + k8sinformers.WithNamespace(kubecertagent.ClusterInfoNamespace), ), kubeSystemNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions( k8sClient, diff --git a/test/integration/concierge_credentialissuerconfig_test.go b/test/integration/concierge_credentialissuer_test.go similarity index 86% rename from test/integration/concierge_credentialissuerconfig_test.go rename to test/integration/concierge_credentialissuer_test.go index 45ce038d..c7ed6e66 100644 --- a/test/integration/concierge_credentialissuerconfig_test.go +++ b/test/integration/concierge_credentialissuer_test.go @@ -72,12 +72,20 @@ func TestCredentialIssuer(t *testing.T) { require.Equal(t, configv1alpha1.SuccessStrategyStatus, actualStatusStrategy.Status) require.Equal(t, configv1alpha1.FetchedKeyStrategyReason, actualStatusStrategy.Reason) require.Equal(t, "Key was fetched successfully", actualStatusStrategy.Message) + require.NotNil(t, actualStatusStrategy.Frontend) + require.Equal(t, configv1alpha1.TokenCredentialRequestAPIFrontendType, actualStatusStrategy.Frontend.Type) + expectedTokenRequestAPIInfo := configv1alpha1.TokenCredentialRequestAPIInfo{ + Server: config.Host, + CertificateAuthorityData: base64.StdEncoding.EncodeToString(config.TLSClientConfig.CAData), + } + require.Equal(t, &expectedTokenRequestAPIInfo, actualStatusStrategy.Frontend.TokenCredentialRequestAPIInfo) + // Verify the published kube config info. require.Equal( t, &configv1alpha1.CredentialIssuerKubeConfigInfo{ - Server: config.Host, - CertificateAuthorityData: base64.StdEncoding.EncodeToString(config.TLSClientConfig.CAData), + Server: expectedTokenRequestAPIInfo.Server, + CertificateAuthorityData: expectedTokenRequestAPIInfo.CertificateAuthorityData, }, actualStatusKubeConfigInfo, )