Skip to content

Commit 3ad2391

Browse files
authored
feat: allowed ACM cert discovery to filter on CA ARNs (#3565) (#3591)
1 parent c6f86fc commit 3ad2391

File tree

7 files changed

+41
-15
lines changed

7 files changed

+41
-15
lines changed

controllers/ingress/group_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ func NewGroupReconciler(cloud aws.Cloud, k8sClient client.Client, eventRecorder
6060
authConfigBuilder, enhancedBackendBuilder, trackingProvider, elbv2TaggingManager, controllerConfig.FeatureGates,
6161
cloud.VpcID(), controllerConfig.ClusterName, controllerConfig.DefaultTags, controllerConfig.ExternalManagedTags,
6262
controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, backendSGProvider, sgResolver,
63-
controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), logger)
63+
controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, controllerConfig.IngressConfig.AllowedCertificateAuthorityARNs, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), logger)
6464
stackMarshaller := deploy.NewDefaultStackMarshaller()
6565
stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, elbv2TaggingManager,
6666
controllerConfig, ingressTagPrefix, logger)

docs/deploy/configurations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Currently, you can set only 1 namespace to watch in this flag. See [this Kuberne
7171
|aws-max-retries | int | 10 | Maximum retries for AWS APIs |
7272
|aws-region | string | [instance metadata](#instance-metadata) | AWS Region for the kubernetes cluster |
7373
|aws-vpc-id | string | [instance metadata](#instance-metadata) | AWS VPC ID for the Kubernetes cluster |
74+
|allowed-certificate-authority-arns | stringList | [] | Specify an optional list of CA ARNs to filter on in cert discovery (empty means all CAs are allowed) |
7475
|backend-security-group | string | | Backend security group id to use for the ingress rules on the worker node SG|
7576
|cluster-name | string | | Kubernetes cluster name|
7677
|default-ssl-policy | string | ELBSecurityPolicy-2016-08 | Default SSL Policy that will be applied to all Ingresses or Services that do not have the SSL Policy annotation |

helm/aws-load-balancer-controller/templates/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ spec:
159159
{{- if .Values.serviceTargetENISGTags }}
160160
- --service-target-eni-security-group-tags={{ .Values.serviceTargetENISGTags }}
161161
{{- end }}
162+
{{- if .Values.certDiscovery.allowedCertificateAuthorityARNs }}
163+
- --allowed-certificate-authority-arns={{ .Values.certDiscovery.allowedCertificateAuthorityARNs }}
164+
{{- end }}
162165
{{- if or .Values.env .Values.envSecretName }}
163166
env:
164167
{{- if .Values.env}}

helm/aws-load-balancer-controller/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,9 @@ controllerConfig:
350350
# NLBHealthCheckAdvancedConfig: true
351351
# ALBSingleSubnet: false
352352

353+
certDiscovery:
354+
allowedCertificateAuthorityARNs: "" # empty means all CAs are in scope
355+
353356
# objectSelector for webhook
354357
objectSelector:
355358
matchExpressions:

pkg/config/ingress_config.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const (
99
flagIngressMaxConcurrentReconciles = "ingress-max-concurrent-reconciles"
1010
flagTolerateNonExistentBackendService = "tolerate-non-existent-backend-service"
1111
flagTolerateNonExistentBackendAction = "tolerate-non-existent-backend-action"
12+
flagAllowedCAArns = "allowed-certificate-authority-arns"
1213
defaultIngressClass = "alb"
1314
defaultDisableIngressClassAnnotation = false
1415
defaultDisableIngressGroupNameAnnotation = false
@@ -42,6 +43,9 @@ type IngressConfig struct {
4243
// TolerateNonExistentBackendAction specifies whether to allow rules that reference a backend action that does not
4344
// exist. In this case, requests to that rule will result in a 503 error.
4445
TolerateNonExistentBackendAction bool
46+
47+
// AllowedCertificateAuthoritiyARNs contains a list of all CAs to consider when discovering certificates for ingress resources
48+
AllowedCertificateAuthorityARNs []string
4549
}
4650

4751
// BindFlags binds the command line flags to the fields in the config object
@@ -58,4 +62,5 @@ func (cfg *IngressConfig) BindFlags(fs *pflag.FlagSet) {
5862
"Tolerate rules that specify a non-existent backend service")
5963
fs.BoolVar(&cfg.TolerateNonExistentBackendAction, flagTolerateNonExistentBackendAction, defaultTolerateNonExistentBackendAction,
6064
"Tolerate rules that specify a non-existent backend action")
65+
fs.StringSliceVar(&cfg.AllowedCertificateAuthorityARNs, flagAllowedCAArns, []string{}, "Specify an optional list of CA ARNs to filter on in cert discovery")
6166
}

pkg/ingress/cert_discovery.go

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@ package ingress
22

33
import (
44
"context"
5+
"slices"
6+
"strings"
7+
"sync"
8+
"time"
9+
510
"github.com/aws/aws-sdk-go/aws"
11+
awssdk "github.com/aws/aws-sdk-go/aws"
612
"github.com/aws/aws-sdk-go/service/acm"
713
"github.com/go-logr/logr"
814
"github.com/google/go-cmp/cmp"
@@ -11,9 +17,6 @@ import (
1117
"k8s.io/apimachinery/pkg/util/cache"
1218
"k8s.io/apimachinery/pkg/util/sets"
1319
"sigs.k8s.io/aws-load-balancer-controller/pkg/aws/services"
14-
"strings"
15-
"sync"
16-
"time"
1720
)
1821

1922
const (
@@ -33,7 +36,7 @@ type CertDiscovery interface {
3336
}
3437

3538
// NewACMCertDiscovery constructs new acmCertDiscovery
36-
func NewACMCertDiscovery(acmClient services.ACM, logger logr.Logger) *acmCertDiscovery {
39+
func NewACMCertDiscovery(acmClient services.ACM, allowedCAARNs []string, logger logr.Logger) *acmCertDiscovery {
3740
return &acmCertDiscovery{
3841
acmClient: acmClient,
3942
logger: logger,
@@ -44,6 +47,7 @@ func NewACMCertDiscovery(acmClient services.ACM, logger logr.Logger) *acmCertDis
4447
certDomainsCache: cache.NewExpiring(),
4548
importedCertDomainsCacheTTL: defaultImportedCertDomainsCacheTTL,
4649
privateCertDomainsCacheTTL: defaultPrivateCertDomainsCacheTTL,
50+
allowedCAARNs: allowedCAARNs,
4751
}
4852
}
4953

@@ -59,6 +63,7 @@ type acmCertDiscovery struct {
5963
certARNsCache *cache.Expiring
6064
certARNsCacheTTL time.Duration
6165
certDomainsCache *cache.Expiring
66+
allowedCAARNs []string
6267
importedCertDomainsCacheTTL time.Duration
6368
privateCertDomainsCacheTTL time.Duration
6469
}
@@ -102,7 +107,10 @@ func (d *acmCertDiscovery) loadDomainsForAllCertificates(ctx context.Context) (m
102107
if err != nil {
103108
return nil, err
104109
}
105-
domainsByCertARN[certARN] = certDomains
110+
if len(certDomains) > 0 {
111+
domainsByCertARN[certARN] = certDomains
112+
}
113+
106114
}
107115
return domainsByCertARN, nil
108116
}
@@ -143,14 +151,20 @@ func (d *acmCertDiscovery) loadDomainsForCertificate(ctx context.Context, certAR
143151
return nil, err
144152
}
145153
certDetail := resp.Certificate
146-
domains := sets.NewString(aws.StringValueSlice(certDetail.SubjectAlternativeNames)...)
147-
switch aws.StringValue(certDetail.Type) {
148-
case acm.CertificateTypeImported:
149-
d.certDomainsCache.Set(certARN, domains, d.importedCertDomainsCacheTTL)
150-
case acm.CertificateTypeAmazonIssued, acm.CertificateTypePrivate:
151-
d.certDomainsCache.Set(certARN, domains, d.privateCertDomainsCacheTTL)
154+
155+
// check if cert is issued from an allowed CA
156+
if len(d.allowedCAARNs) == 0 || slices.Contains(d.allowedCAARNs, awssdk.StringValue(certDetail.CertificateAuthorityArn)) {
157+
domains := sets.NewString(aws.StringValueSlice(certDetail.SubjectAlternativeNames)...)
158+
switch aws.StringValue(certDetail.Type) {
159+
case acm.CertificateTypeImported:
160+
d.certDomainsCache.Set(certARN, domains, d.importedCertDomainsCacheTTL)
161+
case acm.CertificateTypeAmazonIssued, acm.CertificateTypePrivate:
162+
d.certDomainsCache.Set(certARN, domains, d.privateCertDomainsCacheTTL)
163+
}
164+
return domains, nil
152165
}
153-
return domains, nil
166+
return sets.String{}, nil
167+
154168
}
155169

156170
func (d *acmCertDiscovery) domainMatchesHost(domainName string, tlsHost string) bool {

pkg/ingress/model_builder.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ func NewDefaultModelBuilder(k8sClient client.Client, eventRecorder record.EventR
4444
trackingProvider tracking.Provider, elbv2TaggingManager elbv2deploy.TaggingManager, featureGates config.FeatureGates,
4545
vpcID string, clusterName string, defaultTags map[string]string, externalManagedTags []string, defaultSSLPolicy string, defaultTargetType string,
4646
backendSGProvider networkingpkg.BackendSGProvider, sgResolver networkingpkg.SecurityGroupResolver,
47-
enableBackendSG bool, disableRestrictedSGRules bool, enableIPTargetType bool, logger logr.Logger) *defaultModelBuilder {
48-
certDiscovery := NewACMCertDiscovery(acmClient, logger)
47+
enableBackendSG bool, disableRestrictedSGRules bool, allowedCAARNs []string, enableIPTargetType bool, logger logr.Logger) *defaultModelBuilder {
48+
certDiscovery := NewACMCertDiscovery(acmClient, allowedCAARNs, logger)
4949
ruleOptimizer := NewDefaultRuleOptimizer(logger)
5050
return &defaultModelBuilder{
5151
k8sClient: k8sClient,

0 commit comments

Comments
 (0)