Skip to content

Commit

Permalink
Implement mutual TLS authentication support for Ingress (#3532)
Browse files Browse the repository at this point in the history
* Implement mutual TLS authentication support for Ingress

* Addressing comments and adding policy updates

* Adding dependency for maps

* removing ingressClassParam support
  • Loading branch information
shraddhabang authored Jan 26, 2024
1 parent 1a8bfc0 commit d0c13bf
Show file tree
Hide file tree
Showing 16 changed files with 1,264 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ^1.19
go-version: ^1.21

- name: Check out code into the Go module directory
uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion controllers/ingress/group_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder
trackingProvider := tracking.NewDefaultProvider(ingressTagPrefix, controllerConfig.ClusterName)
elbv2TaggingManager := elbv2deploy.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), controllerConfig.FeatureGates, cloud.RGT(), logger)
modelBuilder := ingress.NewDefaultModelBuilder(k8sClient, eventRecorder,
cloud.EC2(), cloud.ACM(),
cloud.EC2(), cloud.ELBV2(), cloud.ACM(),
annotationParser, subnetsResolver,
authConfigBuilder, enhancedBackendBuilder, trackingProvider, elbv2TaggingManager, controllerConfig.FeatureGates,
cloud.VpcID(), controllerConfig.ClusterName, controllerConfig.DefaultTags, controllerConfig.ExternalManagedTags,
Expand Down
3 changes: 2 additions & 1 deletion docs/install/iam_policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DescribeTags"
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DescribeTrustStores"
],
"Resource": "*"
},
Expand Down
3 changes: 2 additions & 1 deletion docs/install/iam_policy_us-gov.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"elasticloadbalancing:DescribeTargetGroups",
"elasticloadbalancing:DescribeTargetGroupAttributes",
"elasticloadbalancing:DescribeTargetHealth",
"elasticloadbalancing:DescribeTags"
"elasticloadbalancing:DescribeTags",
"elasticloadbalancing:DescribeTrustStores"
],
"Resource": "*"
},
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module sigs.k8s.io/aws-load-balancer-controller

go 1.20
go 1.21

require (
github.com/aws/aws-sdk-go v1.47.13
github.com/aws/aws-sdk-go v1.48.10
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/gavv/httpexpect/v2 v2.9.0
github.com/go-logr/logr v1.2.4
Expand All @@ -23,6 +23,7 @@ require (
k8s.io/apimachinery v0.26.5
k8s.io/cli-runtime v0.26.3
k8s.io/client-go v0.26.5
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448
sigs.k8s.io/controller-runtime v0.14.6
sigs.k8s.io/yaml v1.3.0
)
Expand Down Expand Up @@ -156,7 +157,6 @@ require (
k8s.io/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/kubectl v0.26.0 // indirect
k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 // indirect
moul.io/http2curl/v2 v2.3.0 // indirect
oras.land/oras-go v1.2.2 // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ 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.47.13 h1:pJgCtldg5azDAFoEcE0fz6n+FnCc1/FY4krtUa5uvZQ=
github.com/aws/aws-sdk-go v1.47.13/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go v1.48.10 h1:0LIFG3wp2Dt6PsxKWCg1Y1xRrn2vZnW5/gWdgaBalKg=
github.com/aws/aws-sdk-go v1.48.10/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
Expand Down
1 change: 1 addition & 0 deletions pkg/annotations/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const (
IngressSuffixAuthSessionTimeout = "auth-session-timeout"
IngressSuffixTargetNodeLabels = "target-node-labels"
IngressSuffixManageSecurityGroupRules = "manage-backend-security-group-rules"
IngressSuffixMutualAuthentication = "mutual-authentication"

// NLB annotation suffixes
// prefixes service.beta.kubernetes.io, service.kubernetes.io
Expand Down
300 changes: 300 additions & 0 deletions pkg/aws/services/ec2_mocks.go

Large diffs are not rendered by default.

599 changes: 599 additions & 0 deletions pkg/aws/services/elbv2_mocks.go

Large diffs are not rendered by default.

25 changes: 23 additions & 2 deletions pkg/deploy/elbv2/listener_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package elbv2

import (
"context"
"reflect"
"time"

awssdk "github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -134,7 +135,8 @@ func (m *defaultListenerManager) updateSDKListenerWithSettings(ctx context.Conte
return err
}
desiredDefaultCerts, _ := buildSDKCertificates(resLS.Spec.Certificates)
if !isSDKListenerSettingsDrifted(resLS.Spec, sdkLS, desiredDefaultActions, desiredDefaultCerts) {
desiredDefaultMutualAuthentication := buildSDKMutualAuthenticationConfig(resLS.Spec.MutualAuthentication)
if !isSDKListenerSettingsDrifted(resLS.Spec, sdkLS, desiredDefaultActions, desiredDefaultCerts, desiredDefaultMutualAuthentication) {
return nil
}
req := buildSDKModifyListenerInput(resLS.Spec, desiredDefaultActions, desiredDefaultCerts)
Expand Down Expand Up @@ -246,7 +248,7 @@ func (m *defaultListenerManager) fetchSDKListenerExtraCertificateARNs(ctx contex
}

func isSDKListenerSettingsDrifted(lsSpec elbv2model.ListenerSpec, sdkLS ListenerWithTags,
desiredDefaultActions []*elbv2sdk.Action, desiredDefaultCerts []*elbv2sdk.Certificate) bool {
desiredDefaultActions []*elbv2sdk.Action, desiredDefaultCerts []*elbv2sdk.Certificate, desiredDefaultMutualAuthentication *elbv2sdk.MutualAuthenticationAttributes) bool {
if lsSpec.Port != awssdk.Int64Value(sdkLS.Listener.Port) {
return true
}
Expand All @@ -265,6 +267,9 @@ func isSDKListenerSettingsDrifted(lsSpec elbv2model.ListenerSpec, sdkLS Listener
if len(lsSpec.ALPNPolicy) != 0 && !cmp.Equal(lsSpec.ALPNPolicy, awssdk.StringValueSlice(sdkLS.Listener.AlpnPolicy), cmpopts.EquateEmpty()) {
return true
}
if !reflect.DeepEqual(desiredDefaultMutualAuthentication, sdkLS.Listener.MutualAuthentication) {
return true
}

return false
}
Expand All @@ -289,6 +294,8 @@ func buildSDKCreateListenerInput(lsSpec elbv2model.ListenerSpec, featureGates co
if len(lsSpec.ALPNPolicy) != 0 {
sdkObj.AlpnPolicy = awssdk.StringSlice(lsSpec.ALPNPolicy)
}
sdkObj.MutualAuthentication = buildSDKMutualAuthenticationConfig(lsSpec.MutualAuthentication)

return sdkObj, nil
}

Expand All @@ -302,6 +309,8 @@ func buildSDKModifyListenerInput(lsSpec elbv2model.ListenerSpec, desiredDefaultA
if len(lsSpec.ALPNPolicy) != 0 {
sdkObj.AlpnPolicy = awssdk.StringSlice(lsSpec.ALPNPolicy)
}
sdkObj.MutualAuthentication = buildSDKMutualAuthenticationConfig(lsSpec.MutualAuthentication)

return sdkObj
}

Expand All @@ -327,6 +336,18 @@ func buildSDKCertificate(modelCert elbv2model.Certificate) *elbv2sdk.Certificate
}
}

// buildSDKMutualAuthenticationConfig builds the mutual TLS authentication config for listener
func buildSDKMutualAuthenticationConfig(modelMutualAuthenticationCfg *elbv2model.MutualAuthenticationAttributes) *elbv2sdk.MutualAuthenticationAttributes {
if modelMutualAuthenticationCfg == nil {
return nil
}
return &elbv2sdk.MutualAuthenticationAttributes{
IgnoreClientCertificateExpiry: modelMutualAuthenticationCfg.IgnoreClientCertificateExpiry,
Mode: awssdk.String(modelMutualAuthenticationCfg.Mode),
TrustStoreArn: modelMutualAuthenticationCfg.TrustStoreArn,
}
}

func buildResListenerStatus(sdkLS ListenerWithTags) elbv2model.ListenerStatus {
return elbv2model.ListenerStatus{
ListenerARN: awssdk.StringValue(sdkLS.Listener.ListenerArn),
Expand Down
97 changes: 92 additions & 5 deletions pkg/deploy/elbv2/listener_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (

func Test_isSDKListenerSettingsDrifted(t *testing.T) {
type args struct {
lsSpec elbv2model.ListenerSpec
sdkLS ListenerWithTags
desiredDefaultActions []*elbv2sdk.Action
desiredDefaultCerts []*elbv2sdk.Certificate
lsSpec elbv2model.ListenerSpec
sdkLS ListenerWithTags
desiredDefaultActions []*elbv2sdk.Action
desiredDefaultCerts []*elbv2sdk.Certificate
desiredDefaultMutualAuthentication *elbv2sdk.MutualAuthenticationAttributes
}
tests := []struct {
name string
Expand Down Expand Up @@ -49,6 +50,9 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
SslPolicy: awssdk.String("ELBSecurityPolicy-FS-1-2-Res-2019-08"),
AlpnPolicy: awssdk.StringSlice([]string{"HTTP2Preferred"}),
MutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
desiredDefaultCerts: []*elbv2sdk.Certificate{
Expand All @@ -65,6 +69,9 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
},
},
desiredDefaultMutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
{
Expand Down Expand Up @@ -104,6 +111,9 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
SslPolicy: awssdk.String("ELBSecurityPolicy-FS-1-2-Res-2019-08"),
AlpnPolicy: awssdk.StringSlice([]string{"HTTP2Preferred"}),
MutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
desiredDefaultCerts: []*elbv2sdk.Certificate{
Expand All @@ -120,6 +130,9 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
},
},
desiredDefaultMutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
{
Expand Down Expand Up @@ -154,6 +167,75 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
SslPolicy: awssdk.String("ELBSecurityPolicy-FS-1-2-Res-2019-08"),
AlpnPolicy: awssdk.StringSlice([]string{"HTTP2Preferred"}),
MutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
desiredDefaultCerts: []*elbv2sdk.Certificate{
{
CertificateArn: awssdk.String("cert-arn1"),
IsDefault: awssdk.Bool(true),
},
},
desiredDefaultActions: []*elbv2sdk.Action{
{
Type: awssdk.String("forward-config"),
ForwardConfig: &elbv2sdk.ForwardActionConfig{
TargetGroups: []*elbv2sdk.TargetGroupTuple{
{
TargetGroupArn: awssdk.String("target-group"),
},
},
},
},
},
desiredDefaultMutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("off"),
},
},
},
{
name: "listener hasn't drifted if mutualAuthentication verify mode specified",
args: args{
lsSpec: elbv2model.ListenerSpec{
Port: 80,
Protocol: elbv2model.ProtocolHTTPS,
SSLPolicy: awssdk.String("ELBSecurityPolicy-FS-1-2-Res-2019-08"),
MutualAuthentication: &elbv2model.MutualAuthenticationAttributes{
Mode: "verify",
TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:us-east-1:123456789123:truststore/ts-1/8786hghf"),
},
},
sdkLS: ListenerWithTags{
Listener: &elbv2sdk.Listener{
Port: awssdk.Int64(80),
Protocol: awssdk.String("HTTPS"),
Certificates: []*elbv2sdk.Certificate{
{
CertificateArn: awssdk.String("cert-arn1"),
IsDefault: awssdk.Bool(true),
},
},
DefaultActions: []*elbv2sdk.Action{
{
Type: awssdk.String("forward-config"),
ForwardConfig: &elbv2sdk.ForwardActionConfig{
TargetGroups: []*elbv2sdk.TargetGroupTuple{
{
TargetGroupArn: awssdk.String("target-group"),
},
},
},
},
},
SslPolicy: awssdk.String("ELBSecurityPolicy-FS-1-2-Res-2019-08"),
AlpnPolicy: awssdk.StringSlice([]string{"HTTP2Preferred"}),
MutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("verify"),
TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:us-east-1:123456789123:truststore/ts-1/8786hghf"),
IgnoreClientCertificateExpiry: awssdk.Bool(false),
},
},
},
desiredDefaultCerts: []*elbv2sdk.Certificate{
Expand All @@ -174,12 +256,17 @@ func Test_isSDKListenerSettingsDrifted(t *testing.T) {
},
},
},
desiredDefaultMutualAuthentication: &elbv2sdk.MutualAuthenticationAttributes{
Mode: awssdk.String("verify"),
TrustStoreArn: awssdk.String("arn:aws:elasticloadbalancing:us-east-1:123456789123:truststore/ts-1/8786hghf"),
IgnoreClientCertificateExpiry: awssdk.Bool(false),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isSDKListenerSettingsDrifted(tt.args.lsSpec, tt.args.sdkLS, tt.args.desiredDefaultActions, tt.args.desiredDefaultCerts)
got := isSDKListenerSettingsDrifted(tt.args.lsSpec, tt.args.sdkLS, tt.args.desiredDefaultActions, tt.args.desiredDefaultCerts, tt.args.desiredDefaultMutualAuthentication)
assert.Equal(t, tt.want, got)
})
}
Expand Down
Loading

0 comments on commit d0c13bf

Please sign in to comment.