From b0e9edd341bcf81c4c519795381ff5e573128376 Mon Sep 17 00:00:00 2001 From: Zachary Nixon Date: Mon, 9 Dec 2024 18:01:49 -0800 Subject: [PATCH] feat: add advertise ca for mtls listener --- docs/guide/ingress/annotations.md | 1 + go.mod | 8 +- go.sum | 24 +-- pkg/deploy/elbv2/listener_manager.go | 15 +- pkg/deploy/elbv2/listener_manager_test.go | 2 + pkg/ingress/model_build_listener.go | 22 ++- pkg/ingress/model_build_listener_test.go | 192 +++++++++++++++++++++- pkg/model/elbv2/listener.go | 3 +- pkg/service/model_builder_test.go | 1 + 9 files changed, 242 insertions(+), 26 deletions(-) diff --git a/docs/guide/ingress/annotations.md b/docs/guide/ingress/annotations.md index 7035dc80f..2d51c29b8 100644 --- a/docs/guide/ingress/annotations.md +++ b/docs/guide/ingress/annotations.md @@ -805,6 +805,7 @@ TLS support can be controlled with the following annotations: - Both ARN and Name of trustStore are supported values. - `trustStore` is required when mode is `verify`. - `ignoreClientCertificateExpiry : true | false (default)` + - `advertiseTrustStoreCaNames : "on" | "off" (default)` - Once the Mutual Authentication is set, to turn it off, you will have to explicitly pass in this annotation with `mode : "off"`. !!!example diff --git a/go.mod b/go.mod index 1e05dbf7d..baafc0f46 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,13 @@ go 1.22.8 require ( github.com/aws/aws-sdk-go v1.55.5 - github.com/aws/aws-sdk-go-v2 v1.32.5 + github.com/aws/aws-sdk-go-v2 v1.32.6 github.com/aws/aws-sdk-go-v2/config v1.27.27 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 github.com/aws/aws-sdk-go-v2/service/acm v1.28.4 github.com/aws/aws-sdk-go-v2/service/appmesh v1.27.7 github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.42.0 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.1 github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.23.3 github.com/aws/aws-sdk-go-v2/service/servicediscovery v1.31.7 github.com/aws/aws-sdk-go-v2/service/shield v1.27.3 @@ -57,8 +57,8 @@ require ( github.com/andybalholm/brotli v1.0.4 // indirect github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect diff --git a/go.sum b/go.sum index b13e21262..7f48d636b 100644 --- a/go.sum +++ b/go.sum @@ -38,24 +38,18 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0 github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= -github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo= -github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= +github.com/aws/aws-sdk-go-v2 v1.32.6 h1:7BokKRgRPuGmKkFMhEg/jSul+tB9VvXhcViILtfG8b4= +github.com/aws/aws-sdk-go-v2 v1.32.6/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U= github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25 h1:s/fF4+yDQDoElYhfIVvSNyeCydfbuTKzhxSXDXCPasU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.25/go.mod h1:IgPfDv5jqFIzQSNbUEMoitNooSMXjRSDkhXv8jiROvU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25 h1:ZntTCl5EsYnhN/IygQEUugpdwbhdkom9uHcbCftiGgA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.25/go.mod h1:DBdPrgeocww+CSl1C8cEV8PN1mHMBhuCDLpXezyvWkE= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/acm v1.28.4 h1:wiW1Y6/1lysA0eJZRq0I53YYKuV9MNAzL15z2eZRlEE= @@ -64,8 +58,8 @@ github.com/aws/aws-sdk-go-v2/service/appmesh v1.27.7 h1:q44a6kysAfej9zZwRnraOg9s github.com/aws/aws-sdk-go-v2/service/appmesh v1.27.7/go.mod h1:ZYSmrgAMp0rTCHH+SGsoxZo+PPbgsDqBzewTp3tSJ60= github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 h1:ta62lid9JkIpKZtZZXSj6rP2AqY5x1qYGq53ffxqD9Q= github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0/go.mod h1:o6QDjdVKpP5EF0dp/VlvqckzuSDATr1rLdHt3A5m0YY= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.42.0 h1:C4/D90/j3EF/SokpC4HO1aPMkZV1dgqUbmejdpxQiAE= -github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.42.0/go.mod h1:pZP3I+Ts+XuhJJtZE49+ABVjfxm7u9/hxcNUYSpY3OE= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.1 h1:L9Wt9zgtoYKIlaeFTy+EztGjL4oaXBBGtVXA+jaeYko= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.43.1/go.mod h1:yxzLdxt7bVGvIOPYIKFtiaJCJnx2ChlIIvlhW4QgI6M= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= @@ -86,8 +80,6 @@ github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.3 h1:7dr6En0/6KRFoz8VmnYk github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.3/go.mod h1:24TtlRsv4LKAE3VnRJQhpatr8cpX0yj8NSzg8/lxOCw= github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.4 h1:1khBA5uryBRJoCb4G2iR5RT06BkfPEjjDCHAiRb8P3Q= github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.4/go.mod h1:QpFImaPGKNwa+MiZ+oo6LbV1PVQBapc0CnrAMRScoxM= -github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= -github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro= github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= diff --git a/pkg/deploy/elbv2/listener_manager.go b/pkg/deploy/elbv2/listener_manager.go index a9db44077..0a6c92d53 100644 --- a/pkg/deploy/elbv2/listener_manager.go +++ b/pkg/deploy/elbv2/listener_manager.go @@ -365,11 +365,17 @@ func buildSDKMutualAuthenticationConfig(modelMutualAuthenticationCfg *elbv2model if modelMutualAuthenticationCfg == nil { return nil } - return &elbv2types.MutualAuthenticationAttributes{ + attributes := &elbv2types.MutualAuthenticationAttributes{ IgnoreClientCertificateExpiry: modelMutualAuthenticationCfg.IgnoreClientCertificateExpiry, Mode: awssdk.String(modelMutualAuthenticationCfg.Mode), TrustStoreArn: modelMutualAuthenticationCfg.TrustStoreArn, } + + if modelMutualAuthenticationCfg.Mode == string(elbv2model.MutualAuthenticationVerifyMode) { + attributes.AdvertiseTrustStoreCaNames = translateAdvertiseCAToEnum(modelMutualAuthenticationCfg.AdvertiseTrustStoreCaNames) + } + + return attributes } func buildResListenerStatus(sdkLS ListenerWithTags) elbv2model.ListenerStatus { @@ -396,3 +402,10 @@ func getRegionFromARN(arn string) string { func isIsolatedRegion(region string) bool { return strings.Contains(strings.ToLower(region), "-iso-") } + +func translateAdvertiseCAToEnum(s *string) elbv2types.AdvertiseTrustStoreCaNamesEnum { + if s == nil { + return elbv2types.AdvertiseTrustStoreCaNamesEnumOff + } + return elbv2types.AdvertiseTrustStoreCaNamesEnum(*s) +} diff --git a/pkg/deploy/elbv2/listener_manager_test.go b/pkg/deploy/elbv2/listener_manager_test.go index e096b500c..cf7521df7 100644 --- a/pkg/deploy/elbv2/listener_manager_test.go +++ b/pkg/deploy/elbv2/listener_manager_test.go @@ -235,6 +235,7 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) { Mode: awssdk.String("verify"), TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:us-east-1:123456789123:truststore/ts-1/8786hghf"), IgnoreClientCertificateExpiry: awssdk.Bool(false), + AdvertiseTrustStoreCaNames: elbv2types.AdvertiseTrustStoreCaNamesEnumOff, }, }, }, @@ -260,6 +261,7 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) { Mode: awssdk.String("verify"), TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:us-east-1:123456789123:truststore/ts-1/8786hghf"), IgnoreClientCertificateExpiry: awssdk.Bool(false), + AdvertiseTrustStoreCaNames: elbv2types.AdvertiseTrustStoreCaNamesEnumOff, }, }, }, diff --git a/pkg/ingress/model_build_listener.go b/pkg/ingress/model_build_listener.go index 80f848ba3..32c118452 100644 --- a/pkg/ingress/model_build_listener.go +++ b/pkg/ingress/model_build_listener.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "net" "strings" @@ -283,6 +284,7 @@ type MutualAuthenticationConfig struct { Mode string `json:"mode"` TrustStore *string `json:"trustStore,omitempty"` IgnoreClientCertificateExpiry *bool `json:"ignoreClientCertificateExpiry,omitempty"` + AdvertiseTrustStoreCaNames *string `json:"advertiseTrustStoreCaNames,omitempty"` } func (t *defaultModelBuildTask) computeIngressMutualAuthentication(ctx context.Context, ing *ClassifiedIngress) (map[int32]*elbv2model.MutualAuthenticationAttributes, error) { @@ -319,8 +321,9 @@ func (t *defaultModelBuildTask) parseMtlsConfigEntries(_ context.Context, entrie mode := mutualAuthenticationConfig.Mode truststoreNameOrArn := awssdk.ToString(mutualAuthenticationConfig.TrustStore) ignoreClientCert := mutualAuthenticationConfig.IgnoreClientCertificateExpiry + advertiseTrustStoreCaNames := mutualAuthenticationConfig.AdvertiseTrustStoreCaNames - err := t.validateMutualAuthenticationConfig(port, mode, truststoreNameOrArn, ignoreClientCert) + err := t.validateMutualAuthenticationConfig(port, mode, truststoreNameOrArn, ignoreClientCert, advertiseTrustStoreCaNames) if err != nil { return nil, err } @@ -328,12 +331,12 @@ func (t *defaultModelBuildTask) parseMtlsConfigEntries(_ context.Context, entrie if mode == string(elbv2model.MutualAuthenticationVerifyMode) && ignoreClientCert == nil { ignoreClientCert = awssdk.Bool(false) } - portAndMtlsAttributes[port] = &elbv2model.MutualAuthenticationAttributes{Mode: mode, TrustStoreArn: awssdk.String(truststoreNameOrArn), IgnoreClientCertificateExpiry: ignoreClientCert} + portAndMtlsAttributes[port] = &elbv2model.MutualAuthenticationAttributes{Mode: mode, TrustStoreArn: awssdk.String(truststoreNameOrArn), IgnoreClientCertificateExpiry: ignoreClientCert, AdvertiseTrustStoreCaNames: advertiseTrustStoreCaNames} } return portAndMtlsAttributes, nil } -func (t *defaultModelBuildTask) validateMutualAuthenticationConfig(port int32, mode string, truststoreNameOrArn string, ignoreClientCert *bool) error { +func (t *defaultModelBuildTask) validateMutualAuthenticationConfig(port int32, mode string, truststoreNameOrArn string, ignoreClientCert *bool, advertiseTrustStoreCaNames *string) error { // Verify port value is valid for ALB: [1, 65535] if port < 1 || port > 65535 { return errors.Errorf("listen port must be within [1, 65535]: %v", port) @@ -360,6 +363,19 @@ func (t *defaultModelBuildTask) validateMutualAuthenticationConfig(port int32, m return errors.Errorf("Mutual Authentication mode %s does not support ignoring client certificate expiry for port %v", mode, port) } + // Verify advertise trust ca names. + // The value (if specified) must be "on" or "off" + // The value can be only specified when using verify mode on the listener. + if advertiseTrustStoreCaNames != nil { + if mode != string(elbv2model.MutualAuthenticationVerifyMode) { + return errors.Errorf("Mutual Authentication mode %s does not support advertiseTrustStoreCaNames for port %v", mode, port) + } + + if *advertiseTrustStoreCaNames != string(elbv2types.AdvertiseTrustStoreCaNamesEnumOff) && *advertiseTrustStoreCaNames != string(elbv2types.AdvertiseTrustStoreCaNamesEnumOn) { + return errors.Errorf("advertiseTrustStoreCaNames only supports the values \"on\" and \"off\" got value %s for port %v", *advertiseTrustStoreCaNames, port) + } + } + return nil } diff --git a/pkg/ingress/model_build_listener_test.go b/pkg/ingress/model_build_listener_test.go index 9514b8f6e..52ce53709 100644 --- a/pkg/ingress/model_build_listener_test.go +++ b/pkg/ingress/model_build_listener_test.go @@ -2,6 +2,8 @@ package ingress import ( "context" + awssdk "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/aws" "testing" "github.com/stretchr/testify/assert" @@ -54,7 +56,6 @@ func Test_computeIngressListenPortConfigByPort_MutualAuthentication(t *testing.T }, want: []WantStruct{{port: 443, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "off", TrustStoreArn: nil, IgnoreClientCertificateExpiry: nil})}, {port: 80, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "passthrough", TrustStoreArn: nil, IgnoreClientCertificateExpiry: nil})}}, }, - { name: "Listener Config when MutualAuthentication annotation is not specified", @@ -79,6 +80,54 @@ func Test_computeIngressListenPortConfigByPort_MutualAuthentication(t *testing.T }, want: []WantStruct{{port: 443, mutualAuth: nil}, {port: 80, mutualAuth: nil}}, }, + { + name: "Listener Config when MutualAuthentication annotation is specified with advertise trust store CA not set", + fields: fields{ + ingGroup: Group{ + ID: GroupID{Name: "explicit-group"}, + Members: []ClassifiedIngress{ + { + Ing: &networking.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "awesome-ns", + Name: "ing-1", + Annotations: map[string]string{ + "alb.ingress.kubernetes.io/listen-ports": `[{"HTTPS": 443}, {"HTTPS": 80}]`, + "alb.ingress.kubernetes.io/mutual-authentication": `[{"port":443,"mode":"off"}, {"port":80,"mode":"passthrough"}]`, + "alb.ingress.kubernetes.io/certificate-arn": "arn:aws:iam::123456789:server-certificate/new-clb-cert", + }, + }, + }, + }, + }, + }, + }, + want: []WantStruct{{port: 443, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "off", TrustStoreArn: nil, IgnoreClientCertificateExpiry: nil})}, {port: 80, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "passthrough", TrustStoreArn: nil, IgnoreClientCertificateExpiry: nil})}}, + }, + { + name: "Listener Config when MutualAuthentication annotation is specified with advertise trust store CA set", + fields: fields{ + ingGroup: Group{ + ID: GroupID{Name: "explicit-group"}, + Members: []ClassifiedIngress{ + { + Ing: &networking.Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "awesome-ns", + Name: "ing-1", + Annotations: map[string]string{ + "alb.ingress.kubernetes.io/listen-ports": `[{"HTTPS": 443}, {"HTTPS": 80}]`, + "alb.ingress.kubernetes.io/mutual-authentication": `[{"port":443,"mode":"off"}, {"port":80,"mode":"verify", "advertiseTrustStoreCaNames": "on", "trustStore": "arn:aws:elasticloadbalancing:trustStoreArn"}]`, + "alb.ingress.kubernetes.io/certificate-arn": "arn:aws:iam::123456789:server-certificate/new-clb-cert", + }, + }, + }, + }, + }, + }, + }, + want: []WantStruct{{port: 443, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "off", TrustStoreArn: nil, IgnoreClientCertificateExpiry: nil})}, {port: 80, mutualAuth: &(elbv2.MutualAuthenticationAttributes{Mode: "verify", TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:trustStoreArn"), AdvertiseTrustStoreCaNames: awssdk.String("on"), IgnoreClientCertificateExpiry: nil})}}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -96,6 +145,11 @@ func Test_computeIngressListenPortConfigByPort_MutualAuthentication(t *testing.T mutualAuth := tt.want[i].mutualAuth if mutualAuth != nil { assert.Equal(t, mutualAuth.Mode, got[port].mutualAuthentication.Mode) + + if mutualAuth.AdvertiseTrustStoreCaNames != nil { + assert.Equal(t, *mutualAuth.AdvertiseTrustStoreCaNames, *got[port].mutualAuthentication.AdvertiseTrustStoreCaNames) + } + } else { assert.Equal(t, mutualAuth, got[port].mutualAuthentication) } @@ -376,3 +430,139 @@ func Test_buildListenerAttributes(t *testing.T) { }) } } + +func Test_validateMutualAuthenticationConfig(t *testing.T) { + tests := []struct { + name string + port int32 + mode string + trustStoreARN string + ignoreClientCert *bool + advertiseCANames *string + expectedErrorMessage *string + }{ + { + name: "happy path no validation error off mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationOffMode), + }, + { + name: "happy path no validation error pass through mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationPassthroughMode), + }, + { + name: "happy path no validation error verify mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + }, + { + name: "happy path no validation error verify mode, with ignore client cert expiry", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + ignoreClientCert: aws.Bool(true), + }, + { + name: "happy path no validation error verify mode, with ignore client cert expiry false", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + ignoreClientCert: aws.Bool(false), + }, + { + name: "happy path no validation error verify mode, with advertise ca on", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + advertiseCANames: aws.String("on"), + }, + { + name: "happy path no validation error verify mode, with advertise ca off", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + advertiseCANames: aws.String("off"), + }, + { + name: "no mode", + port: 800, + expectedErrorMessage: awssdk.String("mutualAuthentication mode cannot be empty for port 800"), + }, + { + name: "unknown mode", + port: 800, + mode: "foo", + expectedErrorMessage: awssdk.String("mutualAuthentication mode value must be among"), + }, + { + name: "port invalid", + port: 800000, + mode: string(elbv2model.MutualAuthenticationOffMode), + expectedErrorMessage: awssdk.String("listen port must be within [1, 65535]: 800000"), + }, + { + name: "missing truststore arn for verify", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + expectedErrorMessage: awssdk.String("trustStore is required when mutualAuthentication mode is verify for port 800"), + }, + { + name: "truststore arn set but mode not verify", + port: 800, + mode: string(elbv2model.MutualAuthenticationOffMode), + trustStoreARN: "truststore", + expectedErrorMessage: awssdk.String("Mutual Authentication mode off does not support trustStore for port 800"), + }, + { + name: "ignore client cert expiry set for off mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationOffMode), + ignoreClientCert: awssdk.Bool(true), + expectedErrorMessage: awssdk.String("Mutual Authentication mode off does not support ignoring client certificate expiry for port 800"), + }, + { + name: "ignore client cert expiry set for passthrough mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationPassthroughMode), + ignoreClientCert: awssdk.Bool(true), + expectedErrorMessage: awssdk.String("Mutual Authentication mode passthrough does not support ignoring client certificate expiry for port 800"), + }, + { + name: "advertise ca set for off mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationOffMode), + advertiseCANames: awssdk.String("on"), + expectedErrorMessage: awssdk.String("Authentication mode off does not support advertiseTrustStoreCaNames for port 800"), + }, + { + name: "advertise ca set for passthrough mode", + port: 800, + mode: string(elbv2model.MutualAuthenticationPassthroughMode), + advertiseCANames: awssdk.String("on"), + expectedErrorMessage: awssdk.String("Authentication mode passthrough does not support advertiseTrustStoreCaNames for port 800"), + }, + { + name: "advertise ca set with invalid value", + port: 800, + mode: string(elbv2model.MutualAuthenticationVerifyMode), + trustStoreARN: "truststore", + advertiseCANames: awssdk.String("foo"), + expectedErrorMessage: awssdk.String("advertiseTrustStoreCaNames only supports the values \"on\" and \"off\" got value foo for port 800"), + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + task := &defaultModelBuildTask{} + res := task.validateMutualAuthenticationConfig(tt.port, tt.mode, tt.trustStoreARN, tt.ignoreClientCert, tt.advertiseCANames) + + if tt.expectedErrorMessage == nil { + assert.Nil(t, res) + } else { + assert.Contains(t, res.Error(), *tt.expectedErrorMessage) + } + }) + } +} diff --git a/pkg/model/elbv2/listener.go b/pkg/model/elbv2/listener.go index 19aeef5e1..7de19c7d2 100644 --- a/pkg/model/elbv2/listener.go +++ b/pkg/model/elbv2/listener.go @@ -104,7 +104,8 @@ type MutualAuthenticationAttributes struct { TrustStoreArn *string `json:"trustStoreArn,omitempty"` - IgnoreClientCertificateExpiry *bool `json:"ignoreClientCertificateExpiry,omitempty"` + IgnoreClientCertificateExpiry *bool `json:"ignoreClientCertificateExpiry,omitempty"` + AdvertiseTrustStoreCaNames *string `json:"advertiseTrustStoreCaNames,omitempty"` } type AuthenticateCognitoActionConditionalBehavior string diff --git a/pkg/service/model_builder_test.go b/pkg/service/model_builder_test.go index 0ed7f9b77..44db576ae 100644 --- a/pkg/service/model_builder_test.go +++ b/pkg/service/model_builder_test.go @@ -6501,6 +6501,7 @@ func Test_defaultModelBuilderTask_Build(t *testing.T) { "type":"network", "scheme":"internet-facing", "securityGroupsInboundRulesOnPrivateLink":"on", + "enablePrefixForIpv6SourceNat": "off", "ipAddressType":"ipv4", "subnetMapping":[ {