WIP: not using impersonator.config just credentialissuer directly
Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
parent
9af3cb1115
commit
51f1a0ec13
@ -1,83 +0,0 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package impersonator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
||||
)
|
||||
|
||||
type Mode string
|
||||
|
||||
const (
|
||||
// Explicitly enable the impersonation proxy.
|
||||
ModeEnabled Mode = "enabled"
|
||||
|
||||
// Explicitly disable the impersonation proxy.
|
||||
ModeDisabled Mode = "disabled"
|
||||
|
||||
// Allow the proxy to decide if it should be enabled or disabled based upon the cluster in which it is running.
|
||||
ModeAuto Mode = "auto"
|
||||
)
|
||||
|
||||
const (
|
||||
ConfigMapDataKey = "config.yaml"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
// Enable or disable the impersonation proxy. Optional. Defaults to ModeAuto.
|
||||
Mode Mode `json:"mode,omitempty"`
|
||||
|
||||
// Used when creating TLS certificates and for clients to discover the endpoint. Optional. When not specified, if the
|
||||
// impersonation proxy is started, then it will automatically create a LoadBalancer Service and use its ingress as the
|
||||
// endpoint.
|
||||
//
|
||||
// When specified, it may be a hostname or IP address, optionally with a port number, of the impersonation proxy
|
||||
// for clients to use from outside the cluster. E.g. myhost.mycompany.com:8443. Clients should assume that they should
|
||||
// connect via HTTPS to this service.
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
}
|
||||
|
||||
func (c *Config) HasEndpoint() bool {
|
||||
return c.Endpoint != ""
|
||||
}
|
||||
|
||||
func NewConfig() *Config {
|
||||
return &Config{Mode: ModeAuto}
|
||||
}
|
||||
|
||||
func ConfigFromConfigMap(configMap *v1.ConfigMap) (*Config, error) {
|
||||
stringConfig, ok := configMap.Data[ConfigMapDataKey]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf(`ConfigMap is missing expected key "%s"`, ConfigMapDataKey)
|
||||
}
|
||||
config := NewConfig()
|
||||
if err := yaml.Unmarshal([]byte(stringConfig), config); err != nil {
|
||||
return nil, fmt.Errorf("decode yaml: %w", err)
|
||||
}
|
||||
if config.Mode != ModeAuto && config.Mode != ModeEnabled && config.Mode != ModeDisabled {
|
||||
return nil, fmt.Errorf(`illegal value for "mode": %s`, config.Mode)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func ConfigFromCredentialIssuer(credIssuer *v1alpha1.CredentialIssuer) (*Config, error) {
|
||||
config := NewConfig()
|
||||
switch mode := credIssuer.Spec.ImpersonationProxy.Mode; mode {
|
||||
case v1alpha1.ImpersonationProxyModeAuto:
|
||||
config.Mode = ModeAuto
|
||||
case v1alpha1.ImpersonationProxyModeDisabled:
|
||||
config.Mode = ModeDisabled
|
||||
case v1alpha1.ImpersonationProxyModeEnabled:
|
||||
config.Mode = ModeEnabled
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid impersonation proxy mode %q, valid values are auto, disabled, or enabled", mode)
|
||||
}
|
||||
config.Endpoint = credIssuer.Spec.ImpersonationProxy.ExternalEndpoint
|
||||
return config, nil
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package impersonator
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"go.pinniped.dev/internal/here"
|
||||
)
|
||||
|
||||
func TestNewConfig(t *testing.T) {
|
||||
// It defaults the mode.
|
||||
require.Equal(t, &Config{Mode: ModeAuto}, NewConfig())
|
||||
}
|
||||
|
||||
func TestHasEndpoint(t *testing.T) {
|
||||
configWithoutEndpoint := Config{}
|
||||
configWithEndpoint := Config{Endpoint: "something"}
|
||||
require.False(t, configWithoutEndpoint.HasEndpoint())
|
||||
require.True(t, configWithEndpoint.HasEndpoint())
|
||||
}
|
||||
|
||||
func TestConfigFromConfigMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
configMap *v1.ConfigMap
|
||||
wantConfig *Config
|
||||
wantError string
|
||||
}{
|
||||
{
|
||||
name: "fully configured, valid config",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": here.Doc(`
|
||||
mode: enabled
|
||||
endpoint: proxy.example.com:8443
|
||||
`),
|
||||
},
|
||||
},
|
||||
wantConfig: &Config{
|
||||
Mode: "enabled",
|
||||
Endpoint: "proxy.example.com:8443",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty, valid config",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "",
|
||||
},
|
||||
},
|
||||
wantConfig: &Config{
|
||||
Mode: "auto",
|
||||
Endpoint: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid config with mode enabled",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "mode: enabled",
|
||||
},
|
||||
},
|
||||
wantConfig: &Config{
|
||||
Mode: "enabled",
|
||||
Endpoint: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid config with mode disabled",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "mode: disabled",
|
||||
},
|
||||
},
|
||||
wantConfig: &Config{
|
||||
Mode: "disabled",
|
||||
Endpoint: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "valid config with mode auto",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "mode: auto",
|
||||
},
|
||||
},
|
||||
wantConfig: &Config{
|
||||
Mode: "auto",
|
||||
Endpoint: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "wrong key in configmap",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"wrong-key": "",
|
||||
},
|
||||
},
|
||||
wantError: `ConfigMap is missing expected key "config.yaml"`,
|
||||
},
|
||||
{
|
||||
name: "illegal yaml in configmap",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "this is not yaml",
|
||||
},
|
||||
},
|
||||
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type impersonator.Config",
|
||||
},
|
||||
{
|
||||
name: "illegal value for mode in configmap",
|
||||
configMap: &v1.ConfigMap{
|
||||
TypeMeta: metav1.TypeMeta{},
|
||||
ObjectMeta: metav1.ObjectMeta{},
|
||||
Data: map[string]string{
|
||||
"config.yaml": "mode: unexpected-value",
|
||||
},
|
||||
},
|
||||
wantError: `illegal value for "mode": unexpected-value`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
test := tt
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
config, err := ConfigFromConfigMap(test.configMap)
|
||||
require.Equal(t, test.wantConfig, config)
|
||||
if test.wantError != "" {
|
||||
require.EqualError(t, err, test.wantError)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -259,55 +259,53 @@ func (c *impersonatorConfigController) doSync(syncCtx controllerlib.Context) (*v
|
||||
return credentialIssuerStrategyResult, nil
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) loadImpersonationProxyConfiguration() (*impersonator.Config, error) {
|
||||
func (c *impersonatorConfigController) loadImpersonationProxyConfiguration() (*v1alpha1.ImpersonationProxySpec, error) {
|
||||
credIssuer, err := c.credIssuerInformer.Lister().Get(c.credentialIssuerResourceName)
|
||||
|
||||
if k8serrors.IsNotFound(err) {
|
||||
plog.Info("Did not find impersonation proxy config: using default config values",
|
||||
"credentialIssuer", c.credentialIssuerResourceName,
|
||||
)
|
||||
return impersonator.NewConfig(), nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get %s CredentialIssuer: %w", c.credentialIssuerResourceName, err)
|
||||
}
|
||||
|
||||
config, err := impersonator.ConfigFromCredentialIssuer(credIssuer)
|
||||
credIssuer = credIssuer.DeepCopy()
|
||||
err = validateCredentialIssuerSpec(credIssuer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid impersonator configuration: %v", err)
|
||||
}
|
||||
plog.Info("Read impersonation proxy config",
|
||||
"credentialIssuer", c.credentialIssuerResourceName,
|
||||
)
|
||||
return config, nil
|
||||
if credIssuer.Spec.ImpersonationProxy.Service.Type == "" {
|
||||
credIssuer.Spec.ImpersonationProxy.Service.Type = v1alpha1.ImpersonationProxyServiceTypeLoadBalancer
|
||||
}
|
||||
return &credIssuer.Spec.ImpersonationProxy, nil
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) shouldHaveImpersonator(config *impersonator.Config) bool {
|
||||
return c.enabledByAutoMode(config) || config.Mode == impersonator.ModeEnabled
|
||||
func (c *impersonatorConfigController) shouldHaveImpersonator(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return c.enabledByAutoMode(config) || config.Mode == v1alpha1.ImpersonationProxyModeEnabled
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) enabledByAutoMode(config *impersonator.Config) bool {
|
||||
return config.Mode == impersonator.ModeAuto && !*c.hasControlPlaneNodes
|
||||
func (c *impersonatorConfigController) enabledByAutoMode(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return config.Mode == v1alpha1.ImpersonationProxyModeAuto && !*c.hasControlPlaneNodes
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) disabledByAutoMode(config *impersonator.Config) bool {
|
||||
return config.Mode == impersonator.ModeAuto && *c.hasControlPlaneNodes
|
||||
func (c *impersonatorConfigController) disabledByAutoMode(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return config.Mode == v1alpha1.ImpersonationProxyModeAuto && *c.hasControlPlaneNodes
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) disabledExplicitly(config *impersonator.Config) bool {
|
||||
return config.Mode == impersonator.ModeDisabled
|
||||
func (c *impersonatorConfigController) disabledExplicitly(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return config.Mode == v1alpha1.ImpersonationProxyModeDisabled
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) shouldHaveLoadBalancer(config *impersonator.Config) bool {
|
||||
return c.shouldHaveImpersonator(config) && !config.HasEndpoint()
|
||||
func (c *impersonatorConfigController) shouldHaveLoadBalancer(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return c.shouldHaveImpersonator(config) && config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeLoadBalancer
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) shouldHaveTLSSecret(config *impersonator.Config) bool {
|
||||
func (c *impersonatorConfigController) shouldHaveTLSSecret(config *v1alpha1.ImpersonationProxySpec) bool {
|
||||
return c.shouldHaveImpersonator(config)
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) updateStrategy(ctx context.Context, strategy *v1alpha1.CredentialIssuerStrategy) error {
|
||||
// TODO use informer client rather than api client for reading
|
||||
return issuerconfig.UpdateStrategy(ctx, c.credentialIssuerResourceName, c.labels, c.pinnipedAPIClient, *strategy)
|
||||
}
|
||||
|
||||
@ -652,15 +650,25 @@ func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*cer
|
||||
return impersonationCA, nil
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) findDesiredTLSCertificateName(config *impersonator.Config) (*certNameInfo, error) {
|
||||
if config.HasEndpoint() {
|
||||
func (c *impersonatorConfigController) findDesiredTLSCertificateName(config *v1alpha1.ImpersonationProxySpec) (*certNameInfo, error) {
|
||||
// possible valid options:
|
||||
// - you have a loadbalancer and are autoconfiguring the endpoint -> get cert info based on load balancer ip/hostnome
|
||||
// - you have a loadbalancer AND an external endpoint -> either should work since they should be the same
|
||||
// - external endpoint no loadbalancer or other service -> use the endpoint config
|
||||
// - external endpoint and ClusterIP -> use external endpoint?
|
||||
//
|
||||
// - is it legal to have a clusterip and no external endpoint???
|
||||
if config.ExternalEndpoint != "" {
|
||||
return c.findTLSCertificateNameFromEndpointConfig(config), nil
|
||||
} else if config.Service.Type == v1alpha1.ImpersonationProxyServiceTypeClusterIP {
|
||||
// c.findTLSCertificateNameFromClusterIPService()
|
||||
// TODO implement this
|
||||
}
|
||||
return c.findTLSCertificateNameFromLoadBalancer()
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) findTLSCertificateNameFromEndpointConfig(config *impersonator.Config) *certNameInfo {
|
||||
endpointMaybeWithPort := config.Endpoint
|
||||
func (c *impersonatorConfigController) findTLSCertificateNameFromEndpointConfig(config *v1alpha1.ImpersonationProxySpec) *certNameInfo {
|
||||
endpointMaybeWithPort := config.ExternalEndpoint
|
||||
endpointWithoutPort := strings.Split(endpointMaybeWithPort, ":")[0]
|
||||
parsedAsIP := net.ParseIP(endpointWithoutPort)
|
||||
if parsedAsIP != nil {
|
||||
@ -820,7 +828,7 @@ func (c *impersonatorConfigController) clearSignerCA() {
|
||||
c.impersonationSigningCertProvider.UnsetCertKeyContent()
|
||||
}
|
||||
|
||||
func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, config *impersonator.Config, ca *certauthority.CA) *v1alpha1.CredentialIssuerStrategy {
|
||||
func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, config *v1alpha1.ImpersonationProxySpec, ca *certauthority.CA) *v1alpha1.CredentialIssuerStrategy {
|
||||
switch {
|
||||
case c.disabledExplicitly(config):
|
||||
return &v1alpha1.CredentialIssuerStrategy{
|
||||
@ -863,3 +871,16 @@ func (c *impersonatorConfigController) doSyncResult(nameInfo *certNameInfo, conf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateCredentialIssuerSpec(credIssuer *v1alpha1.CredentialIssuer) error {
|
||||
// TODO check external endpoint for valid ip or hostname
|
||||
// TODO if service type is none and externalendpoint is "" return error
|
||||
switch mode := credIssuer.Spec.ImpersonationProxy.Mode; mode {
|
||||
case v1alpha1.ImpersonationProxyModeAuto:
|
||||
case v1alpha1.ImpersonationProxyModeDisabled:
|
||||
case v1alpha1.ImpersonationProxyModeEnabled:
|
||||
default:
|
||||
return fmt.Errorf("invalid impersonation proxy mode %q, valid values are auto, disabled, or enabled", mode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -980,11 +980,87 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
closeTestHTTPServer()
|
||||
})
|
||||
|
||||
when("the CredentialIssuer does not yet exist or it was deleted (defaults to auto mode)", func() {
|
||||
when("the CredentialIssuer does not yet exist or it was deleted (sync returns an error)", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
})
|
||||
|
||||
when("there are visible control plane nodes and a loadbalancer and a tls Secret", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
addLoadBalancerServiceToTracker(loadBalancerServiceName, kubeInformerClient)
|
||||
addLoadBalancerServiceToTracker(loadBalancerServiceName, kubeAPIClient)
|
||||
addSecretToTrackers(newEmptySecret(tlsSecretName), kubeAPIClient, kubeInformerClient)
|
||||
})
|
||||
|
||||
it("errors and does nothing else", func() {
|
||||
startInformersAndController()
|
||||
r.EqualError(runControllerSync(), "failed to get some-credential-issuer-resource-name CredentialIssuer: credentialissuer.config.concierge.pinniped.dev \"some-credential-issuer-resource-name\" not found")
|
||||
requireTLSServerWasNeverStarted()
|
||||
r.Len(kubeAPIClient.Actions(), 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("the configuration is auto mode with an endpoint and service type none", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
ExternalEndpoint: localhostIP,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
when("there are visible control plane nodes", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
})
|
||||
|
||||
it("does not start the impersonator", func() {
|
||||
startInformersAndController()
|
||||
r.NoError(runControllerSync())
|
||||
requireTLSServerWasNeverStarted()
|
||||
requireNodesListed(kubeAPIClient.Actions()[0])
|
||||
r.Len(kubeAPIClient.Actions(), 1)
|
||||
requireCredentialIssuer(newAutoDisabledStrategy())
|
||||
requireSigningCertProviderIsEmpty()
|
||||
})
|
||||
})
|
||||
|
||||
when("there are not visible control plane nodes", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
})
|
||||
|
||||
it("starts the impersonator according to the settings in the CredentialIssuer", func() {
|
||||
startInformersAndController()
|
||||
r.NoError(runControllerSync())
|
||||
r.Len(kubeAPIClient.Actions(), 3)
|
||||
requireNodesListed(kubeAPIClient.Actions()[0])
|
||||
ca := requireCASecretWasCreated(kubeAPIClient.Actions()[1])
|
||||
requireTLSSecretWasCreated(kubeAPIClient.Actions()[2], ca)
|
||||
requireTLSServerIsRunning(ca, testServerAddr(), nil)
|
||||
requireCredentialIssuer(newSuccessStrategy(localhostIP, ca))
|
||||
requireSigningCertProviderHasLoadedCerts(signingCACertPEM, signingCAKeyPEM)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("the configuration is auto mode", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
when("there are visible control plane nodes", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
@ -1271,60 +1347,12 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
requireSigningCertProviderIsEmpty()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("the CredentialIssuer is already present", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
})
|
||||
|
||||
when("the configuration is auto mode with an endpoint", func() {
|
||||
it.Before(func() {
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
ExternalEndpoint: localhostIP,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
when("there are visible control plane nodes", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
})
|
||||
|
||||
it("does not start the impersonator", func() {
|
||||
startInformersAndController()
|
||||
r.NoError(runControllerSync())
|
||||
requireTLSServerWasNeverStarted()
|
||||
requireNodesListed(kubeAPIClient.Actions()[0])
|
||||
r.Len(kubeAPIClient.Actions(), 1)
|
||||
requireCredentialIssuer(newAutoDisabledStrategy())
|
||||
requireSigningCertProviderIsEmpty()
|
||||
})
|
||||
})
|
||||
|
||||
when("there are not visible control plane nodes", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
})
|
||||
|
||||
it("starts the impersonator according to the settings in the CredentialIssuer", func() {
|
||||
startInformersAndController()
|
||||
r.NoError(runControllerSync())
|
||||
r.Len(kubeAPIClient.Actions(), 3)
|
||||
requireNodesListed(kubeAPIClient.Actions()[0])
|
||||
ca := requireCASecretWasCreated(kubeAPIClient.Actions()[1])
|
||||
requireTLSSecretWasCreated(kubeAPIClient.Actions()[2], ca)
|
||||
requireTLSServerIsRunning(ca, testServerAddr(), nil)
|
||||
requireCredentialIssuer(newSuccessStrategy(localhostIP, ca))
|
||||
requireSigningCertProviderHasLoadedCerts(signingCACertPEM, signingCAKeyPEM)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("the configuration is disabled mode", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeDisabled,
|
||||
@ -1345,6 +1373,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
})
|
||||
|
||||
when("the configuration is enabled mode", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
})
|
||||
when("no load balancer", func() {
|
||||
it.Before(func() {
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
@ -1438,13 +1469,16 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("the CredentialIssuer has a hostname specified for the endpoint", func() {
|
||||
when("the CredentialIssuer has a hostname specified and service type none", func() {
|
||||
const fakeHostname = "fake.example.com"
|
||||
it.Before(func() {
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1471,6 +1505,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeIPWithPort,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1490,13 +1527,16 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("the CredentialIssuer has a endpoint which is a hostname with a port", func() {
|
||||
when("the CredentialIssuer has a endpoint which is a hostname with a port, service type none", func() {
|
||||
const fakeHostnameWithPort = "fake.example.com:3000"
|
||||
it.Before(func() {
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostnameWithPort,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1524,12 +1564,18 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}
|
||||
var ipAddressConfig = v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeIP,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -1592,6 +1638,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1634,6 +1683,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1679,6 +1731,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1743,6 +1798,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
|
||||
when("the configuration switches from enabled to disabled mode", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
@ -1800,12 +1856,16 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
when("the endpoint switches from specified, to not specified, to specified again", func() {
|
||||
when("the endpoint and mode switch from specified with no service, to not specified, to specified again", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: localhostIP,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -1869,11 +1929,14 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
// Simulate the informer cache's background update from its watch.
|
||||
addObjectFromCreateActionToInformerAndWait(kubeAPIClient.Actions()[5], kubeInformers.Core().V1().Secrets())
|
||||
|
||||
// Now switch back to having the "endpoint" specified, so the load balancer is not needed anymore.
|
||||
// Now switch back to having the "endpoint" specified and explicitly saying that we don't want the load balancer service.
|
||||
updateCredentialIssuerInInformerAndWait(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: localhostIP,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformers.Config().V1alpha1().CredentialIssuers())
|
||||
|
||||
@ -1887,12 +1950,16 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
requireSigningCertProviderHasLoadedCerts(signingCACertPEM, signingCAKeyPEM)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
when("sync is called more than once", func() {
|
||||
it.Before(func() {
|
||||
addSecretToTrackers(signingCASecret, kubeInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
it("only starts the impersonator once and only lists the cluster's nodes once", func() {
|
||||
@ -2028,6 +2095,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
|
||||
when("getting the control plane nodes returns an error, e.g. when there are no nodes", func() {
|
||||
it("returns an error", func() {
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
startInformersAndController()
|
||||
r.EqualError(runControllerSync(), "no nodes found")
|
||||
requireCredentialIssuer(newErrorStrategy("no nodes found"))
|
||||
@ -2040,6 +2112,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
impersonatorFuncReturnedFuncError = errors.New("some immediate impersonator startup error")
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
it("causes an immediate resync, returns an error on that next sync, and then restarts the server in a following sync", func() {
|
||||
@ -2095,6 +2172,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
when("the impersonator server dies for no apparent reason after running for a while", func() {
|
||||
it.Before(func() {
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
it("causes an immediate resync, returns an error on that next sync, and then restarts the server in a following sync", func() {
|
||||
@ -2169,6 +2251,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
kubeAPIClient.PrependReactor("create", "services", func(action coretesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, nil, fmt.Errorf("error on create")
|
||||
})
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
it("returns an error", func() {
|
||||
@ -2186,6 +2273,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: "example.com",
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
@ -2217,6 +2307,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: "example.com",
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("control-plane", kubeAPIClient)
|
||||
@ -2248,6 +2341,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: "example.com",
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addSecretToTrackers(newEmptySecret(caSecretName), kubeAPIClient, kubeInformerClient)
|
||||
@ -2319,6 +2415,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: localhostIP,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
@ -2438,6 +2537,11 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
addSecretToTrackers(tlsSecret, kubeAPIClient, kubeInformerClient)
|
||||
addLoadBalancerServiceWithIngressToTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP}}, kubeInformerClient)
|
||||
addLoadBalancerServiceWithIngressToTracker(loadBalancerServiceName, []corev1.LoadBalancerIngress{{IP: localhostIP}}, kubeAPIClient)
|
||||
addCredentialIssuerToTracker(credentialIssuerResourceName, v1alpha1.CredentialIssuerSpec{
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeAuto,
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
})
|
||||
|
||||
it("deletes the invalid certs, creates new certs, and starts the impersonator", func() {
|
||||
@ -2509,6 +2613,9 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
|
||||
ImpersonationProxy: v1alpha1.ImpersonationProxySpec{
|
||||
Mode: v1alpha1.ImpersonationProxyModeEnabled,
|
||||
ExternalEndpoint: fakeHostname,
|
||||
Service: v1alpha1.ImpersonationProxyServiceSpec{
|
||||
Type: v1alpha1.ImpersonationProxyServiceTypeNone,
|
||||
},
|
||||
},
|
||||
}, pinnipedInformerClient)
|
||||
addNodeWithRoleToTracker("worker", kubeAPIClient)
|
||||
|
Loading…
Reference in New Issue
Block a user