2022-01-14 18:49:22 +00:00
// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
2021-02-12 01:22:47 +00:00
// SPDX-License-Identifier: Apache-2.0
package impersonatorconfig
import (
"context"
"crypto/tls"
2021-02-24 18:56:24 +00:00
"crypto/x509"
2021-03-03 00:51:35 +00:00
"encoding/base64"
2021-02-26 20:05:17 +00:00
"encoding/pem"
2021-02-12 01:22:47 +00:00
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
2021-03-04 23:36:51 +00:00
"reflect"
2021-03-04 21:52:34 +00:00
"regexp"
2021-03-10 18:30:06 +00:00
"sync"
2021-02-12 01:22:47 +00:00
"testing"
"time"
"github.com/sclevine/spec"
"github.com/sclevine/spec/report"
2021-03-04 21:52:34 +00:00
"github.com/stretchr/testify/assert"
2021-02-12 01:22:47 +00:00
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
2021-05-27 16:13:10 +00:00
k8serrors "k8s.io/apimachinery/pkg/api/errors"
2021-02-12 01:22:47 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2021-02-16 23:57:02 +00:00
"k8s.io/apimachinery/pkg/runtime"
2021-02-12 01:22:47 +00:00
"k8s.io/apimachinery/pkg/runtime/schema"
2021-05-26 20:03:04 +00:00
"k8s.io/apimachinery/pkg/util/intstr"
2021-02-12 01:22:47 +00:00
kubeinformers "k8s.io/client-go/informers"
kubernetesfake "k8s.io/client-go/kubernetes/fake"
coretesting "k8s.io/client-go/testing"
2021-12-10 22:22:36 +00:00
clocktesting "k8s.io/utils/clock/testing"
2021-02-12 01:22:47 +00:00
2021-03-02 22:48:58 +00:00
"go.pinniped.dev/generated/latest/apis/concierge/config/v1alpha1"
pinnipedfake "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned/fake"
2021-05-17 22:08:05 +00:00
pinnipedinformers "go.pinniped.dev/generated/latest/client/concierge/informers/externalversions"
2021-02-24 18:56:24 +00:00
"go.pinniped.dev/internal/certauthority"
2021-03-10 18:30:06 +00:00
"go.pinniped.dev/internal/controller/apicerts"
2021-02-12 01:22:47 +00:00
"go.pinniped.dev/internal/controllerlib"
2021-03-10 18:30:06 +00:00
"go.pinniped.dev/internal/dynamiccert"
2021-03-04 23:36:51 +00:00
"go.pinniped.dev/internal/kubeclient"
2021-02-12 01:22:47 +00:00
"go.pinniped.dev/internal/testutil"
2021-05-26 17:42:50 +00:00
"go.pinniped.dev/internal/testutil/testlogger"
2021-02-12 01:22:47 +00:00
)
func TestImpersonatorConfigControllerOptions ( t * testing . T ) {
spec . Run ( t , "options" , func ( t * testing . T , when spec . G , it spec . S ) {
const installedInNamespace = "some-namespace"
2021-11-17 21:27:59 +00:00
const impersonationProxyPort = 8444
2021-05-17 22:08:05 +00:00
const credentialIssuerResourceName = "some-credential-issuer-resource-name"
2021-02-12 01:22:47 +00:00
const generatedLoadBalancerServiceName = "some-service-resource-name"
2021-05-20 00:00:28 +00:00
const generatedClusterIPServiceName = "some-cluster-ip-resource-name"
2021-03-02 01:02:08 +00:00
const tlsSecretName = "some-tls-secret-name" //nolint:gosec // this is not a credential
const caSecretName = "some-ca-secret-name"
2021-03-10 18:30:06 +00:00
const caSignerName = "some-ca-signer-name"
2021-02-12 01:22:47 +00:00
var r * require . Assertions
var observableWithInformerOption * testutil . ObservableWithInformerOption
2021-05-17 22:08:05 +00:00
var credIssuerInformerFilter controllerlib . Filter
2021-02-18 01:22:13 +00:00
var servicesInformerFilter controllerlib . Filter
2021-02-24 18:56:24 +00:00
var secretsInformerFilter controllerlib . Filter
2021-05-26 17:42:50 +00:00
var testLog * testlogger . Logger
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
r = require . New ( t )
observableWithInformerOption = testutil . NewObservableWithInformerOption ( )
2021-05-17 22:08:05 +00:00
pinnipedInformerFactory := pinnipedinformers . NewSharedInformerFactory ( nil , 0 )
2021-02-18 01:22:13 +00:00
sharedInformerFactory := kubeinformers . NewSharedInformerFactory ( nil , 0 )
2021-05-17 22:08:05 +00:00
credIssuerInformer := pinnipedInformerFactory . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( )
2021-02-18 01:22:13 +00:00
servicesInformer := sharedInformerFactory . Core ( ) . V1 ( ) . Services ( )
2021-02-24 18:56:24 +00:00
secretsInformer := sharedInformerFactory . Core ( ) . V1 ( ) . Secrets ( )
2021-05-26 17:42:50 +00:00
testLog = testlogger . New ( t )
2021-02-18 01:22:13 +00:00
2021-02-12 01:22:47 +00:00
_ = NewImpersonatorConfigController (
installedInNamespace ,
2021-05-17 22:08:05 +00:00
credentialIssuerResourceName ,
2021-03-02 22:48:58 +00:00
nil ,
2021-02-12 01:22:47 +00:00
nil ,
2021-05-17 22:08:05 +00:00
credIssuerInformer ,
2021-02-18 01:22:13 +00:00
servicesInformer ,
2021-02-24 18:56:24 +00:00
secretsInformer ,
2021-02-12 01:22:47 +00:00
observableWithInformerOption . WithInformer ,
2021-11-17 21:27:59 +00:00
impersonationProxyPort ,
2021-02-12 01:22:47 +00:00
generatedLoadBalancerServiceName ,
2021-05-20 00:00:28 +00:00
generatedClusterIPServiceName ,
2021-02-24 18:56:24 +00:00
tlsSecretName ,
2021-03-02 01:02:08 +00:00
caSecretName ,
2021-02-12 01:22:47 +00:00
nil ,
nil ,
2021-02-16 23:57:02 +00:00
nil ,
2021-03-10 18:30:06 +00:00
caSignerName ,
2021-03-02 22:48:58 +00:00
nil ,
2021-12-10 22:22:36 +00:00
testLog . Logger ,
2021-02-12 01:22:47 +00:00
)
2021-05-17 22:08:05 +00:00
credIssuerInformerFilter = observableWithInformerOption . GetFilterForInformer ( credIssuerInformer )
2021-02-18 01:22:13 +00:00
servicesInformerFilter = observableWithInformerOption . GetFilterForInformer ( servicesInformer )
2021-02-24 18:56:24 +00:00
secretsInformerFilter = observableWithInformerOption . GetFilterForInformer ( secretsInformer )
2021-02-12 01:22:47 +00:00
} )
2021-05-17 22:08:05 +00:00
when ( "watching CredentialIssuer objects" , func ( ) {
2021-02-12 01:22:47 +00:00
var subject controllerlib . Filter
2021-05-17 22:08:05 +00:00
var target , wrongName , otherWrongName * v1alpha1 . CredentialIssuer
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
2021-05-17 22:08:05 +00:00
subject = credIssuerInformerFilter
target = & v1alpha1 . CredentialIssuer { ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } }
wrongName = & v1alpha1 . CredentialIssuer { ObjectMeta : metav1 . ObjectMeta { Name : "wrong-name" } }
otherWrongName = & v1alpha1 . CredentialIssuer { ObjectMeta : metav1 . ObjectMeta { Name : "other-wrong-name" } }
2021-02-12 01:22:47 +00:00
} )
2021-05-17 22:08:05 +00:00
when ( "the target CredentialIssuer changes" , func ( ) {
2021-02-12 01:22:47 +00:00
it ( "returns true to trigger the sync method" , func ( ) {
r . True ( subject . Add ( target ) )
2021-05-17 22:08:05 +00:00
r . True ( subject . Update ( target , wrongName ) )
r . True ( subject . Update ( wrongName , target ) )
2021-02-12 01:22:47 +00:00
r . True ( subject . Delete ( target ) )
} )
} )
2021-05-17 22:08:05 +00:00
when ( "a CredentialIssuer with a different name changes" , func ( ) {
2021-02-12 01:22:47 +00:00
it ( "returns false to avoid triggering the sync method" , func ( ) {
r . False ( subject . Add ( wrongName ) )
2021-05-17 22:08:05 +00:00
r . False ( subject . Update ( wrongName , otherWrongName ) )
r . False ( subject . Update ( otherWrongName , wrongName ) )
2021-02-12 01:22:47 +00:00
r . False ( subject . Delete ( wrongName ) )
} )
} )
} )
2021-02-18 01:22:13 +00:00
when ( "watching Service objects" , func ( ) {
var subject controllerlib . Filter
2021-07-28 16:57:18 +00:00
var targetLBService , targetClusterIPService , wrongNamespace , wrongName , unrelated * corev1 . Service
2021-02-18 01:22:13 +00:00
it . Before ( func ( ) {
subject = servicesInformerFilter
2021-07-28 16:57:18 +00:00
targetLBService = & corev1 . Service { ObjectMeta : metav1 . ObjectMeta { Name : generatedLoadBalancerServiceName , Namespace : installedInNamespace } }
targetClusterIPService = & corev1 . Service { ObjectMeta : metav1 . ObjectMeta { Name : generatedClusterIPServiceName , Namespace : installedInNamespace } }
2021-02-18 01:22:13 +00:00
wrongNamespace = & corev1 . Service { ObjectMeta : metav1 . ObjectMeta { Name : generatedLoadBalancerServiceName , Namespace : "wrong-namespace" } }
wrongName = & corev1 . Service { ObjectMeta : metav1 . ObjectMeta { Name : "wrong-name" , Namespace : installedInNamespace } }
unrelated = & corev1 . Service { ObjectMeta : metav1 . ObjectMeta { Name : "wrong-name" , Namespace : "wrong-namespace" } }
} )
when ( "the target Service changes" , func ( ) {
it ( "returns true to trigger the sync method" , func ( ) {
2021-07-28 16:57:18 +00:00
r . True ( subject . Add ( targetLBService ) )
r . True ( subject . Update ( targetLBService , unrelated ) )
r . True ( subject . Update ( unrelated , targetLBService ) )
r . True ( subject . Delete ( targetLBService ) )
r . True ( subject . Add ( targetClusterIPService ) )
r . True ( subject . Update ( targetClusterIPService , unrelated ) )
r . True ( subject . Update ( unrelated , targetClusterIPService ) )
r . True ( subject . Delete ( targetClusterIPService ) )
2021-02-18 01:22:13 +00:00
} )
} )
when ( "a Service 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 Service 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 Service 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 ) )
} )
} )
} )
2021-02-24 18:56:24 +00:00
when ( "watching Secret objects" , func ( ) {
var subject controllerlib . Filter
2021-03-10 18:30:06 +00:00
var target1 , target2 , target3 , wrongNamespace1 , wrongNamespace2 , wrongName , unrelated * corev1 . Secret
2021-02-24 18:56:24 +00:00
it . Before ( func ( ) {
subject = secretsInformerFilter
2021-03-02 01:02:08 +00:00
target1 = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : tlsSecretName , Namespace : installedInNamespace } }
target2 = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : caSecretName , Namespace : installedInNamespace } }
2021-03-10 18:30:06 +00:00
target3 = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : caSignerName , Namespace : installedInNamespace } }
2021-03-02 01:02:08 +00:00
wrongNamespace1 = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : tlsSecretName , Namespace : "wrong-namespace" } }
wrongNamespace2 = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : caSecretName , Namespace : "wrong-namespace" } }
2021-02-24 18:56:24 +00:00
wrongName = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : "wrong-name" , Namespace : installedInNamespace } }
unrelated = & corev1 . Secret { ObjectMeta : metav1 . ObjectMeta { Name : "wrong-name" , Namespace : "wrong-namespace" } }
} )
2021-03-02 01:02:08 +00:00
when ( "one of the target Secrets changes" , func ( ) {
2021-02-24 18:56:24 +00:00
it ( "returns true to trigger the sync method" , func ( ) {
2021-03-02 01:02:08 +00:00
r . True ( subject . Add ( target1 ) )
r . True ( subject . Update ( target1 , unrelated ) )
r . True ( subject . Update ( unrelated , target1 ) )
r . True ( subject . Delete ( target1 ) )
r . True ( subject . Add ( target2 ) )
r . True ( subject . Update ( target2 , unrelated ) )
r . True ( subject . Update ( unrelated , target2 ) )
r . True ( subject . Delete ( target2 ) )
2021-03-10 18:30:06 +00:00
r . True ( subject . Add ( target3 ) )
r . True ( subject . Update ( target3 , unrelated ) )
r . True ( subject . Update ( unrelated , target3 ) )
r . True ( subject . Delete ( target3 ) )
2021-02-24 18:56:24 +00:00
} )
} )
when ( "a Secret from another namespace changes" , func ( ) {
it ( "returns false to avoid triggering the sync method" , func ( ) {
2021-03-02 01:02:08 +00:00
r . False ( subject . Add ( wrongNamespace1 ) )
r . False ( subject . Update ( wrongNamespace1 , unrelated ) )
r . False ( subject . Update ( unrelated , wrongNamespace1 ) )
r . False ( subject . Delete ( wrongNamespace1 ) )
r . False ( subject . Add ( wrongNamespace2 ) )
r . False ( subject . Update ( wrongNamespace2 , unrelated ) )
r . False ( subject . Update ( unrelated , wrongNamespace2 ) )
r . False ( subject . Delete ( wrongNamespace2 ) )
2021-02-24 18:56:24 +00:00
} )
} )
when ( "a Secret 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 Secret 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 ) )
} )
} )
} )
2021-02-12 01:22:47 +00:00
} , spec . Parallel ( ) , spec . Report ( report . Terminal { } ) )
}
func TestImpersonatorConfigControllerSync ( t * testing . T ) {
2021-03-11 21:20:25 +00:00
name := t . Name ( )
2021-02-12 01:22:47 +00:00
spec . Run ( t , "Sync" , func ( t * testing . T , when spec . G , it spec . S ) {
const installedInNamespace = "some-namespace"
2021-11-17 21:27:59 +00:00
const impersonationProxyPort = 8444
2021-03-02 22:48:58 +00:00
const credentialIssuerResourceName = "some-credential-issuer-resource-name"
2021-02-26 21:53:30 +00:00
const loadBalancerServiceName = "some-service-resource-name"
2021-05-20 00:00:28 +00:00
const clusterIPServiceName = "some-cluster-ip-resource-name"
2021-03-02 01:02:08 +00:00
const tlsSecretName = "some-tls-secret-name" //nolint:gosec // this is not a credential
const caSecretName = "some-ca-secret-name"
2021-03-10 18:30:06 +00:00
const caSignerName = "some-ca-signer-name"
2021-02-26 19:27:19 +00:00
const localhostIP = "127.0.0.1"
2021-02-26 21:53:30 +00:00
const httpsPort = ":443"
2021-03-04 21:52:34 +00:00
const fakeServerResponseBody = "hello, world!"
2021-02-16 23:57:02 +00:00
var labels = map [ string ] string { "app" : "app-name" , "other-key" : "other-value" }
2021-02-12 01:22:47 +00:00
var r * require . Assertions
var subject controllerlib . Controller
var kubeAPIClient * kubernetesfake . Clientset
2021-03-02 22:48:58 +00:00
var pinnipedAPIClient * pinnipedfake . Clientset
2021-05-17 22:08:05 +00:00
var pinnipedInformerClient * pinnipedfake . Clientset
var pinnipedInformers pinnipedinformers . SharedInformerFactory
2021-02-12 01:22:47 +00:00
var kubeInformerClient * kubernetesfake . Clientset
var kubeInformers kubeinformers . SharedInformerFactory
2021-03-05 01:25:43 +00:00
var cancelContext context . Context
var cancelContextCancelFunc context . CancelFunc
2021-02-12 01:22:47 +00:00
var syncContext * controllerlib . Context
2021-03-02 22:48:58 +00:00
var frozenNow time . Time
2021-08-10 16:05:04 +00:00
var tlsServingCertDynamicCertProvider dynamiccert . Private
2021-03-10 18:30:06 +00:00
var signingCertProvider dynamiccert . Provider
var signingCACertPEM , signingCAKeyPEM [ ] byte
var signingCASecret * corev1 . Secret
2021-03-10 19:24:42 +00:00
var impersonatorFuncWasCalled int
var impersonatorFuncError error
var impersonatorFuncReturnedFuncError error
var startedTLSListener net . Listener
var startedTLSListenerMutex sync . RWMutex
2021-03-10 18:30:06 +00:00
var testHTTPServer * http . Server
var testHTTPServerMutex sync . RWMutex
var testHTTPServerInterruptCh chan struct { }
var queue * testQueue
var validClientCert * tls . Certificate
2021-05-26 17:42:50 +00:00
var testLog * testlogger . Logger
2021-03-10 18:30:06 +00:00
var impersonatorFunc = func (
port int ,
2021-03-11 21:20:25 +00:00
dynamicCertProvider dynamiccert . Private ,
impersonationProxySignerCAProvider dynamiccert . Public ,
2021-03-10 18:30:06 +00:00
) ( func ( stopCh <- chan struct { } ) error , error ) {
impersonatorFuncWasCalled ++
r . Equal ( 8444 , port )
r . NotNil ( dynamicCertProvider )
r . NotNil ( impersonationProxySignerCAProvider )
if impersonatorFuncError != nil {
return nil , impersonatorFuncError
2021-02-12 01:22:47 +00:00
}
2021-03-10 18:30:06 +00:00
2021-03-10 19:24:42 +00:00
startedTLSListenerMutex . Lock ( ) // this is to satisfy the race detector
defer startedTLSListenerMutex . Unlock ( )
var err error
// Bind a listener to the port. Automatically choose the port for unit tests instead of using the real port.
startedTLSListener , err = tls . Listen ( "tcp" , localhostIP + ":0" , & tls . Config {
MinVersion : tls . VersionTLS12 ,
GetCertificate : func ( info * tls . ClientHelloInfo ) ( * tls . Certificate , error ) {
certPEM , keyPEM := dynamicCertProvider . CurrentCertKeyContent ( )
if certPEM != nil && keyPEM != nil {
tlsCert , err := tls . X509KeyPair ( certPEM , keyPEM )
r . NoError ( err )
return & tlsCert , nil
}
return nil , nil // no cached TLS certs
} ,
ClientAuth : tls . RequestClientCert ,
VerifyPeerCertificate : func ( rawCerts [ ] [ ] byte , _ [ ] [ ] * x509 . Certificate ) error {
// Docs say that this will always be called in tls.RequestClientCert mode
// and that the second parameter will always be nil in that case.
// rawCerts will be raw ASN.1 certificates provided by the peer.
if len ( rawCerts ) != 1 {
return fmt . Errorf ( "expected to get one client cert on incoming request to test server" )
}
clientCert := rawCerts [ 0 ]
currentClientCertCA := impersonationProxySignerCAProvider . CurrentCABundleContent ( )
if currentClientCertCA == nil {
return fmt . Errorf ( "impersonationProxySignerCAProvider does not have a current CA certificate" )
}
// Assert that the client's cert was signed by the CA cert that the controller put into
// the CAContentProvider that was passed in.
parsed , err := x509 . ParseCertificate ( clientCert )
require . NoError ( t , err )
roots := x509 . NewCertPool ( )
require . True ( t , roots . AppendCertsFromPEM ( currentClientCertCA ) )
2021-03-13 00:09:16 +00:00
opts := x509 . VerifyOptions {
Roots : roots ,
KeyUsages : [ ] x509 . ExtKeyUsage { x509 . ExtKeyUsageClientAuth } ,
}
2021-03-10 19:24:42 +00:00
_ , err = parsed . Verify ( opts )
require . NoError ( t , err )
return nil
} ,
} )
r . NoError ( err )
2021-03-10 18:30:06 +00:00
// Return a func that starts a fake server when called, and shuts down the fake server when stopCh is closed.
// This fake server is enough like the real impersonation proxy server for this unit test because it
// uses the supplied providers to serve TLS. The goal of this unit test is to make sure that the server
// was started/stopped/configured correctly, not to test the actual impersonation behavior.
return func ( stopCh <- chan struct { } ) error {
if impersonatorFuncReturnedFuncError != nil {
return impersonatorFuncReturnedFuncError
}
testHTTPServerMutex . Lock ( ) // this is to satisfy the race detector
testHTTPServer = & http . Server { Handler : http . HandlerFunc ( func ( w http . ResponseWriter , req * http . Request ) {
_ , err := fmt . Fprint ( w , fakeServerResponseBody )
r . NoError ( err )
} ) }
testHTTPServerMutex . Unlock ( )
// Start serving requests in the background.
go func ( ) {
2021-03-10 19:24:42 +00:00
startedTLSListenerMutex . RLock ( ) // this is to satisfy the race detector
listener := startedTLSListener
startedTLSListenerMutex . RUnlock ( )
err := testHTTPServer . Serve ( listener )
2021-03-10 18:30:06 +00:00
if ! errors . Is ( err , http . ErrServerClosed ) {
t . Log ( "Got an unexpected error while starting the fake http server!" )
r . NoError ( err ) // causes the test to crash, which is good enough because this should never happen
}
} ( )
if testHTTPServerInterruptCh == nil {
// Wait in the foreground for the stopCh to be closed, and kill the server when that happens.
// This is similar to the behavior of the real impersonation server.
<- stopCh
} else {
// The test supplied an interrupt channel because it wants to test unexpected termination
// of the server, so wait for that channel to close instead of waiting for the one that
// was passed in from the production code.
<- testHTTPServerInterruptCh
}
2021-03-10 19:24:42 +00:00
err := testHTTPServer . Close ( )
2021-03-10 18:30:06 +00:00
t . Log ( "Got an unexpected error while stopping the fake http server!" )
r . NoError ( err ) // causes the test to crash, which is good enough because this should never happen
return nil
} , nil
2021-02-12 01:22:47 +00:00
}
2021-02-26 21:53:30 +00:00
var testServerAddr = func ( ) string {
2021-03-10 19:24:42 +00:00
var listener net . Listener
2021-03-10 18:30:06 +00:00
require . Eventually ( t , func ( ) bool {
2021-03-10 19:24:42 +00:00
startedTLSListenerMutex . RLock ( ) // this is to satisfy the race detector
listener = startedTLSListener
defer startedTLSListenerMutex . RUnlock ( )
return listener != nil
2021-03-10 18:30:06 +00:00
} , 20 * time . Second , 50 * time . Millisecond , "TLS listener never became not nil" )
2021-03-10 19:24:42 +00:00
return listener . Addr ( ) . String ( )
2021-02-26 21:53:30 +00:00
}
2021-03-10 18:30:06 +00:00
var closeTestHTTPServer = func ( ) {
// If a test left it running, then close it.
testHTTPServerMutex . RLock ( ) // this is to satisfy the race detector
defer testHTTPServerMutex . RUnlock ( )
if testHTTPServer != nil {
err := testHTTPServer . Close ( )
r . NoError ( err )
2021-02-12 01:22:47 +00:00
}
}
2021-08-10 16:05:04 +00:00
var requireTLSSecretProviderHasLoadedCerts = func ( ) {
actualCert , actualKey := tlsServingCertDynamicCertProvider . CurrentCertKeyContent ( )
r . NotEmpty ( actualCert )
r . NotEmpty ( actualKey )
_ , err := tls . X509KeyPair ( actualCert , actualKey )
r . NoError ( err )
}
var requireTLSSecretProviderIsEmpty = func ( ) {
actualCert , actualKey := tlsServingCertDynamicCertProvider . CurrentCertKeyContent ( )
r . Nil ( actualCert )
r . Nil ( actualKey )
}
2021-02-25 00:03:17 +00:00
var requireTLSServerIsRunning = func ( caCrt [ ] byte , addr string , dnsOverrides map [ string ] string ) {
2021-03-10 18:30:06 +00:00
r . Greater ( impersonatorFuncWasCalled , 0 )
2021-02-12 01:22:47 +00:00
2021-02-25 00:03:17 +00:00
realDialer := & net . Dialer { }
overrideDialContext := func ( ctx context . Context , network , addr string ) ( net . Conn , error ) {
replacementAddr , hasKey := dnsOverrides [ addr ]
if hasKey {
t . Logf ( "DialContext replacing addr %s with %s" , addr , replacementAddr )
addr = replacementAddr
} else if dnsOverrides != nil {
2021-05-26 00:01:42 +00:00
t . Fatalf ( "dnsOverrides was provided but not used, which was probably a mistake. addr %s" , addr )
2021-02-25 00:03:17 +00:00
}
return realDialer . DialContext ( ctx , network , addr )
}
2021-02-24 18:56:24 +00:00
var tr * http . Transport
if caCrt == nil {
tr = & http . Transport {
TLSClientConfig : & tls . Config { InsecureSkipVerify : true } , //nolint:gosec
2021-02-25 00:03:17 +00:00
DialContext : overrideDialContext ,
2021-02-24 18:56:24 +00:00
}
} else {
rootCAs := x509 . NewCertPool ( )
rootCAs . AppendCertsFromPEM ( caCrt )
tr = & http . Transport {
2021-03-10 18:30:06 +00:00
TLSClientConfig : & tls . Config {
// Server's TLS serving cert CA
RootCAs : rootCAs ,
// Client cert which is supposed to work against the server's dynamic CAContentProvider
Certificates : [ ] tls . Certificate { * validClientCert } ,
} ,
DialContext : overrideDialContext ,
2021-02-24 18:56:24 +00:00
}
2021-02-12 01:22:47 +00:00
}
client := & http . Client { Transport : tr }
2021-02-25 00:03:17 +00:00
url := "https://" + addr
2021-02-12 01:22:47 +00:00
req , err := http . NewRequestWithContext ( context . Background ( ) , "GET" , url , nil )
r . NoError ( err )
2021-03-05 01:25:43 +00:00
2021-03-04 21:52:34 +00:00
var resp * http . Response
assert . Eventually ( t , func ( ) bool {
resp , err = client . Do ( req . Clone ( context . Background ( ) ) ) //nolint:bodyclose
return err == nil
2021-03-05 01:25:43 +00:00
} , 20 * time . Second , 50 * time . Millisecond )
2021-02-12 01:22:47 +00:00
r . NoError ( err )
r . Equal ( http . StatusOK , resp . StatusCode )
body , err := ioutil . ReadAll ( resp . Body )
r . NoError ( resp . Body . Close ( ) )
r . NoError ( err )
2021-03-04 21:52:34 +00:00
r . Equal ( fakeServerResponseBody , string ( body ) )
2021-08-10 16:05:04 +00:00
requireTLSSecretProviderHasLoadedCerts ( )
2021-02-12 01:22:47 +00:00
}
2021-02-24 18:56:24 +00:00
var requireTLSServerIsRunningWithoutCerts = func ( ) {
2021-03-10 18:30:06 +00:00
r . Greater ( impersonatorFuncWasCalled , 0 )
2021-02-24 18:56:24 +00:00
tr := & http . Transport {
TLSClientConfig : & tls . Config { InsecureSkipVerify : true } , //nolint:gosec
}
client := & http . Client { Transport : tr }
2021-02-26 21:53:30 +00:00
url := "https://" + testServerAddr ( )
2021-02-24 18:56:24 +00:00
req , err := http . NewRequestWithContext ( context . Background ( ) , "GET" , url , nil )
r . NoError ( err )
2021-03-05 01:25:43 +00:00
2021-03-04 21:52:34 +00:00
expectedErrorRegex := "Get .*: remote error: tls: unrecognized name"
expectedErrorRegexCompiled , err := regexp . Compile ( expectedErrorRegex )
r . NoError ( err )
assert . Eventually ( t , func ( ) bool {
_ , err = client . Do ( req . Clone ( context . Background ( ) ) ) //nolint:bodyclose
return err != nil && expectedErrorRegexCompiled . MatchString ( err . Error ( ) )
2021-03-05 01:25:43 +00:00
} , 20 * time . Second , 50 * time . Millisecond )
2021-02-24 18:56:24 +00:00
r . Error ( err )
2021-03-04 21:52:34 +00:00
r . Regexp ( expectedErrorRegex , err . Error ( ) )
2021-08-10 16:05:04 +00:00
requireTLSSecretProviderIsEmpty ( )
2021-02-24 18:56:24 +00:00
}
2021-02-12 01:22:47 +00:00
var requireTLSServerIsNoLongerRunning = func ( ) {
2021-03-10 18:30:06 +00:00
r . Greater ( impersonatorFuncWasCalled , 0 )
2021-03-04 21:52:34 +00:00
var err error
expectedErrorRegex := "dial tcp .*: connect: connection refused"
expectedErrorRegexCompiled , err := regexp . Compile ( expectedErrorRegex )
r . NoError ( err )
assert . Eventually ( t , func ( ) bool {
_ , err = tls . Dial (
2021-03-10 18:30:06 +00:00
"tcp" ,
2021-03-04 21:52:34 +00:00
testServerAddr ( ) ,
& tls . Config { InsecureSkipVerify : true } , //nolint:gosec
)
return err != nil && expectedErrorRegexCompiled . MatchString ( err . Error ( ) )
2021-03-05 01:25:43 +00:00
} , 20 * time . Second , 50 * time . Millisecond )
2021-02-12 01:22:47 +00:00
r . Error ( err )
2021-03-04 21:52:34 +00:00
r . Regexp ( expectedErrorRegex , err . Error ( ) )
2021-08-10 16:05:04 +00:00
requireTLSSecretProviderIsEmpty ( )
2021-02-12 01:22:47 +00:00
}
var requireTLSServerWasNeverStarted = func ( ) {
2021-03-10 18:30:06 +00:00
r . Equal ( 0 , impersonatorFuncWasCalled )
2021-08-10 16:05:04 +00:00
requireTLSSecretProviderIsEmpty ( )
2021-02-12 01:22:47 +00:00
}
// 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 = NewImpersonatorConfigController (
installedInNamespace ,
2021-03-02 22:48:58 +00:00
credentialIssuerResourceName ,
2021-12-10 22:22:36 +00:00
kubeAPIClient ,
2021-03-02 22:48:58 +00:00
pinnipedAPIClient ,
2021-05-17 22:08:05 +00:00
pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) ,
2021-02-18 01:22:13 +00:00
kubeInformers . Core ( ) . V1 ( ) . Services ( ) ,
2021-02-24 18:56:24 +00:00
kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) ,
2021-02-12 01:22:47 +00:00
controllerlib . WithInformer ,
2021-11-17 21:27:59 +00:00
impersonationProxyPort ,
2021-02-26 21:53:30 +00:00
loadBalancerServiceName ,
2021-05-20 00:00:28 +00:00
clusterIPServiceName ,
2021-02-24 18:56:24 +00:00
tlsSecretName ,
2021-03-02 01:02:08 +00:00
caSecretName ,
2021-02-16 23:57:02 +00:00
labels ,
2021-12-10 22:22:36 +00:00
clocktesting . NewFakeClock ( frozenNow ) ,
2021-03-10 18:30:06 +00:00
impersonatorFunc ,
caSignerName ,
signingCertProvider ,
2021-12-10 22:22:36 +00:00
testLog . Logger ,
2021-02-12 01:22:47 +00:00
)
2021-08-10 16:05:04 +00:00
controllerlib . TestWrap ( t , subject , func ( syncer controllerlib . Syncer ) controllerlib . Syncer {
tlsServingCertDynamicCertProvider = syncer . ( * impersonatorConfigController ) . tlsServingCertDynamicCertProvider
return syncer
} )
2021-02-12 01:22:47 +00:00
// Set this at the last second to support calling subject.Name().
syncContext = & controllerlib . Context {
2021-03-05 01:25:43 +00:00
Context : cancelContext ,
2021-02-12 01:22:47 +00:00
Name : subject . Name ( ) ,
Key : controllerlib . Key {
2021-05-17 22:08:05 +00:00
Name : credentialIssuerResourceName ,
2021-02-12 01:22:47 +00:00
} ,
2021-03-10 18:30:06 +00:00
Queue : queue ,
2021-02-12 01:22:47 +00:00
}
// Must start informers before calling TestRunSynchronously()
2021-03-05 01:25:43 +00:00
kubeInformers . Start ( cancelContext . Done ( ) )
2021-05-17 22:08:05 +00:00
pinnipedInformers . Start ( cancelContext . Done ( ) )
2021-02-12 01:22:47 +00:00
controllerlib . TestRunSynchronously ( t , subject )
}
2021-05-20 17:26:07 +00:00
var addCredentialIssuerToTrackers = func ( credIssuer v1alpha1 . CredentialIssuer , informerClient * pinnipedfake . Clientset , mainClient * pinnipedfake . Clientset ) {
t . Logf ( "adding CredentialIssuer %s to informer and main clientsets" , credIssuer . Name )
r . NoError ( informerClient . Tracker ( ) . Add ( & credIssuer ) )
r . NoError ( mainClient . Tracker ( ) . Add ( & credIssuer ) )
2021-02-12 01:22:47 +00:00
}
2021-02-26 21:53:30 +00:00
var newSecretWithData = func ( resourceName string , data map [ string ] [ ] byte ) * corev1 . Secret {
2021-02-24 18:56:24 +00:00
return & corev1 . Secret {
ObjectMeta : metav1 . ObjectMeta {
2021-08-10 16:05:04 +00:00
Name : resourceName ,
Namespace : installedInNamespace ,
UID : "uid-1234" , // simulate KAS filling out UID and RV
ResourceVersion : "rv-5678" ,
2021-02-24 18:56:24 +00:00
} ,
2021-02-26 19:27:19 +00:00
Data : data ,
2021-02-24 18:56:24 +00:00
}
}
2021-03-02 01:02:08 +00:00
var newEmptySecret = func ( resourceName string ) * corev1 . Secret {
2021-02-26 21:53:30 +00:00
return newSecretWithData ( resourceName , map [ string ] [ ] byte { } )
2021-02-26 19:27:19 +00:00
}
2021-03-02 01:02:08 +00:00
var newCA = func ( ) * certauthority . CA {
2021-03-13 00:09:16 +00:00
ca , err := certauthority . New ( "test CA" , 24 * time . Hour )
2021-03-02 01:02:08 +00:00
r . NoError ( err )
return ca
}
var newCACertSecretData = func ( ca * certauthority . CA ) map [ string ] [ ] byte {
keyPEM , err := ca . PrivateKeyToPEM ( )
2021-02-24 18:56:24 +00:00
r . NoError ( err )
2021-03-02 01:02:08 +00:00
return map [ string ] [ ] byte {
"ca.crt" : ca . Bundle ( ) ,
"ca.key" : keyPEM ,
}
}
var newTLSCertSecretData = func ( ca * certauthority . CA , dnsNames [ ] string , ip string ) map [ string ] [ ] byte {
2021-03-13 00:09:16 +00:00
impersonationCert , err := ca . IssueServerCert ( dnsNames , [ ] net . IP { net . ParseIP ( ip ) } , 24 * time . Hour )
2021-02-24 18:56:24 +00:00
r . NoError ( err )
certPEM , keyPEM , err := certauthority . ToPEM ( impersonationCert )
2021-02-25 00:03:17 +00:00
r . NoError ( err )
2021-02-26 21:53:30 +00:00
return map [ string ] [ ] byte {
2021-02-26 19:27:19 +00:00
corev1 . TLSPrivateKeyKey : keyPEM ,
corev1 . TLSCertKey : certPEM ,
2021-02-26 21:53:30 +00:00
}
2021-02-24 18:56:24 +00:00
}
2021-03-02 01:02:08 +00:00
var newActualCASecret = func ( ca * certauthority . CA , resourceName string ) * corev1 . Secret {
return newSecretWithData ( resourceName , newCACertSecretData ( ca ) )
2021-02-26 01:03:34 +00:00
}
2021-03-02 01:02:08 +00:00
var newActualTLSSecret = func ( ca * certauthority . CA , resourceName string , ip string ) * corev1 . Secret {
return newSecretWithData ( resourceName , newTLSCertSecretData ( ca , nil , ip ) )
}
var newActualTLSSecretWithMultipleHostnames = func ( ca * certauthority . CA , resourceName string , ip string ) * corev1 . Secret {
return newSecretWithData ( resourceName , newTLSCertSecretData ( ca , [ ] string { "foo" , "bar" } , ip ) )
2021-02-26 21:53:30 +00:00
}
2021-03-10 18:30:06 +00:00
var newSigningKeySecret = func ( resourceName string , certPEM , keyPEM [ ] byte ) * corev1 . Secret {
return newSecretWithData ( resourceName , map [ string ] [ ] byte {
apicerts . CACertificateSecretKey : certPEM ,
apicerts . CACertificatePrivateKeySecretKey : keyPEM ,
} )
}
2021-02-26 21:53:30 +00:00
var newLoadBalancerService = func ( resourceName string , status corev1 . ServiceStatus ) * corev1 . Service {
return & corev1 . Service {
2021-02-18 01:22:13 +00:00
ObjectMeta : metav1 . ObjectMeta {
Name : resourceName ,
Namespace : installedInNamespace ,
2021-05-26 20:03:04 +00:00
Labels : labels ,
2021-02-18 01:22:13 +00:00
} ,
Spec : corev1 . ServiceSpec {
Type : corev1 . ServiceTypeLoadBalancer ,
2021-05-26 20:03:04 +00:00
Ports : [ ] corev1 . ServicePort {
{
TargetPort : intstr . FromInt ( impersonationProxyPort ) ,
Port : defaultHTTPSPort ,
Protocol : corev1 . ProtocolTCP ,
} ,
} ,
Selector : map [ string ] string { appLabelKey : labels [ appLabelKey ] } ,
2021-02-18 01:22:13 +00:00
} ,
2021-02-26 21:53:30 +00:00
Status : status ,
2021-02-18 01:22:13 +00:00
}
2021-02-26 21:53:30 +00:00
}
2021-05-20 18:57:07 +00:00
var newClusterIPService = func ( resourceName string , status corev1 . ServiceStatus , spec corev1 . ServiceSpec ) * corev1 . Service {
return & corev1 . Service {
ObjectMeta : metav1 . ObjectMeta {
Name : resourceName ,
Namespace : installedInNamespace ,
2021-05-26 20:03:04 +00:00
Labels : labels ,
2021-05-20 18:57:07 +00:00
} ,
Spec : spec ,
Status : status ,
}
}
2021-03-04 23:36:51 +00:00
// Anytime an object is added/updated/deleted in the informer's client *after* the informer is started, then we
// need to wait for the informer's cache to asynchronously pick up that change from its "watch".
// If an object is added to the informer's client *before* the informer is started, then waiting is
// not needed because the informer's initial "list" will pick up the object.
var waitForObjectToAppearInInformer = func ( obj kubeclient . Object , informer controllerlib . InformerGetter ) {
2021-03-05 01:25:43 +00:00
var objFromInformer interface { }
var exists bool
var err error
assert . Eventually ( t , func ( ) bool {
objFromInformer , exists , err = informer . Informer ( ) . GetIndexer ( ) . GetByKey ( installedInNamespace + "/" + obj . GetName ( ) )
return err == nil && exists && reflect . DeepEqual ( objFromInformer . ( kubeclient . Object ) , obj )
} , 30 * time . Second , 10 * time . Millisecond )
r . NoError ( err )
r . True ( exists , "this object should have existed in informer but didn't: %+v" , obj )
r . Equal ( obj , objFromInformer , "was waiting for expected to be found in informer, but found actual" )
2021-02-18 01:22:13 +00:00
}
2021-05-17 22:08:05 +00:00
var waitForClusterScopedObjectToAppearInInformer = func ( obj kubeclient . Object , informer controllerlib . InformerGetter ) {
var objFromInformer interface { }
var exists bool
var err error
assert . Eventually ( t , func ( ) bool {
objFromInformer , exists , err = informer . Informer ( ) . GetIndexer ( ) . GetByKey ( obj . GetName ( ) )
return err == nil && exists && reflect . DeepEqual ( objFromInformer . ( kubeclient . Object ) , obj )
} , 30 * time . Second , 10 * time . Millisecond )
r . NoError ( err )
r . True ( exists , "this object should have existed in informer but didn't: %+v" , obj )
r . Equal ( obj , objFromInformer , "was waiting for expected to be found in informer, but found actual" )
}
2021-03-04 23:36:51 +00:00
// See comment for waitForObjectToAppearInInformer above.
var waitForObjectToBeDeletedFromInformer = func ( resourceName string , informer controllerlib . InformerGetter ) {
2021-03-05 01:25:43 +00:00
var objFromInformer interface { }
var exists bool
var err error
assert . Eventually ( t , func ( ) bool {
objFromInformer , exists , err = informer . Informer ( ) . GetIndexer ( ) . GetByKey ( installedInNamespace + "/" + resourceName )
2021-03-04 23:36:51 +00:00
return err == nil && ! exists
2021-03-05 01:25:43 +00:00
} , 30 * time . Second , 10 * time . Millisecond )
r . NoError ( err )
r . False ( exists , "this object should have been deleted from informer but wasn't: %s" , objFromInformer )
2021-02-26 21:53:30 +00:00
}
2021-05-17 22:08:05 +00:00
var addObjectToKubeInformerAndWait = func ( obj kubeclient . Object , informer controllerlib . InformerGetter ) {
2021-03-04 23:36:51 +00:00
r . NoError ( kubeInformerClient . Tracker ( ) . Add ( obj ) )
waitForObjectToAppearInInformer ( obj , informer )
}
var addObjectFromCreateActionToInformerAndWait = func ( action coretesting . Action , informer controllerlib . InformerGetter ) {
createdObject , ok := action . ( coretesting . CreateAction ) . GetObject ( ) . ( kubeclient . Object )
r . True ( ok , "should have been able to cast this action's object to kubeclient.Object: %v" , action )
2021-08-10 16:05:04 +00:00
if secret , ok := createdObject . ( * corev1 . Secret ) ; ok && len ( secret . ResourceVersion ) == 0 {
secret = secret . DeepCopy ( )
secret . UID = "uid-1234" // simulate KAS filling out UID and RV
secret . ResourceVersion = "rv-5678"
createdObject = secret
}
2021-05-17 22:08:05 +00:00
addObjectToKubeInformerAndWait ( createdObject , informer )
2021-03-04 23:36:51 +00:00
}
2021-05-17 22:08:05 +00:00
var updateCredentialIssuerInInformerAndWait = func ( resourceName string , credIssuerSpec v1alpha1 . CredentialIssuerSpec , informer controllerlib . InformerGetter ) {
credIssuersGVR := v1alpha1 . Resource ( "credentialissuers" ) . WithVersion ( "v1alpha1" )
credIssuerObj , err := pinnipedInformerClient . Tracker ( ) . Get ( credIssuersGVR , "" , resourceName )
r . NoError ( err , "could not find CredentialIssuer to update for test" )
credIssuer := credIssuerObj . ( * v1alpha1 . CredentialIssuer )
credIssuer = credIssuer . DeepCopy ( ) // don't edit the original from the tracker
credIssuer . Spec = credIssuerSpec
r . NoError ( pinnipedInformerClient . Tracker ( ) . Update ( credIssuersGVR , credIssuer , "" ) )
waitForClusterScopedObjectToAppearInInformer ( credIssuer , informer )
2021-02-26 21:53:30 +00:00
}
2021-03-04 23:36:51 +00:00
var updateLoadBalancerServiceInInformerAndWait = func ( resourceName string , ingresses [ ] corev1 . LoadBalancerIngress , informer controllerlib . InformerGetter ) {
serviceObj , err := kubeInformerClient . Tracker ( ) . Get (
2021-02-26 21:53:30 +00:00
schema . GroupVersionResource { Version : "v1" , Resource : "services" } ,
installedInNamespace ,
resourceName ,
)
r . NoError ( err )
service := serviceObj . ( * corev1 . Service )
2021-03-04 23:36:51 +00:00
service = service . DeepCopy ( ) // don't edit the original from the tracker
2021-02-26 21:53:30 +00:00
service . Status = corev1 . ServiceStatus { LoadBalancer : corev1 . LoadBalancerStatus { Ingress : ingresses } }
2021-03-04 23:36:51 +00:00
r . NoError ( kubeInformerClient . Tracker ( ) . Update (
2021-02-25 00:03:17 +00:00
schema . GroupVersionResource { Version : "v1" , Resource : "services" } ,
2021-02-26 21:53:30 +00:00
service ,
2021-02-25 00:03:17 +00:00
installedInNamespace ,
) )
2021-03-04 23:36:51 +00:00
waitForObjectToAppearInInformer ( service , informer )
}
var addLoadBalancerServiceToTracker = func ( resourceName string , client * kubernetesfake . Clientset ) {
loadBalancerService := newLoadBalancerService ( resourceName , corev1 . ServiceStatus { } )
r . NoError ( client . Tracker ( ) . Add ( loadBalancerService ) )
}
var addLoadBalancerServiceWithIngressToTracker = func ( resourceName string , ingress [ ] corev1 . LoadBalancerIngress , client * kubernetesfake . Clientset ) {
loadBalancerService := newLoadBalancerService ( resourceName , corev1 . ServiceStatus {
LoadBalancer : corev1 . LoadBalancerStatus { Ingress : ingress } ,
} )
r . NoError ( client . Tracker ( ) . Add ( loadBalancerService ) )
}
2021-05-20 18:57:07 +00:00
var addClusterIPServiceToTracker = func ( resourceName string , clusterIP string , client * kubernetesfake . Clientset ) {
clusterIPService := newClusterIPService ( resourceName , corev1 . ServiceStatus { } , corev1 . ServiceSpec {
Type : corev1 . ServiceTypeClusterIP ,
ClusterIP : clusterIP ,
2021-05-26 20:03:04 +00:00
Ports : [ ] corev1 . ServicePort {
{
TargetPort : intstr . FromInt ( impersonationProxyPort ) ,
Port : defaultHTTPSPort ,
Protocol : corev1 . ProtocolTCP ,
} ,
} ,
Selector : map [ string ] string { appLabelKey : labels [ appLabelKey ] } ,
2021-05-20 18:57:07 +00:00
} )
r . NoError ( client . Tracker ( ) . Add ( clusterIPService ) )
}
2021-05-26 00:01:42 +00:00
var addDualStackClusterIPServiceToTracker = func ( resourceName string , clusterIP0 string , clusterIP1 string , client * kubernetesfake . Clientset ) {
clusterIPService := newClusterIPService ( resourceName , corev1 . ServiceStatus { } , corev1 . ServiceSpec {
Type : corev1 . ServiceTypeClusterIP ,
ClusterIP : clusterIP0 ,
ClusterIPs : [ ] string { clusterIP0 , clusterIP1 } ,
2021-05-26 20:03:04 +00:00
Ports : [ ] corev1 . ServicePort {
{
TargetPort : intstr . FromInt ( impersonationProxyPort ) ,
Port : defaultHTTPSPort ,
Protocol : corev1 . ProtocolTCP ,
} ,
} ,
Selector : map [ string ] string { appLabelKey : labels [ appLabelKey ] } ,
2021-05-26 00:01:42 +00:00
} )
r . NoError ( client . Tracker ( ) . Add ( clusterIPService ) )
}
2021-03-04 23:36:51 +00:00
var addSecretToTrackers = func ( secret * corev1 . Secret , clients ... * kubernetesfake . Clientset ) {
for _ , client := range clients {
secretCopy := secret . DeepCopy ( )
r . NoError ( client . Tracker ( ) . Add ( secretCopy ) )
}
2021-02-25 00:03:17 +00:00
}
2021-07-23 00:09:50 +00:00
var addServiceToTrackers = func ( service * corev1 . Service , clients ... * kubernetesfake . Clientset ) {
for _ , client := range clients {
serviceCopy := service . DeepCopy ( )
r . NoError ( client . Tracker ( ) . Add ( serviceCopy ) )
}
}
2021-03-02 01:02:08 +00:00
var deleteServiceFromTracker = func ( resourceName string , client * kubernetesfake . Clientset ) {
2021-02-18 01:22:13 +00:00
r . NoError ( client . Tracker ( ) . Delete (
schema . GroupVersionResource { Version : "v1" , Resource : "services" } ,
installedInNamespace ,
resourceName ,
) )
}
2021-03-02 01:02:08 +00:00
var deleteSecretFromTracker = func ( resourceName string , client * kubernetesfake . Clientset ) {
2021-02-25 00:03:17 +00:00
r . NoError ( client . Tracker ( ) . Delete (
schema . GroupVersionResource { Version : "v1" , Resource : "secrets" } ,
installedInNamespace ,
resourceName ,
) )
}
2021-02-26 21:53:30 +00:00
var addNodeWithRoleToTracker = func ( role string , client * kubernetesfake . Clientset ) {
r . NoError ( client . Tracker ( ) . Add (
2021-02-12 01:22:47 +00:00
& corev1 . Node {
ObjectMeta : metav1 . ObjectMeta {
Name : "node" ,
Labels : map [ string ] string { "kubernetes.io/node-role" : role } ,
} ,
} ,
) )
}
2021-02-18 01:22:13 +00:00
var requireNodesListed = func ( action coretesting . Action ) {
r . Equal (
coretesting . NewListAction (
schema . GroupVersionResource { Version : "v1" , Resource : "nodes" } ,
schema . GroupVersionKind { Group : "" , Version : "v1" , Kind : "Node" } ,
"" ,
metav1 . ListOptions { } ) ,
action ,
)
}
2021-03-03 00:51:35 +00:00
var newSuccessStrategy = func ( endpoint string , ca [ ] byte ) v1alpha1 . CredentialIssuerStrategy {
2021-03-02 22:48:58 +00:00
return v1alpha1 . CredentialIssuerStrategy {
Type : v1alpha1 . ImpersonationProxyStrategyType ,
Status : v1alpha1 . SuccessStrategyStatus ,
Reason : v1alpha1 . ListeningStrategyReason ,
Message : "impersonation proxy is ready to accept client connections" ,
LastUpdateTime : metav1 . NewTime ( frozenNow ) ,
2021-03-03 00:51:35 +00:00
Frontend : & v1alpha1 . CredentialIssuerFrontend {
Type : v1alpha1 . ImpersonationProxyFrontendType ,
ImpersonationProxyInfo : & v1alpha1 . ImpersonationProxyInfo {
Endpoint : "https://" + endpoint ,
CertificateAuthorityData : base64 . StdEncoding . EncodeToString ( ca ) ,
} ,
} ,
2021-03-02 22:48:58 +00:00
}
}
var newAutoDisabledStrategy = func ( ) v1alpha1 . CredentialIssuerStrategy {
return v1alpha1 . CredentialIssuerStrategy {
Type : v1alpha1 . ImpersonationProxyStrategyType ,
Status : v1alpha1 . ErrorStrategyStatus ,
Reason : v1alpha1 . DisabledStrategyReason ,
Message : "automatically determined that impersonation proxy should be disabled" ,
LastUpdateTime : metav1 . NewTime ( frozenNow ) ,
2021-03-03 00:51:35 +00:00
Frontend : nil ,
2021-03-02 22:48:58 +00:00
}
}
var newManuallyDisabledStrategy = func ( ) v1alpha1 . CredentialIssuerStrategy {
s := newAutoDisabledStrategy ( )
s . Message = "impersonation proxy was explicitly disabled by configuration"
return s
}
2021-05-27 16:13:10 +00:00
var newPendingStrategy = func ( msg string ) v1alpha1 . CredentialIssuerStrategy {
2021-03-02 22:48:58 +00:00
return v1alpha1 . CredentialIssuerStrategy {
Type : v1alpha1 . ImpersonationProxyStrategyType ,
Status : v1alpha1 . ErrorStrategyStatus ,
2021-03-02 23:27:54 +00:00
Reason : v1alpha1 . PendingStrategyReason ,
2021-05-27 16:13:10 +00:00
Message : msg ,
2021-03-02 22:48:58 +00:00
LastUpdateTime : metav1 . NewTime ( frozenNow ) ,
2021-03-03 00:51:35 +00:00
Frontend : nil ,
2021-03-02 22:48:58 +00:00
}
}
2021-05-27 16:13:10 +00:00
var newPendingStrategyWaitingForLB = func ( ) v1alpha1 . CredentialIssuerStrategy {
return newPendingStrategy ( "waiting for load balancer Service to be assigned IP or hostname" )
}
2021-03-02 22:48:58 +00:00
var newErrorStrategy = func ( msg string ) v1alpha1 . CredentialIssuerStrategy {
return 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 : msg ,
LastUpdateTime : metav1 . NewTime ( frozenNow ) ,
2021-03-03 00:51:35 +00:00
Frontend : nil ,
2021-03-02 22:48:58 +00:00
}
}
2021-03-03 17:37:08 +00:00
var getCredentialIssuer = func ( ) * v1alpha1 . CredentialIssuer {
2021-03-02 22:48:58 +00:00
credentialIssuerObj , err := pinnipedAPIClient . Tracker ( ) . Get (
schema . GroupVersionResource {
Group : v1alpha1 . SchemeGroupVersion . Group ,
Version : v1alpha1 . SchemeGroupVersion . Version ,
Resource : "credentialissuers" ,
} , "" , credentialIssuerResourceName ,
)
r . NoError ( err )
credentialIssuer , ok := credentialIssuerObj . ( * v1alpha1 . CredentialIssuer )
r . True ( ok , "should have been able to cast this obj to CredentialIssuer: %v" , credentialIssuerObj )
2021-03-03 17:37:08 +00:00
return credentialIssuer
}
var requireCredentialIssuer = func ( expectedStrategy v1alpha1 . CredentialIssuerStrategy ) {
// Rather than looking at the specific API actions on pinnipedAPIClient, we just look
// at the final result here.
// This is because the implementation is using a helper from another package to create
// and update the CredentialIssuer, and the specific API actions performed by that
// implementation are pretty complex and are already tested by its own unit tests.
// As long as we get the final result that we wanted then we are happy for the purposes
// of this test.
credentialIssuer := getCredentialIssuer ( )
2021-03-02 22:48:58 +00:00
r . Equal ( [ ] v1alpha1 . CredentialIssuerStrategy { expectedStrategy } , credentialIssuer . Status . Strategies )
}
2021-05-21 16:57:46 +00:00
var requireServiceWasDeleted = func ( action coretesting . Action , serviceName string ) {
deleteAction , ok := action . ( coretesting . DeleteAction )
r . True ( ok , "should have been able to cast this action to DeleteAction: %v" , action )
r . Equal ( "delete" , deleteAction . GetVerb ( ) )
r . Equal ( serviceName , deleteAction . GetName ( ) )
r . Equal ( "services" , deleteAction . GetResource ( ) . Resource )
}
2021-05-18 23:54:59 +00:00
var requireLoadBalancerWasCreated = func ( action coretesting . Action ) * corev1 . Service {
2021-03-02 01:02:08 +00:00
createAction , ok := action . ( coretesting . CreateAction )
r . True ( ok , "should have been able to cast this action to CreateAction: %v" , action )
2021-02-24 18:56:24 +00:00
r . Equal ( "create" , createAction . GetVerb ( ) )
createdLoadBalancerService := createAction . GetObject ( ) . ( * corev1 . Service )
2021-02-26 21:53:30 +00:00
r . Equal ( loadBalancerServiceName , createdLoadBalancerService . Name )
2021-02-18 01:22:13 +00:00
r . Equal ( installedInNamespace , createdLoadBalancerService . Namespace )
r . Equal ( corev1 . ServiceTypeLoadBalancer , createdLoadBalancerService . Spec . Type )
r . Equal ( "app-name" , createdLoadBalancerService . Spec . Selector [ "app" ] )
r . Equal ( labels , createdLoadBalancerService . Labels )
2021-05-18 23:54:59 +00:00
return createdLoadBalancerService
2021-02-18 01:22:13 +00:00
}
2021-05-18 23:54:59 +00:00
var requireLoadBalancerWasUpdated = func ( action coretesting . Action ) * corev1 . Service {
updateAction , ok := action . ( coretesting . UpdateAction )
r . True ( ok , "should have been able to cast this action to UpdateAction: %v" , action )
r . Equal ( "update" , updateAction . GetVerb ( ) )
updatedLoadBalancerService := updateAction . GetObject ( ) . ( * corev1 . Service )
r . Equal ( loadBalancerServiceName , updatedLoadBalancerService . Name )
r . Equal ( installedInNamespace , updatedLoadBalancerService . Namespace )
r . Equal ( corev1 . ServiceTypeLoadBalancer , updatedLoadBalancerService . Spec . Type )
r . Equal ( "app-name" , updatedLoadBalancerService . Spec . Selector [ "app" ] )
r . Equal ( labels , updatedLoadBalancerService . Labels )
return updatedLoadBalancerService
}
2021-05-20 23:21:10 +00:00
var requireClusterIPWasCreated = func ( action coretesting . Action ) * corev1 . Service {
2021-05-20 00:00:28 +00:00
createAction , ok := action . ( coretesting . CreateAction )
r . True ( ok , "should have been able to cast this action to CreateAction: %v" , action )
r . Equal ( "create" , createAction . GetVerb ( ) )
createdClusterIPService := createAction . GetObject ( ) . ( * corev1 . Service )
r . Equal ( clusterIPServiceName , createdClusterIPService . Name )
r . Equal ( corev1 . ServiceTypeClusterIP , createdClusterIPService . Spec . Type )
r . Equal ( "app-name" , createdClusterIPService . Spec . Selector [ "app" ] )
r . Equal ( labels , createdClusterIPService . Labels )
2021-05-20 23:21:10 +00:00
return createdClusterIPService
2021-05-20 00:00:28 +00:00
}
2021-05-20 23:21:10 +00:00
var requireClusterIPWasUpdated = func ( action coretesting . Action ) * corev1 . Service {
updateAction , ok := action . ( coretesting . UpdateAction )
r . True ( ok , "should have been able to cast this action to UpdateAction: %v" , action )
r . Equal ( "update" , updateAction . GetVerb ( ) )
updatedLoadBalancerService := updateAction . GetObject ( ) . ( * corev1 . Service )
r . Equal ( clusterIPServiceName , updatedLoadBalancerService . Name )
r . Equal ( installedInNamespace , updatedLoadBalancerService . Namespace )
r . Equal ( corev1 . ServiceTypeClusterIP , updatedLoadBalancerService . Spec . Type )
r . Equal ( "app-name" , updatedLoadBalancerService . Spec . Selector [ "app" ] )
r . Equal ( labels , updatedLoadBalancerService . Labels )
return updatedLoadBalancerService
}
2021-03-02 01:02:08 +00:00
var requireTLSSecretWasDeleted = func ( action coretesting . Action ) {
deleteAction , ok := action . ( coretesting . DeleteAction )
r . True ( ok , "should have been able to cast this action to DeleteAction: %v" , action )
2021-02-24 18:56:24 +00:00
r . Equal ( "delete" , deleteAction . GetVerb ( ) )
r . Equal ( tlsSecretName , deleteAction . GetName ( ) )
r . Equal ( "secrets" , deleteAction . GetResource ( ) . Resource )
2021-08-10 16:05:04 +00:00
// validate that we set delete preconditions correctly
2021-12-10 22:22:36 +00:00
r . Equal ( testutil . NewPreconditions ( "uid-1234" , "rv-5678" ) , deleteAction . GetDeleteOptions ( ) )
2021-02-24 18:56:24 +00:00
}
2021-03-02 01:02:08 +00:00
var requireCASecretWasCreated = func ( action coretesting . Action ) [ ] byte {
createAction , ok := action . ( coretesting . CreateAction )
r . True ( ok , "should have been able to cast this action to CreateAction: %v" , action )
2021-02-24 18:56:24 +00:00
r . Equal ( "create" , createAction . GetVerb ( ) )
createdSecret := createAction . GetObject ( ) . ( * corev1 . Secret )
2021-03-02 01:02:08 +00:00
r . Equal ( caSecretName , createdSecret . Name )
2021-02-24 18:56:24 +00:00
r . Equal ( installedInNamespace , createdSecret . Namespace )
2021-03-02 01:02:08 +00:00
r . Equal ( corev1 . SecretTypeOpaque , createdSecret . Type )
2021-02-24 18:56:24 +00:00
r . Equal ( labels , createdSecret . Labels )
2021-03-02 01:02:08 +00:00
r . Len ( createdSecret . Data , 2 )
createdCertPEM := createdSecret . Data [ "ca.crt" ]
createdKeyPEM := createdSecret . Data [ "ca.key" ]
r . NotNil ( createdCertPEM )
r . NotNil ( createdKeyPEM )
_ , err := tls . X509KeyPair ( createdCertPEM , createdKeyPEM )
r . NoError ( err , "key does not match cert" )
// Decode and parse the cert to check some of its fields.
block , _ := pem . Decode ( createdCertPEM )
2021-02-26 20:05:17 +00:00
require . NotNil ( t , block )
caCert , err := x509 . ParseCertificate ( block . Bytes )
require . NoError ( t , err )
2021-10-06 15:46:54 +00:00
require . Equal ( t , "Pinniped Impersonation Proxy Serving CA" , caCert . Subject . CommonName )
2021-09-21 13:19:50 +00:00
require . WithinDuration ( t , time . Now ( ) . Add ( - 5 * time . Minute ) , caCert . NotBefore , 10 * time . Second )
2021-02-26 20:05:17 +00:00
require . WithinDuration ( t , time . Now ( ) . Add ( 100 * time . Hour * 24 * 365 ) , caCert . NotAfter , 10 * time . Second )
2021-03-02 01:02:08 +00:00
return createdCertPEM
}
var requireTLSSecretWasCreated = func ( action coretesting . Action , caCert [ ] byte ) {
createAction , ok := action . ( coretesting . CreateAction )
r . True ( ok , "should have been able to cast this action to CreateAction: %v" , action )
r . Equal ( "create" , createAction . GetVerb ( ) )
createdSecret := createAction . GetObject ( ) . ( * corev1 . Secret )
r . Equal ( tlsSecretName , createdSecret . Name )
r . Equal ( installedInNamespace , createdSecret . Namespace )
r . Equal ( corev1 . SecretTypeTLS , createdSecret . Type )
r . Equal ( labels , createdSecret . Labels )
r . Len ( createdSecret . Data , 2 )
createdCertPEM := createdSecret . Data [ corev1 . TLSCertKey ]
createdKeyPEM := createdSecret . Data [ corev1 . TLSPrivateKeyKey ]
r . NotNil ( createdKeyPEM )
r . NotNil ( createdCertPEM )
2021-03-13 00:09:16 +00:00
validCert := testutil . ValidateServerCertificate ( t , string ( caCert ) , string ( createdCertPEM ) )
2021-03-02 01:02:08 +00:00
validCert . RequireMatchesPrivateKey ( string ( createdKeyPEM ) )
2021-09-21 13:19:50 +00:00
validCert . RequireLifetime ( time . Now ( ) . Add ( - 5 * time . Minute ) , time . Now ( ) . Add ( 100 * time . Hour * 24 * 365 ) , 10 * time . Second )
2021-02-18 01:22:13 +00:00
}
2021-03-10 18:30:06 +00:00
var requireSigningCertProviderHasLoadedCerts = func ( certPEM , keyPEM [ ] byte ) {
actualCert , actualKey := signingCertProvider . CurrentCertKeyContent ( )
// Cast to string for better failure messages.
r . Equal ( string ( certPEM ) , string ( actualCert ) )
r . Equal ( string ( keyPEM ) , string ( actualKey ) )
}
var requireSigningCertProviderIsEmpty = func ( ) {
actualCert , actualKey := signingCertProvider . CurrentCertKeyContent ( )
r . Nil ( actualCert )
r . Nil ( actualKey )
}
2021-02-26 21:53:30 +00:00
var runControllerSync = func ( ) error {
return controllerlib . TestSync ( t , subject , * syncContext )
}
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
r = require . New ( t )
2021-03-10 18:30:06 +00:00
queue = & testQueue { }
2021-03-05 01:25:43 +00:00
cancelContext , cancelContextCancelFunc = context . WithCancel ( context . Background ( ) )
2021-05-17 22:08:05 +00:00
pinnipedInformerClient = pinnipedfake . NewSimpleClientset ( )
pinnipedInformers = pinnipedinformers . NewSharedInformerFactoryWithOptions ( pinnipedInformerClient , 0 )
2021-02-12 01:22:47 +00:00
kubeInformerClient = kubernetesfake . NewSimpleClientset ( )
kubeInformers = kubeinformers . NewSharedInformerFactoryWithOptions ( kubeInformerClient , 0 ,
kubeinformers . WithNamespace ( installedInNamespace ) ,
)
kubeAPIClient = kubernetesfake . NewSimpleClientset ( )
2021-03-02 22:48:58 +00:00
pinnipedAPIClient = pinnipedfake . NewSimpleClientset ( )
frozenNow = time . Date ( 2021 , time . March , 2 , 7 , 42 , 0 , 0 , time . Local )
2021-03-15 16:24:07 +00:00
signingCertProvider = dynamiccert . NewCA ( name )
2021-03-10 18:30:06 +00:00
ca := newCA ( )
signingCACertPEM = ca . Bundle ( )
var err error
signingCAKeyPEM , err = ca . PrivateKeyToPEM ( )
r . NoError ( err )
signingCASecret = newSigningKeySecret ( caSignerName , signingCACertPEM , signingCAKeyPEM )
2021-03-13 00:09:16 +00:00
validClientCert , err = ca . IssueClientCert ( "username" , nil , time . Hour )
2021-03-10 18:30:06 +00:00
r . NoError ( err )
2021-05-26 17:42:50 +00:00
testLog = testlogger . New ( t )
2021-02-12 01:22:47 +00:00
} )
it . After ( func ( ) {
2021-03-05 01:25:43 +00:00
cancelContextCancelFunc ( )
2021-03-10 18:30:06 +00:00
closeTestHTTPServer ( )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
when ( "the CredentialIssuer does not yet exist or it was deleted (sync returns an error)" , func ( ) {
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
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 ( )
2021-05-20 17:26:07 +00:00
r . EqualError ( runControllerSync ( ) , ` could not get CredentialIssuer to update: credentialissuer.config.concierge.pinniped.dev "some-credential-issuer-resource-name" not found ` )
2021-05-18 19:16:27 +00:00
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 )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
} )
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 )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
} )
2021-02-12 01:22:47 +00:00
when ( "there are visible control plane nodes" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
2021-02-12 01:22:47 +00:00
} )
2021-02-18 01:22:13 +00:00
it ( "does not start the impersonator or load balancer" , func ( ) {
2021-02-12 01:22:47 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-12 01:22:47 +00:00
requireTLSServerWasNeverStarted ( )
2021-02-18 01:29:56 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 1 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newAutoDisabledStrategy ( ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-18 01:22:13 +00:00
} )
} )
2021-02-24 18:56:24 +00:00
when ( "there are visible control plane nodes and a loadbalancer and a tls Secret" , func ( ) {
2021-02-18 01:22:13 +00:00
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeInformerClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeAPIClient )
2021-03-02 01:02:08 +00:00
addSecretToTrackers ( newEmptySecret ( tlsSecretName ) , kubeAPIClient , kubeInformerClient )
2021-02-18 01:22:13 +00:00
} )
2021-02-24 18:56:24 +00:00
it ( "does not start the impersonator, deletes the loadbalancer, deletes the Secret" , func ( ) {
2021-02-18 01:22:13 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-18 01:22:13 +00:00
requireTLSServerWasNeverStarted ( )
2021-02-24 18:56:24 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-21 16:57:46 +00:00
requireServiceWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] , loadBalancerServiceName )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newAutoDisabledStrategy ( ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-12 01:22:47 +00:00
} )
} )
when ( "there are not visible control plane nodes" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-02-16 23:57:02 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-12 01:22:47 +00:00
} )
2021-02-16 23:57:02 +00:00
it ( "starts the load balancer automatically" , func ( ) {
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-03-02 01:02:08 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-18 01:22:13 +00:00
} )
} )
2021-03-02 22:48:58 +00:00
when ( "there are not visible control plane nodes and a load balancer already exists without an IP/hostname" , func ( ) {
2021-02-18 01:22:13 +00:00
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeInformerClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeAPIClient )
2021-02-18 01:22:13 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-18 01:22:13 +00:00
} )
it ( "does not start the load balancer automatically" , func ( ) {
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 2 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-16 23:57:02 +00:00
} )
2021-02-12 01:22:47 +00:00
} )
2021-02-25 19:40:14 +00:00
when ( "there are not visible control plane nodes and a load balancer already exists with empty ingress" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "" , Hostname : "" } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "" , Hostname : "" } } , kubeAPIClient )
2021-02-25 19:40:14 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-25 19:40:14 +00:00
} )
it ( "does not start the load balancer automatically" , func ( ) {
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 2 )
2021-02-25 19:40:14 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-25 19:40:14 +00:00
} )
} )
when ( "there are not visible control plane nodes and a load balancer already exists with invalid ip" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "not-an-ip" } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "not-an-ip" } } , kubeAPIClient )
2021-02-25 19:40:14 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . EqualError ( runControllerSync ( ) , "could not find valid IP addresses or hostnames from load balancer some-namespace/some-service-resource-name" )
2021-02-25 19:40:14 +00:00
} )
it ( "does not start the load balancer automatically" , func ( ) {
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-03 17:22:35 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 1 )
2021-02-25 19:40:14 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "could not find valid IP addresses or hostnames from load balancer some-namespace/some-service-resource-name" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-25 19:40:14 +00:00
} )
} )
2021-02-26 01:03:34 +00:00
when ( "there are not visible control plane nodes and a load balancer already exists with multiple ips" , func ( ) {
2021-03-03 00:51:35 +00:00
const fakeIP = "127.0.0.123"
2021-02-26 01:03:34 +00:00
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-03-03 00:51:35 +00:00
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : fakeIP } , { IP : "127.0.0.456" } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : fakeIP } , { IP : "127.0.0.456" } } , kubeAPIClient )
2021-02-26 01:03:34 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 01:03:34 +00:00
} )
it ( "starts the impersonator with certs that match the first IP address" , func ( ) {
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-26 01:03:34 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
2021-03-03 00:51:35 +00:00
requireTLSServerIsRunning ( ca , fakeIP , map [ string ] string { fakeIP + ":443" : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-03-03 00:51:35 +00:00
// keeps the secret around after resync
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 ) // nothing changed
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
} )
} )
when ( "there are not visible control plane nodes and a load balancer already exists with multiple hostnames" , func ( ) {
firstHostname := "fake-1.example.com"
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { Hostname : firstHostname } , { Hostname : "fake-2.example.com" } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { Hostname : firstHostname } , { Hostname : "fake-2.example.com" } } , kubeAPIClient )
2021-02-26 01:03:34 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 01:03:34 +00:00
} )
it ( "starts the impersonator with certs that match the first hostname" , func ( ) {
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-26 01:03:34 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunning ( ca , firstHostname , map [ string ] string { firstHostname + httpsPort : testServerAddr ( ) } )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( firstHostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-03-03 00:51:35 +00:00
// keeps the secret around after resync
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 ) // nothing changed
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( firstHostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
} )
} )
when ( "there are not visible control plane nodes and a load balancer already exists with hostnames and ips" , func ( ) {
firstHostname := "fake-1.example.com"
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "127.0.0.254" } , { Hostname : firstHostname } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "127.0.0.254" } , { Hostname : firstHostname } } , kubeAPIClient )
2021-02-26 01:03:34 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 01:03:34 +00:00
} )
it ( "starts the impersonator with certs that match the first hostname" , func ( ) {
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-26 01:03:34 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunning ( ca , firstHostname , map [ string ] string { firstHostname + httpsPort : testServerAddr ( ) } )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( firstHostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-03-03 00:51:35 +00:00
// keeps the secret around after resync
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 ) // nothing changed
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( firstHostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
} )
} )
2021-03-02 01:02:08 +00:00
when ( "there are not visible control plane nodes, a TLS secret exists with multiple hostnames and an IP" , func ( ) {
var caCrt [ ] byte
2021-02-26 01:03:34 +00:00
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeAPIClient )
2021-03-02 01:02:08 +00:00
ca := newCA ( )
caSecret := newActualCASecret ( ca , caSecretName )
caCrt = caSecret . Data [ "ca.crt" ]
addSecretToTrackers ( caSecret , kubeAPIClient , kubeInformerClient )
addSecretToTrackers ( newActualTLSSecretWithMultipleHostnames ( ca , tlsSecretName , localhostIP ) , kubeAPIClient , kubeInformerClient )
2021-02-26 01:03:34 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 01:03:34 +00:00
} )
it ( "deletes and recreates the secret to match the IP in the load balancer without the extra hostnames" , func ( ) {
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , caCrt )
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , caCrt ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 01:03:34 +00:00
} )
} )
2021-02-26 18:58:56 +00:00
when ( "the cert's name needs to change but there is an error while deleting the tls Secret" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "127.0.0.42" } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "127.0.0.42" } } , kubeAPIClient )
2021-03-02 01:02:08 +00:00
ca := newCA ( )
addSecretToTrackers ( newActualCASecret ( ca , caSecretName ) , kubeAPIClient , kubeInformerClient )
addSecretToTrackers ( newActualTLSSecretWithMultipleHostnames ( ca , tlsSecretName , localhostIP ) , kubeAPIClient , kubeInformerClient )
2021-02-26 18:58:56 +00:00
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
} )
it ( "returns an error and runs the proxy without certs" , func ( ) {
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . Error ( runControllerSync ( ) , "error on delete" )
2021-02-26 18:58:56 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 2 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "error on delete" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-26 18:58:56 +00:00
} )
} )
when ( "the cert's name might need to change but there is an error while determining the new name" , func ( ) {
2021-03-02 01:02:08 +00:00
var caCrt [ ] byte
2021-02-26 18:58:56 +00:00
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeAPIClient )
2021-03-02 01:02:08 +00:00
ca := newCA ( )
caSecret := newActualCASecret ( ca , caSecretName )
caCrt = caSecret . Data [ "ca.crt" ]
addSecretToTrackers ( caSecret , kubeAPIClient , kubeInformerClient )
tlsSecret := newActualTLSSecret ( ca , tlsSecretName , localhostIP )
addSecretToTrackers ( tlsSecret , kubeAPIClient , kubeInformerClient )
2021-02-26 18:58:56 +00:00
} )
2021-03-10 18:30:06 +00:00
it ( "returns an error and keeps the proxy running but now without certs" , func ( ) {
2021-02-26 18:58:56 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 18:58:56 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 1 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil )
2021-02-26 18:58:56 +00:00
2021-03-04 23:36:51 +00:00
updateLoadBalancerServiceInInformerAndWait ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : "not-an-ip" } } , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-02-26 18:58:56 +00:00
2021-03-02 22:48:58 +00:00
errString := "could not find valid IP addresses or hostnames from load balancer some-namespace/some-service-resource-name"
r . EqualError ( runControllerSync ( ) , errString )
2021-08-10 16:05:04 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 1 ) // no new actions
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil ) // serving certificate is not unloaded in this case
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 18:58:56 +00:00
} )
} )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
when ( "the configuration is disabled mode" , func ( ) {
2021-03-10 18:30:06 +00:00
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-03-10 18:30:06 +00:00
} )
2021-05-18 19:16:27 +00:00
it ( "does not start the impersonator" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
requireTLSServerWasNeverStarted ( )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
r . Len ( kubeAPIClient . Actions ( ) , 1 )
requireCredentialIssuer ( newManuallyDisabledStrategy ( ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
when ( "the configuration is enabled mode" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
} )
when ( "no load balancer" , func ( ) {
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator and creates a load balancer" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
it ( "returns an error when the impersonation TLS server fails to start" , func ( ) {
impersonatorFuncError = errors . New ( "impersonation server start error" )
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "impersonation server start error" )
requireCredentialIssuer ( newErrorStrategy ( "impersonation server start error" ) )
requireSigningCertProviderIsEmpty ( )
2021-02-12 01:22:47 +00:00
} )
} )
2021-05-18 19:16:27 +00:00
when ( "a loadbalancer already exists" , func ( ) {
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-05-18 19:16:27 +00:00
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeInformerClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeAPIClient )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator without creating a load balancer" , func ( ) {
2021-02-12 01:22:47 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-05-18 19:16:27 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 2 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-18 19:16:27 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-12 01:22:47 +00:00
} )
2021-02-18 01:22:13 +00:00
2021-05-18 19:16:27 +00:00
it ( "returns an error when the impersonation TLS server fails to start" , func ( ) {
impersonatorFuncError = errors . New ( "impersonation server start error" )
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "impersonation server start error" )
requireCredentialIssuer ( newErrorStrategy ( "impersonation server start error" ) )
requireSigningCertProviderIsEmpty ( )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-12 01:22:47 +00:00
2021-05-20 18:57:07 +00:00
when ( "a clusterip already exists with ingress" , func ( ) {
const fakeIP = "127.0.0.123"
it . Before ( func ( ) {
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addClusterIPServiceToTracker ( clusterIPServiceName , fakeIP , kubeInformerClient )
addClusterIPServiceToTracker ( clusterIPServiceName , fakeIP , kubeAPIClient )
} )
it ( "starts the impersonator without creating a clusterip" , 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 , fakeIP , map [ string ] string { fakeIP + ":443" : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
// requireSigningCertProviderHasLoadedCerts()
} )
} )
2021-05-26 00:01:42 +00:00
when ( "a clusterip service exists with dual stack ips" , func ( ) {
const fakeIP1 = "127.0.0.123"
2021-05-26 17:30:33 +00:00
const fakeIP2 = "fd00::5118"
2021-05-26 00:01:42 +00:00
it . Before ( func ( ) {
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
addDualStackClusterIPServiceToTracker ( clusterIPServiceName , fakeIP1 , fakeIP2 , kubeInformerClient )
addDualStackClusterIPServiceToTracker ( clusterIPServiceName , fakeIP1 , fakeIP2 , kubeAPIClient )
} )
it ( "certs are valid for both ip addresses" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
2021-05-26 17:30:33 +00:00
requireTLSServerIsRunning ( ca , "[" + fakeIP2 + "]" , map [ string ] string { "[fd00::5118]:443" : testServerAddr ( ) } )
2021-05-26 00:01:42 +00:00
requireTLSServerIsRunning ( ca , fakeIP1 , map [ string ] string { fakeIP1 + ":443" : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP1 , ca ) )
} )
} )
2021-05-18 19:16:27 +00:00
when ( "a load balancer and a secret already exists" , func ( ) {
var caCrt [ ] byte
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
ca := newCA ( )
caSecret := newActualCASecret ( ca , caSecretName )
caCrt = caSecret . Data [ "ca.crt" ]
addSecretToTrackers ( caSecret , kubeAPIClient , kubeInformerClient )
tlsSecret := newActualTLSSecret ( ca , tlsSecretName , localhostIP )
addSecretToTrackers ( tlsSecret , kubeAPIClient , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeAPIClient )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator with the existing tls certs, does not start loadbalancer or make tls secret" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 1 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , caCrt ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-25 00:03:17 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-25 00:03:17 +00:00
2021-05-18 23:54:59 +00:00
when ( "credentialissuer has service type loadbalancer and custom annotations" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
2021-07-23 00:09:50 +00:00
Annotations : map [ string ] string { "some-annotation-key" : "some-annotation-value" } ,
2021-05-20 17:26:07 +00:00
} ,
2021-05-18 23:54:59 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 23:54:59 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator, generates a valid cert for the specified hostname, starts a loadbalancer" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
lbService := requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-07-23 00:09:50 +00:00
require . Equal ( t , lbService . Annotations , map [ string ] string {
"some-annotation-key" : "some-annotation-value" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["some-annotation-key"] ` ,
} )
2021-05-18 23:54:59 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-05-18 23:54:59 +00:00
} )
} )
2021-05-18 19:16:27 +00:00
when ( "the CredentialIssuer has a hostname specified and service type none" , func ( ) {
const fakeHostname = "fake.example.com"
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-02-25 01:08:58 +00:00
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator, generates a valid cert for the specified hostname" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-25 18:27:19 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-25 18:27:19 +00:00
2021-05-18 20:50:52 +00:00
when ( "the CredentialIssuer has a hostname specified and service type loadbalancer" , func ( ) {
const fakeHostname = "fake.example.com"
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
} ,
2021-05-18 20:50:52 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 20:50:52 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator, generates a valid cert for the specified hostname, starts a loadbalancer" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-05-20 00:00:28 +00:00
when ( "the CredentialIssuer has a hostname specified and service type clusterip" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
2021-05-20 00:00:28 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-20 00:00:28 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator and creates a clusterip service" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireClusterIPWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
// Check that the server is running without certs.
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-05-20 00:00:28 +00:00
} )
} )
2021-05-18 19:16:27 +00:00
when ( "the CredentialIssuer has a endpoint which is an IP address with a port" , func ( ) {
const fakeIPWithPort = "127.0.0.1:3000"
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeIPWithPort ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-02-26 23:01:38 +00:00
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator, generates a valid cert for the specified IP address" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeIPWithPort.
requireTLSServerIsRunning ( ca , fakeIPWithPort , map [ string ] string { fakeIPWithPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIPWithPort , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 23:01:38 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-26 23:01:38 +00:00
2021-05-18 19:16:27 +00:00
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 ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostnameWithPort ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-02-26 23:01:38 +00:00
2021-05-18 19:16:27 +00:00
it ( "starts the impersonator, generates a valid cert for the specified hostname" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostnameWithPort.
requireTLSServerIsRunning ( ca , fakeHostnameWithPort , map [ string ] string { fakeHostnameWithPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostnameWithPort , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 23:01:38 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-26 23:01:38 +00:00
2021-05-18 23:54:59 +00:00
when ( "the CredentialIssuer has a endpoint which is a hostname with a port, service type loadbalancer with loadbalancerip" , func ( ) {
2021-05-18 20:50:52 +00:00
const fakeHostnameWithPort = "fake.example.com:3000"
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostnameWithPort ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
LoadBalancerIP : localhostIP ,
} ,
2021-05-18 20:50:52 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 20:50:52 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator, starts the loadbalancer, generates a valid cert for the specified hostname" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-18 23:54:59 +00:00
lbService := requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , lbService . Spec . LoadBalancerIP , localhostIP )
2021-05-18 20:50:52 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostnameWithPort.
requireTLSServerIsRunning ( ca , fakeHostnameWithPort , map [ string ] string { fakeHostnameWithPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostnameWithPort , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-05-18 19:16:27 +00:00
when ( "switching the CredentialIssuer from ip address endpoint to hostname endpoint and back to ip address" , func ( ) {
const fakeHostname = "fake.example.com"
const fakeIP = "127.0.0.42"
2021-05-17 22:08:05 +00:00
2021-05-18 19:16:27 +00:00
var hostnameConfig = v1alpha1 . CredentialIssuerSpec {
2021-05-19 16:40:32 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
2021-05-18 19:16:27 +00:00
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
}
var ipAddressConfig = v1alpha1 . CredentialIssuerSpec {
2021-05-19 16:40:32 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
2021-05-18 19:16:27 +00:00
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
}
2021-02-25 18:27:19 +00:00
2021-05-18 19:16:27 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : ipAddressConfig ,
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-02-25 01:08:58 +00:00
} )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
it ( "regenerates the cert for the hostname, then regenerates it for the IP again" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeIP.
requireTLSServerIsRunning ( ca , fakeIP , map [ string ] string { fakeIP + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
// Switch the endpoint config to a hostname.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , hostnameConfig , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 4 ] , ca ) // reuses the old CA
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
// Simulate the informer cache's background update from its watch.
deleteSecretFromTracker ( tlsSecretName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( tlsSecretName , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 4 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
// Switch the endpoint config back to an IP.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , ipAddressConfig , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
2021-03-02 01:02:08 +00:00
2021-05-18 19:16:27 +00:00
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 7 )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 5 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 6 ] , ca ) // reuses the old CA again
// Check that the server is running and that TLS certs that are being served are are for fakeIP.
requireTLSServerIsRunning ( ca , fakeIP , map [ string ] string { fakeIP + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
} )
2021-02-12 01:22:47 +00:00
} )
2021-05-18 19:16:27 +00:00
when ( "the TLS cert goes missing and needs to be recreated, e.g. when a user manually deleted it" , func ( ) {
const fakeHostname = "fake.example.com"
2021-02-12 01:22:47 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-02-12 01:22:47 +00:00
startInformersAndController ( )
2021-05-18 19:16:27 +00:00
} )
2021-02-12 01:22:47 +00:00
2021-05-18 19:16:27 +00:00
it ( "uses the existing CA cert the make a new TLS cert" , func ( ) {
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-18 19:16:27 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-18 01:22:13 +00:00
2021-02-26 21:53:30 +00:00
// Simulate the informer cache's background update from its watch.
2021-05-18 19:16:27 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-02-12 01:22:47 +00:00
2021-05-18 19:16:27 +00:00
// Delete the TLS Secret that was just created from the Kube API server. Note that we never
// simulated it getting added to the informer cache, so we don't need to remove it from there.
deleteSecretFromTracker ( tlsSecretName , kubeAPIClient )
2021-02-12 01:22:47 +00:00
2021-05-18 19:16:27 +00:00
// Run again. It should create a new TLS cert using the old CA cert.
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 )
2021-05-18 19:16:27 +00:00
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-02-12 01:22:47 +00:00
2021-05-18 19:16:27 +00:00
when ( "the CA cert goes missing and needs to be recreated, e.g. when a user manually deleted it" , func ( ) {
const fakeHostname = "fake.example.com"
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
startInformersAndController ( )
} )
2021-02-12 01:22:47 +00:00
2021-05-18 19:16:27 +00:00
it ( "makes a new CA cert, deletes the old TLS cert, and makes a new TLS cert using the new CA" , func ( ) {
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-05-18 19:16:27 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Delete the CA Secret that was just created from the Kube API server. Note that we never
// simulated it getting added to the informer cache, so we don't need to remove it from there.
deleteSecretFromTracker ( caSecretName , kubeAPIClient )
// Run again. It should create both a new CA cert and a new TLS cert using the new CA cert.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 6 )
ca = requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 4 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 5 ] , ca ) // created using the new CA
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-12 01:22:47 +00:00
} )
} )
2021-02-16 23:57:02 +00:00
2021-05-18 19:16:27 +00:00
when ( "the CA cert is overwritten by another valid CA cert" , func ( ) {
const fakeHostname = "fake.example.com"
var caCrt [ ] byte
2021-02-16 23:57:02 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-02-16 23:57:02 +00:00
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-18 01:22:13 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-18 19:16:27 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
2021-05-18 19:16:27 +00:00
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-16 23:57:02 +00:00
2021-02-26 21:53:30 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-02-25 00:03:17 +00:00
2021-05-18 19:16:27 +00:00
// Simulate someone updating the CA Secret out of band, e.g. when a human edits it with kubectl.
// Delete the CA Secret that was just created from the Kube API server. Note that we never
// simulated it getting added to the informer cache, so we don't need to remove it from there.
// Then add a new one. Delete + new = update, since only the final state is observed.
deleteSecretFromTracker ( caSecretName , kubeAPIClient )
anotherCA := newCA ( )
newCASecret := newActualCASecret ( anotherCA , caSecretName )
caCrt = newCASecret . Data [ "ca.crt" ]
addSecretToTrackers ( newCASecret , kubeAPIClient )
addObjectToKubeInformerAndWait ( newCASecret , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
} )
2021-02-16 23:57:02 +00:00
2021-05-18 19:16:27 +00:00
it ( "deletes the old TLS cert and makes a new TLS cert using the new CA" , func ( ) {
// Run again. It should use the updated CA cert to create a new TLS cert.
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 5 )
2021-05-18 19:16:27 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 4 ] , caCrt ) // created using the updated CA
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( caCrt , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , caCrt ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
2021-02-18 01:22:13 +00:00
2021-05-18 19:16:27 +00:00
when ( "deleting the TLS cert due to mismatched CA results in an error" , func ( ) {
it . Before ( func ( ) {
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
if action . ( coretesting . DeleteAction ) . GetName ( ) == tlsSecretName {
return true , nil , fmt . Errorf ( "error on tls secret delete" )
}
return false , nil , nil
} )
} )
2021-02-16 23:57:02 +00:00
2021-05-18 19:16:27 +00:00
it ( "returns an error" , func ( ) {
r . Error ( runControllerSync ( ) , "error on tls secret delete" )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] ) // tried to delete cert but failed
requireCredentialIssuer ( newErrorStrategy ( "error on tls secret delete" ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-05-18 19:16:27 +00:00
} )
} )
} )
} )
2021-02-25 00:03:17 +00:00
2021-05-18 19:16:27 +00:00
when ( "the configuration switches from enabled to disabled mode" , func ( ) {
2021-05-20 18:57:07 +00:00
when ( "service type loadbalancer" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator and loadbalancer, then shuts it down, then starts it again" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM ) // load when enabled
2021-05-20 18:57:07 +00:00
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Update the CredentialIssuer.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsNoLongerRunning ( )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
2021-05-21 16:57:46 +00:00
requireServiceWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] , loadBalancerServiceName )
2021-05-20 18:57:07 +00:00
requireCredentialIssuer ( newManuallyDisabledStrategy ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderIsEmpty ( ) // only unload when disabled
2021-05-20 18:57:07 +00:00
deleteServiceFromTracker ( loadBalancerServiceName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( loadBalancerServiceName , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
// Update the CredentialIssuer again.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
2021-05-20 17:26:07 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
2021-05-20 18:57:07 +00:00
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 5 )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 4 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM ) // load again when enabled
2021-05-20 18:57:07 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
2021-02-25 00:03:17 +00:00
2021-05-20 18:57:07 +00:00
when ( "service type clusterip" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-02-26 18:58:56 +00:00
2021-05-20 18:57:07 +00:00
it ( "starts the impersonator and clusterip, then shuts it down, then starts it again" , func ( ) {
startInformersAndController ( )
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireClusterIPWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM ) // load when enabled
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
// Update the CredentialIssuer.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
r . NoError ( runControllerSync ( ) )
requireTLSServerIsNoLongerRunning ( )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
2021-05-21 16:57:46 +00:00
requireServiceWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] , clusterIPServiceName )
2021-05-20 18:57:07 +00:00
requireCredentialIssuer ( newManuallyDisabledStrategy ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderIsEmpty ( ) // only unload when disabled
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
deleteServiceFromTracker ( clusterIPServiceName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( clusterIPServiceName , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-05-18 19:16:27 +00:00
2021-05-20 18:57:07 +00:00
// Update the CredentialIssuer again.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 5 )
requireClusterIPWasCreated ( kubeAPIClient . Actions ( ) [ 4 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM ) // load again when enabled
} )
} )
when ( "service type none with a hostname" , func ( ) {
const fakeHostname = "hello.com"
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "starts the impersonator, then shuts it down, then starts it again" , 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 , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
// load when enabled
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
requireTLSSecretProviderHasLoadedCerts ( )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Update the CredentialIssuer.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsNoLongerRunning ( )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 3 ] )
requireCredentialIssuer ( newManuallyDisabledStrategy ( ) )
// only unload when disabled
2021-05-20 18:57:07 +00:00
requireSigningCertProviderIsEmpty ( )
2021-08-10 16:05:04 +00:00
requireTLSSecretProviderIsEmpty ( )
deleteSecretFromTracker ( tlsSecretName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( tlsSecretName , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Update the CredentialIssuer again.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
r . Len ( kubeAPIClient . Actions ( ) , 5 )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 4 ] , ca )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
// load again when enabled
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
requireTLSSecretProviderHasLoadedCerts ( )
2021-05-20 18:57:07 +00:00
} )
2021-05-18 19:16:27 +00:00
} )
} )
when ( "the endpoint and mode switch from specified with no service, to not specified, to specified again" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 19:16:27 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-02-16 23:57:02 +00:00
2021-05-18 19:16:27 +00:00
it ( "doesn't create, then creates, then deletes the load balancer" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with an "endpoint", so no load balancer is needed.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] ) // created immediately because "endpoint" was specified
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Switch to "enabled" mode without an "endpoint", so a load balancer is needed now.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
2021-05-19 16:40:32 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
2021-05-18 19:16:27 +00:00
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 4 ] ) // the Secret was deleted because it contained a cert with the wrong IP
2021-08-10 16:05:04 +00:00
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil ) // serving certificate is not unloaded in this case
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-05-18 19:16:27 +00:00
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
deleteSecretFromTracker ( tlsSecretName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( tlsSecretName , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// The controller should be waiting for the load balancer's ingress to become available.
r . NoError ( runControllerSync ( ) )
2021-08-10 16:05:04 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 5 ) // no new actions while it is waiting for the load balancer's ingress
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil ) // serving certificate is not unloaded in this case
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-05-18 19:16:27 +00:00
// Update the ingress of the LB in the informer's client and run Sync again.
fakeIP := "127.0.0.123"
updateLoadBalancerServiceInInformerAndWait ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : fakeIP } } , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 6 )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 5 ] , ca ) // reuses the existing CA
// Check that the server is running and that TLS certs that are being served are are for fakeIP.
requireTLSServerIsRunning ( ca , fakeIP , map [ string ] string { fakeIP + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// 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 and explicitly saying that we don't want the load balancer service.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
2021-05-19 16:40:32 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
2021-05-18 19:16:27 +00:00
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 9 )
2021-05-21 16:57:46 +00:00
requireServiceWasDeleted ( kubeAPIClient . Actions ( ) [ 6 ] , loadBalancerServiceName )
2021-05-18 19:16:27 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 7 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 8 ] , ca ) // recreated because the endpoint was updated, reused the old CA
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-16 23:57:02 +00:00
} )
} )
2021-05-18 23:54:59 +00:00
when ( "requesting a load balancer via CredentialIssuer, then updating the annotations" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
} ,
2021-05-18 23:54:59 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 23:54:59 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "creates the load balancer without annotations, then adds them" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with service type load balancer, so one is created.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
lbService := requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , map [ string ] string ( nil ) , lbService . Annotations ) // there should be no annotations at first
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-07-23 00:09:50 +00:00
// Simulate another actor in the system, like a human user or a non-Pinniped controller,
// updating the new Service's annotations. The map was nil, so we can overwrite the whole thing,
lbService . Annotations = map [ string ] string {
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
"my-annotation-key" : "my-annotation-from-unrelated-controller-val" ,
}
2021-05-18 23:54:59 +00:00
// Simulate the informer cache's background update from its watch.
2021-07-23 00:09:50 +00:00
addObjectToKubeInformerAndWait ( lbService , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-05-18 23:54:59 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-07-23 00:09:50 +00:00
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 ) // no new actions because the controller decides there is nothing to update on the Service
// Add annotations to the CredentialIssuer spec.
credentialIssuerAnnotations := map [ string ] string { "my-annotation-key" : "my-annotation-val" }
2021-05-18 23:54:59 +00:00
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
2021-05-19 16:40:32 +00:00
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
2021-05-18 23:54:59 +00:00
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
2021-07-23 00:09:50 +00:00
Annotations : credentialIssuerAnnotations ,
2021-05-18 23:54:59 +00:00
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 ) // one more item to update the loadbalancer
lbService = requireLoadBalancerWasUpdated ( kubeAPIClient . Actions ( ) [ 4 ] )
2021-07-23 00:09:50 +00:00
require . Equal ( t , map [ string ] string {
// Now the CredentialIssuer annotations should be merged on the load balancer.
// In the unlikely case where keys conflict, the CredentialIssuer value overwrites the other value.
// Otherwise the annotations from the other actor should not be modified.
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
"my-annotation-key" : "my-annotation-val" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["my-annotation-key"] ` ,
} , lbService . Annotations )
2021-05-18 23:54:59 +00:00
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-05-20 23:21:10 +00:00
when ( "requesting a cluster ip via CredentialIssuer, then updating the annotations" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "creates the cluster ip without annotations, then adds them" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with service type load balancer, so one is created.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
clusterIPService := requireClusterIPWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , map [ string ] string ( nil ) , clusterIPService . Annotations ) // there should be no annotations at first
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-07-23 00:09:50 +00:00
// Simulate another actor in the system, like a human user or a non-Pinniped controller,
// updating the new Service's annotations.
clusterIPService . Annotations = map [ string ] string {
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
"my-annotation-key" : "my-annotation-from-unrelated-controller-val" ,
}
2021-05-20 23:21:10 +00:00
// Simulate the informer cache's background update from its watch.
2021-07-23 00:09:50 +00:00
addObjectToKubeInformerAndWait ( clusterIPService , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-05-20 23:21:10 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-07-23 00:09:50 +00:00
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 ) // no new actions because the controller decides there is nothing to update on the Service
// Add annotations to the CredentialIssuer spec.
credentialIssuerAnnotations := map [ string ] string { "my-annotation-key" : "my-annotation-val" }
2021-05-20 23:21:10 +00:00
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
2021-07-23 00:09:50 +00:00
Annotations : credentialIssuerAnnotations ,
2021-05-20 23:21:10 +00:00
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 ) // one more item to update the loadbalancer
clusterIPService = requireClusterIPWasUpdated ( kubeAPIClient . Actions ( ) [ 4 ] )
2021-07-23 00:09:50 +00:00
require . Equal ( t , map [ string ] string {
// Now the CredentialIssuer annotations should be merged on the load balancer.
// In the unlikely case where keys conflict, the CredentialIssuer value overwrites the other value.
// Otherwise the annotations from the other actor should not be modified.
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
"my-annotation-key" : "my-annotation-val" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["my-annotation-key"] ` ,
} , clusterIPService . Annotations )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
when ( "requesting a load balancer via CredentialIssuer with annotations, then updating the CredentialIssuer annotations to remove one" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
Annotations : map [ string ] string {
"my-initial-annotation1-key" : "my-initial-annotation1-val" ,
"my-initial-annotation2-key" : "my-initial-annotation2-val" ,
"my-initial-annotation3-key" : "my-initial-annotation3-val" ,
} ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "creates the load balancer with annotations, then removes the removed annotation" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with service type load balancer, so one is created.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
lbService := requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , map [ string ] string {
"my-initial-annotation1-key" : "my-initial-annotation1-val" ,
"my-initial-annotation2-key" : "my-initial-annotation2-val" ,
"my-initial-annotation3-key" : "my-initial-annotation3-val" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["my-initial-annotation1-key","my-initial-annotation2-key","my-initial-annotation3-key"] ` ,
} , lbService . Annotations ) // there should be some annotations at first
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Simulate another actor in the system, like a human user or a non-Pinniped controller,
// updating the new Service to add another annotation.
lbService . Annotations [ "annotation-from-unrelated-controller-key" ] = "annotation-from-unrelated-controller-val"
// Simulate the informer cache's background update from its watch.
addObjectToKubeInformerAndWait ( lbService , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 ) // no new actions because the controller decides there is nothing to update on the Service
// Remove one of the annotations from the CredentialIssuer spec.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
Annotations : map [ string ] string {
"my-initial-annotation1-key" : "my-initial-annotation1-val" ,
"my-initial-annotation3-key" : "my-initial-annotation3-val" ,
} ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 ) // one more item to update the loadbalancer
lbService = requireLoadBalancerWasUpdated ( kubeAPIClient . Actions ( ) [ 4 ] )
require . Equal ( t , map [ string ] string {
// Now the CredentialIssuer annotations should be merged on the load balancer.
// Since the user removed the "my-initial-annotation2-key" key from the CredentialIssuer spec,
// it should be removed from the Service.
// The annotations from the other actor should not be modified.
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
"my-initial-annotation1-key" : "my-initial-annotation1-val" ,
"my-initial-annotation3-key" : "my-initial-annotation3-val" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["my-initial-annotation1-key","my-initial-annotation3-key"] ` ,
} , lbService . Annotations )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Remove all the rest of the annotations from the CredentialIssuer spec so there are none remaining.
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
Annotations : map [ string ] string { } ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 6 ) // one more item to update the loadbalancer
lbService = requireLoadBalancerWasUpdated ( kubeAPIClient . Actions ( ) [ 5 ] )
require . Equal ( t , map [ string ] string {
// Since the user removed all annotations from the CredentialIssuer spec,
// they should all be removed from the Service, along with the special bookkeeping annotation too.
// The annotations from the other actor should not be modified.
"annotation-from-unrelated-controller-key" : "annotation-from-unrelated-controller-val" ,
} , lbService . Annotations )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
when ( "requesting a load balancer via CredentialIssuer, but there is already a load balancer with an invalid bookkeeping annotation value" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
Annotations : map [ string ] string { "some-annotation" : "annotation-value" } ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
// Add a Service with a messed up bookkeeping annotation.
loadBalancerService := newLoadBalancerService ( loadBalancerServiceName , corev1 . ServiceStatus { } )
loadBalancerService . Annotations = map [ string ] string {
annotationKeysKey : ` ["this is not valid json ` ,
}
addServiceToTrackers ( loadBalancerService , kubeInformerClient , kubeAPIClient )
} )
it ( "just acts like the annotation wasn't present since that is better than becoming inoperable" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with service type load balancer, so one is created.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
lbService := requireLoadBalancerWasUpdated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , map [ string ] string {
"some-annotation" : "annotation-value" ,
"credentialissuer.pinniped.dev/annotation-keys" : ` ["some-annotation"] ` ,
} , lbService . Annotations )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
2021-05-20 23:21:10 +00:00
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-05-19 21:16:15 +00:00
when ( "requesting a load balancer via CredentialIssuer, then adding a static loadBalancerIP to the spec" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
} ,
2021-05-19 21:16:15 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-19 21:16:15 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "creates the load balancer without loadBalancerIP set, then adds it" , func ( ) {
startInformersAndController ( )
// Should have started in "enabled" mode with service type load balancer, so one is created.
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
lbService := requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
require . Equal ( t , map [ string ] string ( nil ) , lbService . Annotations ) // there should be no annotations at first
require . Equal ( t , "" , lbService . Spec . LoadBalancerIP )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Add annotations to the spec.
loadBalancerIP := "1.2.3.4"
updateCredentialIssuerInInformerAndWait ( credentialIssuerResourceName , v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeLoadBalancer ,
LoadBalancerIP : loadBalancerIP ,
} ,
} ,
} , pinnipedInformers . Config ( ) . V1alpha1 ( ) . CredentialIssuers ( ) )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 5 ) // one more item to update the loadbalancer
lbService = requireLoadBalancerWasUpdated ( kubeAPIClient . Actions ( ) [ 4 ] )
require . Equal ( t , loadBalancerIP , lbService . Spec . LoadBalancerIP )
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
2021-03-02 01:02:08 +00:00
when ( "sync is called more than once" , func ( ) {
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-03-02 01:02:08 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
} )
it ( "only starts the impersonator once and only lists the cluster's nodes once" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-10 18:30:06 +00:00
r . Equal ( 1 , impersonatorFuncWasCalled ) // wasn't started a second time
requireTLSServerIsRunningWithoutCerts ( ) // still running
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 22:48:58 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 ) // no new API calls
2021-03-02 01:02:08 +00:00
} )
it ( "creates certs from the ip address listed on the load balancer" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
2021-03-04 23:36:51 +00:00
updateLoadBalancerServiceInInformerAndWait ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-03-02 01:02:08 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-10 18:30:06 +00:00
r . Equal ( 1 , impersonatorFuncWasCalled ) // wasn't started a second time
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca ) // uses the ca from last time
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil ) // running with certs now
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-10 18:30:06 +00:00
r . Equal ( 1 , impersonatorFuncWasCalled ) // wasn't started again
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 ) // no more actions
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil ) // still running
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
} )
it ( "creates certs from the hostname listed on the load balancer" , func ( ) {
hostname := "fake.example.com"
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-04 21:52:34 +00:00
2021-03-04 23:36:51 +00:00
updateLoadBalancerServiceInInformerAndWait ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP , Hostname : hostname } } , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
2021-03-02 01:02:08 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-10 18:30:06 +00:00
r . Equal ( 1 , impersonatorFuncWasCalled ) // wasn't started a second time
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca ) // uses the ca from last time
requireTLSServerIsRunning ( ca , hostname , map [ string ] string { hostname + httpsPort : testServerAddr ( ) } ) // running with certs now
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( hostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
// Simulate the informer cache's background update from its watch.
2021-03-04 23:36:51 +00:00
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 3 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-03-02 01:02:08 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-10 18:30:06 +00:00
r . Equal ( 1 , impersonatorFuncWasCalled ) // wasn't started a third time
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 ) // no more actions
requireTLSServerIsRunning ( ca , hostname , map [ string ] string { hostname + httpsPort : testServerAddr ( ) } ) // still running
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( hostname , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
} )
} )
when ( "there is already a CredentialIssuer" , func ( ) {
preExistingStrategy := v1alpha1 . CredentialIssuerStrategy {
Type : v1alpha1 . KubeClusterSigningCertificateStrategyType ,
Status : v1alpha1 . SuccessStrategyStatus ,
Reason : v1alpha1 . FetchedKeyStrategyReason ,
Message : "happy other unrelated strategy" ,
LastUpdateTime : metav1 . NewTime ( frozenNow ) ,
Frontend : & v1alpha1 . CredentialIssuerFrontend {
Type : v1alpha1 . TokenCredentialRequestAPIFrontendType ,
} ,
}
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
2021-03-10 18:30:06 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
2021-05-20 17:26:07 +00:00
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
} ,
Status : v1alpha1 . CredentialIssuerStatus {
Strategies : [ ] v1alpha1 . CredentialIssuerStrategy {
preExistingStrategy ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-10 18:30:06 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
it ( "merges into the existing strategy array on the CredentialIssuer" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
credentialIssuer := getCredentialIssuer ( )
2021-05-27 16:13:10 +00:00
r . Equal ( [ ] v1alpha1 . CredentialIssuerStrategy { preExistingStrategy , newPendingStrategyWaitingForLB ( ) } , credentialIssuer . Status . Strategies )
2021-03-02 01:02:08 +00:00
} )
} )
when ( "getting the control plane nodes returns an error, e.g. when there are no nodes" , func ( ) {
it ( "returns an error" , func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "no nodes found" )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "no nodes found" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-03-02 01:02:08 +00:00
requireTLSServerWasNeverStarted ( )
} )
} )
2021-03-10 18:30:06 +00:00
when ( "the impersonator start function returned by the impersonatorFunc returns an error immediately" , func ( ) {
2021-03-02 01:02:08 +00:00
it . Before ( func ( ) {
2021-08-10 16:05:04 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-03-02 01:02:08 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-03-10 18:30:06 +00:00
impersonatorFuncReturnedFuncError = errors . New ( "some immediate impersonator startup error" )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
} )
2021-03-10 18:30:06 +00:00
it ( "causes an immediate resync, returns an error on that next sync, and then restarts the server in a following sync" , func ( ) {
2021-03-02 01:02:08 +00:00
startInformersAndController ( )
2021-03-10 18:30:06 +00:00
// The failure happens in a background goroutine, so the first sync succeeds.
r . NoError ( runControllerSync ( ) )
2021-03-10 19:24:42 +00:00
// The imperonatorFunc was called to construct an impersonator.
2021-03-10 18:30:06 +00:00
r . Equal ( impersonatorFuncWasCalled , 1 )
2021-03-10 19:24:42 +00:00
// Without waiting too long because we don't want the test to be slow, check if it seems like the
// server never started.
r . Never ( func ( ) bool {
testHTTPServerMutex . RLock ( ) // this is to satisfy the race detector
defer testHTTPServerMutex . RUnlock ( )
return testHTTPServer != nil
} , 2 * time . Second , 50 * time . Millisecond )
2021-03-10 18:30:06 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// The controller's first sync should have started a background routine which, when the server dies,
// requests to re-enqueue the original sync key to cause its sync method to get called again in the near future.
r . Eventually ( func ( ) bool {
queue . mutex . RLock ( ) // this is to satisfy the race detector
defer queue . mutex . RUnlock ( )
return syncContext . Key == queue . key
} , 10 * time . Second , 10 * time . Millisecond )
// The next sync should error because the server died in the background. This second
// sync should be able to detect the error and return it.
r . EqualError ( runControllerSync ( ) , "some immediate impersonator startup error" )
requireCredentialIssuer ( newErrorStrategy ( "some immediate impersonator startup error" ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
// Next time the controller starts the server, the server will start successfully.
impersonatorFuncReturnedFuncError = nil
// One more sync and the controller should try to restart the server.
// Now everything should be working correctly.
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
} )
} )
when ( "the impersonator server dies for no apparent reason after running for a while" , func ( ) {
it . Before ( func ( ) {
2021-08-10 16:05:04 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-03-10 18:30:06 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-10 18:30:06 +00:00
} )
it ( "causes an immediate resync, returns an error on that next sync, and then restarts the server in a following sync" , func ( ) {
// Prepare to be able to cause the server to die for no apparent reason.
testHTTPServerInterruptCh = make ( chan struct { } )
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireLoadBalancerWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
requireTLSServerIsRunningWithoutCerts ( )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Services ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Simulate that impersonation server dies for no apparent reason.
close ( testHTTPServerInterruptCh )
// The controller's first sync should have started a background routine which, when the server dies,
// requests to re-enqueue the original sync key to cause its sync method to get called again in the near future.
r . Eventually ( func ( ) bool {
queue . mutex . RLock ( ) // this is to satisfy the race detector
defer queue . mutex . RUnlock ( )
return syncContext . Key == queue . key
} , 10 * time . Second , 10 * time . Millisecond )
// The next sync should error because the server died in the background. This second
// sync should be able to detect the error and return it.
r . EqualError ( runControllerSync ( ) , "unexpected shutdown of proxy server" )
requireCredentialIssuer ( newErrorStrategy ( "unexpected shutdown of proxy server" ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
// Next time the controller starts the server, the server should behave as normal.
testHTTPServerInterruptCh = nil
// One more sync and the controller should try to restart the server.
// Now everything should be working correctly.
r . NoError ( runControllerSync ( ) )
requireTLSServerIsRunningWithoutCerts ( )
2021-05-27 16:13:10 +00:00
requireCredentialIssuer ( newPendingStrategyWaitingForLB ( ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-02 01:02:08 +00:00
} )
} )
2021-05-19 16:40:32 +00:00
when ( "the CredentialIssuer has nil impersonation spec" , func ( ) {
2021-03-02 01:02:08 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : nil ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-19 16:40:32 +00:00
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
errString := ` could not load CredentialIssuer: spec.impersonationProxy is nil `
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerWasNeverStarted ( )
} )
} )
when ( "the CredentialIssuer has invalid mode" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : "not-valid" ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
2021-05-19 16:40:32 +00:00
errString := ` could not load CredentialIssuer spec.impersonationProxy: invalid proxy mode "not-valid" (expected auto, disabled, or enabled) `
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerWasNeverStarted ( )
} )
} )
when ( "the CredentialIssuer has invalid service type" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : "not-valid" ,
} ,
2021-05-19 16:40:32 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-19 16:40:32 +00:00
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
errString := ` could not load CredentialIssuer spec.impersonationProxy: invalid service type "not-valid" (expected None, LoadBalancer, or ClusterIP) `
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerWasNeverStarted ( )
} )
} )
when ( "the CredentialIssuer has invalid LoadBalancerIP" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
LoadBalancerIP : "invalid-ip-address" ,
} ,
2021-05-19 16:40:32 +00:00
} ,
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-19 16:40:32 +00:00
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
errString := ` could not load CredentialIssuer spec.impersonationProxy: invalid LoadBalancerIP "invalid-ip-address" `
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerWasNeverStarted ( )
} )
} )
when ( "the CredentialIssuer has invalid ExternalEndpoint" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : "[invalid" ,
} ,
2021-05-19 16:40:32 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-19 16:40:32 +00:00
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
errString := ` could not load CredentialIssuer spec.impersonationProxy: invalid ExternalEndpoint "[invalid": address [invalid:443: missing ']' in address `
2021-03-02 22:48:58 +00:00
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-03-02 01:02:08 +00:00
requireTLSServerWasNeverStarted ( )
} )
} )
2021-02-16 23:57:02 +00:00
when ( "there is an error creating the load balancer" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-02-16 23:57:02 +00:00
kubeAPIClient . PrependReactor ( "create" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
2021-05-27 16:13:10 +00:00
return true , nil , k8serrors . NewAlreadyExists (
action . GetResource ( ) . GroupResource ( ) ,
action . ( coretesting . CreateAction ) . GetObject ( ) . ( * corev1 . Service ) . Name ,
)
2021-02-16 23:57:02 +00:00
} )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-16 23:57:02 +00:00
} )
2021-03-02 22:48:58 +00:00
it ( "returns an error" , func ( ) {
startInformersAndController ( )
2021-05-27 16:13:10 +00:00
r . EqualError ( runControllerSync ( ) , ` services "some-service-resource-name" already exists ` )
requireCredentialIssuer ( newPendingStrategy ( ` services "some-service-resource-name" already exists ` ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-03-02 22:48:58 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-05-20 23:21:10 +00:00
} )
} )
2021-05-21 20:47:06 +00:00
when ( "there is an error deleting the load balancer" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
kubeAPIClient . PrependReactor ( "delete" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeAPIClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeInformerClient )
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "error on delete" )
requireCredentialIssuer ( newErrorStrategy ( "error on delete" ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
2021-05-20 23:21:10 +00:00
when ( "there is an error creating the cluster ip" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
kubeAPIClient . PrependReactor ( "create" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on create" )
} )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "error on create" )
requireCredentialIssuer ( newErrorStrategy ( "error on create" ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerIsRunningWithoutCerts ( )
} )
} )
when ( "there is an error updating the cluster ip" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
kubeAPIClient . PrependReactor ( "update" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on update" )
} )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeClusterIP ,
Annotations : map [ string ] string { "key" : "val" } ,
} ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addClusterIPServiceToTracker ( clusterIPServiceName , localhostIP , kubeAPIClient )
addClusterIPServiceToTracker ( clusterIPServiceName , localhostIP , kubeInformerClient )
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "error on update" )
requireCredentialIssuer ( newErrorStrategy ( "error on update" ) )
requireSigningCertProviderIsEmpty ( )
requireTLSServerIsRunningWithoutCerts ( )
2021-02-16 23:57:02 +00:00
} )
2021-02-12 01:22:47 +00:00
} )
2021-02-24 18:56:24 +00:00
2021-05-21 20:47:06 +00:00
when ( "there is an error deleting the cluster ip" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
kubeAPIClient . PrependReactor ( "delete" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
} ,
} , pinnipedInformerClient , pinnipedAPIClient )
addClusterIPServiceToTracker ( clusterIPServiceName , localhostIP , kubeAPIClient )
addClusterIPServiceToTracker ( clusterIPServiceName , localhostIP , kubeInformerClient )
} )
it ( "returns an error" , func ( ) {
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "error on delete" )
requireCredentialIssuer ( newErrorStrategy ( "error on delete" ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
2021-02-26 18:58:56 +00:00
when ( "there is an error creating the tls secret" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : "example.com" ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
2021-02-26 18:58:56 +00:00
kubeAPIClient . PrependReactor ( "create" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
2021-03-02 01:02:08 +00:00
createdSecret := action . ( coretesting . CreateAction ) . GetObject ( ) . ( * corev1 . Secret )
if createdSecret . Name == tlsSecretName {
return true , nil , fmt . Errorf ( "error on tls secret create" )
}
return false , nil , nil
2021-02-26 18:58:56 +00:00
} )
} )
it ( "starts the impersonator without certs and returns an error" , func ( ) {
startInformersAndController ( )
2021-03-02 01:02:08 +00:00
r . EqualError ( runControllerSync ( ) , "error on tls secret create" )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "error on tls secret create" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-03-02 01:02:08 +00:00
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
} )
} )
when ( "there is an error creating the CA secret" , func ( ) {
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : "example.com" ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
kubeAPIClient . PrependReactor ( "create" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
createdSecret := action . ( coretesting . CreateAction ) . GetObject ( ) . ( * corev1 . Secret )
if createdSecret . Name == caSecretName {
return true , nil , fmt . Errorf ( "error on ca secret create" )
}
return false , nil , nil
} )
} )
it ( "starts the impersonator without certs and returns an error" , func ( ) {
startInformersAndController ( )
r . EqualError ( runControllerSync ( ) , "error on ca secret create" )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "error on ca secret create" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 2 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
} )
} )
when ( "the CA secret exists but is invalid while the TLS secret needs to be created" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : "example.com" ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-02 01:02:08 +00:00
addSecretToTrackers ( newEmptySecret ( caSecretName ) , kubeAPIClient , kubeInformerClient )
} )
it ( "starts the impersonator without certs and returns an error" , func ( ) {
startInformersAndController ( )
2021-03-02 22:48:58 +00:00
errString := "could not load CA: tls: failed to find any PEM data in certificate input"
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-03-02 01:02:08 +00:00
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 1 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-02-26 18:58:56 +00:00
} )
} )
2021-02-24 18:56:24 +00:00
when ( "there is an error deleting the tls secret" , func ( ) {
it . Before ( func ( ) {
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeInformerClient )
addLoadBalancerServiceToTracker ( loadBalancerServiceName , kubeAPIClient )
2021-03-02 01:02:08 +00:00
addSecretToTrackers ( newEmptySecret ( tlsSecretName ) , kubeAPIClient , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:54:04 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-24 18:56:24 +00:00
startInformersAndController ( )
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
} )
it ( "does not start the impersonator, deletes the loadbalancer, returns an error" , func ( ) {
2021-02-26 21:53:30 +00:00
r . EqualError ( runControllerSync ( ) , "error on delete" )
2021-03-02 22:48:58 +00:00
requireCredentialIssuer ( newErrorStrategy ( "error on delete" ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-24 18:56:24 +00:00
requireTLSServerWasNeverStarted ( )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-05-21 16:57:46 +00:00
requireServiceWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] , loadBalancerServiceName )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 2 ] )
2021-02-24 18:56:24 +00:00
} )
} )
2021-02-26 18:58:56 +00:00
2021-03-30 21:43:04 +00:00
when ( "deleting the tls secret when informer and api are out of sync" , func ( ) {
it . Before ( func ( ) {
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
addSecretToTrackers ( newEmptySecret ( tlsSecretName ) , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeDisabled ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-30 21:43:04 +00:00
} )
it ( "does not pass the not found error through" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
requireTLSServerWasNeverStarted ( )
r . Len ( kubeAPIClient . Actions ( ) , 2 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] )
requireCredentialIssuer ( newManuallyDisabledStrategy ( ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
2021-03-02 01:02:08 +00:00
when ( "the PEM formatted data in the TLS Secret is not a valid cert" , func ( ) {
2021-02-26 18:58:56 +00:00
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : localhostIP ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-08-10 16:05:04 +00:00
tlsSecret := newSecretWithData ( tlsSecretName , map [ string ] [ ] byte {
// "aGVsbG8gd29ybGQK" is "hello world" base64 encoded which is not a valid cert
corev1 . TLSCertKey : [ ] byte ( "-----BEGIN CERTIFICATE-----\naGVsbG8gd29ybGQK\n-----END CERTIFICATE-----\n" ) ,
} )
2021-03-02 01:02:08 +00:00
addSecretToTrackers ( tlsSecret , kubeAPIClient , kubeInformerClient )
2021-02-26 18:58:56 +00:00
} )
it ( "deletes the invalid certs, creates new certs, and starts the impersonator" , func ( ) {
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 4 )
2021-02-26 18:58:56 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 2 ] ) // deleted the bad cert
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 3 ] , ca )
2021-02-26 21:53:30 +00:00
requireTLSServerIsRunning ( ca , testServerAddr ( ) , nil )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , ca ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 18:58:56 +00:00
} )
when ( "there is an error while the invalid cert is being deleted" , func ( ) {
it . Before ( func ( ) {
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
} )
it ( "tries to delete the invalid cert, starts the impersonator without certs, and returns an error" , func ( ) {
startInformersAndController ( )
2021-03-02 22:48:58 +00:00
errString := "PEM data represented an invalid cert, but got error while deleting it: error on delete"
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
2021-03-02 01:02:08 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
2021-02-26 18:58:56 +00:00
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 2 ] ) // tried deleted the bad cert, which failed
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
} )
} )
} )
when ( "a tls secret already exists but it is not valid" , func ( ) {
2021-03-02 01:02:08 +00:00
var caCrt [ ] byte
2021-02-26 18:58:56 +00:00
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-03-02 01:02:08 +00:00
ca := newCA ( )
caSecret := newActualCASecret ( ca , caSecretName )
caCrt = caSecret . Data [ "ca.crt" ]
addSecretToTrackers ( caSecret , kubeAPIClient , kubeInformerClient )
addSecretToTrackers ( newEmptySecret ( tlsSecretName ) , kubeAPIClient , kubeInformerClient ) // secret exists but lacks certs
2021-02-26 21:53:30 +00:00
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeAPIClient )
2021-02-26 18:58:56 +00:00
} )
it ( "deletes the invalid certs, creates new certs, and starts the impersonator" , func ( ) {
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 18:58:56 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] ) // deleted the bad cert
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , caCrt )
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , caCrt ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 18:58:56 +00:00
} )
when ( "there is an error while the invalid cert is being deleted" , func ( ) {
it . Before ( func ( ) {
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
} )
it ( "tries to delete the invalid cert, starts the impersonator without certs, and returns an error" , func ( ) {
startInformersAndController ( )
2021-03-02 22:48:58 +00:00
errString := "found missing or not PEM-encoded data in TLS Secret, but got error while deleting it: error on delete"
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 2 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] ) // tried deleted the bad cert, which failed
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
} )
} )
} )
when ( "a tls secret already exists but the private key is not valid" , func ( ) {
2021-03-02 01:02:08 +00:00
var caCrt [ ] byte
2021-02-26 18:58:56 +00:00
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-02-26 21:53:30 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-03-02 01:02:08 +00:00
ca := newCA ( )
caSecret := newActualCASecret ( ca , caSecretName )
caCrt = caSecret . Data [ "ca.crt" ]
addSecretToTrackers ( caSecret , kubeAPIClient , kubeInformerClient )
tlsSecret := newActualTLSSecret ( ca , tlsSecretName , localhostIP )
2021-02-26 18:58:56 +00:00
tlsSecret . Data [ "tls.key" ] = nil
2021-03-02 01:02:08 +00:00
addSecretToTrackers ( tlsSecret , kubeAPIClient , kubeInformerClient )
2021-02-26 21:53:30 +00:00
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeInformerClient )
addLoadBalancerServiceWithIngressToTracker ( loadBalancerServiceName , [ ] corev1 . LoadBalancerIngress { { IP : localhostIP } } , kubeAPIClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-02-26 18:58:56 +00:00
} )
it ( "deletes the invalid certs, creates new certs, and starts the impersonator" , func ( ) {
startInformersAndController ( )
2021-02-26 21:53:30 +00:00
r . NoError ( runControllerSync ( ) )
2021-02-26 18:58:56 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] ) // deleted the bad cert
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , caCrt )
requireTLSServerIsRunning ( caCrt , testServerAddr ( ) , nil )
2021-03-03 00:51:35 +00:00
requireCredentialIssuer ( newSuccessStrategy ( localhostIP , caCrt ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-02-26 18:58:56 +00:00
} )
when ( "there is an error while the invalid cert is being deleted" , func ( ) {
it . Before ( func ( ) {
kubeAPIClient . PrependReactor ( "delete" , "secrets" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on delete" )
} )
} )
it ( "tries to delete the invalid cert, starts the impersonator without certs, and returns an error" , func ( ) {
startInformersAndController ( )
2021-03-02 22:48:58 +00:00
errString := "cert had an invalid private key, but got error while deleting it: error on delete"
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-03-10 18:30:06 +00:00
requireSigningCertProviderIsEmpty ( )
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
r . Len ( kubeAPIClient . Actions ( ) , 2 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
2021-03-02 01:02:08 +00:00
requireTLSSecretWasDeleted ( kubeAPIClient . Actions ( ) [ 1 ] ) // tried deleted the bad cert, which failed
2021-02-26 18:58:56 +00:00
requireTLSServerIsRunningWithoutCerts ( )
} )
} )
} )
2021-03-02 22:48:58 +00:00
when ( "there is an error while creating or updating the CredentialIssuer status" , func ( ) {
it . Before ( func ( ) {
2021-03-10 18:30:06 +00:00
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-03-02 22:48:58 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeAuto ,
} ,
2021-05-18 19:54:04 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
pinnipedAPIClient . PrependReactor ( "update" , "credentialissuers" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on update" )
2021-03-02 22:48:58 +00:00
} )
} )
it ( "returns the error" , func ( ) {
startInformersAndController ( )
2021-05-20 17:26:07 +00:00
r . EqualError ( runControllerSync ( ) , "failed to update CredentialIssuer status: error on update" )
2021-03-02 22:48:58 +00:00
} )
when ( "there is also a more fundamental error while starting the impersonator" , func ( ) {
it . Before ( func ( ) {
kubeAPIClient . PrependReactor ( "create" , "services" , func ( action coretesting . Action ) ( handled bool , ret runtime . Object , err error ) {
return true , nil , fmt . Errorf ( "error on service creation" )
} )
} )
2021-05-20 17:26:07 +00:00
it ( "returns both errors" , func ( ) {
2021-03-02 22:48:58 +00:00
startInformersAndController ( )
2021-05-20 17:26:07 +00:00
r . EqualError ( runControllerSync ( ) , "[error on service creation, failed to update CredentialIssuer status: error on update]" )
2021-03-02 22:48:58 +00:00
} )
} )
} )
2021-03-03 17:37:08 +00:00
2021-03-10 18:30:06 +00:00
when ( "the impersonator is ready but there is a problem with the signing secret, which should be created by another controller" , func ( ) {
const fakeHostname = "foo.example.com"
2021-03-03 17:37:08 +00:00
it . Before ( func ( ) {
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : fakeHostname ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 19:16:27 +00:00
} ,
2021-05-17 22:08:05 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-03-03 17:37:08 +00:00
addNodeWithRoleToTracker ( "worker" , kubeAPIClient )
} )
2021-03-10 18:30:06 +00:00
when ( "it does not exist in the informers" , func ( ) {
it ( "returns the error" , func ( ) {
startInformersAndController ( )
errString := ` could not load the impersonator's credential signing secret: secret "some-ca-signer-name" not found `
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
when ( "it does not have the expected fields" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( newEmptySecret ( caSignerName ) , kubeInformerClient )
} )
it ( "returns the error" , func ( ) {
startInformersAndController ( )
2021-08-10 16:05:04 +00:00
errString := ` could not set the impersonator's credential signing secret: TestImpersonatorConfigControllerSync: attempt to set invalid key pair: tls: failed to find any PEM data in certificate input `
2021-03-10 18:30:06 +00:00
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
when ( "the cert is invalid" , func ( ) {
it . Before ( func ( ) {
signingCASecret . Data [ apicerts . CACertificateSecretKey ] = [ ] byte ( "not a valid PEM formatted cert" )
addSecretToTrackers ( signingCASecret , kubeInformerClient )
} )
it ( "returns the error" , func ( ) {
startInformersAndController ( )
2021-08-10 16:05:04 +00:00
errString := ` could not set the impersonator's credential signing secret: TestImpersonatorConfigControllerSync: attempt to set invalid key pair: tls: failed to find any PEM data in certificate input `
2021-03-10 18:30:06 +00:00
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
requireSigningCertProviderIsEmpty ( )
} )
} )
when ( "the cert goes from being valid to being invalid" , func ( ) {
const fakeHostname = "foo.example.com"
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
} )
it ( "returns the error and clears the dynamic provider" , func ( ) {
startInformersAndController ( )
r . NoError ( runControllerSync ( ) )
r . Len ( kubeAPIClient . Actions ( ) , 3 )
requireNodesListed ( kubeAPIClient . Actions ( ) [ 0 ] )
ca := requireCASecretWasCreated ( kubeAPIClient . Actions ( ) [ 1 ] )
requireTLSSecretWasCreated ( kubeAPIClient . Actions ( ) [ 2 ] , ca )
// Check that the server is running and that TLS certs that are being served are are for fakeHostname.
requireTLSServerIsRunning ( ca , fakeHostname , map [ string ] string { fakeHostname + httpsPort : testServerAddr ( ) } )
requireCredentialIssuer ( newSuccessStrategy ( fakeHostname , ca ) )
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
// Simulate the informer cache's background update from its watch.
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 1 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
addObjectFromCreateActionToInformerAndWait ( kubeAPIClient . Actions ( ) [ 2 ] , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
// Now update the signer CA to something invalid.
deleteSecretFromTracker ( caSignerName , kubeInformerClient )
waitForObjectToBeDeletedFromInformer ( caSignerName , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
updatedSigner := newEmptySecret ( caSignerName )
addSecretToTrackers ( updatedSigner , kubeInformerClient )
waitForObjectToAppearInInformer ( updatedSigner , kubeInformers . Core ( ) . V1 ( ) . Secrets ( ) )
2021-08-10 16:05:04 +00:00
errString := ` could not set the impersonator's credential signing secret: TestImpersonatorConfigControllerSync: attempt to set invalid key pair: tls: failed to find any PEM data in certificate input `
2021-03-10 18:30:06 +00:00
r . EqualError ( runControllerSync ( ) , errString )
requireCredentialIssuer ( newErrorStrategy ( errString ) )
2021-08-10 16:05:04 +00:00
requireSigningCertProviderHasLoadedCerts ( signingCACertPEM , signingCAKeyPEM )
2021-03-10 18:30:06 +00:00
} )
2021-03-03 17:37:08 +00:00
} )
} )
2021-05-18 20:50:52 +00:00
2021-05-18 23:54:59 +00:00
when ( "CredentialIssuer spec validation" , func ( ) {
when ( "the impersonator is enabled but the service type is none and the external endpoint is empty" , func ( ) {
it . Before ( func ( ) {
addSecretToTrackers ( signingCASecret , kubeInformerClient )
2021-05-20 17:26:07 +00:00
addCredentialIssuerToTrackers ( v1alpha1 . CredentialIssuer {
ObjectMeta : metav1 . ObjectMeta { Name : credentialIssuerResourceName } ,
Spec : v1alpha1 . CredentialIssuerSpec {
ImpersonationProxy : & v1alpha1 . ImpersonationProxySpec {
Mode : v1alpha1 . ImpersonationProxyModeEnabled ,
ExternalEndpoint : "" ,
Service : v1alpha1 . ImpersonationProxyServiceSpec {
Type : v1alpha1 . ImpersonationProxyServiceTypeNone ,
} ,
2021-05-18 23:54:59 +00:00
} ,
2021-05-18 20:50:52 +00:00
} ,
2021-05-20 17:26:07 +00:00
} , pinnipedInformerClient , pinnipedAPIClient )
2021-05-18 23:54:59 +00:00
addNodeWithRoleToTracker ( "control-plane" , kubeAPIClient )
} )
2021-05-18 20:50:52 +00:00
2021-05-18 23:54:59 +00:00
it ( "returns a validation error" , func ( ) {
startInformersAndController ( )
2021-05-19 16:40:32 +00:00
r . EqualError ( runControllerSync ( ) , "could not load CredentialIssuer spec.impersonationProxy: externalEndpoint must be set when service.type is None" )
2021-05-18 23:54:59 +00:00
r . Len ( kubeAPIClient . Actions ( ) , 0 )
} )
2021-05-18 20:50:52 +00:00
} )
} )
2021-05-26 17:57:51 +00:00
} , spec . Parallel ( ) , spec . Report ( report . Terminal { } ) )
2021-02-12 01:22:47 +00:00
}
2021-03-10 18:30:06 +00:00
type testQueue struct {
key controllerlib . Key
mutex sync . RWMutex
controllerlib . Queue
}
func ( q * testQueue ) AddRateLimited ( key controllerlib . Key ) {
q . mutex . Lock ( ) // this is to satisfy the race detector
defer q . mutex . Unlock ( )
if q . key != ( controllerlib . Key { } ) {
panic ( "called more than once" )
}
if key == ( controllerlib . Key { } ) {
panic ( "unexpected empty key" )
}
q . key = key
}