From 1d055076d2adb8c9789e0dee08f8f69e78a48b54 Mon Sep 17 00:00:00 2001 From: Julio Camarero Date: Mon, 9 Dec 2024 11:25:51 +0100 Subject: [PATCH] parse new annotations --- internal/ingress/annotations/proxyssl/main.go | 44 +++++++++++++++ .../ingress/annotations/proxyssl/main_test.go | 56 +++++++++++++++++-- 2 files changed, 95 insertions(+), 5 deletions(-) diff --git a/internal/ingress/annotations/proxyssl/main.go b/internal/ingress/annotations/proxyssl/main.go index f1725ad9a..aeb791809 100644 --- a/internal/ingress/annotations/proxyssl/main.go +++ b/internal/ingress/annotations/proxyssl/main.go @@ -241,6 +241,50 @@ func (p proxySSL) Parse(ing *networking.Ingress) (interface{}, error) { } config.AuthSSLCert = *proxyCert + proxysslclientsecret, err := parser.GetStringAnnotation(proxySSLClientSecretAnnotation, ing, p.annotationConfig.Annotations) + if err != nil { + return &Config{}, err + } + + ns, _, err = k8s.ParseNameNS(proxysslclientsecret) + if err != nil { + return &Config{}, ing_errors.NewLocationDenied(err.Error()) + } + + // We don't accept different namespaces for secrets. + if !secCfg.AllowCrossNamespaceResources && ns != ing.Namespace { + return &Config{}, ing_errors.NewLocationDenied("cross namespace secrets are not supported") + } + + sslClientCert, err := p.r.GetSSLClientCert(proxysslclientsecret) + if err != nil { + e := fmt.Errorf("error obtaining ssl client certificate: %w", err) + return &Config{}, ing_errors.LocationDeniedError{Reason: e} + } + config.ProxySSLClientCert = *sslClientCert + + proxysslcaconfigmap, err := parser.GetStringAnnotation(proxySSLCAConfigMapAnnotation, ing, p.annotationConfig.Annotations) + if err != nil { + return &Config{}, err + } + + ns, _, err = k8s.ParseNameNS(proxysslcaconfigmap) + if err != nil { + return &Config{}, ing_errors.NewLocationDenied(err.Error()) + } + + // We don't accept different namespaces for configmaps. + if !secCfg.AllowCrossNamespaceResources && ns != ing.Namespace { + return &Config{}, ing_errors.NewLocationDenied("cross namespace configmaps are not supported") + } + + sslCA, err := p.r.GetSSLCA(proxysslcaconfigmap) + if err != nil { + e := fmt.Errorf("error obtaining ssl certificate authority: %w", err) + return &Config{}, ing_errors.LocationDeniedError{Reason: e} + } + config.ProxySSLCA = *sslCA + config.Ciphers, err = parser.GetStringAnnotation(proxySSLCiphersAnnotation, ing, p.annotationConfig.Annotations) if err != nil { if ing_errors.IsValidationError(err) { diff --git a/internal/ingress/annotations/proxyssl/main_test.go b/internal/ingress/annotations/proxyssl/main_test.go index cfa31f1d1..ed834de22 100644 --- a/internal/ingress/annotations/proxyssl/main_test.go +++ b/internal/ingress/annotations/proxyssl/main_test.go @@ -28,11 +28,12 @@ import ( ) const ( - defaultDemoSecret = "default/demo-secret" - proxySslCiphers = "HIGH:-SHA" - off = "off" - sslServerName = "w00t" - defaultProtocol = "TLSv1.2 TLSv1.3" + defaultDemoSecret = "default/demo-secret" + defaultDemoConfigMap = "default/demo-configmap" + proxySslCiphers = "HIGH:-SHA" + off = "off" + sslServerName = "w00t" + defaultProtocol = "TLSv1.2 TLSv1.3" ) func buildIngress() *networking.Ingress { @@ -96,11 +97,37 @@ func (m mockSecret) GetAuthCertificate(name string) (*resolver.AuthSSLCert, erro }, nil } +// GetSSLClientCert resolves a given secret name into an SSL certificate. +func (m mockSecret) GetSSLClientCert(name string) (*resolver.SSLClientCert, error) { + if name != defaultDemoSecret { + return nil, errors.Errorf("there is no secret with name %v", name) + } + + return &resolver.SSLClientCert{ + Secret: defaultDemoSecret, + }, nil +} + +// GetSSLCA resolves a given configMap name into an SSL CA. +func (m mockSecret) GetSSLCA(name string) (*resolver.SSLCA, error) { + if name != defaultDemoConfigMap { + return nil, errors.Errorf("there is no configmap with name %v", name) + } + + return &resolver.SSLCA{ + ConfigMap: defaultDemoConfigMap, + CAFileName: "/ssl/ca.crt", + CASHA: "abc", + }, nil +} + func TestAnnotations(t *testing.T) { ing := buildIngress() data := map[string]string{} data[parser.GetAnnotationWithPrefix(proxySSLSecretAnnotation)] = defaultDemoSecret + data[parser.GetAnnotationWithPrefix(proxySSLClientSecretAnnotation)] = defaultDemoSecret + data[parser.GetAnnotationWithPrefix(proxySSLCAConfigMapAnnotation)] = defaultDemoConfigMap data[parser.GetAnnotationWithPrefix("proxy-ssl-ciphers")] = proxySslCiphers data[parser.GetAnnotationWithPrefix("proxy-ssl-name")] = "$host" data[parser.GetAnnotationWithPrefix("proxy-ssl-protocols")] = "TLSv1.3 TLSv1.2" @@ -126,10 +153,24 @@ func TestAnnotations(t *testing.T) { if err != nil { t.Errorf("unexpected error getting secret %v", err) } + clientSecret, err := fakeSecret.GetSSLClientCert(defaultDemoSecret) + if err != nil { + t.Errorf("unexpected error getting secret %v", err) + } + configMap, err := fakeSecret.GetSSLCA(defaultDemoConfigMap) + if err != nil { + t.Errorf("unexpected error getting configmap %v", err) + } if u.AuthSSLCert.Secret != secret.Secret { t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret) } + if u.ProxySSLClientCert.Secret != clientSecret.Secret { + t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret) + } + if u.ProxySSLCA.ConfigMap != configMap.ConfigMap { + t.Errorf("expected %v but got %v", secret.Secret, u.AuthSSLCert.Secret) + } if u.Ciphers != proxySslCiphers { t.Errorf("expected %v but got %v", proxySslCiphers, u.Ciphers) } @@ -179,6 +220,8 @@ func TestInvalidAnnotations(t *testing.T) { // Invalid optional Annotations data[parser.GetAnnotationWithPrefix("proxy-ssl-secret")] = defaultDemoSecret + data[parser.GetAnnotationWithPrefix("proxy-ssl-client-secret")] = defaultDemoSecret + data[parser.GetAnnotationWithPrefix("proxy-ssl-ca-configmap")] = defaultDemoConfigMap data[parser.GetAnnotationWithPrefix("proxy-ssl-protocols")] = "TLSv111 SSLv1" data[parser.GetAnnotationWithPrefix("proxy-ssl-server-name")] = sslServerName data[parser.GetAnnotationWithPrefix("proxy-ssl-session-reuse")] = sslServerName @@ -237,6 +280,9 @@ func TestEquals(t *testing.T) { t.Errorf("Expected false") } cfg2.AuthSSLCert = sslCert1 + // TODO: Different client certs + + // TODO: Different CAs // Different Ciphers cfg1.Ciphers = "DEFAULT"