2021-02-12 01:22:47 +00:00
|
|
|
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
package impersonatorconfig
|
|
|
|
|
|
|
|
import (
|
2021-02-16 23:57:02 +00:00
|
|
|
"context"
|
2021-02-12 01:22:47 +00:00
|
|
|
"crypto/tls"
|
2021-02-25 00:03:17 +00:00
|
|
|
"crypto/x509"
|
2021-02-12 01:22:47 +00:00
|
|
|
"crypto/x509/pkix"
|
2021-02-25 00:03:17 +00:00
|
|
|
"encoding/pem"
|
2021-02-12 01:22:47 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"net/http"
|
2021-02-26 23:01:38 +00:00
|
|
|
"strings"
|
2021-02-24 18:56:24 +00:00
|
|
|
"sync"
|
2021-02-12 01:22:47 +00:00
|
|
|
"time"
|
|
|
|
|
2021-02-16 23:57:02 +00:00
|
|
|
v1 "k8s.io/api/core/v1"
|
2021-02-12 01:22:47 +00:00
|
|
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
2021-02-16 23:57:02 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2021-03-02 22:48:58 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/clock"
|
2021-02-16 23:57:02 +00:00
|
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
2021-02-12 01:22:47 +00:00
|
|
|
corev1informers "k8s.io/client-go/informers/core/v1"
|
|
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
|
|
|
|
pinnipedclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
|
2021-02-12 01:22:47 +00:00
|
|
|
"go.pinniped.dev/internal/certauthority"
|
|
|
|
"go.pinniped.dev/internal/clusterhost"
|
|
|
|
"go.pinniped.dev/internal/concierge/impersonator"
|
|
|
|
pinnipedcontroller "go.pinniped.dev/internal/controller"
|
2021-03-02 22:48:58 +00:00
|
|
|
"go.pinniped.dev/internal/controller/issuerconfig"
|
2021-02-12 01:22:47 +00:00
|
|
|
"go.pinniped.dev/internal/controllerlib"
|
|
|
|
"go.pinniped.dev/internal/plog"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2021-03-02 01:02:08 +00:00
|
|
|
impersonationProxyPort = "8444"
|
|
|
|
defaultHTTPSPort = 443
|
|
|
|
oneYear = 100 * 365 * 24 * time.Hour
|
|
|
|
caCommonName = "Pinniped Impersonation Proxy CA"
|
|
|
|
caCrtKey = "ca.crt"
|
|
|
|
caKeyKey = "ca.key"
|
|
|
|
appLabelKey = "app"
|
2021-02-12 01:22:47 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type impersonatorConfigController struct {
|
|
|
|
namespace string
|
|
|
|
configMapResourceName string
|
2021-03-02 22:48:58 +00:00
|
|
|
credentialIssuerResourceName string
|
2021-02-12 01:22:47 +00:00
|
|
|
generatedLoadBalancerServiceName string
|
2021-02-24 18:56:24 +00:00
|
|
|
tlsSecretName string
|
2021-03-02 01:02:08 +00:00
|
|
|
caSecretName string
|
2021-03-02 22:48:58 +00:00
|
|
|
|
|
|
|
k8sClient kubernetes.Interface
|
|
|
|
pinnipedAPIClient pinnipedclientset.Interface
|
|
|
|
|
|
|
|
configMapsInformer corev1informers.ConfigMapInformer
|
|
|
|
servicesInformer corev1informers.ServiceInformer
|
|
|
|
secretsInformer corev1informers.SecretInformer
|
|
|
|
|
|
|
|
labels map[string]string
|
|
|
|
clock clock.Clock
|
|
|
|
startTLSListenerFunc StartTLSListenerFunc
|
|
|
|
httpHandlerFactory func() (http.Handler, error)
|
2021-02-12 01:22:47 +00:00
|
|
|
|
|
|
|
server *http.Server
|
|
|
|
hasControlPlaneNodes *bool
|
2021-03-02 01:02:08 +00:00
|
|
|
tlsCert *tls.Certificate // always read/write using tlsCertMutex
|
2021-02-24 18:56:24 +00:00
|
|
|
tlsCertMutex sync.RWMutex
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type StartTLSListenerFunc func(network, listenAddress string, config *tls.Config) (net.Listener, error)
|
|
|
|
|
|
|
|
func NewImpersonatorConfigController(
|
|
|
|
namespace string,
|
|
|
|
configMapResourceName string,
|
2021-03-02 22:48:58 +00:00
|
|
|
credentialIssuerResourceName string,
|
2021-02-12 01:22:47 +00:00
|
|
|
k8sClient kubernetes.Interface,
|
2021-03-02 22:48:58 +00:00
|
|
|
pinnipedAPIClient pinnipedclientset.Interface,
|
2021-02-12 01:22:47 +00:00
|
|
|
configMapsInformer corev1informers.ConfigMapInformer,
|
2021-02-18 01:22:13 +00:00
|
|
|
servicesInformer corev1informers.ServiceInformer,
|
2021-02-24 18:56:24 +00:00
|
|
|
secretsInformer corev1informers.SecretInformer,
|
2021-02-12 01:22:47 +00:00
|
|
|
withInformer pinnipedcontroller.WithInformerOptionFunc,
|
|
|
|
withInitialEvent pinnipedcontroller.WithInitialEventOptionFunc,
|
|
|
|
generatedLoadBalancerServiceName string,
|
2021-02-24 18:56:24 +00:00
|
|
|
tlsSecretName string,
|
2021-03-02 01:02:08 +00:00
|
|
|
caSecretName string,
|
2021-02-16 23:57:02 +00:00
|
|
|
labels map[string]string,
|
2021-03-02 22:48:58 +00:00
|
|
|
clock clock.Clock,
|
2021-02-12 01:22:47 +00:00
|
|
|
startTLSListenerFunc StartTLSListenerFunc,
|
|
|
|
httpHandlerFactory func() (http.Handler, error),
|
|
|
|
) controllerlib.Controller {
|
|
|
|
return controllerlib.New(
|
|
|
|
controllerlib.Config{
|
|
|
|
Name: "impersonator-config-controller",
|
|
|
|
Syncer: &impersonatorConfigController{
|
|
|
|
namespace: namespace,
|
|
|
|
configMapResourceName: configMapResourceName,
|
2021-03-02 22:48:58 +00:00
|
|
|
credentialIssuerResourceName: credentialIssuerResourceName,
|
|
|
|
generatedLoadBalancerServiceName: generatedLoadBalancerServiceName,
|
|
|
|
tlsSecretName: tlsSecretName,
|
|
|
|
caSecretName: caSecretName,
|
2021-02-12 01:22:47 +00:00
|
|
|
k8sClient: k8sClient,
|
2021-03-02 22:48:58 +00:00
|
|
|
pinnipedAPIClient: pinnipedAPIClient,
|
2021-02-12 01:22:47 +00:00
|
|
|
configMapsInformer: configMapsInformer,
|
2021-02-18 01:22:13 +00:00
|
|
|
servicesInformer: servicesInformer,
|
2021-02-24 18:56:24 +00:00
|
|
|
secretsInformer: secretsInformer,
|
2021-02-16 23:57:02 +00:00
|
|
|
labels: labels,
|
2021-03-02 22:48:58 +00:00
|
|
|
clock: clock,
|
2021-02-12 01:22:47 +00:00
|
|
|
startTLSListenerFunc: startTLSListenerFunc,
|
|
|
|
httpHandlerFactory: httpHandlerFactory,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
withInformer(
|
|
|
|
configMapsInformer,
|
|
|
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(configMapResourceName, namespace),
|
|
|
|
controllerlib.InformerOption{},
|
|
|
|
),
|
2021-02-18 01:22:13 +00:00
|
|
|
withInformer(
|
|
|
|
servicesInformer,
|
|
|
|
pinnipedcontroller.NameAndNamespaceExactMatchFilterFactory(generatedLoadBalancerServiceName, namespace),
|
|
|
|
controllerlib.InformerOption{},
|
|
|
|
),
|
2021-02-24 18:56:24 +00:00
|
|
|
withInformer(
|
|
|
|
secretsInformer,
|
2021-03-02 01:02:08 +00:00
|
|
|
pinnipedcontroller.SimpleFilter(func(obj metav1.Object) bool {
|
|
|
|
return (obj.GetName() == tlsSecretName || obj.GetName() == caSecretName) && obj.GetNamespace() == namespace
|
|
|
|
}, nil),
|
2021-02-24 18:56:24 +00:00
|
|
|
controllerlib.InformerOption{},
|
|
|
|
),
|
2021-03-02 01:02:08 +00:00
|
|
|
// Be sure to run once even if the ConfigMap that the informer is watching doesn't exist so we can implement
|
|
|
|
// the default configuration behavior.
|
2021-02-12 01:22:47 +00:00
|
|
|
withInitialEvent(controllerlib.Key{
|
|
|
|
Namespace: namespace,
|
|
|
|
Name: configMapResourceName,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) Sync(syncCtx controllerlib.Context) error {
|
2021-02-18 23:58:27 +00:00
|
|
|
plog.Debug("Starting impersonatorConfigController Sync")
|
2021-02-12 01:22:47 +00:00
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
strategy, err := c.doSync(syncCtx.Context)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
strategy = &v1alpha1.CredentialIssuerStrategy{
|
|
|
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
|
|
|
Status: v1alpha1.ErrorStrategyStatus,
|
2021-03-02 23:27:54 +00:00
|
|
|
Reason: v1alpha1.ErrorDuringSetupStrategyReason,
|
2021-03-02 22:48:58 +00:00
|
|
|
Message: err.Error(),
|
|
|
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateStrategyErr := c.updateStrategy(syncCtx.Context, strategy)
|
|
|
|
if updateStrategyErr != nil {
|
|
|
|
plog.Error("error while updating the CredentialIssuer status", err)
|
|
|
|
if err == nil {
|
|
|
|
err = updateStrategyErr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
plog.Debug("Successfully finished impersonatorConfigController Sync")
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) doSync(ctx context.Context) (*v1alpha1.CredentialIssuerStrategy, error) {
|
2021-03-02 01:02:08 +00:00
|
|
|
config, err := c.loadImpersonationProxyConfiguration()
|
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make a live API call to avoid the cost of having an informer watch all node changes on the cluster,
|
|
|
|
// since there could be lots and we don't especially care about node changes.
|
|
|
|
// Once we have concluded that there is or is not a visible control plane, then cache that decision
|
|
|
|
// to avoid listing nodes very often.
|
|
|
|
if c.hasControlPlaneNodes == nil {
|
2021-03-02 01:02:08 +00:00
|
|
|
hasControlPlaneNodes, err := clusterhost.New(c.k8sClient).HasControlPlaneNodes(ctx)
|
2021-02-12 01:22:47 +00:00
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
c.hasControlPlaneNodes = &hasControlPlaneNodes
|
|
|
|
plog.Debug("Queried for control plane nodes", "foundControlPlaneNodes", hasControlPlaneNodes)
|
|
|
|
}
|
|
|
|
|
2021-02-18 01:22:13 +00:00
|
|
|
if c.shouldHaveImpersonator(config) {
|
|
|
|
if err = c.ensureImpersonatorIsStarted(); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-02-18 01:22:13 +00:00
|
|
|
if err = c.ensureImpersonatorIsStopped(); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 01:22:13 +00:00
|
|
|
if c.shouldHaveLoadBalancer(config) {
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureLoadBalancerIsStarted(ctx); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-16 23:57:02 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureLoadBalancerIsStopped(ctx); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-16 23:57:02 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-12 01:22:47 +00:00
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
waitingForLoadBalancer := false
|
2021-02-24 18:56:24 +00:00
|
|
|
if c.shouldHaveTLSSecret(config) {
|
2021-03-02 01:02:08 +00:00
|
|
|
var impersonationCA *certauthority.CA
|
|
|
|
if impersonationCA, err = c.ensureCASecretIsCreated(ctx); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
2021-03-02 22:48:58 +00:00
|
|
|
if waitingForLoadBalancer, err = c.ensureTLSSecret(ctx, config, impersonationCA); err != nil {
|
|
|
|
return nil, err
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
} else if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return nil, err
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
return c.doSyncResult(waitingForLoadBalancer, config), nil
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) loadImpersonationProxyConfiguration() (*impersonator.Config, error) {
|
|
|
|
configMap, err := c.configMapsInformer.Lister().ConfigMaps(c.namespace).Get(c.configMapResourceName)
|
2021-02-25 00:03:17 +00:00
|
|
|
notFound := k8serrors.IsNotFound(err)
|
2021-03-02 01:02:08 +00:00
|
|
|
if err != nil && !notFound {
|
|
|
|
return nil, fmt.Errorf("failed to get %s/%s configmap: %w", c.namespace, c.configMapResourceName, err)
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
|
|
|
|
var config *impersonator.Config
|
|
|
|
if notFound {
|
|
|
|
plog.Info("Did not find impersonation proxy config: using default config values",
|
|
|
|
"configmap", c.configMapResourceName,
|
|
|
|
"namespace", c.namespace,
|
|
|
|
)
|
|
|
|
config = impersonator.NewConfig() // use default configuration options
|
|
|
|
} else {
|
|
|
|
config, err = impersonator.ConfigFromConfigMap(configMap)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid impersonator configuration: %v", err)
|
|
|
|
}
|
|
|
|
plog.Info("Read impersonation proxy config",
|
|
|
|
"configmap", c.configMapResourceName,
|
|
|
|
"namespace", c.namespace,
|
|
|
|
)
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
|
|
|
|
return config, nil
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 01:22:13 +00:00
|
|
|
func (c *impersonatorConfigController) shouldHaveImpersonator(config *impersonator.Config) bool {
|
2021-03-02 22:48:58 +00:00
|
|
|
return c.enabledByAutoMode(config) || config.Mode == impersonator.ModeEnabled
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) enabledByAutoMode(config *impersonator.Config) bool {
|
|
|
|
return config.Mode == impersonator.ModeAuto && !*c.hasControlPlaneNodes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) disabledByAutoMode(config *impersonator.Config) bool {
|
|
|
|
return config.Mode == impersonator.ModeAuto && *c.hasControlPlaneNodes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) disabledExplicitly(config *impersonator.Config) bool {
|
|
|
|
return config.Mode == impersonator.ModeDisabled
|
2021-02-18 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) shouldHaveLoadBalancer(config *impersonator.Config) bool {
|
2021-02-24 18:56:24 +00:00
|
|
|
return c.shouldHaveImpersonator(config) && config.Endpoint == ""
|
2021-02-18 01:22:13 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 00:03:17 +00:00
|
|
|
func (c *impersonatorConfigController) shouldHaveTLSSecret(config *impersonator.Config) bool {
|
2021-02-26 01:03:34 +00:00
|
|
|
return c.shouldHaveImpersonator(config)
|
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
func (c *impersonatorConfigController) updateStrategy(ctx context.Context, strategy *v1alpha1.CredentialIssuerStrategy) error {
|
|
|
|
return issuerconfig.UpdateStrategy(ctx, c.credentialIssuerResourceName, c.labels, c.pinnipedAPIClient, *strategy)
|
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) loadBalancerExists() (bool, error) {
|
|
|
|
_, err := c.servicesInformer.Lister().Services(c.namespace).Get(c.generatedLoadBalancerServiceName)
|
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if notFound {
|
|
|
|
return false, nil
|
2021-02-26 01:03:34 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
2021-02-26 01:03:34 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) tlsSecretExists() (bool, *v1.Secret, error) {
|
|
|
|
secret, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.tlsSecretName)
|
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if notFound {
|
|
|
|
return false, nil, nil
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return false, nil, err
|
|
|
|
}
|
|
|
|
return true, secret, nil
|
2021-02-12 01:22:47 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 01:22:13 +00:00
|
|
|
func (c *impersonatorConfigController) ensureImpersonatorIsStarted() error {
|
2021-02-12 01:22:47 +00:00
|
|
|
if c.server != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
handler, err := c.httpHandlerFactory()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
listener, err := c.startTLSListenerFunc("tcp", ":"+impersonationProxyPort, &tls.Config{
|
2021-02-12 01:22:47 +00:00
|
|
|
MinVersion: tls.VersionTLS12, // Allow v1.2 because clients like the default `curl` on MacOS don't support 1.3 yet.
|
|
|
|
GetCertificate: func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
2021-02-24 18:56:24 +00:00
|
|
|
return c.getTLSCert(), nil
|
2021-02-12 01:22:47 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
c.server = &http.Server{Handler: handler}
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
plog.Info("Starting impersonation proxy", "port", impersonationProxyPort)
|
|
|
|
err = c.server.Serve(listener)
|
|
|
|
if errors.Is(err, http.ErrServerClosed) {
|
|
|
|
plog.Info("The impersonation proxy server has shut down")
|
|
|
|
} else {
|
|
|
|
plog.Error("Unexpected shutdown of the impersonation proxy server", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
2021-02-16 23:57:02 +00:00
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) ensureImpersonatorIsStopped() error {
|
|
|
|
if c.server != nil {
|
|
|
|
plog.Info("Stopping impersonation proxy", "port", impersonationProxyPort)
|
|
|
|
err := c.server.Close()
|
|
|
|
c.server = nil
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return nil
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
|
|
|
|
2021-02-18 01:22:13 +00:00
|
|
|
func (c *impersonatorConfigController) ensureLoadBalancerIsStarted(ctx context.Context) error {
|
2021-03-02 01:02:08 +00:00
|
|
|
running, err := c.loadBalancerExists()
|
2021-02-18 01:22:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if running {
|
|
|
|
return nil
|
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
appNameLabel := c.labels[appLabelKey]
|
2021-02-16 23:57:02 +00:00
|
|
|
loadBalancer := v1.Service{
|
|
|
|
Spec: v1.ServiceSpec{
|
2021-03-02 01:02:08 +00:00
|
|
|
Type: v1.ServiceTypeLoadBalancer,
|
2021-02-16 23:57:02 +00:00
|
|
|
Ports: []v1.ServicePort{
|
|
|
|
{
|
2021-03-02 01:02:08 +00:00
|
|
|
TargetPort: intstr.FromString(impersonationProxyPort),
|
|
|
|
Port: defaultHTTPSPort,
|
2021-02-16 23:57:02 +00:00
|
|
|
Protocol: v1.ProtocolTCP,
|
|
|
|
},
|
|
|
|
},
|
2021-03-02 01:02:08 +00:00
|
|
|
Selector: map[string]string{appLabelKey: appNameLabel},
|
2021-02-16 23:57:02 +00:00
|
|
|
},
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: c.generatedLoadBalancerServiceName,
|
|
|
|
Namespace: c.namespace,
|
|
|
|
Labels: c.labels,
|
|
|
|
},
|
|
|
|
}
|
2021-02-18 01:22:13 +00:00
|
|
|
plog.Info("creating load balancer for impersonation proxy",
|
|
|
|
"service", c.generatedLoadBalancerServiceName,
|
|
|
|
"namespace", c.namespace)
|
|
|
|
_, err = c.k8sClient.CoreV1().Services(c.namespace).Create(ctx, &loadBalancer, metav1.CreateOptions{})
|
2021-03-02 01:02:08 +00:00
|
|
|
return err
|
2021-02-16 23:57:02 +00:00
|
|
|
}
|
2021-02-24 18:56:24 +00:00
|
|
|
|
2021-02-25 00:03:17 +00:00
|
|
|
func (c *impersonatorConfigController) ensureLoadBalancerIsStopped(ctx context.Context) error {
|
2021-03-02 01:02:08 +00:00
|
|
|
running, err := c.loadBalancerExists()
|
2021-02-24 18:56:24 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-02-25 00:03:17 +00:00
|
|
|
if !running {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
plog.Info("Deleting load balancer for impersonation proxy",
|
|
|
|
"service", c.generatedLoadBalancerServiceName,
|
|
|
|
"namespace", c.namespace)
|
2021-03-02 01:02:08 +00:00
|
|
|
return c.k8sClient.CoreV1().Services(c.namespace).Delete(ctx, c.generatedLoadBalancerServiceName, metav1.DeleteOptions{})
|
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
func (c *impersonatorConfigController) ensureTLSSecret(ctx context.Context, config *impersonator.Config, ca *certauthority.CA) (bool, error) {
|
2021-03-02 01:02:08 +00:00
|
|
|
secretFromInformer, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.tlsSecretName)
|
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if !notFound && err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
if !notFound {
|
|
|
|
secretWasDeleted, err := c.deleteTLSSecretWhenCertificateDoesNotMatchDesiredState(ctx, config, ca, secretFromInformer)
|
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-03-02 01:02:08 +00:00
|
|
|
}
|
|
|
|
// If it was deleted by the above call, then set it to nil. This allows us to avoid waiting
|
|
|
|
// for the informer cache to update before deciding to proceed to create the new Secret below.
|
|
|
|
if secretWasDeleted {
|
|
|
|
secretFromInformer = nil
|
|
|
|
}
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
return c.ensureTLSSecretIsCreatedAndLoaded(ctx, config, secretFromInformer, ca)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) deleteTLSSecretWhenCertificateDoesNotMatchDesiredState(ctx context.Context, config *impersonator.Config, ca *certauthority.CA, secret *v1.Secret) (bool, error) {
|
2021-02-25 00:03:17 +00:00
|
|
|
certPEM := secret.Data[v1.TLSCertKey]
|
|
|
|
block, _ := pem.Decode(certPEM)
|
|
|
|
if block == nil {
|
2021-02-26 18:58:56 +00:00
|
|
|
plog.Warning("Found missing or not PEM-encoded data in TLS Secret",
|
2021-03-02 01:02:08 +00:00
|
|
|
"invalidCertPEM", string(certPEM),
|
2021-02-26 18:58:56 +00:00
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
|
|
|
deleteErr := c.ensureTLSSecretIsRemoved(ctx)
|
|
|
|
if deleteErr != nil {
|
2021-03-02 01:02:08 +00:00
|
|
|
return false, fmt.Errorf("found missing or not PEM-encoded data in TLS Secret, but got error while deleting it: %w", deleteErr)
|
2021-02-26 18:58:56 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
2021-02-26 18:58:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
actualCertFromSecret, err := x509.ParseCertificate(block.Bytes)
|
|
|
|
if err != nil {
|
|
|
|
plog.Error("Found invalid PEM data in TLS Secret", err,
|
2021-03-02 01:02:08 +00:00
|
|
|
"invalidCertPEM", string(certPEM),
|
2021-02-26 18:58:56 +00:00
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
|
|
|
return false, fmt.Errorf("PEM data represented an invalid cert, but got error while deleting it: %w", err)
|
2021-02-26 18:58:56 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
2021-02-26 18:58:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
keyPEM := secret.Data[v1.TLSPrivateKeyKey]
|
|
|
|
_, err = tls.X509KeyPair(certPEM, keyPEM)
|
|
|
|
if err != nil {
|
|
|
|
plog.Error("Found invalid private key PEM data in TLS Secret", err,
|
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
|
|
|
return false, fmt.Errorf("cert had an invalid private key, but got error while deleting it: %w", err)
|
2021-02-26 18:58:56 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
opts := x509.VerifyOptions{Roots: ca.Pool()}
|
|
|
|
if _, err = actualCertFromSecret.Verify(opts); err != nil {
|
|
|
|
// The TLS cert was not signed by the current CA. Since they are mismatched, delete the TLS cert
|
|
|
|
// so we can recreate it using the current CA.
|
|
|
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
|
|
|
return true, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
desiredIP, desiredHostname, nameIsReady, err := c.findDesiredTLSCertificateName(config)
|
2021-02-25 00:03:17 +00:00
|
|
|
if err != nil {
|
2021-03-02 01:02:08 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
if !nameIsReady {
|
|
|
|
// We currently have a secret but we are waiting for a load balancer to be assigned an ingress, so
|
|
|
|
// our current secret must be old/unwanted.
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 18:27:19 +00:00
|
|
|
actualIPs := actualCertFromSecret.IPAddresses
|
|
|
|
actualHostnames := actualCertFromSecret.DNSNames
|
|
|
|
plog.Info("Checking TLS certificate names",
|
2021-02-26 01:03:34 +00:00
|
|
|
"desiredIP", desiredIP,
|
|
|
|
"desiredHostname", desiredHostname,
|
2021-02-25 18:27:19 +00:00
|
|
|
"actualIPs", actualIPs,
|
|
|
|
"actualHostnames", actualHostnames,
|
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
if certHostnameAndIPMatchDesiredState(desiredIP, actualIPs, desiredHostname, actualHostnames) {
|
2021-02-26 18:58:56 +00:00
|
|
|
// The cert already matches the desired state, so there is no need to delete/recreate it.
|
2021-03-02 01:02:08 +00:00
|
|
|
return false, nil
|
2021-02-25 18:27:19 +00:00
|
|
|
}
|
2021-02-26 18:58:56 +00:00
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
if err = c.ensureTLSSecretIsRemoved(ctx); err != nil {
|
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-03-02 01:02:08 +00:00
|
|
|
return true, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func certHostnameAndIPMatchDesiredState(desiredIP net.IP, actualIPs []net.IP, desiredHostname string, actualHostnames []string) bool {
|
|
|
|
if desiredIP != nil && len(actualIPs) == 1 && desiredIP.Equal(actualIPs[0]) && len(actualHostnames) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
if desiredHostname != "" && len(actualHostnames) == 1 && desiredHostname == actualHostnames[0] && len(actualIPs) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
func (c *impersonatorConfigController) ensureTLSSecretIsCreatedAndLoaded(ctx context.Context, config *impersonator.Config, secret *v1.Secret, ca *certauthority.CA) (bool, error) {
|
2021-02-25 00:03:17 +00:00
|
|
|
if secret != nil {
|
|
|
|
err := c.loadTLSCertFromSecret(secret)
|
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, nil
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
2021-02-25 00:03:17 +00:00
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
ip, hostname, nameIsReady, err := c.findDesiredTLSCertificateName(config)
|
2021-02-25 00:03:17 +00:00
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
if !nameIsReady {
|
|
|
|
// Sync will get called again when the load balancer is updated with its ingress info, so this is not an error.
|
2021-03-02 22:48:58 +00:00
|
|
|
// Return "true" meaning that we are waiting for the load balancer.
|
|
|
|
return true, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
newTLSSecret, err := c.createNewTLSSecret(ctx, ca, ip, hostname)
|
2021-02-25 00:03:17 +00:00
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = c.loadTLSCertFromSecret(newTLSSecret)
|
|
|
|
if err != nil {
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, err
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
return false, nil
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) ensureCASecretIsCreated(ctx context.Context) (*certauthority.CA, error) {
|
|
|
|
caSecret, err := c.secretsInformer.Lister().Secrets(c.namespace).Get(c.caSecretName)
|
|
|
|
if err != nil && !k8serrors.IsNotFound(err) {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var impersonationCA *certauthority.CA
|
|
|
|
if k8serrors.IsNotFound(err) {
|
|
|
|
impersonationCA, err = c.createCASecret(ctx)
|
|
|
|
} else {
|
|
|
|
crtBytes := caSecret.Data[caCrtKey]
|
|
|
|
keyBytes := caSecret.Data[caKeyKey]
|
|
|
|
impersonationCA, err = certauthority.Load(string(crtBytes), string(keyBytes))
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return impersonationCA, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) createCASecret(ctx context.Context) (*certauthority.CA, error) {
|
|
|
|
impersonationCA, err := certauthority.New(pkix.Name{CommonName: caCommonName}, oneYear)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("could not create impersonation CA: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
caPrivateKeyPEM, err := impersonationCA.PrivateKeyToPEM()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
secret := v1.Secret{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: c.caSecretName,
|
|
|
|
Namespace: c.namespace,
|
|
|
|
Labels: c.labels,
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
|
|
caCrtKey: impersonationCA.Bundle(),
|
|
|
|
caKeyKey: caPrivateKeyPEM,
|
|
|
|
},
|
|
|
|
Type: v1.SecretTypeOpaque,
|
|
|
|
}
|
|
|
|
|
|
|
|
plog.Info("Creating CA certificates for impersonation proxy",
|
|
|
|
"secret", c.caSecretName,
|
|
|
|
"namespace", c.namespace)
|
|
|
|
if _, err = c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, &secret, metav1.CreateOptions{}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return impersonationCA, nil
|
|
|
|
}
|
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
func (c *impersonatorConfigController) findDesiredTLSCertificateName(config *impersonator.Config) (net.IP, string, bool, error) {
|
2021-02-25 18:27:19 +00:00
|
|
|
if config.Endpoint != "" {
|
|
|
|
return c.findTLSCertificateNameFromEndpointConfig(config)
|
|
|
|
}
|
|
|
|
return c.findTLSCertificateNameFromLoadBalancer()
|
|
|
|
}
|
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
func (c *impersonatorConfigController) findTLSCertificateNameFromEndpointConfig(config *impersonator.Config) (net.IP, string, bool, error) {
|
2021-02-26 23:01:38 +00:00
|
|
|
endpointWithoutPort := strings.Split(config.Endpoint, ":")[0]
|
|
|
|
parsedAsIP := net.ParseIP(endpointWithoutPort)
|
2021-02-25 18:27:19 +00:00
|
|
|
if parsedAsIP != nil {
|
2021-02-26 01:03:34 +00:00
|
|
|
return parsedAsIP, "", true, nil
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
2021-02-26 23:01:38 +00:00
|
|
|
return nil, endpointWithoutPort, true, nil
|
2021-02-25 18:27:19 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 01:03:34 +00:00
|
|
|
func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer() (net.IP, string, bool, error) {
|
2021-02-25 18:27:19 +00:00
|
|
|
lb, err := c.servicesInformer.Lister().Services(c.namespace).Get(c.generatedLoadBalancerServiceName)
|
|
|
|
notFound := k8serrors.IsNotFound(err)
|
|
|
|
if notFound {
|
2021-03-02 01:02:08 +00:00
|
|
|
// Although we created the load balancer, maybe it hasn't been cached in the informer yet.
|
|
|
|
// We aren't ready and will try again later in this case.
|
2021-02-26 01:03:34 +00:00
|
|
|
return nil, "", false, nil
|
2021-02-25 18:27:19 +00:00
|
|
|
}
|
|
|
|
if err != nil {
|
2021-02-26 01:03:34 +00:00
|
|
|
return nil, "", false, err
|
2021-02-25 18:27:19 +00:00
|
|
|
}
|
|
|
|
ingresses := lb.Status.LoadBalancer.Ingress
|
2021-02-25 19:40:14 +00:00
|
|
|
if len(ingresses) == 0 || (ingresses[0].Hostname == "" && ingresses[0].IP == "") {
|
2021-02-25 18:27:19 +00:00
|
|
|
plog.Info("load balancer for impersonation proxy does not have an ingress yet, so skipping tls cert generation while we wait",
|
|
|
|
"service", c.generatedLoadBalancerServiceName,
|
|
|
|
"namespace", c.namespace)
|
2021-02-26 01:03:34 +00:00
|
|
|
return nil, "", false, nil
|
2021-02-25 18:27:19 +00:00
|
|
|
}
|
2021-02-26 01:03:34 +00:00
|
|
|
for _, ingress := range ingresses {
|
|
|
|
hostname := ingress.Hostname
|
|
|
|
if hostname != "" {
|
|
|
|
return nil, hostname, true, nil
|
|
|
|
}
|
2021-02-25 19:40:14 +00:00
|
|
|
}
|
2021-02-26 01:03:34 +00:00
|
|
|
for _, ingress := range ingresses {
|
|
|
|
ip := ingress.IP
|
|
|
|
parsedIP := net.ParseIP(ip)
|
|
|
|
if parsedIP != nil {
|
|
|
|
return parsedIP, "", true, nil
|
|
|
|
}
|
2021-02-25 19:40:14 +00:00
|
|
|
}
|
2021-02-26 01:03:34 +00:00
|
|
|
|
|
|
|
return nil, "", false, fmt.Errorf("could not find valid IP addresses or hostnames from load balancer %s/%s", c.namespace, lb.Name)
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
2021-03-02 01:02:08 +00:00
|
|
|
func (c *impersonatorConfigController) createNewTLSSecret(ctx context.Context, ca *certauthority.CA, ip net.IP, hostname string) (*v1.Secret, error) {
|
|
|
|
var hostnames []string
|
|
|
|
var ips []net.IP
|
|
|
|
if hostname != "" {
|
|
|
|
hostnames = []string{hostname}
|
|
|
|
}
|
|
|
|
if ip != nil {
|
|
|
|
ips = []net.IP{ip}
|
|
|
|
}
|
|
|
|
|
|
|
|
impersonationCert, err := ca.Issue(pkix.Name{}, hostnames, ips, oneYear)
|
2021-02-24 18:56:24 +00:00
|
|
|
if err != nil {
|
2021-02-25 00:03:17 +00:00
|
|
|
return nil, fmt.Errorf("could not create impersonation cert: %w", err)
|
2021-02-24 18:56:24 +00:00
|
|
|
}
|
|
|
|
|
2021-02-26 18:58:56 +00:00
|
|
|
certPEM, keyPEM, err := certauthority.ToPEM(impersonationCert)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-24 18:56:24 +00:00
|
|
|
|
2021-02-25 00:03:17 +00:00
|
|
|
newTLSSecret := &v1.Secret{
|
2021-02-24 18:56:24 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
Name: c.tlsSecretName,
|
|
|
|
Namespace: c.namespace,
|
|
|
|
Labels: c.labels,
|
|
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
|
|
v1.TLSPrivateKeyKey: keyPEM,
|
|
|
|
v1.TLSCertKey: certPEM,
|
|
|
|
},
|
2021-03-02 01:02:08 +00:00
|
|
|
Type: v1.SecretTypeTLS,
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
2021-02-26 18:58:56 +00:00
|
|
|
|
2021-02-25 18:27:19 +00:00
|
|
|
plog.Info("Creating TLS certificates for impersonation proxy",
|
|
|
|
"ips", ips,
|
|
|
|
"hostnames", hostnames,
|
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
2021-03-02 01:02:08 +00:00
|
|
|
return c.k8sClient.CoreV1().Secrets(c.namespace).Create(ctx, newTLSSecret, metav1.CreateOptions{})
|
2021-02-25 00:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) loadTLSCertFromSecret(tlsSecret *v1.Secret) error {
|
|
|
|
certPEM := tlsSecret.Data[v1.TLSCertKey]
|
|
|
|
keyPEM := tlsSecret.Data[v1.TLSPrivateKeyKey]
|
|
|
|
tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
|
|
|
|
if err != nil {
|
2021-02-26 18:58:56 +00:00
|
|
|
c.setTLSCert(nil)
|
2021-02-25 00:03:17 +00:00
|
|
|
return fmt.Errorf("could not parse TLS cert PEM data from Secret: %w", err)
|
|
|
|
}
|
2021-02-25 18:27:19 +00:00
|
|
|
plog.Info("Loading TLS certificates for impersonation proxy",
|
2021-03-02 01:02:08 +00:00
|
|
|
"certPEM", string(certPEM),
|
2021-02-25 18:27:19 +00:00
|
|
|
"secret", c.tlsSecretName,
|
|
|
|
"namespace", c.namespace)
|
2021-02-25 00:03:17 +00:00
|
|
|
c.setTLSCert(&tlsCert)
|
2021-02-24 18:56:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) ensureTLSSecretIsRemoved(ctx context.Context) error {
|
|
|
|
tlsSecretExists, _, err := c.tlsSecretExists()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !tlsSecretExists {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
plog.Info("Deleting TLS certificates for impersonation proxy",
|
2021-02-25 18:27:19 +00:00
|
|
|
"secret", c.tlsSecretName,
|
2021-02-24 18:56:24 +00:00
|
|
|
"namespace", c.namespace)
|
|
|
|
err = c.k8sClient.CoreV1().Secrets(c.namespace).Delete(ctx, c.tlsSecretName, metav1.DeleteOptions{})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-02-25 00:03:17 +00:00
|
|
|
c.setTLSCert(nil)
|
|
|
|
|
2021-02-24 18:56:24 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-02 22:48:58 +00:00
|
|
|
func (c *impersonatorConfigController) doSyncResult(waitingForLoadBalancer bool, config *impersonator.Config) *v1alpha1.CredentialIssuerStrategy {
|
|
|
|
switch {
|
|
|
|
case waitingForLoadBalancer:
|
|
|
|
return &v1alpha1.CredentialIssuerStrategy{
|
|
|
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
|
|
|
Status: v1alpha1.ErrorStrategyStatus,
|
2021-03-02 23:27:54 +00:00
|
|
|
Reason: v1alpha1.PendingStrategyReason,
|
2021-03-02 22:48:58 +00:00
|
|
|
Message: "waiting for load balancer Service to be assigned IP or hostname",
|
|
|
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
|
|
|
}
|
|
|
|
case c.disabledExplicitly(config):
|
|
|
|
return &v1alpha1.CredentialIssuerStrategy{
|
|
|
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
|
|
|
Status: v1alpha1.ErrorStrategyStatus,
|
|
|
|
Reason: v1alpha1.DisabledStrategyReason,
|
|
|
|
Message: "impersonation proxy was explicitly disabled by configuration",
|
|
|
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
|
|
|
}
|
|
|
|
case c.disabledByAutoMode(config):
|
|
|
|
return &v1alpha1.CredentialIssuerStrategy{
|
|
|
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
|
|
|
Status: v1alpha1.ErrorStrategyStatus,
|
|
|
|
Reason: v1alpha1.DisabledStrategyReason,
|
|
|
|
Message: "automatically determined that impersonation proxy should be disabled",
|
|
|
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return &v1alpha1.CredentialIssuerStrategy{
|
|
|
|
Type: v1alpha1.ImpersonationProxyStrategyType,
|
|
|
|
Status: v1alpha1.SuccessStrategyStatus,
|
|
|
|
Reason: v1alpha1.ListeningStrategyReason,
|
|
|
|
Message: "impersonation proxy is ready to accept client connections",
|
|
|
|
LastUpdateTime: metav1.NewTime(c.clock.Now()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-24 18:56:24 +00:00
|
|
|
func (c *impersonatorConfigController) setTLSCert(cert *tls.Certificate) {
|
|
|
|
c.tlsCertMutex.Lock()
|
|
|
|
defer c.tlsCertMutex.Unlock()
|
|
|
|
c.tlsCert = cert
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *impersonatorConfigController) getTLSCert() *tls.Certificate {
|
|
|
|
c.tlsCertMutex.RLock()
|
|
|
|
defer c.tlsCertMutex.RUnlock()
|
|
|
|
return c.tlsCert
|
|
|
|
}
|