mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2026-09-05 23:57:12 +00:00
pay attention to web proxy settings during connection probes
- WebhookAuthenticator will now detect the proxy setting and skip dialing the connection probe if it should go through a proxy - GitHubIdentityProvider will avoid using tls.Dial altogether by instead making a real request to the GitHub API as its connection probe, because this will respect the proxy settings
This commit is contained in:
@@ -39,6 +39,7 @@ import (
|
||||
"go.pinniped.dev/internal/endpointaddr"
|
||||
"go.pinniped.dev/internal/kubeclient"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/proxydetect"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -49,10 +50,12 @@ const (
|
||||
typeEndpointURLValid = "EndpointURLValid"
|
||||
typeAuthenticatorValid = "AuthenticatorValid"
|
||||
|
||||
reasonUnableToCreateClient = "UnableToCreateClient"
|
||||
reasonUnableToInstantiateWebhook = "UnableToInstantiateWebhook"
|
||||
reasonInvalidEndpointURL = "InvalidEndpointURL"
|
||||
reasonInvalidEndpointURLScheme = "InvalidEndpointURLScheme"
|
||||
reasonUnableToCreateClient = "UnableToCreateClient"
|
||||
reasonUnableToInstantiateWebhook = "UnableToInstantiateWebhook"
|
||||
reasonInvalidEndpointURL = "InvalidEndpointURL"
|
||||
reasonInvalidEndpointURLScheme = "InvalidEndpointURLScheme"
|
||||
reasonInvalidEndpointCannotDetermineProxy = "InvalidEndpointCannotDetermineProxy"
|
||||
reasonUnableToDialServer = "UnableToDialServer"
|
||||
)
|
||||
|
||||
type cachedWebhookAuthenticator struct {
|
||||
@@ -77,6 +80,7 @@ func New(
|
||||
clock clock.Clock,
|
||||
log plog.Logger,
|
||||
dialer ptls.Dialer,
|
||||
proxyDetector proxydetect.ProxyDetect,
|
||||
) controllerlib.Controller {
|
||||
return controllerlib.New(
|
||||
controllerlib.Config{
|
||||
@@ -91,6 +95,7 @@ func New(
|
||||
clock: clock,
|
||||
log: log.WithName(controllerName),
|
||||
dialer: dialer,
|
||||
proxyDetector: proxyDetector,
|
||||
},
|
||||
},
|
||||
withInformer(
|
||||
@@ -127,6 +132,7 @@ type webhookCacheFillerController struct {
|
||||
clock clock.Clock
|
||||
log plog.Logger
|
||||
dialer ptls.Dialer
|
||||
proxyDetector proxydetect.ProxyDetect
|
||||
}
|
||||
|
||||
// Sync implements controllerlib.Syncer.
|
||||
@@ -173,7 +179,7 @@ func (c *webhookCacheFillerController) syncIndividualWebhookAuthenticator(ctx co
|
||||
|
||||
caBundle, conditions, tlsBundleOk := c.validateTLSBundle(webhookAuthenticator.Spec.TLS, conditions)
|
||||
|
||||
endpointHostPort, conditions, endpointOk := c.validateEndpoint(webhookAuthenticator.Spec.Endpoint, conditions)
|
||||
endpointHostPort, conditions, usingProxyForHost, endpointOk := c.validateEndpoint(webhookAuthenticator.Spec.Endpoint, conditions)
|
||||
okSoFar := tlsBundleOk && endpointOk
|
||||
|
||||
// Only revalidate and update the cache if the cached authenticator is different from the desired authenticator.
|
||||
@@ -194,12 +200,14 @@ func (c *webhookCacheFillerController) syncIndividualWebhookAuthenticator(ctx co
|
||||
// if they need to be updated.
|
||||
logger.Info("cached webhook authenticator and desired webhook authenticator are the same: already cached, so skipping validations")
|
||||
conditions = append(conditions,
|
||||
successfulWebhookConnectionValidCondition(),
|
||||
successfulWebhookConnectionValidCondition(usingProxyForHost),
|
||||
successfulAuthenticatorValidCondition(),
|
||||
)
|
||||
} else {
|
||||
// Run all remaining validations.
|
||||
a, moreConditions, moreErrs := c.doExpensiveValidations(ctx, webhookAuthenticator, endpointHostPort, caBundle, okSoFar, logger)
|
||||
a, moreConditions, moreErrs := c.doExpensiveValidations(
|
||||
ctx, webhookAuthenticator, endpointHostPort, caBundle, okSoFar, usingProxyForHost, logger,
|
||||
)
|
||||
newWebhookAuthenticatorForCache = a
|
||||
conditions = append(conditions, moreConditions...)
|
||||
errs = append(errs, moreErrs...)
|
||||
@@ -243,13 +251,14 @@ func (c *webhookCacheFillerController) doExpensiveValidations(
|
||||
endpointHostPort *endpointaddr.HostPort,
|
||||
caBundle *tlsconfigutil.CABundle,
|
||||
okSoFar bool,
|
||||
usingProxyForHost bool,
|
||||
logger plog.Logger,
|
||||
) (*cachedWebhookAuthenticator, []*metav1.Condition, []error) {
|
||||
var newWebhookAuthenticatorForCache *cachedWebhookAuthenticator
|
||||
var conditions []*metav1.Condition
|
||||
var errs []error
|
||||
|
||||
conditions, tlsNegotiateErr := c.validateConnection(ctx, caBundle.CertPool(), endpointHostPort, conditions, okSoFar, logger)
|
||||
conditions, tlsNegotiateErr := c.validateConnection(ctx, caBundle.CertPool(), endpointHostPort, conditions, okSoFar, usingProxyForHost, logger)
|
||||
errs = append(errs, tlsNegotiateErr)
|
||||
okSoFar = okSoFar && tlsNegotiateErr == nil
|
||||
|
||||
@@ -405,12 +414,16 @@ func newWebhookAuthenticator(
|
||||
return webhookAuthenticator, conditions, nil
|
||||
}
|
||||
|
||||
func successfulWebhookConnectionValidCondition() *metav1.Condition {
|
||||
func successfulWebhookConnectionValidCondition(usingProxyForHost bool) *metav1.Condition {
|
||||
msg := "successfully dialed webhook server"
|
||||
if usingProxyForHost {
|
||||
msg = "skipped dialing connection probe because HTTPS_PROXY is configured for use with the specified host"
|
||||
}
|
||||
return &metav1.Condition{
|
||||
Type: typeWebhookConnectionValid,
|
||||
Status: metav1.ConditionTrue,
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "successfully dialed webhook server",
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +433,7 @@ func (c *webhookCacheFillerController) validateConnection(
|
||||
endpointHostPort *endpointaddr.HostPort,
|
||||
conditions []*metav1.Condition,
|
||||
prereqOk bool,
|
||||
usingProxyForHost bool,
|
||||
logger plog.Logger,
|
||||
) ([]*metav1.Condition, error) {
|
||||
if !prereqOk {
|
||||
@@ -432,6 +446,13 @@ func (c *webhookCacheFillerController) validateConnection(
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
if usingProxyForHost {
|
||||
// We cannot assume that we can directly dial the host in the case where we should
|
||||
// be using a web proxy to reach the host, so skip the dial probe in that case.
|
||||
conditions = append(conditions, successfulWebhookConnectionValidCondition(usingProxyForHost))
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
dialCtx, dialCancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer dialCancel()
|
||||
err := c.dialer.IsReachableAndTLSValidationSucceeds(dialCtx, endpointHostPort.Endpoint(), certPool, logger)
|
||||
@@ -442,17 +463,17 @@ func (c *webhookCacheFillerController) validateConnection(
|
||||
conditions = append(conditions, &metav1.Condition{
|
||||
Type: typeWebhookConnectionValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: conditionsutil.ReasonUnableToDialServer,
|
||||
Reason: reasonUnableToDialServer,
|
||||
Message: msg,
|
||||
})
|
||||
return conditions, fmt.Errorf("%s: %w", errText, err)
|
||||
}
|
||||
|
||||
conditions = append(conditions, successfulWebhookConnectionValidCondition())
|
||||
conditions = append(conditions, successfulWebhookConnectionValidCondition(usingProxyForHost))
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditions []*metav1.Condition) (*endpointaddr.HostPort, []*metav1.Condition, bool) {
|
||||
func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditions []*metav1.Condition) (*endpointaddr.HostPort, []*metav1.Condition, bool, bool) {
|
||||
endpointURL, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("%s: %s", "spec.endpoint URL cannot be parsed", err.Error())
|
||||
@@ -462,7 +483,7 @@ func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditi
|
||||
Reason: reasonInvalidEndpointURL,
|
||||
Message: msg,
|
||||
})
|
||||
return nil, conditions, false
|
||||
return nil, conditions, false, false
|
||||
}
|
||||
|
||||
// handles empty string and other issues as well.
|
||||
@@ -474,7 +495,7 @@ func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditi
|
||||
Reason: reasonInvalidEndpointURLScheme,
|
||||
Message: msg,
|
||||
})
|
||||
return nil, conditions, false
|
||||
return nil, conditions, false, false
|
||||
}
|
||||
|
||||
endpointHostPort, err := endpointaddr.ParseFromURL(endpointURL, 443)
|
||||
@@ -486,7 +507,19 @@ func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditi
|
||||
Reason: reasonInvalidEndpointURL,
|
||||
Message: msg,
|
||||
})
|
||||
return nil, conditions, false
|
||||
return nil, conditions, false, false
|
||||
}
|
||||
|
||||
usingProxyForHost, err := c.proxyDetector.UsingProxyForHost(endpointHostPort.Host)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("%s: %s", "spec.endpoint URL error", err.Error())
|
||||
conditions = append(conditions, &metav1.Condition{
|
||||
Type: typeEndpointURLValid,
|
||||
Status: metav1.ConditionFalse,
|
||||
Reason: reasonInvalidEndpointCannotDetermineProxy,
|
||||
Message: msg,
|
||||
})
|
||||
return nil, conditions, false, false
|
||||
}
|
||||
|
||||
conditions = append(conditions, &metav1.Condition{
|
||||
@@ -495,7 +528,7 @@ func (c *webhookCacheFillerController) validateEndpoint(endpoint string, conditi
|
||||
Reason: conditionsutil.ReasonSuccess,
|
||||
Message: "spec.endpoint is a valid URL",
|
||||
})
|
||||
return &endpointHostPort, conditions, true
|
||||
return &endpointHostPort, conditions, usingProxyForHost, true
|
||||
}
|
||||
|
||||
func (c *webhookCacheFillerController) updateStatus(
|
||||
|
||||
@@ -44,8 +44,10 @@ import (
|
||||
"go.pinniped.dev/internal/crypto/ptls"
|
||||
"go.pinniped.dev/internal/mocks/mockcachevalue"
|
||||
"go.pinniped.dev/internal/plog"
|
||||
"go.pinniped.dev/internal/proxydetect"
|
||||
"go.pinniped.dev/internal/testutil"
|
||||
"go.pinniped.dev/internal/testutil/conditionstestutil"
|
||||
"go.pinniped.dev/internal/testutil/fakeproxydetect"
|
||||
"go.pinniped.dev/internal/testutil/tlsserver"
|
||||
)
|
||||
|
||||
@@ -302,6 +304,11 @@ func TestController(t *testing.T) {
|
||||
Message: "successfully dialed webhook server",
|
||||
}
|
||||
}
|
||||
happyWebhookConnectionValidWithoutDialingDueToProxy := func(time metav1.Time, observedGeneration int64) metav1.Condition {
|
||||
c := happyWebhookConnectionValid(time, observedGeneration)
|
||||
c.Message = "skipped dialing connection probe because HTTPS_PROXY is configured for use with the specified host"
|
||||
return c
|
||||
}
|
||||
unknownWebhookConnectionValid := func(time metav1.Time, observedGeneration int64) metav1.Condition {
|
||||
return metav1.Condition{
|
||||
Type: "WebhookConnectionValid",
|
||||
@@ -373,7 +380,16 @@ func TestController(t *testing.T) {
|
||||
Message: fmt.Sprintf(`spec.endpoint URL %s has invalid scheme, require 'https'`, endpoint),
|
||||
}
|
||||
}
|
||||
|
||||
sadEndpointURLValidProxyDetectErr := func(msg string, time metav1.Time, observedGeneration int64) metav1.Condition {
|
||||
return metav1.Condition{
|
||||
Type: "EndpointURLValid",
|
||||
Status: "False",
|
||||
ObservedGeneration: observedGeneration,
|
||||
LastTransitionTime: time,
|
||||
Reason: "InvalidEndpointCannotDetermineProxy",
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
sadEndpointURLValidWithMessage := func(time metav1.Time, observedGeneration int64, msg string) metav1.Condition {
|
||||
return metav1.Condition{
|
||||
Type: "EndpointURLValid",
|
||||
@@ -412,10 +428,11 @@ func TestController(t *testing.T) {
|
||||
webhookAuthenticators []runtime.Object
|
||||
secretsAndConfigMaps []runtime.Object
|
||||
// for modifying the clients to hack in arbitrary api responses
|
||||
configClient func(*conciergefake.Clientset)
|
||||
wantSyncErr testutil.RequireErrorStringFunc
|
||||
wantLogLines []string
|
||||
wantActions func() []coretesting.Action
|
||||
configClient func(*conciergefake.Clientset)
|
||||
proxyDetector func(t *testing.T) proxydetect.ProxyDetect
|
||||
wantSyncErr testutil.RequireErrorStringFunc
|
||||
wantLogLines []string
|
||||
wantActions func() []coretesting.Action
|
||||
// random comment so lines above don't have huge indents
|
||||
wantNamesOfWebhookAuthenticatorsInCache []string
|
||||
}{
|
||||
@@ -1011,6 +1028,80 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
wantNamesOfWebhookAuthenticatorsInCache: []string{"test-name"}, // keeps the old entry in the cache
|
||||
},
|
||||
{
|
||||
name: "Sync: previously cached valid authenticator with unchanged endpoint URL and CA bundle hash has invalid status conditions in informer cache, as can happen on subsequent sync soon after multiple quick status updates (when the informer cache finally catches up), and the webhook host would be reached through a proxy: should update status in current sync",
|
||||
cache: func(t *testing.T, cache *authncache.Cache) {
|
||||
oldCA, err := base64.StdEncoding.DecodeString(goodWebhookAuthenticatorSpecWithCA.TLS.CertificateAuthorityData)
|
||||
require.NoError(t, err)
|
||||
cache.Store(
|
||||
authncache.Key{
|
||||
Name: "test-name",
|
||||
Kind: "WebhookAuthenticator",
|
||||
APIGroup: authenticationv1alpha1.SchemeGroupVersion.Group,
|
||||
},
|
||||
newCacheValue(t, goodWebhookAuthenticatorSpecWithCA, string(oldCA)),
|
||||
)
|
||||
},
|
||||
webhookAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
Generation: 1234,
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
Status: authenticationv1alpha1.WebhookAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodWebhookDefaultServingCertEndpoint, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadTLSConfigurationValid(frozenMetav1Now, 0),
|
||||
unknownWebhookConnectionValid(frozenMetav1Now, 0),
|
||||
unknownAuthenticatorValid(frozenMetav1Now, 0),
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
},
|
||||
},
|
||||
proxyDetector: func(t *testing.T) proxydetect.ProxyDetect {
|
||||
// Detect that a proxy is required for the webhook host.
|
||||
fakeProxyDetect := fakeproxydetect.New(true, nil)
|
||||
t.Cleanup(func() {
|
||||
require.Equal(t, 1, fakeProxyDetect.NumberOfInvocations())
|
||||
require.Equal(t, "127.0.0.1", fakeProxyDetect.ReceivedHostDuringMostRecentInvocation())
|
||||
})
|
||||
return fakeProxyDetect
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).syncIndividualWebhookAuthenticator","message":"cached webhook authenticator and desired webhook authenticator are the same: already cached, so skipping validations","webhookAuthenticator":"test-name","endpoint":"%s"}`, goodWebhookAuthenticatorSpecWithCA.Endpoint),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).updateStatus","message":"webhookauthenticator status successfully updated","webhookAuthenticator":"test-name","endpoint":"%s","phase":"Ready"}`, goodWebhookAuthenticatorSpecWithCA.Endpoint),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(webhookAuthenticatorGVR, "", &authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
Generation: 1234,
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
Status: authenticationv1alpha1.WebhookAuthenticatorStatus{ // updates the status to ready
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodWebhookDefaultServingCertEndpoint, frozenMetav1Now, 1234),
|
||||
[]metav1.Condition{
|
||||
happyWebhookConnectionValidWithoutDialingDueToProxy(frozenMetav1Now, 1234),
|
||||
},
|
||||
),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(webhookAuthenticatorGVR, webhookAuthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(webhookAuthenticatorGVR, "", metav1.ListOptions{}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantNamesOfWebhookAuthenticatorsInCache: []string{"test-name"}, // keeps the old entry in the cache
|
||||
},
|
||||
{
|
||||
name: "Sync: valid WebhookAuthenticator with CA: will complete sync loop successfully with success conditions and ready phase",
|
||||
webhookAuthenticators: []runtime.Object{
|
||||
@@ -1021,6 +1112,15 @@ func TestController(t *testing.T) {
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
},
|
||||
},
|
||||
proxyDetector: func(t *testing.T) proxydetect.ProxyDetect {
|
||||
// Detect that a proxy is not required for the webhook host.
|
||||
fakeProxyDetect := fakeproxydetect.New(false, nil)
|
||||
t.Cleanup(func() {
|
||||
require.Equal(t, 1, fakeProxyDetect.NumberOfInvocations())
|
||||
require.Equal(t, "127.0.0.1", fakeProxyDetect.ReceivedHostDuringMostRecentInvocation())
|
||||
})
|
||||
return fakeProxyDetect
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).updateStatus","message":"webhookauthenticator status successfully updated","webhookAuthenticator":"test-name","endpoint":"%s","phase":"Ready"}`, goodWebhookDefaultServingCertEndpoint),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).syncIndividualWebhookAuthenticator","message":"added or updated webhook authenticator in cache","webhookAuthenticator":"test-name","endpoint":"%s","isOverwrite":false}`, goodWebhookDefaultServingCertEndpoint),
|
||||
@@ -1045,6 +1145,104 @@ func TestController(t *testing.T) {
|
||||
},
|
||||
wantNamesOfWebhookAuthenticatorsInCache: []string{"test-name"},
|
||||
},
|
||||
{
|
||||
name: "Sync: valid WebhookAuthenticator when webhook host will use web proxy: will complete sync loop successfully with success conditions and ready phase",
|
||||
webhookAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
},
|
||||
},
|
||||
proxyDetector: func(t *testing.T) proxydetect.ProxyDetect {
|
||||
// Detect that a proxy is required for the webhook host.
|
||||
fakeProxyDetect := fakeproxydetect.New(true, nil)
|
||||
t.Cleanup(func() {
|
||||
require.Equal(t, 1, fakeProxyDetect.NumberOfInvocations())
|
||||
require.Equal(t, "127.0.0.1", fakeProxyDetect.ReceivedHostDuringMostRecentInvocation())
|
||||
})
|
||||
return fakeProxyDetect
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).updateStatus","message":"webhookauthenticator status successfully updated","webhookAuthenticator":"test-name","endpoint":"%s","phase":"Ready"}`, goodWebhookDefaultServingCertEndpoint),
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).syncIndividualWebhookAuthenticator","message":"added or updated webhook authenticator in cache","webhookAuthenticator":"test-name","endpoint":"%s","isOverwrite":false}`, goodWebhookDefaultServingCertEndpoint),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(webhookAuthenticatorGVR, "", &authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
Status: authenticationv1alpha1.WebhookAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodWebhookDefaultServingCertEndpoint, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
happyWebhookConnectionValidWithoutDialingDueToProxy(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Ready",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(webhookAuthenticatorGVR, webhookAuthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(webhookAuthenticatorGVR, "", metav1.ListOptions{}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
wantNamesOfWebhookAuthenticatorsInCache: []string{"test-name"},
|
||||
},
|
||||
{
|
||||
name: "Sync: valid WebhookAuthenticator when error while checking if webhook host will use web proxy: will complete sync loop successfully with error conditions and error phase",
|
||||
webhookAuthenticators: []runtime.Object{
|
||||
&authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
},
|
||||
},
|
||||
proxyDetector: func(t *testing.T) proxydetect.ProxyDetect {
|
||||
// Return a fake error when trying to determine if a proxy is needed for the webhook host.
|
||||
fakeProxyDetect := fakeproxydetect.New(false, errors.New("fake proxy detector error"))
|
||||
t.Cleanup(func() {
|
||||
require.Equal(t, 1, fakeProxyDetect.NumberOfInvocations())
|
||||
require.Equal(t, "127.0.0.1", fakeProxyDetect.ReceivedHostDuringMostRecentInvocation())
|
||||
})
|
||||
return fakeProxyDetect
|
||||
},
|
||||
wantLogLines: []string{
|
||||
fmt.Sprintf(`{"level":"info","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).syncIndividualWebhookAuthenticator","message":"invalid webhook authenticator","webhookAuthenticator":"test-name","endpoint":"%s","removedFromCache":false}`, goodWebhookDefaultServingCertEndpoint),
|
||||
fmt.Sprintf(`{"level":"debug","timestamp":"2099-08-08T13:57:36.123456Z","logger":"webhookcachefiller-controller","caller":"webhookcachefiller/webhookcachefiller.go:<line>$webhookcachefiller.(*webhookCacheFillerController).updateStatus","message":"webhookauthenticator status successfully updated","webhookAuthenticator":"test-name","endpoint":"%s","phase":"Error"}`, goodWebhookDefaultServingCertEndpoint),
|
||||
},
|
||||
wantActions: func() []coretesting.Action {
|
||||
updateStatusAction := coretesting.NewUpdateAction(webhookAuthenticatorGVR, "", &authenticationv1alpha1.WebhookAuthenticator{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-name",
|
||||
},
|
||||
Spec: goodWebhookAuthenticatorSpecWithCA,
|
||||
Status: authenticationv1alpha1.WebhookAuthenticatorStatus{
|
||||
Conditions: conditionstestutil.Replace(
|
||||
allHappyConditionsSuccess(goodWebhookDefaultServingCertEndpoint, frozenMetav1Now, 0),
|
||||
[]metav1.Condition{
|
||||
sadEndpointURLValidProxyDetectErr("spec.endpoint URL error: fake proxy detector error", frozenMetav1Now, 0),
|
||||
unknownWebhookConnectionValid(frozenMetav1Now, 0),
|
||||
unknownAuthenticatorValid(frozenMetav1Now, 0),
|
||||
sadReadyCondition(frozenMetav1Now, 0),
|
||||
},
|
||||
),
|
||||
Phase: "Error",
|
||||
},
|
||||
})
|
||||
updateStatusAction.Subresource = "status"
|
||||
return []coretesting.Action{
|
||||
coretesting.NewListAction(webhookAuthenticatorGVR, webhookAuthenticatorGVK, "", metav1.ListOptions{}),
|
||||
coretesting.NewWatchAction(webhookAuthenticatorGVR, "", metav1.ListOptions{}),
|
||||
updateStatusAction,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Sync: valid WebhookAuthenticator with IPV6 and CA: will complete sync loop successfully with success conditions and ready phase",
|
||||
webhookAuthenticators: []runtime.Object{
|
||||
@@ -1925,6 +2123,13 @@ func TestController(t *testing.T) {
|
||||
tt.cache(t, cache)
|
||||
}
|
||||
|
||||
if tt.proxyDetector == nil {
|
||||
// By default, detect that a proxy is not required for any webhook hosts.
|
||||
tt.proxyDetector = func(t *testing.T) proxydetect.ProxyDetect {
|
||||
return fakeproxydetect.New(false, nil)
|
||||
}
|
||||
}
|
||||
|
||||
controller := New(
|
||||
"concierge", // namespace for controller
|
||||
cache,
|
||||
@@ -1935,7 +2140,9 @@ func TestController(t *testing.T) {
|
||||
controllerlib.WithInformer,
|
||||
frozenClock,
|
||||
logger,
|
||||
ptls.NewDialer())
|
||||
ptls.NewDialer(),
|
||||
tt.proxyDetector(t),
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
@@ -2179,7 +2386,9 @@ func TestControllerFilterSecret(t *testing.T) {
|
||||
observableInformers.WithInformer,
|
||||
frozenClock,
|
||||
logger,
|
||||
ptls.NewDialer())
|
||||
ptls.NewDialer(),
|
||||
fakeproxydetect.New(false, nil),
|
||||
)
|
||||
|
||||
unrelated := &corev1.Secret{}
|
||||
filter := observableInformers.GetFilterForInformer(secretInformer)
|
||||
@@ -2241,7 +2450,9 @@ func TestControllerFilterConfigMap(t *testing.T) {
|
||||
observableInformers.WithInformer,
|
||||
frozenClock,
|
||||
logger,
|
||||
ptls.NewDialer())
|
||||
ptls.NewDialer(),
|
||||
fakeproxydetect.New(false, nil),
|
||||
)
|
||||
|
||||
unrelated := &corev1.ConfigMap{}
|
||||
filter := observableInformers.GetFilterForInformer(configMapInformer)
|
||||
|
||||
Reference in New Issue
Block a user