Skip to content

Commit 2de8e2e

Browse files
committed
add support for multiple certificates
1 parent 72962fc commit 2de8e2e

File tree

8 files changed

+428
-195
lines changed

8 files changed

+428
-195
lines changed

internal/alb/ls/listener.go

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ import (
44
"context"
55
"fmt"
66

7+
"k8s.io/apimachinery/pkg/util/sets"
8+
9+
"github.com/kubernetes-sigs/aws-alb-ingress-controller/internal/ingress/annotations/parser"
10+
"github.com/pkg/errors"
11+
712
"github.com/kubernetes-sigs/aws-alb-ingress-controller/internal/ingress/auth"
813

914
"github.com/aws/aws-sdk-go/aws/awsutil"
@@ -18,6 +23,15 @@ import (
1823
extensions "k8s.io/api/extensions/v1beta1"
1924
)
2025

26+
const (
27+
AnnotationSSLPolicy = "ssl-policy"
28+
AnnotationCertificateARN = "certificate-arn"
29+
)
30+
31+
const (
32+
DefaultSSLPolicy = "ELBSecurityPolicy-2016-08"
33+
)
34+
2135
type ReconcileOptions struct {
2236
LBArn string
2337
Ingress *extensions.Ingress
@@ -52,9 +66,11 @@ type defaultController struct {
5266
type listenerConfig struct {
5367
Port *int64
5468
Protocol *string
55-
SslPolicy *string
56-
Certificates []*elbv2.Certificate
5769
DefaultActions []*elbv2.Action
70+
71+
SslPolicy *string
72+
DefaultCertificate []*elbv2.Certificate
73+
ExtraCertificateARNs []string
5874
}
5975

6076
func (controller *defaultController) Reconcile(ctx context.Context, options ReconcileOptions) error {
@@ -73,6 +89,14 @@ func (controller *defaultController) Reconcile(ctx context.Context, options Reco
7389
return fmt.Errorf("failed to reconcile listener due to %v", err)
7490
}
7591
}
92+
93+
if options.Port.Scheme == elbv2.ProtocolEnumHttps {
94+
lsArn := aws.StringValue(instance.ListenerArn)
95+
if err := controller.reconcileExtraCertificates(ctx, lsArn, config.ExtraCertificateARNs); err != nil {
96+
return errors.Wrapf(err, "failed to reconcile extra certificates on listener %v", lsArn)
97+
}
98+
}
99+
76100
if err := controller.rulesController.Reconcile(ctx, instance, options.Ingress, options.IngressAnnos, options.TGGroup); err != nil {
77101
return fmt.Errorf("failed to reconcile rules due to %v", err)
78102
}
@@ -85,7 +109,7 @@ func (controller *defaultController) newLSInstance(ctx context.Context, lbArn st
85109
LoadBalancerArn: aws.String(lbArn),
86110
Port: config.Port,
87111
Protocol: config.Protocol,
88-
Certificates: config.Certificates,
112+
Certificates: config.DefaultCertificate,
89113
SslPolicy: config.SslPolicy,
90114
DefaultActions: config.DefaultActions,
91115
})
@@ -102,7 +126,7 @@ func (controller *defaultController) reconcileLSInstance(ctx context.Context, in
102126
ListenerArn: instance.ListenerArn,
103127
Port: config.Port,
104128
Protocol: config.Protocol,
105-
Certificates: config.Certificates,
129+
Certificates: config.DefaultCertificate,
106130
SslPolicy: config.SslPolicy,
107131
DefaultActions: config.DefaultActions,
108132
})
@@ -124,8 +148,8 @@ func (controller *defaultController) LSInstanceNeedsModification(ctx context.Con
124148
albctx.GetLogger(ctx).DebugLevelf(1, "listener protocol needs modification: %v => %v", awsutil.Prettify(instance.Protocol), awsutil.Prettify(config.Protocol))
125149
needModification = true
126150
}
127-
if !util.DeepEqual(instance.Certificates, config.Certificates) {
128-
albctx.GetLogger(ctx).DebugLevelf(1, "listener certificates needs modification: %v => %v", awsutil.Prettify(instance.Certificates), awsutil.Prettify(config.Certificates))
151+
if !util.DeepEqual(instance.Certificates, config.DefaultCertificate) {
152+
albctx.GetLogger(ctx).DebugLevelf(1, "listener certificates needs modification: %v => %v", awsutil.Prettify(instance.Certificates), awsutil.Prettify(config.DefaultCertificate))
129153
needModification = true
130154
}
131155
if !util.DeepEqual(instance.SslPolicy, config.SslPolicy) {
@@ -139,22 +163,71 @@ func (controller *defaultController) LSInstanceNeedsModification(ctx context.Con
139163
return needModification
140164
}
141165

166+
func (controller *defaultController) reconcileExtraCertificates(ctx context.Context, lsArn string, extraCertificateARNs []string) error {
167+
certificates, err := controller.cloud.DescribeListenerCertificates(ctx, lsArn)
168+
if err != nil {
169+
return err
170+
}
171+
actualExtraCertificateArns := sets.NewString()
172+
for _, certificate := range certificates {
173+
if !aws.BoolValue(certificate.IsDefault) {
174+
actualExtraCertificateArns.Insert(aws.StringValue(certificate.CertificateArn))
175+
}
176+
}
177+
desiredExtraCertificateArns := sets.NewString(extraCertificateARNs...)
178+
179+
certificatesToAdd := desiredExtraCertificateArns.Difference(actualExtraCertificateArns)
180+
certificatesToRemove := actualExtraCertificateArns.Difference(desiredExtraCertificateArns)
181+
for certARN := range certificatesToAdd {
182+
albctx.GetLogger(ctx).Infof("adding certificate %v to listener %v", certARN, lsArn)
183+
if _, err := controller.cloud.AddListenerCertificates(ctx, &elbv2.AddListenerCertificatesInput{
184+
ListenerArn: aws.String(lsArn),
185+
Certificates: []*elbv2.Certificate{
186+
{
187+
CertificateArn: aws.String(certARN),
188+
},
189+
},
190+
}); err != nil {
191+
return err
192+
}
193+
}
194+
for certARN := range certificatesToRemove {
195+
albctx.GetLogger(ctx).Infof("removing certificate %v from listener %v", certARN, lsArn)
196+
if _, err := controller.cloud.RemoveListenerCertificates(ctx, &elbv2.RemoveListenerCertificatesInput{
197+
ListenerArn: aws.String(lsArn),
198+
Certificates: []*elbv2.Certificate{
199+
{
200+
CertificateArn: aws.String(certARN),
201+
},
202+
},
203+
}); err != nil {
204+
return err
205+
}
206+
}
207+
return nil
208+
}
209+
142210
func (controller *defaultController) buildListenerConfig(ctx context.Context, options ReconcileOptions) (listenerConfig, error) {
143211
config := listenerConfig{
144212
Port: aws.Int64(options.Port.Port),
145213
Protocol: aws.String(options.Port.Scheme),
146214
}
147215
if options.Port.Scheme == elbv2.ProtocolEnumHttps {
148-
if options.IngressAnnos.Listener.CertificateArn != nil {
149-
config.Certificates = []*elbv2.Certificate{
150-
{
151-
CertificateArn: options.IngressAnnos.Listener.CertificateArn,
152-
},
153-
}
216+
sslPolicy := DefaultSSLPolicy
217+
_ = annotations.LoadStringAnnotation(AnnotationSSLPolicy, &sslPolicy, options.Ingress.Annotations)
218+
config.SslPolicy = aws.String(sslPolicy)
219+
220+
var certificateARNs []string
221+
_ = annotations.LoadStringSliceAnnotation(AnnotationCertificateARN, &certificateARNs, options.Ingress.Annotations)
222+
if len(certificateARNs) == 0 {
223+
return config, errors.Errorf("annotation %v must be specified for https listener", parser.GetAnnotationWithPrefix(AnnotationCertificateARN))
154224
}
155-
if options.IngressAnnos.Listener.SslPolicy != nil {
156-
config.SslPolicy = options.IngressAnnos.Listener.SslPolicy
225+
config.DefaultCertificate = []*elbv2.Certificate{
226+
{
227+
CertificateArn: aws.String(certificateARNs[0]),
228+
},
157229
}
230+
config.ExtraCertificateARNs = certificateARNs[1:]
158231
}
159232

160233
actions, err := controller.buildDefaultActions(ctx, options)

0 commit comments

Comments
 (0)