diff --git a/internal/ingress/annotations/authtls/main.go b/internal/ingress/annotations/authtls/main.go index adedb084a..762dcc2af 100644 --- a/internal/ingress/annotations/authtls/main.go +++ b/internal/ingress/annotations/authtls/main.go @@ -32,12 +32,13 @@ const ( defaultAuthTLSDepth = 1 defaultAuthVerifyClient = "on" - annotationAuthTLSSecret = "auth-tls-secret" //#nosec G101 - annotationAuthTLSVerifyClient = "auth-tls-verify-client" - annotationAuthTLSVerifyDepth = "auth-tls-verify-depth" - annotationAuthTLSErrorPage = "auth-tls-error-page" - annotationAuthTLSPassCertToUpstream = "auth-tls-pass-certificate-to-upstream" //#nosec G101 - annotationAuthTLSMatchCN = "auth-tls-match-cn" + annotationAuthTLSSecret = "auth-tls-secret" //#nosec G101 + annotationAuthTLSVerifyClient = "auth-tls-verify-client" + annotationAuthTLSVerifyDepth = "auth-tls-verify-depth" + annotationAuthTLSErrorPage = "auth-tls-error-page" + annotationAuthTLSPassCertToUpstream = "auth-tls-pass-certificate-to-upstream" //#nosec G101 + annotationAuthTLSPassCertToUpstreamHeader = "auth-tls-pass-certificate-to-upstream-header" //#nosec G101 + annotationAuthTLSMatchCN = "auth-tls-match-cn" ) var ( @@ -80,6 +81,12 @@ var authTLSAnnotations = parser.Annotation{ Risk: parser.AnnotationRiskLow, Documentation: `This annotation defines if the received certificates should be passed or not to the upstream server in the header "ssl-client-cert"`, }, + annotationAuthTLSPassCertToUpstreamHeader: { + Validator: parser.ValidateNull, + Scope: parser.AnnotationScopeLocation, + Risk: parser.AnnotationRiskLow, + Documentation: `This annotation defines the header name in which the client certificate will be passed to the upstream server`, + }, annotationAuthTLSMatchCN: { Validator: parser.ValidateRegex(commonNameRegex, true), Scope: parser.AnnotationScopeLocation, @@ -93,12 +100,13 @@ var authTLSAnnotations = parser.Annotation{ // and the configured ValidationDepth type Config struct { resolver.AuthSSLCert - VerifyClient string `json:"verify_client"` - ValidationDepth int `json:"validationDepth"` - ErrorPage string `json:"errorPage"` - PassCertToUpstream bool `json:"passCertToUpstream"` - MatchCN string `json:"matchCN"` - AuthTLSError string + VerifyClient string `json:"verify_client"` + ValidationDepth int `json:"validationDepth"` + ErrorPage string `json:"errorPage"` + PassCertToUpstream bool `json:"passCertToUpstream"` + PassCertToUpstreamHeader string `json:"passCertToUpstreamHeader"` + MatchCN string `json:"matchCN"` + AuthTLSError string } // Equal tests for equality between two Config types @@ -125,6 +133,10 @@ func (assl1 *Config) Equal(assl2 *Config) bool { return false } + if assl1.PassCertToUpstreamHeader != assl2.PassCertToUpstreamHeader { + return false + } + return true } @@ -200,6 +212,14 @@ func (a authTLS) Parse(ing *networking.Ingress) (interface{}, error) { config.PassCertToUpstream = false } + config.PassCertToUpstreamHeader, err = parser.GetStringAnnotation(annotationAuthTLSPassCertToUpstreamHeader, ing, a.annotationConfig.Annotations) + if err != nil { + if ing_errors.IsValidationError(err) { + return &Config{}, err + } + config.PassCertToUpstreamHeader = "ssl-client-cert" + } + config.MatchCN, err = parser.GetStringAnnotation(annotationAuthTLSMatchCN, ing, a.annotationConfig.Annotations) if err != nil { if ing_errors.IsValidationError(err) { diff --git a/internal/ingress/annotations/authtls/main_test.go b/internal/ingress/annotations/authtls/main_test.go index 0dd442e4f..6efe0dac3 100644 --- a/internal/ingress/annotations/authtls/main_test.go +++ b/internal/ingress/annotations/authtls/main_test.go @@ -132,6 +132,9 @@ func TestAnnotations(t *testing.T) { if u.PassCertToUpstream != false { t.Errorf("expected %v but got %v", false, u.PassCertToUpstream) } + if u.PassCertToUpstreamHeader != "ssl-client-cert" { + t.Errorf("expected %v but got %v", "ssl-client-cert", u.PassCertToUpstreamHeader) + } if u.MatchCN != "" { t.Errorf("expected empty string, but got %v", u.MatchCN) } @@ -140,6 +143,7 @@ func TestAnnotations(t *testing.T) { data[parser.GetAnnotationWithPrefix(annotationAuthTLSVerifyDepth)] = "2" data[parser.GetAnnotationWithPrefix(annotationAuthTLSErrorPage)] = "ok.com/error" data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)] = "true" + data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstreamHeader)] = "X-SSL-CERT" data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "CN=(hello-app|ok|goodbye)" ing.SetAnnotations(data) @@ -169,6 +173,9 @@ func TestAnnotations(t *testing.T) { if u.PassCertToUpstream != true { t.Errorf("expected %v but got %v", true, u.PassCertToUpstream) } + if u.PassCertToUpstreamHeader != "X-SSL-CERT" { + t.Errorf("expected %v but got %v", "X-SSL-CERT", u.PassCertToUpstreamHeader) + } if u.MatchCN != "CN=(hello-app|ok|goodbye)" { t.Errorf("expected %v but got %v", "CN=(hello-app|ok|goodbye)", u.MatchCN) } @@ -235,6 +242,14 @@ func TestInvalidAnnotations(t *testing.T) { } delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstream)) + data[parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstreamHeader)] = 1 + ing.SetAnnotations(data) + _, err = NewParser(fakeSecret).Parse(ing) + if err == nil { + t.Errorf("Expected error with ingress but got nil") + } + delete(data, parser.GetAnnotationWithPrefix(annotationAuthTLSPassCertToUpstreamHeader)) + data[parser.GetAnnotationWithPrefix(annotationAuthTLSMatchCN)] = "" ing.SetAnnotations(data) _, err = NewParser(fakeSecret).Parse(ing) @@ -263,6 +278,9 @@ func TestInvalidAnnotations(t *testing.T) { if u.PassCertToUpstream != false { t.Errorf("expected %v but got %v", false, u.PassCertToUpstream) } + if u.PassCertToUpstreamHeader != "ssl-client-cert" { + t.Errorf("expected %v but got %v", "ssl-client-cert", u.PassCertToUpstreamHeader) + } if u.MatchCN != "" { t.Errorf("expected empty string but got %v", u.MatchCN) } @@ -333,6 +351,15 @@ func TestEquals(t *testing.T) { } cfg2.PassCertToUpstream = true + // Different Pass to Upstream Header + cfg1.PassCertToUpstreamHeader = "ssl-client-cert" + cfg2.PassCertToUpstreamHeader = "X-SSL-CERT" + result = cfg1.Equal(cfg2) + if result != false { + t.Errorf("Expected false") + } + cfg2.PassCertToUpstreamHeader = "ssl-client-cert" + // Equal Configs result = cfg1.Equal(cfg2) if result != true { diff --git a/rootfs/etc/nginx/template/nginx.tmpl b/rootfs/etc/nginx/template/nginx.tmpl index ccd7b4411..952f49bc6 100644 --- a/rootfs/etc/nginx/template/nginx.tmpl +++ b/rootfs/etc/nginx/template/nginx.tmpl @@ -1182,7 +1182,7 @@ stream { # Pass the extracted client certificate to the auth provider {{ if not (empty $server.CertificateAuth.CAFileName) }} {{ if $server.CertificateAuth.PassCertToUpstream }} - proxy_set_header ssl-client-cert $ssl_client_escaped_cert; + proxy_set_header {{ $server.CertificateAuth.PassCertToUpstreamHeader }} $ssl_client_escaped_cert; {{ end }} proxy_set_header ssl-client-verify $ssl_client_verify; proxy_set_header ssl-client-subject-dn $ssl_client_s_dn;