Skip to content

Commit 074beee

Browse files
authored
Merge pull request #3147 from carflo/abitrary-tags-for-nlb-sg
Enables providing multiple tags for worker node security group discovery
2 parents 4e697f8 + f3a9742 commit 074beee

File tree

7 files changed

+423
-38
lines changed

7 files changed

+423
-38
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ _As contributors and maintainers of this project, and in the interest of fosteri
77
## Getting Started
88

99
### Building the project
10-
[Controller developement documentation](/docs/controller-devel.md) has instructions on how to build the project and project specific expectations.
10+
[Controller development documentation](/docs/controller-devel.md) has instructions on how to build the project and project specific expectations.
1111

1212
### Contributing to docs
1313

docs/guide/service/nlb.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
The AWS Load Balancer Controller (LBC) supports reconciliation for Kubernetes Service resources of type `LoadBalancer` by provisioning an AWS Network Load Balancer (NLB) with an `instance` or `ip` [target type](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#target-type).
44

55
!!! info "Secure by default"
6-
Since the [:octicons-tag-24: v2.2.0](https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/tag/v2.2.0) release, the LBC provisions an `internal` NLB by default.
7-
6+
Since the [:octicons-tag-24: v2.2.0](https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/tag/v2.2.0) release, the LBC provisions an `internal` NLB by default.
7+
88
To create an `internet-facing` NLB, the following annotation is required on your service:
99

1010
```yaml
@@ -28,16 +28,16 @@ The AWS Load Balancer Controller (LBC) supports reconciliation for Kubernetes Se
2828

2929
## Configuration
3030

31-
By default, Kubernetes Service resources of type `LoadBalancer` get reconciled by the Kubernetes controller built into the `CloudProvider` component of the `kube-controller-manager` or the `cloud-controller-manager`(also known as the in-tree controller).
31+
By default, Kubernetes Service resources of type `LoadBalancer` get reconciled by the Kubernetes controller built into the `CloudProvider` component of the `kube-controller-manager` or the `cloud-controller-manager`(also known as the in-tree controller).
3232

3333
In order for the LBC to manage the reconciliation of Kubernetes Service resources of type `LoadBalancer`, you need to offload the reconciliation from the in-tree controller to the LBC, explicitly.
3434

3535

3636
=== "With LoadBalancerClass"
37-
The LBC supports the `LoadBalancerClass` feature since the [:octicons-tag-24: v2.4.0](https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/tag/v2.4.0) release for Kubernetes v1.22+ clusters.
38-
37+
The LBC supports the `LoadBalancerClass` feature since the [:octicons-tag-24: v2.4.0](https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/tag/v2.4.0) release for Kubernetes v1.22+ clusters.
38+
3939
The `LoadBalancerClass` feature provides a `CloudProvider` agnostic way of offloading the reconciliation for Kubernetes Service resources of type `LoadBalancer` to an external controller.
40-
40+
4141
When you specify the `spec.loadBalancerClass` to be `service.k8s.aws/nlb` on a Kubernetes Service resource of type `LoadBalancer`, the LBC takes charge of reconciliation by provisioning an NLB.
4242

4343
!!! warning
@@ -89,22 +89,22 @@ In order for the LBC to manage the reconciliation of Kubernetes Service resource
8989
```
9090

9191
=== "With `service.beta.kubernetes.io/aws-load-balancer-type` annotation"
92-
The AWS in-tree controller supports an AWS specific way of offloading the reconciliation for Kubernetes Service resources of type `LoadBalancer` to an external controller.
92+
The AWS in-tree controller supports an AWS specific way of offloading the reconciliation for Kubernetes Service resources of type `LoadBalancer` to an external controller.
9393

9494
When you specify the [`service.beta.kubernetes.io/aws-load-balancer-type` annotation](./annotations.md#lb-type) to be `external` on a Kubernetes Service resource of type `LoadBalancer`, the in-tree controller ignores the Service resource. In addition, if you specify the [`service.beta.kubernetes.io/aws-load-balancer-nlb-target-type` annotation](./annotations.md#nlb-target-type) on the Service resource, the LBC takes charge of reconciliation by provisioning an NLB.
9595

9696
!!! warning
9797
- It's not recommended to modify or add the `service.beta.kubernetes.io/aws-load-balancer-type` annotation on an existing Service resource. If a change is desired, delete the existing Service resource and create a new one instead of modifying an existing Service.
9898

99-
- If you modify this annotation on an existing Service resource, you might end up with leaked LBC resources.
99+
- If you modify this annotation on an existing Service resource, you might end up with leaked LBC resources.
100100

101101
!!! note "backwards compatibility for `nlb-ip` type"
102102
For backwards compatibility, both the in-tree and LBC controller supports `nlb-ip` as a value for the `service.beta.kubernetes.io/aws-load-balancer-type` annotation. The controllers treats it as if you specified both of the following annotations:
103103
```
104104
service.beta.kubernetes.io/aws-load-balancer-type: external
105105
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
106106
```
107-
107+
108108
!!! example "Example: instance mode"
109109
```yaml hl_lines="6 7"
110110
apiVersion: v1
@@ -144,7 +144,7 @@ In order for the LBC to manage the reconciliation of Kubernetes Service resource
144144
```
145145

146146
## Protocols
147-
The LBC supports both TCP and UDP protocols. The controller also configures TLS termination on your NLB if you configure the Service with a certificate annotation.
147+
The LBC supports both TCP and UDP protocols. The controller also configures TLS termination on your NLB if you configure the Service with a certificate annotation.
148148

149149
In the case of TCP, an NLB with IP targets doesn't pass the client source IP address, unless you specifically configure it to using target group attributes. Your application pods might not see the actual client IP address, even if the NLB passes it along. For example, if you're using instance mode with `externalTrafficPolicy` set to `Cluster`.
150150
In such cases, you can configure [NLB proxy protocol v2](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol) using an [annotation](https://kubernetes.io/docs/concepts/services-networking/service/#proxy-protocol-support-on-aws) if you need visibility into
@@ -183,6 +183,8 @@ The controller automatically selects the worker node security groups that it mod
183183

184184
`${cluster-name}` is the name of the Kubernetes cluster.
185185

186+
If it is possible for multiple security groups with the tag `kubernetes.io/cluster/${cluster-name}` to be on a target ENI, you may use the `--service-target-eni-security-group-tags` flag to specify additional tags that must also match in order for a security group to be used.
187+
186188
### Worker node security groups rules
187189

188190
=== "When client IP preservation is enabled"

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func main() {
108108
tgbResManager := targetgroupbinding.NewDefaultResourceManager(mgr.GetClient(), cloud.ELBV2(), cloud.EC2(),
109109
podInfoRepo, sgManager, sgReconciler, vpcInfoProvider,
110110
cloud.VpcID(), controllerCFG.ClusterName, controllerCFG.FeatureGates.Enabled(config.EndpointsFailOpen), controllerCFG.EnableEndpointSlices, controllerCFG.DisableRestrictedSGRules,
111-
mgr.GetEventRecorderFor("targetGroupBinding"), ctrl.Log)
111+
controllerCFG.ServiceTargetENISGTags, mgr.GetEventRecorderFor("targetGroupBinding"), ctrl.Log)
112112
backendSGProvider := networking.NewBackendSGProvider(controllerCFG.ClusterName, controllerCFG.BackendSecurityGroup,
113113
cloud.VpcID(), cloud.EC2(), mgr.GetClient(), controllerCFG.DefaultTags, ctrl.Log.WithName("backend-sg-provider"))
114114
sgResolver := networking.NewDefaultSecurityGroupResolver(cloud.EC2(), cloud.VpcID())

pkg/config/controller_config.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const (
1818
flagDefaultTags = "default-tags"
1919
flagDefaultTargetType = "default-target-type"
2020
flagExternalManagedTags = "external-managed-tags"
21+
flagServiceTargetENISGTags = "service-target-eni-security-group-tags"
2122
flagServiceMaxConcurrentReconciles = "service-max-concurrent-reconciles"
2223
flagTargetGroupBindingMaxConcurrentReconciles = "targetgroupbinding-max-concurrent-reconciles"
2324
flagTargetGroupBindingMaxExponentialBackoffDelay = "targetgroupbinding-max-exponential-backoff-delay"
@@ -74,6 +75,9 @@ type ControllerConfig struct {
7475
// List of Tag keys on AWS resources that will be managed externally.
7576
ExternalManagedTags []string
7677

78+
// ServiceTargetENISGTags are AWS tags, in addition to the cluster tags, for finding the target ENI security group to which to add inbound rules from NLBs.
79+
ServiceTargetENISGTags map[string]string
80+
7781
// Default SSL Policy that will be applied to all ingresses or services that do not have
7882
// the SSL Policy annotation.
7983
DefaultSSLPolicy string
@@ -128,7 +132,8 @@ func (cfg *ControllerConfig) BindFlags(fs *pflag.FlagSet) {
128132
"Enable EndpointSlices for IP targets instead of Endpoints")
129133
fs.BoolVar(&cfg.DisableRestrictedSGRules, flagDisableRestrictedSGRules, defaultDisableRestrictedSGRules,
130134
"Disable the usage of restricted security group rules")
131-
135+
fs.StringToStringVar(&cfg.ServiceTargetENISGTags, flagServiceTargetENISGTags, nil,
136+
"AWS Tags, in addition to cluster tags, for finding the target ENI security group to which to add inbound rules from NLBs")
132137
cfg.FeatureGates.BindFlags(fs)
133138
cfg.AWSConfig.BindFlags(fs)
134139
cfg.RuntimeConfig.BindFlags(fs)

pkg/targetgroupbinding/networking_manager.go

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,18 @@ type NetworkingManager interface {
4646

4747
// NewDefaultNetworkingManager constructs defaultNetworkingManager.
4848
func NewDefaultNetworkingManager(k8sClient client.Client, podENIResolver networking.PodENIInfoResolver, nodeENIResolver networking.NodeENIInfoResolver,
49-
sgManager networking.SecurityGroupManager, sgReconciler networking.SecurityGroupReconciler, vpcID string, clusterName string, logger logr.Logger, disabledRestrictedSGRulesFlag bool) *defaultNetworkingManager {
49+
sgManager networking.SecurityGroupManager, sgReconciler networking.SecurityGroupReconciler, vpcID string, clusterName string, serviceTargetENISGTags map[string]string, logger logr.Logger, disabledRestrictedSGRulesFlag bool) *defaultNetworkingManager {
5050

5151
return &defaultNetworkingManager{
52-
k8sClient: k8sClient,
53-
podENIResolver: podENIResolver,
54-
nodeENIResolver: nodeENIResolver,
55-
sgManager: sgManager,
56-
sgReconciler: sgReconciler,
57-
vpcID: vpcID,
58-
clusterName: clusterName,
59-
logger: logger,
52+
k8sClient: k8sClient,
53+
podENIResolver: podENIResolver,
54+
nodeENIResolver: nodeENIResolver,
55+
sgManager: sgManager,
56+
sgReconciler: sgReconciler,
57+
vpcID: vpcID,
58+
clusterName: clusterName,
59+
serviceTargetENISGTags: serviceTargetENISGTags,
60+
logger: logger,
6061

6162
mutex: sync.Mutex{},
6263
ingressPermissionsPerSGByTGB: make(map[types.NamespacedName]map[string][]networking.IPPermissionInfo),
@@ -68,14 +69,15 @@ func NewDefaultNetworkingManager(k8sClient client.Client, podENIResolver network
6869

6970
// default implementation for NetworkingManager.
7071
type defaultNetworkingManager struct {
71-
k8sClient client.Client
72-
podENIResolver networking.PodENIInfoResolver
73-
nodeENIResolver networking.NodeENIInfoResolver
74-
sgManager networking.SecurityGroupManager
75-
sgReconciler networking.SecurityGroupReconciler
76-
vpcID string
77-
clusterName string
78-
logger logr.Logger
72+
k8sClient client.Client
73+
podENIResolver networking.PodENIInfoResolver
74+
nodeENIResolver networking.NodeENIInfoResolver
75+
sgManager networking.SecurityGroupManager
76+
sgReconciler networking.SecurityGroupReconciler
77+
vpcID string
78+
clusterName string
79+
serviceTargetENISGTags map[string]string
80+
logger logr.Logger
7981

8082
// mutex will serialize our TargetGroup's networking reconcile requests.
8183
mutex sync.Mutex
@@ -526,19 +528,33 @@ func (m *defaultNetworkingManager) resolveEndpointSGForENI(ctx context.Context,
526528
return "", err
527529
}
528530
clusterResourceTagKey := fmt.Sprintf("kubernetes.io/cluster/%s", m.clusterName)
529-
sgIDsWithClusterTag := sets.NewString()
531+
sgIDsWithMatchingEndpointSGTags := sets.NewString()
530532
for sgID, sgInfo := range sgInfoByID {
531533
if _, ok := sgInfo.Tags[clusterResourceTagKey]; ok {
532-
sgIDsWithClusterTag.Insert(sgID)
534+
matchesEndpointSGTags := true
535+
for endpointSGTagKey, endpointSGTagValue := range m.serviceTargetENISGTags {
536+
if _, ok := sgInfo.Tags[endpointSGTagKey]; !ok || sgInfo.Tags[endpointSGTagKey] != endpointSGTagValue {
537+
matchesEndpointSGTags = false
538+
break
539+
}
540+
}
541+
if matchesEndpointSGTags {
542+
sgIDsWithMatchingEndpointSGTags.Insert(sgID)
543+
}
533544
}
534545
}
535-
if len(sgIDsWithClusterTag) != 1 {
546+
547+
if len(sgIDsWithMatchingEndpointSGTags) != 1 {
536548
// user may provide incorrect `--cluster-name` at bootstrap or modify the tag key unexpectedly, it is hard to find out if no clusterName included in error message.
537549
// having `clusterName` included in error message might be helpful for shorten the troubleshooting time spent.
538-
return "", errors.Errorf("expect exactly one securityGroup tagged with %v for eni %v, got: %v (clusterName: %v)",
539-
clusterResourceTagKey, eniInfo.NetworkInterfaceID, sgIDsWithClusterTag.List(), m.clusterName)
550+
if len(m.serviceTargetENISGTags) == 0 {
551+
return "", errors.Errorf("expected exactly one securityGroup tagged with %v for eni %v, got: %v (clusterName: %v)",
552+
clusterResourceTagKey, eniInfo.NetworkInterfaceID, sgIDsWithMatchingEndpointSGTags.List(), m.clusterName)
553+
}
554+
return "", errors.Errorf("expected exactly one securityGroup tagged with %v and %v for eni %v, got: %v (clusterName: %v)",
555+
clusterResourceTagKey, m.serviceTargetENISGTags, eniInfo.NetworkInterfaceID, sgIDsWithMatchingEndpointSGTags.List(), m.clusterName)
540556
}
541-
sgID, _ := sgIDsWithClusterTag.PopAny()
557+
sgID, _ := sgIDsWithMatchingEndpointSGTags.PopAny()
542558
return sgID, nil
543559
}
544560

0 commit comments

Comments
 (0)