Get hostname from load balancer ingress to use for impersonator certs

Signed-off-by: Margo Crawford <margaretc@vmware.com>
This commit is contained in:
Ryan Richard 2021-02-25 11:40:14 -08:00 committed by Margo Crawford
parent 9a8c80f20a
commit 0cae72b391
2 changed files with 88 additions and 11 deletions

View File

@ -362,7 +362,7 @@ func (c *impersonatorConfigController) deleteTLSCertificateWithWrongName(ctx con
actualCertFromSecret, _ := x509.ParseCertificate(block.Bytes) actualCertFromSecret, _ := x509.ParseCertificate(block.Bytes)
// TODO handle err // TODO handle err
desiredIPs, desiredHostnames, nameIsReady, err := c.findTLSCertificateName(config) // TODO check this for hostnames too, not just ips desiredIPs, desiredHostnames, nameIsReady, err := c.findTLSCertificateName(config)
//nolint:staticcheck // TODO remove this nolint when we fix the TODO below //nolint:staticcheck // TODO remove this nolint when we fix the TODO below
if err != nil { if err != nil {
// TODO return err // TODO return err
@ -474,15 +474,22 @@ func (c *impersonatorConfigController) findTLSCertificateNameFromLoadBalancer()
return nil, nil, false, err return nil, nil, false, err
} }
ingresses := lb.Status.LoadBalancer.Ingress ingresses := lb.Status.LoadBalancer.Ingress
if len(ingresses) == 0 { if len(ingresses) == 0 || (ingresses[0].Hostname == "" && ingresses[0].IP == "") {
plog.Info("load balancer for impersonation proxy does not have an ingress yet, so skipping tls cert generation while we wait", plog.Info("load balancer for impersonation proxy does not have an ingress yet, so skipping tls cert generation while we wait",
"service", c.generatedLoadBalancerServiceName, "service", c.generatedLoadBalancerServiceName,
"namespace", c.namespace) "namespace", c.namespace)
return nil, nil, false, nil return nil, nil, false, nil
} }
// TODO get all IPs and all hostnames from ingresses and put them in the cert hostname := ingresses[0].Hostname
if hostname != "" {
return nil, []string{hostname}, true, nil
}
ip := ingresses[0].IP ip := ingresses[0].IP
ips = []net.IP{net.ParseIP(ip)} parsedIP := net.ParseIP(ip)
if parsedIP == nil {
return nil, nil, false, fmt.Errorf("could not parse IP address from load balancer %s: %s", lb.Name, ip)
}
ips = []net.IP{parsedIP}
return ips, hostnames, true, nil return ips, hostnames, true, nil
} }

View File

@ -558,7 +558,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
)) ))
} }
var addLoadBalancerServiceWithIPToTracker = func(resourceName string, client *kubernetesfake.Clientset) { var addLoadBalancerServiceWithIngressToTracker = func(resourceName string, ip string, hostname string, client *kubernetesfake.Clientset) {
loadBalancerService := &corev1.Service{ loadBalancerService := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: resourceName, Name: resourceName,
@ -574,7 +574,10 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
Status: corev1.ServiceStatus{ Status: corev1.ServiceStatus{
LoadBalancer: corev1.LoadBalancerStatus{ LoadBalancer: corev1.LoadBalancerStatus{
Ingress: []corev1.LoadBalancerIngress{ Ingress: []corev1.LoadBalancerIngress{
{IP: "127.0.0.1"}, {
IP: ip,
Hostname: hostname,
},
}, },
}, },
}, },
@ -759,6 +762,44 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireNodesListed(kubeAPIClient.Actions()[0]) requireNodesListed(kubeAPIClient.Actions()[0])
}) })
}) })
when("there are not visible control plane nodes and a load balancer already exists with empty ingress", func() {
it.Before(func() {
addNodeWithRoleToTracker("worker")
addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "", "", kubeInformerClient)
addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "", "", kubeAPIClient)
startInformersAndController()
r.NoError(controllerlib.TestSync(t, subject, *syncContext))
})
it("starts the impersonator without tls certs", func() {
requireTLSServerIsRunningWithoutCerts()
})
it("does not start the load balancer automatically", func() {
r.Len(kubeAPIClient.Actions(), 1)
requireNodesListed(kubeAPIClient.Actions()[0])
})
})
when("there are not visible control plane nodes and a load balancer already exists with invalid ip", func() {
it.Before(func() {
addNodeWithRoleToTracker("worker")
addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "not-an-ip", "", kubeInformerClient)
addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "not-an-ip", "", kubeAPIClient)
startInformersAndController()
r.EqualError(controllerlib.TestSync(t, subject, *syncContext), "could not parse IP address from load balancer some-service-resource-name: not-an-ip")
})
it("starts the impersonator without tls certs", func() {
requireTLSServerIsRunningWithoutCerts()
})
it("does not start the load balancer automatically", func() {
r.Len(kubeAPIClient.Actions(), 1)
requireNodesListed(kubeAPIClient.Actions()[0])
})
})
}) })
when("sync is called more than once", func() { when("sync is called more than once", func() {
@ -793,7 +834,7 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
requireTLSServerIsRunningWithoutCerts() requireTLSServerIsRunningWithoutCerts()
// update manually because the kubeAPIClient isn't connected to the informer in the tests // update manually because the kubeAPIClient isn't connected to the informer in the tests
addLoadBalancerServiceWithIPToTracker(generatedLoadBalancerServiceName, kubeInformerClient) addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", "", kubeInformerClient)
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "0") waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "0")
r.NoError(controllerlib.TestSync(t, subject, *syncContext)) r.NoError(controllerlib.TestSync(t, subject, *syncContext))
@ -811,6 +852,35 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
r.Len(kubeAPIClient.Actions(), 3) // no more actions r.Len(kubeAPIClient.Actions(), 3) // no more actions
requireTLSServerIsRunning(ca, startedTLSListener.Addr().String(), nil) // still running requireTLSServerIsRunning(ca, startedTLSListener.Addr().String(), nil) // still running
}) })
it("creates certs from the hostname listed on the load balancer", func() {
hostname := "fake.example.com"
startInformersAndController()
r.NoError(controllerlib.TestSync(t, subject, *syncContext))
r.Len(kubeAPIClient.Actions(), 2)
requireNodesListed(kubeAPIClient.Actions()[0])
requireLoadBalancerWasCreated(kubeAPIClient.Actions()[1])
requireTLSServerIsRunningWithoutCerts()
// update manually because the kubeAPIClient isn't connected to the informer in the tests
addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", hostname, kubeInformerClient)
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Services().Informer(), "0")
r.NoError(controllerlib.TestSync(t, subject, *syncContext))
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a second time
r.Len(kubeAPIClient.Actions(), 3)
ca := requireTLSSecretWasCreated(kubeAPIClient.Actions()[2])
requireTLSServerIsRunning(ca, hostname, map[string]string{hostname + ":443": startedTLSListener.Addr().String()}) // running with certs now
// update manually because the kubeAPIClient isn't connected to the informer in the tests
addSecretFromCreateActionToTracker(kubeAPIClient.Actions()[2], kubeInformerClient, "1")
waitForInformerCacheToSeeResourceVersion(kubeInformers.Core().V1().Secrets().Informer(), "1")
r.NoError(controllerlib.TestSync(t, subject, *syncContext))
r.Equal(1, startTLSListenerFuncWasCalled) // wasn't started a third time
r.Len(kubeAPIClient.Actions(), 3) // no more actions
requireTLSServerIsRunning(ca, hostname, map[string]string{hostname + ":443": startedTLSListener.Addr().String()}) // still running
})
}) })
when("getting the control plane nodes returns an error, e.g. when there are no nodes", func() { when("getting the control plane nodes returns an error, e.g. when there are no nodes", func() {
@ -966,8 +1036,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
ca = tlsSecret.Data["ca.crt"] ca = tlsSecret.Data["ca.crt"]
r.NoError(kubeAPIClient.Tracker().Add(tlsSecret)) r.NoError(kubeAPIClient.Tracker().Add(tlsSecret))
r.NoError(kubeInformerClient.Tracker().Add(tlsSecret)) r.NoError(kubeInformerClient.Tracker().Add(tlsSecret))
addLoadBalancerServiceWithIPToTracker(generatedLoadBalancerServiceName, kubeInformerClient) addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", "", kubeInformerClient)
addLoadBalancerServiceWithIPToTracker(generatedLoadBalancerServiceName, kubeAPIClient) addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", "", kubeAPIClient)
}) })
it("starts the impersonator with the existing tls certs, does not start loadbalancer or make tls secret", func() { it("starts the impersonator with the existing tls certs, does not start loadbalancer or make tls secret", func() {
@ -987,8 +1057,8 @@ func TestImpersonatorConfigControllerSync(t *testing.T) {
tlsSecret = createStubTLSSecret(tlsSecretName) // secret exists but lacks certs tlsSecret = createStubTLSSecret(tlsSecretName) // secret exists but lacks certs
r.NoError(kubeAPIClient.Tracker().Add(tlsSecret)) r.NoError(kubeAPIClient.Tracker().Add(tlsSecret))
r.NoError(kubeInformerClient.Tracker().Add(tlsSecret)) r.NoError(kubeInformerClient.Tracker().Add(tlsSecret))
addLoadBalancerServiceWithIPToTracker(generatedLoadBalancerServiceName, kubeInformerClient) addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", "", kubeInformerClient)
addLoadBalancerServiceWithIPToTracker(generatedLoadBalancerServiceName, kubeAPIClient) addLoadBalancerServiceWithIngressToTracker(generatedLoadBalancerServiceName, "127.0.0.1", "", kubeAPIClient)
}) })
it("returns an error and leaves the impersonator running without tls certs", func() { it("returns an error and leaves the impersonator running without tls certs", func() {