Merge branch 'main' of github.com:vmware-tanzu/pinniped into impersonation-proxy

This is more than an automatic merge. It also includes a rewrite of the CredentialIssuer API impersonation proxy fields using the new structure, and updates to the CLI to account for that new API.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer 2021-03-02 16:06:19 -06:00
commit 60f92d5fe2
No known key found for this signature in database
GPG Key ID: EAE88AD172C5AE2D
35 changed files with 1550 additions and 1087 deletions

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -251,25 +251,36 @@ func configureConcierge(credentialIssuer *configv1alpha1.CredentialIssuer, authe
// Autodiscover the --concierge-mode. // Autodiscover the --concierge-mode.
if flags.concierge.mode == modeUnknown { if flags.concierge.mode == modeUnknown {
switch {
case credentialIssuer.Status.KubeConfigInfo != nil: for _, strategy := range credentialIssuer.Status.Strategies {
// Prefer the TokenCredentialRequest API if available. fe := strategy.Frontend
flags.concierge.mode = modeTokenCredentialRequestAPI if strategy.Status != configv1alpha1.SuccessStrategyStatus || fe == nil {
case credentialIssuer.Status.ImpersonationProxyInfo != nil: continue
// Otherwise prefer the impersonation proxy if it seems configured.
flags.concierge.mode = modeImpersonationProxy
default:
return fmt.Errorf("could not autodiscover --concierge-mode and none was provided")
}
} }
if flags.concierge.mode == modeImpersonationProxy && credentialIssuer.Status.ImpersonationProxyInfo != nil { switch fe.Type {
flags.concierge.endpoint = credentialIssuer.Status.ImpersonationProxyInfo.Endpoint case configv1alpha1.TokenCredentialRequestAPIFrontendType:
flags.concierge.mode = modeTokenCredentialRequestAPI
case configv1alpha1.ImpersonationProxyFrontendType:
flags.concierge.mode = modeImpersonationProxy
flags.concierge.endpoint = fe.ImpersonationProxyInfo.Endpoint
var err error var err error
conciergeCABundleData, err = base64.StdEncoding.DecodeString(credentialIssuer.Status.ImpersonationProxyInfo.CertificateAuthorityData) conciergeCABundleData, err = base64.StdEncoding.DecodeString(fe.ImpersonationProxyInfo.CertificateAuthorityData)
if err != nil { if err != nil {
return fmt.Errorf("autodiscovered Concierge CA bundle is invalid: %w", err) return fmt.Errorf("autodiscovered Concierge CA bundle is invalid: %w", err)
} }
default:
// Skip any unknown frontend types.
}
}
if flags.concierge.mode == modeUnknown {
// Fall back to deprecated field for backwards compatibility.
if credentialIssuer.Status.KubeConfigInfo != nil {
flags.concierge.mode = modeTokenCredentialRequestAPI
} else {
return fmt.Errorf("could not autodiscover --concierge-mode and none was provided")
}
}
} }
switch auth := authenticator.(type) { switch auth := authenticator.(type) {

View File

@ -303,12 +303,41 @@ func TestGetKubeconfig(t *testing.T) {
&configv1alpha1.CredentialIssuer{ &configv1alpha1.CredentialIssuer{
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}, ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
ImpersonationProxyInfo: &configv1alpha1.CredentialIssuerImpersonationProxyInfo{ Strategies: []configv1alpha1.CredentialIssuerStrategy{
{
Type: "SomeBrokenType",
Status: configv1alpha1.ErrorStrategyStatus,
Reason: "SomeFailureReason",
Message: "Some error message",
LastUpdateTime: metav1.Now(),
},
{
Type: "SomeUnknownType",
Status: configv1alpha1.SuccessStrategyStatus,
Reason: "SomeReason",
Message: "Some error message",
LastUpdateTime: metav1.Now(),
Frontend: &configv1alpha1.CredentialIssuerFrontend{
Type: "SomeUnknownFrontendType",
},
},
{
Type: "SomeType",
Status: configv1alpha1.SuccessStrategyStatus,
Reason: "SomeReason",
Message: "Some message",
LastUpdateTime: metav1.Now(),
Frontend: &configv1alpha1.CredentialIssuerFrontend{
Type: configv1alpha1.ImpersonationProxyFrontendType,
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
Endpoint: "https://impersonation-endpoint", Endpoint: "https://impersonation-endpoint",
CertificateAuthorityData: "invalid-base-64", CertificateAuthorityData: "invalid-base-64",
}, },
}, },
}, },
},
},
},
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}}, &conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
}, },
wantError: true, wantError: true,
@ -325,11 +354,21 @@ func TestGetKubeconfig(t *testing.T) {
&configv1alpha1.CredentialIssuer{ &configv1alpha1.CredentialIssuer{
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}, ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{ Strategies: []configv1alpha1.CredentialIssuerStrategy{{
Type: "SomeType",
Status: configv1alpha1.SuccessStrategyStatus,
Reason: "SomeReason",
Message: "Some message",
LastUpdateTime: metav1.Now(),
Frontend: &configv1alpha1.CredentialIssuerFrontend{
Type: configv1alpha1.TokenCredentialRequestAPIFrontendType,
TokenCredentialRequestAPIInfo: &configv1alpha1.TokenCredentialRequestAPIInfo{
Server: "https://concierge-endpoint", Server: "https://concierge-endpoint",
CertificateAuthorityData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==", CertificateAuthorityData: "ZmFrZS1jZXJ0aWZpY2F0ZS1hdXRob3JpdHktZGF0YS12YWx1ZQ==",
}, },
}, },
}},
},
}, },
&conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}}, &conciergev1alpha1.WebhookAuthenticator{ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}},
}, },
@ -749,11 +788,21 @@ func TestGetKubeconfig(t *testing.T) {
&configv1alpha1.CredentialIssuer{ &configv1alpha1.CredentialIssuer{
ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"}, ObjectMeta: metav1.ObjectMeta{Name: "test-credential-issuer"},
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
ImpersonationProxyInfo: &configv1alpha1.CredentialIssuerImpersonationProxyInfo{ Strategies: []configv1alpha1.CredentialIssuerStrategy{{
Type: "SomeType",
Status: configv1alpha1.SuccessStrategyStatus,
Reason: "SomeReason",
Message: "Some message",
LastUpdateTime: metav1.Now(),
Frontend: &configv1alpha1.CredentialIssuerFrontend{
Type: configv1alpha1.ImpersonationProxyFrontendType,
ImpersonationProxyInfo: &configv1alpha1.ImpersonationProxyInfo{
Endpoint: "https://impersonation-proxy-endpoint.test", Endpoint: "https://impersonation-proxy-endpoint.test",
CertificateAuthorityData: "dGVzdC1jb25jaWVyZ2UtY2E=", CertificateAuthorityData: "dGVzdC1jb25jaWVyZ2UtY2E=",
}, },
}, },
}},
},
}, },
&conciergev1alpha1.JWTAuthenticator{ &conciergev1alpha1.JWTAuthenticator{
ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"}, ObjectMeta: metav1.ObjectMeta{Name: "test-authenticator"},

View File

@ -38,34 +38,17 @@ spec:
status: status:
description: Status of the credential issuer. description: Status of the credential issuer.
properties: properties:
impersonationProxyInfo:
description: Information needed to form a valid Pinniped-based kubeconfig
using the impersonation proxy.
properties:
certificateAuthorityData:
description: The CA bundle to validate connections to the impersonation
proxy.
minLength: 1
type: string
endpoint:
description: The HTTPS endpoint of the impersonation proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- endpoint
type: object
kubeConfigInfo: kubeConfigInfo:
description: Information needed to form a valid Pinniped-based kubeconfig description: Information needed to form a valid Pinniped-based kubeconfig
using the TokenCredentialRequest API. using this credential issuer. This field is deprecated and will
be removed in a future version.
properties: properties:
certificateAuthorityData: certificateAuthorityData:
description: The Kubernetes API server CA bundle. description: The K8s API server CA bundle.
minLength: 1 minLength: 1
type: string type: string
server: server:
description: The Kubernetes API server URL. description: The K8s API server URL.
minLength: 1 minLength: 1
pattern: ^https://|^http:// pattern: ^https://|^http://
type: string type: string
@ -80,6 +63,58 @@ spec:
description: Status of an integration strategy that was attempted description: Status of an integration strategy that was attempted
by Pinniped. by Pinniped.
properties: properties:
frontend:
description: Frontend describes how clients can connect using
this strategy.
properties:
impersonationProxyInfo:
description: ImpersonationProxyInfo describes the parameters
for the impersonation proxy on this Concierge. This field
is only set when Type is "ImpersonationProxy".
properties:
certificateAuthorityData:
description: CertificateAuthorityData is the base64-encoded
PEM CA bundle of the impersonation proxy.
minLength: 1
type: string
server:
description: Endpoint is the HTTPS endpoint of the impersonation
proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- server
type: object
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: lastUpdateTime:
description: When the status was last checked. description: When the status was last checked.
format: date-time format: date-time

View File

@ -236,21 +236,22 @@ Describes the configuration status of a Pinniped credential issuer.
|=== |===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo"] [id="{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerfrontend"]
==== CredentialIssuerImpersonationProxyInfo ==== CredentialIssuerFrontend
.Appears In: .Appears In:
**** ****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$] - xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$]
**** ****
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`endpoint`* __string__ | The HTTPS endpoint of the impersonation proxy. | *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy.
| *`certificateAuthorityData`* __string__ | The CA bundle to validate connections to the impersonation proxy. | *`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".
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-impersonationproxyinfo[$$ImpersonationProxyInfo$$]__ | ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge. This field is only set when Type is "ImpersonationProxy".
|=== |===
@ -267,8 +268,8 @@ Describes the configuration status of a Pinniped credential issuer.
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`server`* __string__ | The Kubernetes API server URL. | *`server`* __string__ | The K8s API server URL.
| *`certificateAuthorityData`* __string__ | The Kubernetes API server CA bundle. | *`certificateAuthorityData`* __string__ | The K8s API server CA bundle.
|=== |===
@ -288,8 +289,7 @@ Status of a credential issuer.
|=== |===
| Field | Description | 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. | *`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 the TokenCredentialRequest API. | *`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.
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-17-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo[$$CredentialIssuerImpersonationProxyInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
|=== |===
@ -311,6 +311,43 @@ Status of a credential issuer.
| *`reason`* __StrategyReason__ | Reason for the current status. | *`reason`* __StrategyReason__ | Reason for the current status.
| *`message`* __string__ | Human-readable description of 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. | *`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-impersonationproxyinfo"]
==== ImpersonationProxyInfo
.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__ | Endpoint is the HTTPS endpoint of the impersonation proxy.
| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
|===
[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.
|=== |===

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -39,17 +39,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopyInto(out *CredentialIssuerImpersonationProxyInfo) { func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) {
*out = *in *out = *in
if in.TokenCredentialRequestAPIInfo != nil {
in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo
*out = new(TokenCredentialRequestAPIInfo)
**out = **in
}
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(ImpersonationProxyInfo)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerImpersonationProxyInfo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopy() *CredentialIssuerImpersonationProxyInfo { func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend {
if in == nil { if in == nil {
return nil return nil
} }
out := new(CredentialIssuerImpersonationProxyInfo) out := new(CredentialIssuerFrontend)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@ -118,11 +128,6 @@ func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
*out = new(CredentialIssuerKubeConfigInfo) *out = new(CredentialIssuerKubeConfigInfo)
**out = **in **out = **in
} }
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(CredentialIssuerImpersonationProxyInfo)
**out = **in
}
return return
} }
@ -140,6 +145,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus {
func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) {
*out = *in *out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
if in.Frontend != nil {
in, out := &in.Frontend, &out.Frontend
*out = new(CredentialIssuerFrontend)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -152,3 +162,35 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImpersonationProxyInfo) DeepCopyInto(out *ImpersonationProxyInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyInfo.
func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
if in == nil {
return nil
}
out := new(ImpersonationProxyInfo)
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
}

View File

@ -38,34 +38,17 @@ spec:
status: status:
description: Status of the credential issuer. description: Status of the credential issuer.
properties: properties:
impersonationProxyInfo:
description: Information needed to form a valid Pinniped-based kubeconfig
using the impersonation proxy.
properties:
certificateAuthorityData:
description: The CA bundle to validate connections to the impersonation
proxy.
minLength: 1
type: string
endpoint:
description: The HTTPS endpoint of the impersonation proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- endpoint
type: object
kubeConfigInfo: kubeConfigInfo:
description: Information needed to form a valid Pinniped-based kubeconfig description: Information needed to form a valid Pinniped-based kubeconfig
using the TokenCredentialRequest API. using this credential issuer. This field is deprecated and will
be removed in a future version.
properties: properties:
certificateAuthorityData: certificateAuthorityData:
description: The Kubernetes API server CA bundle. description: The K8s API server CA bundle.
minLength: 1 minLength: 1
type: string type: string
server: server:
description: The Kubernetes API server URL. description: The K8s API server URL.
minLength: 1 minLength: 1
pattern: ^https://|^http:// pattern: ^https://|^http://
type: string type: string
@ -80,6 +63,58 @@ spec:
description: Status of an integration strategy that was attempted description: Status of an integration strategy that was attempted
by Pinniped. by Pinniped.
properties: properties:
frontend:
description: Frontend describes how clients can connect using
this strategy.
properties:
impersonationProxyInfo:
description: ImpersonationProxyInfo describes the parameters
for the impersonation proxy on this Concierge. This field
is only set when Type is "ImpersonationProxy".
properties:
certificateAuthorityData:
description: CertificateAuthorityData is the base64-encoded
PEM CA bundle of the impersonation proxy.
minLength: 1
type: string
server:
description: Endpoint is the HTTPS endpoint of the impersonation
proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- server
type: object
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: lastUpdateTime:
description: When the status was last checked. description: When the status was last checked.
format: date-time format: date-time

View File

@ -236,21 +236,22 @@ Describes the configuration status of a Pinniped credential issuer.
|=== |===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo"] [id="{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerfrontend"]
==== CredentialIssuerImpersonationProxyInfo ==== CredentialIssuerFrontend
.Appears In: .Appears In:
**** ****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$] - xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$]
**** ****
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`endpoint`* __string__ | The HTTPS endpoint of the impersonation proxy. | *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy.
| *`certificateAuthorityData`* __string__ | The CA bundle to validate connections to the impersonation proxy. | *`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".
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-impersonationproxyinfo[$$ImpersonationProxyInfo$$]__ | ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge. This field is only set when Type is "ImpersonationProxy".
|=== |===
@ -267,8 +268,8 @@ Describes the configuration status of a Pinniped credential issuer.
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`server`* __string__ | The Kubernetes API server URL. | *`server`* __string__ | The K8s API server URL.
| *`certificateAuthorityData`* __string__ | The Kubernetes API server CA bundle. | *`certificateAuthorityData`* __string__ | The K8s API server CA bundle.
|=== |===
@ -288,8 +289,7 @@ Status of a credential issuer.
|=== |===
| Field | Description | 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. | *`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 the TokenCredentialRequest API. | *`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.
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-18-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo[$$CredentialIssuerImpersonationProxyInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
|=== |===
@ -311,6 +311,43 @@ Status of a credential issuer.
| *`reason`* __StrategyReason__ | Reason for the current status. | *`reason`* __StrategyReason__ | Reason for the current status.
| *`message`* __string__ | Human-readable description of 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. | *`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-impersonationproxyinfo"]
==== ImpersonationProxyInfo
.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__ | Endpoint is the HTTPS endpoint of the impersonation proxy.
| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
|===
[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.
|=== |===

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -39,17 +39,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopyInto(out *CredentialIssuerImpersonationProxyInfo) { func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) {
*out = *in *out = *in
if in.TokenCredentialRequestAPIInfo != nil {
in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo
*out = new(TokenCredentialRequestAPIInfo)
**out = **in
}
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(ImpersonationProxyInfo)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerImpersonationProxyInfo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopy() *CredentialIssuerImpersonationProxyInfo { func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend {
if in == nil { if in == nil {
return nil return nil
} }
out := new(CredentialIssuerImpersonationProxyInfo) out := new(CredentialIssuerFrontend)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@ -118,11 +128,6 @@ func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
*out = new(CredentialIssuerKubeConfigInfo) *out = new(CredentialIssuerKubeConfigInfo)
**out = **in **out = **in
} }
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(CredentialIssuerImpersonationProxyInfo)
**out = **in
}
return return
} }
@ -140,6 +145,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus {
func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) {
*out = *in *out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
if in.Frontend != nil {
in, out := &in.Frontend, &out.Frontend
*out = new(CredentialIssuerFrontend)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -152,3 +162,35 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImpersonationProxyInfo) DeepCopyInto(out *ImpersonationProxyInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyInfo.
func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
if in == nil {
return nil
}
out := new(ImpersonationProxyInfo)
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
}

View File

@ -38,34 +38,17 @@ spec:
status: status:
description: Status of the credential issuer. description: Status of the credential issuer.
properties: properties:
impersonationProxyInfo:
description: Information needed to form a valid Pinniped-based kubeconfig
using the impersonation proxy.
properties:
certificateAuthorityData:
description: The CA bundle to validate connections to the impersonation
proxy.
minLength: 1
type: string
endpoint:
description: The HTTPS endpoint of the impersonation proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- endpoint
type: object
kubeConfigInfo: kubeConfigInfo:
description: Information needed to form a valid Pinniped-based kubeconfig description: Information needed to form a valid Pinniped-based kubeconfig
using the TokenCredentialRequest API. using this credential issuer. This field is deprecated and will
be removed in a future version.
properties: properties:
certificateAuthorityData: certificateAuthorityData:
description: The Kubernetes API server CA bundle. description: The K8s API server CA bundle.
minLength: 1 minLength: 1
type: string type: string
server: server:
description: The Kubernetes API server URL. description: The K8s API server URL.
minLength: 1 minLength: 1
pattern: ^https://|^http:// pattern: ^https://|^http://
type: string type: string
@ -80,6 +63,58 @@ spec:
description: Status of an integration strategy that was attempted description: Status of an integration strategy that was attempted
by Pinniped. by Pinniped.
properties: properties:
frontend:
description: Frontend describes how clients can connect using
this strategy.
properties:
impersonationProxyInfo:
description: ImpersonationProxyInfo describes the parameters
for the impersonation proxy on this Concierge. This field
is only set when Type is "ImpersonationProxy".
properties:
certificateAuthorityData:
description: CertificateAuthorityData is the base64-encoded
PEM CA bundle of the impersonation proxy.
minLength: 1
type: string
server:
description: Endpoint is the HTTPS endpoint of the impersonation
proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- server
type: object
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: lastUpdateTime:
description: When the status was last checked. description: When the status was last checked.
format: date-time format: date-time

View File

@ -236,21 +236,22 @@ Describes the configuration status of a Pinniped credential issuer.
|=== |===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo"] [id="{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerfrontend"]
==== CredentialIssuerImpersonationProxyInfo ==== CredentialIssuerFrontend
.Appears In: .Appears In:
**** ****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$] - xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$]
**** ****
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`endpoint`* __string__ | The HTTPS endpoint of the impersonation proxy. | *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy.
| *`certificateAuthorityData`* __string__ | The CA bundle to validate connections to the impersonation proxy. | *`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".
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-impersonationproxyinfo[$$ImpersonationProxyInfo$$]__ | ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge. This field is only set when Type is "ImpersonationProxy".
|=== |===
@ -267,8 +268,8 @@ Describes the configuration status of a Pinniped credential issuer.
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`server`* __string__ | The Kubernetes API server URL. | *`server`* __string__ | The K8s API server URL.
| *`certificateAuthorityData`* __string__ | The Kubernetes API server CA bundle. | *`certificateAuthorityData`* __string__ | The K8s API server CA bundle.
|=== |===
@ -288,8 +289,7 @@ Status of a credential issuer.
|=== |===
| Field | Description | 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. | *`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 the TokenCredentialRequest API. | *`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.
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-19-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo[$$CredentialIssuerImpersonationProxyInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
|=== |===
@ -311,6 +311,43 @@ Status of a credential issuer.
| *`reason`* __StrategyReason__ | Reason for the current status. | *`reason`* __StrategyReason__ | Reason for the current status.
| *`message`* __string__ | Human-readable description of 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. | *`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-impersonationproxyinfo"]
==== ImpersonationProxyInfo
.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__ | Endpoint is the HTTPS endpoint of the impersonation proxy.
| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
|===
[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.
|=== |===

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -39,17 +39,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopyInto(out *CredentialIssuerImpersonationProxyInfo) { func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) {
*out = *in *out = *in
if in.TokenCredentialRequestAPIInfo != nil {
in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo
*out = new(TokenCredentialRequestAPIInfo)
**out = **in
}
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(ImpersonationProxyInfo)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerImpersonationProxyInfo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopy() *CredentialIssuerImpersonationProxyInfo { func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend {
if in == nil { if in == nil {
return nil return nil
} }
out := new(CredentialIssuerImpersonationProxyInfo) out := new(CredentialIssuerFrontend)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@ -118,11 +128,6 @@ func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
*out = new(CredentialIssuerKubeConfigInfo) *out = new(CredentialIssuerKubeConfigInfo)
**out = **in **out = **in
} }
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(CredentialIssuerImpersonationProxyInfo)
**out = **in
}
return return
} }
@ -140,6 +145,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus {
func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) {
*out = *in *out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
if in.Frontend != nil {
in, out := &in.Frontend, &out.Frontend
*out = new(CredentialIssuerFrontend)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -152,3 +162,35 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImpersonationProxyInfo) DeepCopyInto(out *ImpersonationProxyInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyInfo.
func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
if in == nil {
return nil
}
out := new(ImpersonationProxyInfo)
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
}

View File

@ -38,34 +38,17 @@ spec:
status: status:
description: Status of the credential issuer. description: Status of the credential issuer.
properties: properties:
impersonationProxyInfo:
description: Information needed to form a valid Pinniped-based kubeconfig
using the impersonation proxy.
properties:
certificateAuthorityData:
description: The CA bundle to validate connections to the impersonation
proxy.
minLength: 1
type: string
endpoint:
description: The HTTPS endpoint of the impersonation proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- endpoint
type: object
kubeConfigInfo: kubeConfigInfo:
description: Information needed to form a valid Pinniped-based kubeconfig description: Information needed to form a valid Pinniped-based kubeconfig
using the TokenCredentialRequest API. using this credential issuer. This field is deprecated and will
be removed in a future version.
properties: properties:
certificateAuthorityData: certificateAuthorityData:
description: The Kubernetes API server CA bundle. description: The K8s API server CA bundle.
minLength: 1 minLength: 1
type: string type: string
server: server:
description: The Kubernetes API server URL. description: The K8s API server URL.
minLength: 1 minLength: 1
pattern: ^https://|^http:// pattern: ^https://|^http://
type: string type: string
@ -80,6 +63,58 @@ spec:
description: Status of an integration strategy that was attempted description: Status of an integration strategy that was attempted
by Pinniped. by Pinniped.
properties: properties:
frontend:
description: Frontend describes how clients can connect using
this strategy.
properties:
impersonationProxyInfo:
description: ImpersonationProxyInfo describes the parameters
for the impersonation proxy on this Concierge. This field
is only set when Type is "ImpersonationProxy".
properties:
certificateAuthorityData:
description: CertificateAuthorityData is the base64-encoded
PEM CA bundle of the impersonation proxy.
minLength: 1
type: string
server:
description: Endpoint is the HTTPS endpoint of the impersonation
proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- server
type: object
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: lastUpdateTime:
description: When the status was last checked. description: When the status was last checked.
format: date-time format: date-time

View File

@ -236,21 +236,22 @@ Describes the configuration status of a Pinniped credential issuer.
|=== |===
[id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo"] [id="{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerfrontend"]
==== CredentialIssuerImpersonationProxyInfo ==== CredentialIssuerFrontend
.Appears In: .Appears In:
**** ****
- xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstatus[$$CredentialIssuerStatus$$] - xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerstrategy[$$CredentialIssuerStrategy$$]
**** ****
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`endpoint`* __string__ | The HTTPS endpoint of the impersonation proxy. | *`type`* __FrontendType__ | Type describes which frontend mechanism clients can use with a strategy.
| *`certificateAuthorityData`* __string__ | The CA bundle to validate connections to the impersonation proxy. | *`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".
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-impersonationproxyinfo[$$ImpersonationProxyInfo$$]__ | ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge. This field is only set when Type is "ImpersonationProxy".
|=== |===
@ -267,8 +268,8 @@ Describes the configuration status of a Pinniped credential issuer.
[cols="25a,75a", options="header"] [cols="25a,75a", options="header"]
|=== |===
| Field | Description | Field | Description
| *`server`* __string__ | The Kubernetes API server URL. | *`server`* __string__ | The K8s API server URL.
| *`certificateAuthorityData`* __string__ | The Kubernetes API server CA bundle. | *`certificateAuthorityData`* __string__ | The K8s API server CA bundle.
|=== |===
@ -288,8 +289,7 @@ Status of a credential issuer.
|=== |===
| Field | Description | 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. | *`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 the TokenCredentialRequest API. | *`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.
| *`impersonationProxyInfo`* __xref:{anchor_prefix}-go-pinniped-dev-generated-1-20-apis-concierge-config-v1alpha1-credentialissuerimpersonationproxyinfo[$$CredentialIssuerImpersonationProxyInfo$$]__ | Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
|=== |===
@ -311,6 +311,43 @@ Status of a credential issuer.
| *`reason`* __StrategyReason__ | Reason for the current status. | *`reason`* __StrategyReason__ | Reason for the current status.
| *`message`* __string__ | Human-readable description of 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. | *`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-impersonationproxyinfo"]
==== ImpersonationProxyInfo
.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__ | Endpoint is the HTTPS endpoint of the impersonation proxy.
| *`certificateAuthorityData`* __string__ | CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
|===
[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.
|=== |===

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -39,17 +39,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopyInto(out *CredentialIssuerImpersonationProxyInfo) { func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) {
*out = *in *out = *in
if in.TokenCredentialRequestAPIInfo != nil {
in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo
*out = new(TokenCredentialRequestAPIInfo)
**out = **in
}
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(ImpersonationProxyInfo)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerImpersonationProxyInfo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopy() *CredentialIssuerImpersonationProxyInfo { func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend {
if in == nil { if in == nil {
return nil return nil
} }
out := new(CredentialIssuerImpersonationProxyInfo) out := new(CredentialIssuerFrontend)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@ -118,11 +128,6 @@ func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
*out = new(CredentialIssuerKubeConfigInfo) *out = new(CredentialIssuerKubeConfigInfo)
**out = **in **out = **in
} }
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(CredentialIssuerImpersonationProxyInfo)
**out = **in
}
return return
} }
@ -140,6 +145,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus {
func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) {
*out = *in *out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
if in.Frontend != nil {
in, out := &in.Frontend, &out.Frontend
*out = new(CredentialIssuerFrontend)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -152,3 +162,35 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImpersonationProxyInfo) DeepCopyInto(out *ImpersonationProxyInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyInfo.
func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
if in == nil {
return nil
}
out := new(ImpersonationProxyInfo)
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
}

View File

@ -38,34 +38,17 @@ spec:
status: status:
description: Status of the credential issuer. description: Status of the credential issuer.
properties: properties:
impersonationProxyInfo:
description: Information needed to form a valid Pinniped-based kubeconfig
using the impersonation proxy.
properties:
certificateAuthorityData:
description: The CA bundle to validate connections to the impersonation
proxy.
minLength: 1
type: string
endpoint:
description: The HTTPS endpoint of the impersonation proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- endpoint
type: object
kubeConfigInfo: kubeConfigInfo:
description: Information needed to form a valid Pinniped-based kubeconfig description: Information needed to form a valid Pinniped-based kubeconfig
using the TokenCredentialRequest API. using this credential issuer. This field is deprecated and will
be removed in a future version.
properties: properties:
certificateAuthorityData: certificateAuthorityData:
description: The Kubernetes API server CA bundle. description: The K8s API server CA bundle.
minLength: 1 minLength: 1
type: string type: string
server: server:
description: The Kubernetes API server URL. description: The K8s API server URL.
minLength: 1 minLength: 1
pattern: ^https://|^http:// pattern: ^https://|^http://
type: string type: string
@ -80,6 +63,58 @@ spec:
description: Status of an integration strategy that was attempted description: Status of an integration strategy that was attempted
by Pinniped. by Pinniped.
properties: properties:
frontend:
description: Frontend describes how clients can connect using
this strategy.
properties:
impersonationProxyInfo:
description: ImpersonationProxyInfo describes the parameters
for the impersonation proxy on this Concierge. This field
is only set when Type is "ImpersonationProxy".
properties:
certificateAuthorityData:
description: CertificateAuthorityData is the base64-encoded
PEM CA bundle of the impersonation proxy.
minLength: 1
type: string
server:
description: Endpoint is the HTTPS endpoint of the impersonation
proxy.
minLength: 1
pattern: ^https://
type: string
required:
- certificateAuthorityData
- server
type: object
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: lastUpdateTime:
description: When the status was last checked. description: When the status was last checked.
format: date-time format: date-time

View File

@ -8,6 +8,9 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +kubebuilder:validation:Enum=KubeClusterSigningCertificate // +kubebuilder:validation:Enum=KubeClusterSigningCertificate
type StrategyType string type StrategyType string
// +kubebuilder:validation:Enum=TokenCredentialRequestAPI
type FrontendType string
// +kubebuilder:validation:Enum=Success;Error // +kubebuilder:validation:Enum=Success;Error
type StrategyStatus string type StrategyStatus string
@ -16,15 +19,16 @@ type StrategyReason string
const ( const (
KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate") KubeClusterSigningCertificateStrategyType = StrategyType("KubeClusterSigningCertificate")
ImpersonationProxyStrategyType = StrategyType("ImpersonationProxy")
TokenCredentialRequestAPIFrontendType = FrontendType("TokenCredentialRequestAPI")
ImpersonationProxyFrontendType = FrontendType("ImpersonationProxy")
SuccessStrategyStatus = StrategyStatus("Success") SuccessStrategyStatus = StrategyStatus("Success")
ErrorStrategyStatus = StrategyStatus("Error") ErrorStrategyStatus = StrategyStatus("Error")
CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey") CouldNotFetchKeyStrategyReason = StrategyReason("CouldNotFetchKey")
CouldNotGetClusterInfoStrategyReason = StrategyReason("CouldNotGetClusterInfo")
FetchedKeyStrategyReason = StrategyReason("FetchedKey") FetchedKeyStrategyReason = StrategyReason("FetchedKey")
ListeningStrategyReason = StrategyReason("Listening")
DisabledStrategyReason = StrategyReason("Disabled")
) )
// Status of a credential issuer. // Status of a credential issuer.
@ -32,35 +36,20 @@ type CredentialIssuerStatus struct {
// List of integration strategies that were attempted by Pinniped. // List of integration strategies that were attempted by Pinniped.
Strategies []CredentialIssuerStrategy `json:"strategies"` Strategies []CredentialIssuerStrategy `json:"strategies"`
// Information needed to form a valid Pinniped-based kubeconfig using the TokenCredentialRequest API. // 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 // +optional
KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"` KubeConfigInfo *CredentialIssuerKubeConfigInfo `json:"kubeConfigInfo,omitempty"`
// Information needed to form a valid Pinniped-based kubeconfig using the impersonation proxy.
// +optional
ImpersonationProxyInfo *CredentialIssuerImpersonationProxyInfo `json:"impersonationProxyInfo,omitempty"`
} }
// Information needed to connect to the TokenCredentialRequest API on this cluster. // Information needed to form a valid Pinniped-based kubeconfig using this credential issuer.
type CredentialIssuerKubeConfigInfo struct { type CredentialIssuerKubeConfigInfo struct {
// The Kubernetes API server URL. // The K8s API server URL.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://|^http://` // +kubebuilder:validation:Pattern=`^https://|^http://`
Server string `json:"server"` Server string `json:"server"`
// The Kubernetes API server CA bundle. // The K8s API server CA bundle.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
}
// Information needed to connect to the TokenCredentialRequest API on this cluster.
type CredentialIssuerImpersonationProxyInfo struct {
// The HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"endpoint"`
// The CA bundle to validate connections to the impersonation proxy.
// +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"` CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
@ -82,6 +71,46 @@ type CredentialIssuerStrategy struct {
// When the status was last checked. // When the status was last checked.
LastUpdateTime metav1.Time `json:"lastUpdateTime"` 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"`
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
// This field is only set when Type is "ImpersonationProxy".
ImpersonationProxyInfo *ImpersonationProxyInfo `json:"impersonationProxyInfo,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"`
}
// ImpersonationProxyInfo describes the parameters for the impersonation proxy on this Concierge.
type ImpersonationProxyInfo struct {
// Endpoint is the HTTPS endpoint of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Pattern=`^https://`
Endpoint string `json:"server"`
// CertificateAuthorityData is the base64-encoded PEM CA bundle of the impersonation proxy.
// +kubebuilder:validation:MinLength=1
CertificateAuthorityData string `json:"certificateAuthorityData"`
} }
// Describes the configuration status of a Pinniped credential issuer. // Describes the configuration status of a Pinniped credential issuer.

View File

@ -39,17 +39,27 @@ func (in *CredentialIssuer) DeepCopyObject() runtime.Object {
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopyInto(out *CredentialIssuerImpersonationProxyInfo) { func (in *CredentialIssuerFrontend) DeepCopyInto(out *CredentialIssuerFrontend) {
*out = *in *out = *in
if in.TokenCredentialRequestAPIInfo != nil {
in, out := &in.TokenCredentialRequestAPIInfo, &out.TokenCredentialRequestAPIInfo
*out = new(TokenCredentialRequestAPIInfo)
**out = **in
}
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(ImpersonationProxyInfo)
**out = **in
}
return return
} }
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerImpersonationProxyInfo. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CredentialIssuerFrontend.
func (in *CredentialIssuerImpersonationProxyInfo) DeepCopy() *CredentialIssuerImpersonationProxyInfo { func (in *CredentialIssuerFrontend) DeepCopy() *CredentialIssuerFrontend {
if in == nil { if in == nil {
return nil return nil
} }
out := new(CredentialIssuerImpersonationProxyInfo) out := new(CredentialIssuerFrontend)
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
@ -118,11 +128,6 @@ func (in *CredentialIssuerStatus) DeepCopyInto(out *CredentialIssuerStatus) {
*out = new(CredentialIssuerKubeConfigInfo) *out = new(CredentialIssuerKubeConfigInfo)
**out = **in **out = **in
} }
if in.ImpersonationProxyInfo != nil {
in, out := &in.ImpersonationProxyInfo, &out.ImpersonationProxyInfo
*out = new(CredentialIssuerImpersonationProxyInfo)
**out = **in
}
return return
} }
@ -140,6 +145,11 @@ func (in *CredentialIssuerStatus) DeepCopy() *CredentialIssuerStatus {
func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) { func (in *CredentialIssuerStrategy) DeepCopyInto(out *CredentialIssuerStrategy) {
*out = *in *out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
if in.Frontend != nil {
in, out := &in.Frontend, &out.Frontend
*out = new(CredentialIssuerFrontend)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -152,3 +162,35 @@ func (in *CredentialIssuerStrategy) DeepCopy() *CredentialIssuerStrategy {
in.DeepCopyInto(out) in.DeepCopyInto(out)
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ImpersonationProxyInfo) DeepCopyInto(out *ImpersonationProxyInfo) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImpersonationProxyInfo.
func (in *ImpersonationProxyInfo) DeepCopy() *ImpersonationProxyInfo {
if in == nil {
return nil
}
out := new(ImpersonationProxyInfo)
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
}

7
go.sum
View File

@ -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 h1:ijk9G/xzDRZdMU1QRhLYdHuWvNZWqte+NZMOGsiKWbc=
github.com/go-logr/stdr v0.4.0/go.mod h1:NO1vneyJDqKVgJYnxhwXWWmQPOvNM391IG3H8ql3jiA= 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.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.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= 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 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= 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.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.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= 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= 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/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-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/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.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= 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-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-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-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-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 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 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-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-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-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-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 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-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 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 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.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.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.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.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@ -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,
)
}

View File

@ -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{}))
}

View File

@ -42,6 +42,14 @@ func mergeStrategy(configToUpdate *v1alpha1.CredentialIssuerStatus, strategy v1a
configToUpdate.Strategies = append(configToUpdate.Strategies, strategy) configToUpdate.Strategies = append(configToUpdate.Strategies, strategy)
} }
sort.Stable(sortableStrategies(configToUpdate.Strategies)) 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. // TODO: sort strategies by server preference rather than alphanumerically by type.

View File

@ -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", name: "existing entry to update",
configToUpdate: v1alpha1.CredentialIssuerStatus{ configToUpdate: v1alpha1.CredentialIssuerStatus{

View File

@ -33,6 +33,7 @@ const (
type annotaterController struct { type annotaterController struct {
agentPodConfig *AgentPodConfig agentPodConfig *AgentPodConfig
credentialIssuerLocationConfig *CredentialIssuerLocationConfig credentialIssuerLocationConfig *CredentialIssuerLocationConfig
credentialIssuerLabels map[string]string
clock clock.Clock clock clock.Clock
k8sClient kubernetes.Interface k8sClient kubernetes.Interface
pinnipedAPIClient pinnipedclientset.Interface pinnipedAPIClient pinnipedclientset.Interface
@ -51,6 +52,7 @@ type annotaterController struct {
func NewAnnotaterController( func NewAnnotaterController(
agentPodConfig *AgentPodConfig, agentPodConfig *AgentPodConfig,
credentialIssuerLocationConfig *CredentialIssuerLocationConfig, credentialIssuerLocationConfig *CredentialIssuerLocationConfig,
credentialIssuerLabels map[string]string,
clock clock.Clock, clock clock.Clock,
k8sClient kubernetes.Interface, k8sClient kubernetes.Interface,
pinnipedAPIClient pinnipedclientset.Interface, pinnipedAPIClient pinnipedclientset.Interface,
@ -64,6 +66,7 @@ func NewAnnotaterController(
Syncer: &annotaterController{ Syncer: &annotaterController{
agentPodConfig: agentPodConfig, agentPodConfig: agentPodConfig,
credentialIssuerLocationConfig: credentialIssuerLocationConfig, credentialIssuerLocationConfig: credentialIssuerLocationConfig,
credentialIssuerLabels: credentialIssuerLabels,
clock: clock, clock: clock,
k8sClient: k8sClient, k8sClient: k8sClient,
pinnipedAPIClient: pinnipedAPIClient, pinnipedAPIClient: pinnipedAPIClient,
@ -125,7 +128,7 @@ func (c *annotaterController) Sync(ctx controllerlib.Context) error {
strategyResultUpdateErr := issuerconfig.UpdateStrategy( strategyResultUpdateErr := issuerconfig.UpdateStrategy(
ctx.Context, ctx.Context,
c.credentialIssuerLocationConfig.Name, c.credentialIssuerLocationConfig.Name,
nil, c.credentialIssuerLabels,
c.pinnipedAPIClient, c.pinnipedAPIClient,
strategyError(c.clock, err), strategyError(c.clock, err),
) )

View File

@ -41,6 +41,7 @@ func TestAnnotaterControllerFilter(t *testing.T) {
) { ) {
_ = NewAnnotaterController( _ = NewAnnotaterController(
agentPodConfig, agentPodConfig,
nil, // credentialIssuerLabels, shouldn't matter
nil, // credentialIssuerLocationConfig, shouldn't matter nil, // credentialIssuerLocationConfig, shouldn't matter
nil, // clock, shouldn't matter nil, // clock, shouldn't matter
nil, // k8sClient, shouldn't matter nil, // k8sClient, shouldn't matter
@ -85,6 +86,7 @@ func TestAnnotaterControllerSync(t *testing.T) {
var podsGVR schema.GroupVersionResource var podsGVR schema.GroupVersionResource
var credentialIssuerGVR schema.GroupVersionResource var credentialIssuerGVR schema.GroupVersionResource
var frozenNow time.Time var frozenNow time.Time
var credentialIssuerLabels map[string]string
// Defer starting the informers until the last possible moment so that the // Defer starting the informers until the last possible moment so that the
// nested Before's can keep adding things to the informer caches. // nested Before's can keep adding things to the informer caches.
@ -103,6 +105,7 @@ func TestAnnotaterControllerSync(t *testing.T) {
&CredentialIssuerLocationConfig{ &CredentialIssuerLocationConfig{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
}, },
credentialIssuerLabels,
clock.NewFakeClock(frozenNow), clock.NewFakeClock(frozenNow),
kubeAPIClient, kubeAPIClient,
pinnipedAPIClient, pinnipedAPIClient,
@ -238,10 +241,6 @@ func TestAnnotaterControllerSync(t *testing.T) {
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{}, Strategies: []configv1alpha1.CredentialIssuerStrategy{},
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
Server: "some-server",
CertificateAuthorityData: "some-ca-value",
},
}, },
} }
r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer))
@ -301,6 +300,10 @@ func TestAnnotaterControllerSync(t *testing.T) {
}) })
when("there is not already a CredentialIssuer", func() { 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() { it("creates the CredentialIssuer status with the error", func() {
startInformersAndController() startInformersAndController()
err := controllerlib.TestSync(t, subject, *syncContext) err := controllerlib.TestSync(t, subject, *syncContext)
@ -309,6 +312,7 @@ func TestAnnotaterControllerSync(t *testing.T) {
TypeMeta: metav1.TypeMeta{}, TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
Labels: map[string]string{"foo": "bar"},
}, },
} }
@ -316,6 +320,7 @@ func TestAnnotaterControllerSync(t *testing.T) {
TypeMeta: metav1.TypeMeta{}, TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
Labels: map[string]string{"foo": "bar"},
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{ Strategies: []configv1alpha1.CredentialIssuerStrategy{

View File

@ -309,10 +309,6 @@ func TestCreaterControllerSync(t *testing.T) {
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{}, Strategies: []configv1alpha1.CredentialIssuerStrategy{},
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
Server: "some-server",
CertificateAuthorityData: "some-ca-value",
},
}, },
} }
r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer))
@ -449,10 +445,6 @@ func TestCreaterControllerSync(t *testing.T) {
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{}, Strategies: []configv1alpha1.CredentialIssuerStrategy{},
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
Server: "some-server",
CertificateAuthorityData: "some-ca-value",
},
}, },
} }
r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer))

View File

@ -4,14 +4,18 @@
package kubecertagent package kubecertagent
import ( import (
"encoding/base64"
"fmt" "fmt"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/clock" "k8s.io/apimachinery/pkg/util/clock"
corev1informers "k8s.io/client-go/informers/core/v1" corev1informers "k8s.io/client-go/informers/core/v1"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2" "k8s.io/klog/v2"
configv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned" pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
pinnipedcontroller "go.pinniped.dev/internal/controller" pinnipedcontroller "go.pinniped.dev/internal/controller"
"go.pinniped.dev/internal/controller/issuerconfig" "go.pinniped.dev/internal/controller/issuerconfig"
@ -19,13 +23,22 @@ import (
"go.pinniped.dev/internal/dynamiccert" "go.pinniped.dev/internal/dynamiccert"
) )
const (
ClusterInfoNamespace = "kube-public"
clusterInfoName = "cluster-info"
clusterInfoConfigMapKey = "kubeconfig"
)
type execerController struct { type execerController struct {
credentialIssuerLocationConfig *CredentialIssuerLocationConfig credentialIssuerLocationConfig *CredentialIssuerLocationConfig
credentialIssuerLabels map[string]string
discoveryURLOverride *string
dynamicCertProvider dynamiccert.Provider dynamicCertProvider dynamiccert.Provider
podCommandExecutor PodCommandExecutor podCommandExecutor PodCommandExecutor
clock clock.Clock clock clock.Clock
pinnipedAPIClient pinnipedclientset.Interface pinnipedAPIClient pinnipedclientset.Interface
agentPodInformer corev1informers.PodInformer agentPodInformer corev1informers.PodInformer
configMapInformer corev1informers.ConfigMapInformer
} }
// NewExecerController returns a controllerlib.Controller that listens for agent pods with proper // 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. // credentialIssuerLocationConfig, with any errors that it encounters.
func NewExecerController( func NewExecerController(
credentialIssuerLocationConfig *CredentialIssuerLocationConfig, credentialIssuerLocationConfig *CredentialIssuerLocationConfig,
credentialIssuerLabels map[string]string,
discoveryURLOverride *string,
dynamicCertProvider dynamiccert.Provider, dynamicCertProvider dynamiccert.Provider,
podCommandExecutor PodCommandExecutor, podCommandExecutor PodCommandExecutor,
pinnipedAPIClient pinnipedclientset.Interface, pinnipedAPIClient pinnipedclientset.Interface,
clock clock.Clock, clock clock.Clock,
agentPodInformer corev1informers.PodInformer, agentPodInformer corev1informers.PodInformer,
configMapInformer corev1informers.ConfigMapInformer,
withInformer pinnipedcontroller.WithInformerOptionFunc, withInformer pinnipedcontroller.WithInformerOptionFunc,
) controllerlib.Controller { ) controllerlib.Controller {
return controllerlib.New( return controllerlib.New(
@ -48,11 +64,14 @@ func NewExecerController(
Name: "kube-cert-agent-execer-controller", Name: "kube-cert-agent-execer-controller",
Syncer: &execerController{ Syncer: &execerController{
credentialIssuerLocationConfig: credentialIssuerLocationConfig, credentialIssuerLocationConfig: credentialIssuerLocationConfig,
credentialIssuerLabels: credentialIssuerLabels,
discoveryURLOverride: discoveryURLOverride,
dynamicCertProvider: dynamicCertProvider, dynamicCertProvider: dynamicCertProvider,
podCommandExecutor: podCommandExecutor, podCommandExecutor: podCommandExecutor,
pinnipedAPIClient: pinnipedAPIClient, pinnipedAPIClient: pinnipedAPIClient,
clock: clock, clock: clock,
agentPodInformer: agentPodInformer, agentPodInformer: agentPodInformer,
configMapInformer: configMapInformer,
}, },
}, },
withInformer( withInformer(
@ -60,6 +79,11 @@ func NewExecerController(
pinnipedcontroller.SimpleFilter(isAgentPod, nil), // nil parent func is fine because each event is distinct pinnipedcontroller.SimpleFilter(isAgentPod, nil), // nil parent func is fine because each event is distinct
controllerlib.InformerOption{}, 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( strategyResultUpdateErr := issuerconfig.UpdateStrategy(
ctx.Context, ctx.Context,
c.credentialIssuerLocationConfig.Name, c.credentialIssuerLocationConfig.Name,
nil, c.credentialIssuerLabels,
c.pinnipedAPIClient, c.pinnipedAPIClient,
strategyError(c.clock, err), strategyError(c.clock, err),
) )
@ -104,7 +128,7 @@ func (c *execerController) Sync(ctx controllerlib.Context) error {
strategyResultUpdateErr := issuerconfig.UpdateStrategy( strategyResultUpdateErr := issuerconfig.UpdateStrategy(
ctx.Context, ctx.Context,
c.credentialIssuerLocationConfig.Name, c.credentialIssuerLocationConfig.Name,
nil, c.credentialIssuerLabels,
c.pinnipedAPIClient, c.pinnipedAPIClient,
strategyError(c.clock, err), strategyError(c.clock, err),
) )
@ -114,18 +138,74 @@ func (c *execerController) Sync(ctx controllerlib.Context) error {
c.dynamicCertProvider.Set([]byte(certPEM), []byte(keyPEM)) c.dynamicCertProvider.Set([]byte(certPEM), []byte(keyPEM))
err = issuerconfig.UpdateStrategy( apiInfo, err := c.getTokenCredentialRequestAPIInfo()
if err != nil {
strategyResultUpdateErr := issuerconfig.UpdateStrategy(
ctx.Context, ctx.Context,
c.credentialIssuerLocationConfig.Name, c.credentialIssuerLocationConfig.Name,
nil, c.credentialIssuerLabels,
c.pinnipedAPIClient, c.pinnipedAPIClient,
strategySuccess(c.clock), configv1alpha1.CredentialIssuerStrategy{
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,
Status: configv1alpha1.ErrorStrategyStatus,
Reason: configv1alpha1.CouldNotGetClusterInfoStrategyReason,
Message: err.Error(),
LastUpdateTime: metav1.NewTime(c.clock.Now()),
},
) )
if err != nil { klog.ErrorS(strategyResultUpdateErr, "could not create or update CredentialIssuer with strategy success")
return err 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) { func (c *execerController) getKeypairFilePaths(pod *v1.Pod) (string, string) {

View File

@ -27,6 +27,7 @@ import (
pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake" pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
"go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/dynamiccert" "go.pinniped.dev/internal/dynamiccert"
"go.pinniped.dev/internal/here"
"go.pinniped.dev/internal/testutil" "go.pinniped.dev/internal/testutil"
) )
@ -41,16 +42,21 @@ func TestExecerControllerOptions(t *testing.T) {
it.Before(func() { it.Before(func() {
r = require.New(t) r = require.New(t)
observableWithInformerOption = testutil.NewObservableWithInformerOption() 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( _ = NewExecerController(
&CredentialIssuerLocationConfig{ &CredentialIssuerLocationConfig{
Name: "ignored by this test", 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, // dynamicCertProvider, not needed for this test
nil, // podCommandExecutor, not needed for this test nil, // podCommandExecutor, not needed for this test
nil, // pinnipedAPIClient, not needed for this test nil, // pinnipedAPIClient, not needed for this test
nil, // clock, not needed for this test nil, // clock, not needed for this test
agentPodsInformer, agentPodsInformer,
configMapsInformer,
observableWithInformerOption.WithInformer, observableWithInformerOption.WithInformer,
) )
agentPodInformerFilter = observableWithInformerOption.GetFilterForInformer(agentPodsInformer) agentPodInformerFilter = observableWithInformerOption.GetFilterForInformer(agentPodsInformer)
@ -144,9 +150,11 @@ func TestManagerControllerSync(t *testing.T) {
var timeoutContextCancel context.CancelFunc var timeoutContextCancel context.CancelFunc
var syncContext *controllerlib.Context var syncContext *controllerlib.Context
var pinnipedAPIClient *pinnipedfake.Clientset var pinnipedAPIClient *pinnipedfake.Clientset
var agentPodInformer kubeinformers.SharedInformerFactory var kubeInformerFactory kubeinformers.SharedInformerFactory
var agentPodInformerClient *kubernetesfake.Clientset var kubeClientset *kubernetesfake.Clientset
var fakeExecutor *fakePodExecutor var fakeExecutor *fakePodExecutor
var credentialIssuerLabels map[string]string
var discoveryURLOverride *string
var dynamicCertProvider dynamiccert.Provider var dynamicCertProvider dynamiccert.Provider
var fakeCertPEM, fakeKeyPEM string var fakeCertPEM, fakeKeyPEM string
var credentialIssuerGVR schema.GroupVersionResource var credentialIssuerGVR schema.GroupVersionResource
@ -160,11 +168,14 @@ func TestManagerControllerSync(t *testing.T) {
&CredentialIssuerLocationConfig{ &CredentialIssuerLocationConfig{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
}, },
credentialIssuerLabels,
discoveryURLOverride,
dynamicCertProvider, dynamicCertProvider,
fakeExecutor, fakeExecutor,
pinnipedAPIClient, pinnipedAPIClient,
clock.NewFakeClock(frozenNow), clock.NewFakeClock(frozenNow),
agentPodInformer.Core().V1().Pods(), kubeInformerFactory.Core().V1().Pods(),
kubeInformerFactory.Core().V1().ConfigMaps(),
controllerlib.WithInformer, controllerlib.WithInformer,
) )
@ -179,7 +190,7 @@ func TestManagerControllerSync(t *testing.T) {
} }
// Must start informers before calling TestRunSynchronously() // Must start informers before calling TestRunSynchronously()
agentPodInformer.Start(timeoutContext.Done()) kubeInformerFactory.Start(timeoutContext.Done())
controllerlib.TestRunSynchronously(t, subject) controllerlib.TestRunSynchronously(t, subject)
} }
@ -219,8 +230,8 @@ func TestManagerControllerSync(t *testing.T) {
timeoutContext, timeoutContextCancel = context.WithTimeout(context.Background(), time.Second*3) timeoutContext, timeoutContextCancel = context.WithTimeout(context.Background(), time.Second*3)
pinnipedAPIClient = pinnipedfake.NewSimpleClientset() pinnipedAPIClient = pinnipedfake.NewSimpleClientset()
agentPodInformerClient = kubernetesfake.NewSimpleClientset() kubeClientset = kubernetesfake.NewSimpleClientset()
agentPodInformer = kubeinformers.NewSharedInformerFactory(agentPodInformerClient, 0) kubeInformerFactory = kubeinformers.NewSharedInformerFactory(kubeClientset, 0)
fakeExecutor = &fakePodExecutor{r: r} fakeExecutor = &fakePodExecutor{r: r}
frozenNow = time.Date(2020, time.September, 23, 7, 42, 0, 0, time.Local) frozenNow = time.Date(2020, time.September, 23, 7, 42, 0, 0, time.Local)
dynamicCertProvider = dynamiccert.New() dynamicCertProvider = dynamiccert.New()
@ -253,7 +264,7 @@ func TestManagerControllerSync(t *testing.T) {
Namespace: agentPodNamespace, Namespace: agentPodNamespace,
}, },
} }
r.NoError(agentPodInformerClient.Tracker().Add(unrelatedPod)) r.NoError(kubeClientset.Tracker().Add(unrelatedPod))
startInformersAndController() 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() { 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() { it.Before(func() {
agentPod := newAgentPod(agentPodName, false) agentPod := newAgentPod(agentPodName, false)
r.NoError(agentPodInformerClient.Tracker().Add(agentPod)) r.NoError(kubeClientset.Tracker().Add(agentPod))
startInformersAndController() startInformersAndController()
}) })
@ -280,7 +291,7 @@ func TestManagerControllerSync(t *testing.T) {
it.Before(func() { it.Before(func() {
agentPod := newAgentPod(agentPodName, true) agentPod := newAgentPod(agentPodName, true)
agentPod.Status.Phase = corev1.PodPending // not Running agentPod.Status.Phase = corev1.PodPending // not Running
r.NoError(agentPodInformerClient.Tracker().Add(agentPod)) r.NoError(kubeClientset.Tracker().Add(agentPod))
startInformersAndController() startInformersAndController()
}) })
@ -295,8 +306,8 @@ func TestManagerControllerSync(t *testing.T) {
targetAgentPod := newAgentPod(agentPodName, true) targetAgentPod := newAgentPod(agentPodName, true)
targetAgentPod.Status.Phase = corev1.PodRunning targetAgentPod.Status.Phase = corev1.PodRunning
anotherAgentPod := newAgentPod("some-other-agent-pod-which-is-not-the-context-of-this-sync", true) anotherAgentPod := newAgentPod("some-other-agent-pod-which-is-not-the-context-of-this-sync", true)
r.NoError(agentPodInformerClient.Tracker().Add(targetAgentPod)) r.NoError(kubeClientset.Tracker().Add(targetAgentPod))
r.NoError(agentPodInformerClient.Tracker().Add(anotherAgentPod)) r.NoError(kubeClientset.Tracker().Add(anotherAgentPod))
}) })
when("the resulting pod execs will succeed", func() { when("the resulting pod execs will succeed", func() {
@ -304,6 +315,121 @@ func TestManagerControllerSync(t *testing.T) {
fakeExecutor.resultsToReturn = []string{fakeCertPEM, fakeKeyPEM} fakeExecutor.resultsToReturn = []string{fakeCertPEM, fakeKeyPEM}
}) })
when("the cluster-info ConfigMap is not found", func() {
it("returns an error and updates the strategy with an error", func() {
startInformersAndController()
r.EqualError(controllerlib.TestSync(t, subject, *syncContext), `failed to get cluster-info configmap: configmap "cluster-info" not found`)
expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName,
},
}
expectedCredentialIssuer := &configv1alpha1.CredentialIssuer{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName,
},
Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{
{
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,
Status: configv1alpha1.ErrorStrategyStatus,
Reason: configv1alpha1.CouldNotGetClusterInfoStrategyReason,
Message: `failed to get cluster-info configmap: configmap "cluster-info" not found`,
LastUpdateTime: metav1.NewTime(frozenNow),
},
},
},
}
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 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() { it("execs to the agent pod to get the keys and updates the dynamic certificates provider with the new certs", func() {
startInformersAndController() startInformersAndController()
r.NoError(controllerlib.TestSync(t, subject, *syncContext)) r.NoError(controllerlib.TestSync(t, subject, *syncContext))
@ -334,10 +460,6 @@ func TestManagerControllerSync(t *testing.T) {
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{}, Strategies: []configv1alpha1.CredentialIssuerStrategy{},
KubeConfigInfo: &configv1alpha1.CredentialIssuerKubeConfigInfo{
Server: "some-server",
CertificateAuthorityData: "some-ca-value",
},
}, },
} }
r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer)) r.NoError(pinnipedAPIClient.Tracker().Add(initialCredentialIssuer))
@ -347,6 +469,7 @@ func TestManagerControllerSync(t *testing.T) {
startInformersAndController() startInformersAndController()
r.NoError(controllerlib.TestSync(t, subject, *syncContext)) r.NoError(controllerlib.TestSync(t, subject, *syncContext))
// The first update to the CredentialIssuer will set the strategy entry
expectedCredentialIssuer := initialCredentialIssuer.DeepCopy() expectedCredentialIssuer := initialCredentialIssuer.DeepCopy()
expectedCredentialIssuer.Status.Strategies = []configv1alpha1.CredentialIssuerStrategy{ expectedCredentialIssuer.Status.Strategies = []configv1alpha1.CredentialIssuerStrategy{
{ {
@ -355,7 +478,18 @@ func TestManagerControllerSync(t *testing.T) {
Reason: configv1alpha1.FetchedKeyStrategyReason, Reason: configv1alpha1.FetchedKeyStrategyReason,
Message: "Key was fetched successfully", Message: "Key was fetched successfully",
LastUpdateTime: metav1.NewTime(frozenNow), 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) expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
expectedCreateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedCredentialIssuer) expectedCreateAction := coretesting.NewRootUpdateSubresourceAction(credentialIssuerGVR, "status", expectedCredentialIssuer)
@ -383,16 +517,20 @@ func TestManagerControllerSync(t *testing.T) {
when("there is not already a CredentialIssuer", func() { when("there is not already a CredentialIssuer", func() {
it.Before(func() { it.Before(func() {
server := "https://overridden-server-url.example.com"
discoveryURLOverride = &server
credentialIssuerLabels = map[string]string{"foo": "bar"}
startInformersAndController() startInformersAndController()
}) })
it("also creates the the CredentialIssuer with the appropriate status field", func() { it("also creates the the CredentialIssuer with the appropriate status field and labels", func() {
r.NoError(controllerlib.TestSync(t, subject, *syncContext)) r.NoError(controllerlib.TestSync(t, subject, *syncContext))
expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{ expectedCreateCredentialIssuer := &configv1alpha1.CredentialIssuer{
TypeMeta: metav1.TypeMeta{}, TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
Labels: map[string]string{"foo": "bar"},
}, },
} }
@ -400,6 +538,7 @@ func TestManagerControllerSync(t *testing.T) {
TypeMeta: metav1.TypeMeta{}, TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: credentialIssuerResourceName, Name: credentialIssuerResourceName,
Labels: map[string]string{"foo": "bar"},
}, },
Status: configv1alpha1.CredentialIssuerStatus{ Status: configv1alpha1.CredentialIssuerStatus{
Strategies: []configv1alpha1.CredentialIssuerStrategy{ Strategies: []configv1alpha1.CredentialIssuerStrategy{
@ -409,9 +548,20 @@ func TestManagerControllerSync(t *testing.T) {
Reason: configv1alpha1.FetchedKeyStrategyReason, Reason: configv1alpha1.FetchedKeyStrategyReason,
Message: "Key was fetched successfully", Message: "Key was fetched successfully",
LastUpdateTime: metav1.NewTime(frozenNow), 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) expectedGetAction := coretesting.NewRootGetAction(credentialIssuerGVR, credentialIssuerResourceName)
expectedCreateAction := coretesting.NewRootCreateAction(credentialIssuerGVR, expectedCreateCredentialIssuer) expectedCreateAction := coretesting.NewRootCreateAction(credentialIssuerGVR, expectedCreateCredentialIssuer)
@ -420,6 +570,7 @@ func TestManagerControllerSync(t *testing.T) {
}) })
}) })
}) })
})
when("the first resulting pod exec will fail", func() { when("the first resulting pod exec will fail", func() {
var podExecErrorMessage string var podExecErrorMessage string

View File

@ -277,16 +277,6 @@ func findControllerManagerPodForSpecificAgentPod(
return maybeControllerManagerPod, nil 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 { func strategyError(clock clock.Clock, err error) configv1alpha1.CredentialIssuerStrategy {
return configv1alpha1.CredentialIssuerStrategy{ return configv1alpha1.CredentialIssuerStrategy{
Type: configv1alpha1.KubeClusterSigningCertificateStrategyType, Type: configv1alpha1.KubeClusterSigningCertificateStrategyType,

View File

@ -29,7 +29,6 @@ import (
"go.pinniped.dev/internal/controller/authenticator/jwtcachefiller" "go.pinniped.dev/internal/controller/authenticator/jwtcachefiller"
"go.pinniped.dev/internal/controller/authenticator/webhookcachefiller" "go.pinniped.dev/internal/controller/authenticator/webhookcachefiller"
"go.pinniped.dev/internal/controller/impersonatorconfig" "go.pinniped.dev/internal/controller/impersonatorconfig"
"go.pinniped.dev/internal/controller/issuerconfig"
"go.pinniped.dev/internal/controller/kubecertagent" "go.pinniped.dev/internal/controller/kubecertagent"
"go.pinniped.dev/internal/controllerlib" "go.pinniped.dev/internal/controllerlib"
"go.pinniped.dev/internal/deploymentref" "go.pinniped.dev/internal/deploymentref"
@ -133,20 +132,6 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
controllerManager := controllerlib. controllerManager := controllerlib.
NewManager(). 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. // API certs controllers are responsible for managing the TLS certificates used to serve Pinniped's API.
WithController( WithController(
apicerts.NewCertsManagerController( apicerts.NewCertsManagerController(
@ -228,6 +213,7 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
kubecertagent.NewAnnotaterController( kubecertagent.NewAnnotaterController(
agentPodConfig, agentPodConfig,
credentialIssuerLocationConfig, credentialIssuerLocationConfig,
c.Labels,
clock.RealClock{}, clock.RealClock{},
client.Kubernetes, client.Kubernetes,
client.PinnipedConcierge, client.PinnipedConcierge,
@ -240,11 +226,14 @@ func PrepareControllers(c *Config) (func(ctx context.Context), error) {
WithController( WithController(
kubecertagent.NewExecerController( kubecertagent.NewExecerController(
credentialIssuerLocationConfig, credentialIssuerLocationConfig,
c.Labels,
c.DiscoveryURLOverride,
c.DynamicSigningCertProvider, c.DynamicSigningCertProvider,
kubecertagent.NewPodCommandExecutor(client.JSONConfig, client.Kubernetes), kubecertagent.NewPodCommandExecutor(client.JSONConfig, client.Kubernetes),
client.PinnipedConcierge, client.PinnipedConcierge,
clock.RealClock{}, clock.RealClock{},
informers.installationNamespaceK8s.Core().V1().Pods(), informers.installationNamespaceK8s.Core().V1().Pods(),
informers.kubePublicNamespaceK8s.Core().V1().ConfigMaps(),
controllerlib.WithInformer, controllerlib.WithInformer,
), ),
singletonWorker, singletonWorker,
@ -343,7 +332,7 @@ func createInformers(
kubePublicNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions( kubePublicNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions(
k8sClient, k8sClient,
defaultResyncInterval, defaultResyncInterval,
k8sinformers.WithNamespace(issuerconfig.ClusterInfoNamespace), k8sinformers.WithNamespace(kubecertagent.ClusterInfoNamespace),
), ),
kubeSystemNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions( kubeSystemNamespaceK8s: k8sinformers.NewSharedInformerFactoryWithOptions(
k8sClient, k8sClient,

View File

@ -72,12 +72,20 @@ func TestCredentialIssuer(t *testing.T) {
require.Equal(t, configv1alpha1.SuccessStrategyStatus, actualStatusStrategy.Status) require.Equal(t, configv1alpha1.SuccessStrategyStatus, actualStatusStrategy.Status)
require.Equal(t, configv1alpha1.FetchedKeyStrategyReason, actualStatusStrategy.Reason) require.Equal(t, configv1alpha1.FetchedKeyStrategyReason, actualStatusStrategy.Reason)
require.Equal(t, "Key was fetched successfully", actualStatusStrategy.Message) 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. // Verify the published kube config info.
require.Equal( require.Equal(
t, t,
&configv1alpha1.CredentialIssuerKubeConfigInfo{ &configv1alpha1.CredentialIssuerKubeConfigInfo{
Server: config.Host, Server: expectedTokenRequestAPIInfo.Server,
CertificateAuthorityData: base64.StdEncoding.EncodeToString(config.TLSClientConfig.CAData), CertificateAuthorityData: expectedTokenRequestAPIInfo.CertificateAuthorityData,
}, },
actualStatusKubeConfigInfo, actualStatusKubeConfigInfo,
) )