Skip to content

Commit 8e4a36d

Browse files
authored
Merge pull request #415 from lareeth/feature-ssl-policy
Support ALB SslPolicy via a new annotation
2 parents 55f6210 + 46964d9 commit 8e4a36d

File tree

8 files changed

+93
-0
lines changed

8 files changed

+93
-0
lines changed

docs/ingress-resources.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ alb.ingress.kubernetes.io/tags
7070
alb.ingress.kubernetes.io/target-group-attributes
7171
alb.ingress.kubernetes.io/ignore-host-header
7272
alb.ingress.kubernetes.io/ip-address-type
73+
alb.ingress.kubernetes.io/ssl-policy
7374
```
7475
7576
Optional annotations are:
@@ -117,3 +118,5 @@ Optional annotations are:
117118
- **ignore-host-header**: Creates routing rules without [Host Header Checks](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-listeners.html#host-conditions).
118119
119120
- **ip-address-type**: The IP address type thats used to either route IPv4 traffic only or to route both IPv4 and IPv6 traffic. Can be either `dualstack` or `ipv4`. When omitted `ipv4` is used.
121+
122+
- **ssl-policy**: Defines the [Security Policy](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies) that should be assigned to the ALB, allowing you to control the protocol and ciphers.

pkg/alb/listener/listener.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type NewDesiredListenerOptions struct {
2525
Port annotations.PortData
2626
CertificateArn *string
2727
Logger *log.Logger
28+
SslPolicy *string
2829
}
2930

3031
type ReconcileOptions struct {
@@ -52,6 +53,10 @@ func NewDesiredListener(o *NewDesiredListenerOptions) *Listener {
5253
listener.Protocol = aws.String("HTTPS")
5354
}
5455

56+
if o.SslPolicy != nil && o.Port.Scheme == "HTTPS" {
57+
listener.SslPolicy = o.SslPolicy
58+
}
59+
5560
listenerT := &Listener{
5661
Desired: listener,
5762
Logger: o.Logger,
@@ -132,6 +137,7 @@ func (l *Listener) create(rOpts *ReconcileOptions) error {
132137
LoadBalancerArn: l.Desired.LoadBalancerArn,
133138
Protocol: l.Desired.Protocol,
134139
Port: l.Desired.Port,
140+
SslPolicy: l.Desired.SslPolicy,
135141
DefaultActions: []*elbv2.Action{
136142
{
137143
Type: l.Desired.DefaultActions[0].Type,
@@ -221,6 +227,8 @@ func (l *Listener) NeedsModification(target *elbv2.Listener, rOpts *ReconcileOpt
221227
return true
222228
case !util.DeepEqual(l.Current.DefaultActions, target.DefaultActions):
223229
return true
230+
case !util.DeepEqual(l.Current.SslPolicy, target.SslPolicy):
231+
return true
224232
}
225233
return false
226234
}
@@ -241,6 +249,8 @@ func (l *Listener) NeedsModificationCheck(target *elbv2.Listener) bool {
241249
return true
242250
case !util.DeepEqual(l.Current.DefaultActions, target.DefaultActions):
243251
return true
252+
case !util.DeepEqual(l.Current.SslPolicy, target.SslPolicy):
253+
return true
244254
}
245255
return false
246256
}

pkg/alb/listener/listener_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func setup() {
6767
Type: aws.String("default"),
6868
TargetGroupArn: aws.String(newTg),
6969
}},
70+
SslPolicy: aws.String("ELBSecurityPolicy-TLS-1-2-2017-01"),
7071
}
7172
}
7273

@@ -96,9 +97,11 @@ func TestNewHTTPListener(t *testing.T) {
9697
func TestNewHTTPSListener(t *testing.T) {
9798
desiredPort := int64(443)
9899
desiredCertArn := aws.String("abc123")
100+
desiredSslPolicy := aws.String("ELBSecurityPolicy-Test")
99101
o := &NewDesiredListenerOptions{
100102
Port: annotations.PortData{desiredPort, "HTTPS"},
101103
CertificateArn: desiredCertArn,
104+
SslPolicy: desiredSslPolicy,
102105
Logger: logr,
103106
}
104107

@@ -118,6 +121,9 @@ func TestNewHTTPSListener(t *testing.T) {
118121
case *l.Desired.Certificates[0].CertificateArn != *desiredCertArn:
119122
t.Errorf("Invalid certificate ARN. Actual: %s | Expected: %s",
120123
*l.Desired.Certificates[0].CertificateArn, *desiredCertArn)
124+
case *l.Desired.SslPolicy != *desiredSslPolicy:
125+
t.Errorf("Invalid certificate SSL Policy. Actual: %s | Expected: %s",
126+
*l.Desired.SslPolicy, *desiredSslPolicy)
121127
}
122128
}
123129

pkg/alb/listeners/listeners.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ func NewDesiredListeners(o *NewDesiredListenersOptions) (Listeners, error) {
160160
Port: port,
161161
CertificateArn: o.Annotations.CertificateArn,
162162
Logger: o.Logger,
163+
SslPolicy: o.Annotations.SslPolicy,
163164
})
164165

165166
if thisListener != nil {

pkg/annotations/annotations.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const (
4040
inboundCidrsKey = "alb.ingress.kubernetes.io/security-group-inbound-cidrs"
4141
portKey = "alb.ingress.kubernetes.io/listen-ports"
4242
schemeKey = "alb.ingress.kubernetes.io/scheme"
43+
sslPolicyKey = "alb.ingress.kubernetes.io/ssl-policy"
4344
ipAddressTypeKey = "alb.ingress.kubernetes.io/ip-address-type"
4445
securityGroupsKey = "alb.ingress.kubernetes.io/security-groups"
4546
subnetsKey = "alb.ingress.kubernetes.io/subnets"
@@ -77,6 +78,7 @@ type Annotations struct {
7778
Tags []*elbv2.Tag
7879
IgnoreHostHeader *bool
7980
TargetGroupAttributes albelbv2.TargetGroupAttributes
81+
SslPolicy *string
8082
VPCID *string
8183
Attributes []*elbv2.LoadBalancerAttribute
8284
}
@@ -142,6 +144,7 @@ func (vf ValidatingAnnotationFactory) ParseAnnotations(ingress *extensions.Ingre
142144
a.setWafAclId(annotations, vf.validator),
143145
a.setAttributes(annotations),
144146
a.setTargetGroupAttributes(annotations),
147+
a.setSslPolicy(annotations, vf.validator),
145148
} {
146149
if err != nil {
147150
cache.Set(cacheKey, err, 1*time.Hour)
@@ -701,6 +704,16 @@ func (a *Annotations) setWafAclId(annotations map[string]string, validator Valid
701704
return nil
702705
}
703706

707+
func (a *Annotations) setSslPolicy(annotations map[string]string, validator Validator) error {
708+
if sslPolicy, ok := annotations[sslPolicyKey]; ok {
709+
a.SslPolicy = aws.String(sslPolicy)
710+
if err := validator.ValidateSslPolicy(a); err != nil {
711+
return err
712+
}
713+
}
714+
return nil
715+
}
716+
704717
func cacheLookup(key string) *ccache.Item {
705718
i := cache.Get(key)
706719
if i == nil || i.Expired() {

pkg/annotations/annotations_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,33 @@ func TestSetIgnoreHostHeader(t *testing.T) {
112112
}
113113
}
114114

115+
func TestSetSslPolicy(t *testing.T) {
116+
var tests = []struct {
117+
SslPolicy string
118+
expected string
119+
pass bool
120+
}{
121+
{"", "", true}, // ip-address-type has a sane default
122+
{"ELBSecurityPolicy-TLS-1-2-2017-01", "", false},
123+
{"ELBSecurityPolicy-TLS-1-2-2017-01", "ELBSecurityPolicy-TLS-1-2-2017-01", true},
124+
}
125+
126+
for _, tt := range tests {
127+
a := &Annotations{}
128+
129+
err := a.setSslPolicy(map[string]string{sslPolicyKey: tt.SslPolicy}, fakeValidator())
130+
if err != nil && tt.pass {
131+
t.Errorf("setIpAddressType(%v): expected %v, actual %v", tt.SslPolicy, tt.pass, err)
132+
}
133+
if err == nil && tt.pass && tt.expected != *a.SslPolicy {
134+
t.Errorf("setIpAddressType(%v): expected %v, actual %v", tt.SslPolicy, tt.expected, *a.SslPolicy)
135+
}
136+
if err == nil && !tt.pass && tt.expected == *a.SslPolicy {
137+
t.Errorf("setIpAddressType(%v): expected %v, actual %v", tt.SslPolicy, tt.expected, *a.SslPolicy)
138+
}
139+
}
140+
}
141+
115142
// Should fail to create due to healthchecktimeout being greater than HealthcheckIntervalSeconds
116143
func TestHealthcheckSecondsValidation(t *testing.T) {
117144
a := &Annotations{}

pkg/annotations/validation.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"fmt"
55
"net"
66

7+
"github.com/aws/aws-sdk-go/aws/awserr"
78
"github.com/aws/aws-sdk-go/service/ec2"
9+
"github.com/aws/aws-sdk-go/service/elbv2"
810

911
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/acm"
1012
albec2 "github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/ec2"
13+
albelbv2 "github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/elbv2"
1114
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/iam"
1215
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/aws/waf"
1316
"github.com/kubernetes-sigs/aws-alb-ingress-controller/pkg/config"
@@ -22,6 +25,7 @@ type Validator interface {
2225
ValidateInboundCidrs(a *Annotations) error
2326
ValidateScheme(a *Annotations, ingressNamespace, ingressName string) bool
2427
ValidateWafAclId(a *Annotations) error
28+
ValidateSslPolicy(a *Annotations) error
2529
}
2630

2731
type ConcreteValidator struct {
@@ -108,3 +112,24 @@ func (v ConcreteValidator) ValidateWafAclId(a *Annotations) error {
108112
}
109113
return nil
110114
}
115+
116+
func (v ConcreteValidator) ValidateSslPolicy(a *Annotations) error {
117+
in := &elbv2.DescribeSSLPoliciesInput{
118+
Names: []*string{
119+
a.SslPolicy,
120+
},
121+
}
122+
if _, err := albelbv2.ELBV2svc.DescribeSSLPolicies(in); err != nil {
123+
if aerr, ok := err.(awserr.Error); ok {
124+
switch aerr.Code() {
125+
case elbv2.ErrCodeSSLPolicyNotFoundException:
126+
return fmt.Errorf("%s: %s", elbv2.ErrCodeSSLPolicyNotFoundException, aerr.Error())
127+
default:
128+
return fmt.Errorf("Error: %s", aerr.Error())
129+
}
130+
} else {
131+
return fmt.Errorf("Error: %s", aerr.Error())
132+
}
133+
}
134+
return nil
135+
}

pkg/annotations/validation_fake.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type FakeValidator struct {
88
ValidateInboundCidrsDelegate func() error
99
ValidateSchemeDelegate func() bool
1010
ValidateWafAclIdDelegate func() error
11+
ValidateSslPolicyDelegate func() error
1112
}
1213

1314
func (fv FakeValidator) ResolveVPCValidateSubnets(a *Annotations) error {
@@ -52,3 +53,10 @@ func (fv FakeValidator) ValidateWafAclId(a *Annotations) error {
5253
}
5354
return nil
5455
}
56+
57+
func (fv FakeValidator) ValidateSslPolicy(a *Annotations) error {
58+
if fv.ValidateSslPolicyDelegate != nil {
59+
return fv.ValidateSslPolicyDelegate()
60+
}
61+
return nil
62+
}

0 commit comments

Comments
 (0)