Skip to content

Commit 6f0f9f7

Browse files
committed
securitygroup: allow setting allowed IPv6 CIDR for node NodePort services
For IPv4, we have field NodePortIngressRuleCidrBlocks that specifies the allowed source IPv4 CIDR for node NodePort services on port 30000-32767. This extends that field to also accept IPv6 source CIDRs.
1 parent 240c08a commit 6f0f9f7

File tree

7 files changed

+233
-46
lines changed

7 files changed

+233
-46
lines changed

api/v1beta2/network_types.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/aws/aws-sdk-go-v2/service/ec2/types"
2525
"github.com/aws/aws-sdk-go/aws"
26+
"k8s.io/utils/net"
2627
"k8s.io/utils/ptr"
2728
)
2829

@@ -367,7 +368,32 @@ type NetworkSpec struct {
367368
// NodePortIngressRuleCidrBlocks is an optional set of CIDR blocks to allow traffic to nodes' NodePort services.
368369
// If none are specified here, all IPs are allowed to connect.
369370
// +optional
370-
NodePortIngressRuleCidrBlocks []string `json:"nodePortIngressRuleCidrBlocks,omitempty"`
371+
NodePortIngressRuleCidrBlocks CidrBlocks `json:"nodePortIngressRuleCidrBlocks,omitempty"`
372+
}
373+
374+
// CidrBlocks defines a set of CIDR blocks.
375+
type CidrBlocks []string
376+
377+
// IPv4CidrBlocks returns only IPv4 CIDR blocks.
378+
func (c CidrBlocks) IPv4CidrBlocks() CidrBlocks {
379+
var cidrs CidrBlocks
380+
for _, cidr := range c {
381+
if net.IsIPv4CIDRString(cidr) {
382+
cidrs = append(cidrs, cidr)
383+
}
384+
}
385+
return cidrs
386+
}
387+
388+
// IPv6CidrBlocks returns only IPv6 CIDR blocks.
389+
func (c CidrBlocks) IPv6CidrBlocks() CidrBlocks {
390+
var cidrs CidrBlocks
391+
for _, cidr := range c {
392+
if net.IsIPv6CIDRString(cidr) {
393+
cidrs = append(cidrs, cidr)
394+
}
395+
}
396+
return cidrs
371397
}
372398

373399
// IPv6 contains ipv6 specific settings for the network.

api/v1beta2/zz_generated.deepcopy.go

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/cloud/scope/cluster.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,6 @@ func (s *ClusterScope) UnstructuredControlPlane() (*unstructured.Unstructured, e
450450
}
451451

452452
// NodePortIngressRuleCidrBlocks returns the CIDR blocks for the node NodePort ingress rules.
453-
func (s *ClusterScope) NodePortIngressRuleCidrBlocks() []string {
453+
func (s *ClusterScope) NodePortIngressRuleCidrBlocks() infrav1.CidrBlocks {
454454
return s.AWSCluster.Spec.NetworkSpec.DeepCopy().NodePortIngressRuleCidrBlocks
455455
}

pkg/cloud/scope/managedcontrolplane.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,7 @@ func (s *ManagedControlPlaneScope) UnstructuredControlPlane() (*unstructured.Uns
510510
}
511511

512512
// NodePortIngressRuleCidrBlocks returns the CIDR blocks for the node NodePort ingress rules.
513-
func (s *ManagedControlPlaneScope) NodePortIngressRuleCidrBlocks() []string {
513+
func (s *ManagedControlPlaneScope) NodePortIngressRuleCidrBlocks() infrav1.CidrBlocks {
514514
return nil
515515
}
516516

pkg/cloud/scope/sg.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ type SGScope interface {
6464
ControlPlaneLoadBalancers() []*infrav1.AWSLoadBalancerSpec
6565

6666
// NodePortIngressRuleCidrBlocks returns the CIDR blocks for the node NodePort ingress rules.
67-
NodePortIngressRuleCidrBlocks() []string
67+
NodePortIngressRuleCidrBlocks() infrav1.CidrBlocks
6868
}

pkg/cloud/services/securitygroup/securitygroups.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -647,17 +647,27 @@ func (s *Service) getSecurityGroupIngressRules(role infrav1.SecurityGroupRole) (
647647
return append(cniRules, rules...), nil
648648

649649
case infrav1.SecurityGroupNode:
650-
cidrBlocks := []string{services.AnyIPv4CidrBlock}
651-
if scopeCidrBlocks := s.scope.NodePortIngressRuleCidrBlocks(); len(scopeCidrBlocks) > 0 {
652-
cidrBlocks = scopeCidrBlocks
650+
ipv4CidrBlocks := []string{services.AnyIPv4CidrBlock}
651+
if scopeCidrBlocks := s.scope.NodePortIngressRuleCidrBlocks().IPv4CidrBlocks(); len(scopeCidrBlocks) > 0 {
652+
ipv4CidrBlocks = scopeCidrBlocks
653653
}
654+
655+
var ipv6CidrBlocks []string
656+
if s.scope.VPC().IsIPv6Enabled() {
657+
ipv6CidrBlocks = []string{services.AnyIPv6CidrBlock}
658+
if scopeCidrBlocks := s.scope.NodePortIngressRuleCidrBlocks().IPv6CidrBlocks(); len(scopeCidrBlocks) > 0 {
659+
ipv6CidrBlocks = scopeCidrBlocks
660+
}
661+
}
662+
654663
rules := infrav1.IngressRules{
655664
{
656-
Description: "Node Port Services",
657-
Protocol: infrav1.SecurityGroupProtocolTCP,
658-
FromPort: 30000,
659-
ToPort: 32767,
660-
CidrBlocks: cidrBlocks,
665+
Description: "Node Port Services",
666+
Protocol: infrav1.SecurityGroupProtocolTCP,
667+
FromPort: 30000,
668+
ToPort: 32767,
669+
CidrBlocks: ipv4CidrBlocks,
670+
IPv6CidrBlocks: ipv6CidrBlocks,
661671
},
662672
{
663673
Description: "Kubelet API",
@@ -671,18 +681,10 @@ func (s *Service) getSecurityGroupIngressRules(role infrav1.SecurityGroupRole) (
671681
},
672682
},
673683
}
684+
674685
if s.scope.Bastion().Enabled {
675686
rules = append(rules, s.defaultSSHIngressRule(s.scope.SecurityGroups()[infrav1.SecurityGroupBastion].ID))
676687
}
677-
if s.scope.VPC().IsIPv6Enabled() {
678-
rules = append(rules, infrav1.IngressRule{
679-
Description: "Node Port Services IPv6",
680-
Protocol: infrav1.SecurityGroupProtocolTCP,
681-
FromPort: 30000,
682-
ToPort: 32767,
683-
IPv6CidrBlocks: []string{services.AnyIPv6CidrBlock},
684-
})
685-
}
686688

687689
additionalIngressRules, err := s.processIngressRulesSGs(s.scope.AdditionalNodeIngressRules())
688690
if err != nil {

pkg/cloud/services/securitygroup/securitygroups_test.go

Lines changed: 164 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,12 +2332,29 @@ func TestNodePortServicesIngressRules(t *testing.T) {
23322332

23332333
testCases := []struct {
23342334
name string
2335-
cidrBlocks []string
2335+
awsCluster *infrav1.AWSCluster
23362336
expectedIngresRules infrav1.IngressRules
23372337
}{
23382338
{
2339-
name: "default node ports services ingress rules, no node port cidr block provided",
2340-
cidrBlocks: nil,
2339+
name: "default node ports services ingress rules, no node port cidr block provided",
2340+
awsCluster: &infrav1.AWSCluster{
2341+
Spec: infrav1.AWSClusterSpec{
2342+
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2343+
NetworkSpec: infrav1.NetworkSpec{
2344+
VPC: infrav1.VPCSpec{
2345+
CidrBlock: "10.0.0.0/16",
2346+
},
2347+
},
2348+
},
2349+
Status: infrav1.AWSClusterStatus{
2350+
Network: infrav1.NetworkStatus{
2351+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2352+
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2353+
infrav1.SecurityGroupNode: {ID: "Id2"},
2354+
},
2355+
},
2356+
},
2357+
},
23412358
expectedIngresRules: infrav1.IngressRules{
23422359
{
23432360
Description: "Node Port Services",
@@ -2356,8 +2373,65 @@ func TestNodePortServicesIngressRules(t *testing.T) {
23562373
},
23572374
},
23582375
{
2359-
name: "node port cidr block provided, no default cidr block used for node port services ingress rule",
2360-
cidrBlocks: []string{"10.0.0.0/16"},
2376+
name: "default node ports services ingress rules for IPv6, no node port cidr block provided",
2377+
awsCluster: &infrav1.AWSCluster{
2378+
Spec: infrav1.AWSClusterSpec{
2379+
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2380+
NetworkSpec: infrav1.NetworkSpec{
2381+
VPC: infrav1.VPCSpec{
2382+
CidrBlock: "10.0.0.0/16",
2383+
IPv6: &infrav1.IPv6{},
2384+
},
2385+
},
2386+
},
2387+
Status: infrav1.AWSClusterStatus{
2388+
Network: infrav1.NetworkStatus{
2389+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2390+
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2391+
infrav1.SecurityGroupNode: {ID: "Id2"},
2392+
},
2393+
},
2394+
},
2395+
},
2396+
expectedIngresRules: infrav1.IngressRules{
2397+
{
2398+
Description: "Node Port Services",
2399+
Protocol: infrav1.SecurityGroupProtocolTCP,
2400+
FromPort: 30000,
2401+
ToPort: 32767,
2402+
CidrBlocks: []string{services.AnyIPv4CidrBlock},
2403+
IPv6CidrBlocks: []string{services.AnyIPv6CidrBlock},
2404+
},
2405+
{
2406+
Description: "Kubelet API",
2407+
Protocol: infrav1.SecurityGroupProtocolTCP,
2408+
FromPort: 10250,
2409+
ToPort: 10250,
2410+
SourceSecurityGroupIDs: []string{"Id1", "Id2"},
2411+
},
2412+
},
2413+
},
2414+
{
2415+
name: "node port cidr block provided, no default cidr block used for node port services ingress rule",
2416+
awsCluster: &infrav1.AWSCluster{
2417+
Spec: infrav1.AWSClusterSpec{
2418+
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2419+
NetworkSpec: infrav1.NetworkSpec{
2420+
VPC: infrav1.VPCSpec{
2421+
CidrBlock: "10.0.0.0/16",
2422+
},
2423+
NodePortIngressRuleCidrBlocks: []string{"10.0.0.0/16"},
2424+
},
2425+
},
2426+
Status: infrav1.AWSClusterStatus{
2427+
Network: infrav1.NetworkStatus{
2428+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2429+
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2430+
infrav1.SecurityGroupNode: {ID: "Id2"},
2431+
},
2432+
},
2433+
},
2434+
},
23612435
expectedIngresRules: infrav1.IngressRules{
23622436
{
23632437
Description: "Node Port Services",
@@ -2375,6 +2449,90 @@ func TestNodePortServicesIngressRules(t *testing.T) {
23752449
},
23762450
},
23772451
},
2452+
{
2453+
name: "node port cidr block provided for only IPv6, no default cidr block used for node port services ingress rule",
2454+
awsCluster: &infrav1.AWSCluster{
2455+
Spec: infrav1.AWSClusterSpec{
2456+
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2457+
NetworkSpec: infrav1.NetworkSpec{
2458+
VPC: infrav1.VPCSpec{
2459+
CidrBlock: "10.0.0.0/16",
2460+
IPv6: &infrav1.IPv6{
2461+
CidrBlock: "2001:1234:5678:9a40::/56",
2462+
},
2463+
},
2464+
NodePortIngressRuleCidrBlocks: []string{"2001:1234:5678:9a40::/56"},
2465+
},
2466+
},
2467+
Status: infrav1.AWSClusterStatus{
2468+
Network: infrav1.NetworkStatus{
2469+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2470+
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2471+
infrav1.SecurityGroupNode: {ID: "Id2"},
2472+
},
2473+
},
2474+
},
2475+
},
2476+
expectedIngresRules: infrav1.IngressRules{
2477+
{
2478+
Description: "Node Port Services",
2479+
Protocol: infrav1.SecurityGroupProtocolTCP,
2480+
FromPort: 30000,
2481+
ToPort: 32767,
2482+
CidrBlocks: []string{services.AnyIPv4CidrBlock},
2483+
IPv6CidrBlocks: []string{"2001:1234:5678:9a40::/56"},
2484+
},
2485+
{
2486+
Description: "Kubelet API",
2487+
Protocol: infrav1.SecurityGroupProtocolTCP,
2488+
FromPort: 10250,
2489+
ToPort: 10250,
2490+
SourceSecurityGroupIDs: []string{"Id1", "Id2"},
2491+
},
2492+
},
2493+
},
2494+
{
2495+
name: "node port cidr block provided for both IPv4 and IPv6, no default cidr block used for node port services ingress rule",
2496+
awsCluster: &infrav1.AWSCluster{
2497+
Spec: infrav1.AWSClusterSpec{
2498+
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2499+
NetworkSpec: infrav1.NetworkSpec{
2500+
VPC: infrav1.VPCSpec{
2501+
CidrBlock: "10.0.0.0/16",
2502+
IPv6: &infrav1.IPv6{
2503+
CidrBlock: "2001:1234:5678:9a40::/56",
2504+
},
2505+
},
2506+
NodePortIngressRuleCidrBlocks: []string{"10.0.0.0/16", "2001:1234:5678:9a40::/56"},
2507+
},
2508+
},
2509+
Status: infrav1.AWSClusterStatus{
2510+
Network: infrav1.NetworkStatus{
2511+
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2512+
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2513+
infrav1.SecurityGroupNode: {ID: "Id2"},
2514+
},
2515+
},
2516+
},
2517+
},
2518+
expectedIngresRules: infrav1.IngressRules{
2519+
{
2520+
Description: "Node Port Services",
2521+
Protocol: infrav1.SecurityGroupProtocolTCP,
2522+
FromPort: 30000,
2523+
ToPort: 32767,
2524+
CidrBlocks: []string{"10.0.0.0/16"},
2525+
IPv6CidrBlocks: []string{"2001:1234:5678:9a40::/56"},
2526+
},
2527+
{
2528+
Description: "Kubelet API",
2529+
Protocol: infrav1.SecurityGroupProtocolTCP,
2530+
FromPort: 10250,
2531+
ToPort: 10250,
2532+
SourceSecurityGroupIDs: []string{"Id1", "Id2"},
2533+
},
2534+
},
2535+
},
23782536
}
23792537

23802538
for _, tc := range testCases {
@@ -2384,25 +2542,7 @@ func TestNodePortServicesIngressRules(t *testing.T) {
23842542
Cluster: &clusterv1.Cluster{
23852543
ObjectMeta: metav1.ObjectMeta{Name: "test-cluster"},
23862544
},
2387-
AWSCluster: &infrav1.AWSCluster{
2388-
Spec: infrav1.AWSClusterSpec{
2389-
ControlPlaneLoadBalancer: &infrav1.AWSLoadBalancerSpec{},
2390-
NetworkSpec: infrav1.NetworkSpec{
2391-
VPC: infrav1.VPCSpec{
2392-
CidrBlock: "10.0.0.0/16",
2393-
},
2394-
NodePortIngressRuleCidrBlocks: tc.cidrBlocks,
2395-
},
2396-
},
2397-
Status: infrav1.AWSClusterStatus{
2398-
Network: infrav1.NetworkStatus{
2399-
SecurityGroups: map[infrav1.SecurityGroupRole]infrav1.SecurityGroup{
2400-
infrav1.SecurityGroupControlPlane: {ID: "Id1"},
2401-
infrav1.SecurityGroupNode: {ID: "Id2"},
2402-
},
2403-
},
2404-
},
2405-
},
2545+
AWSCluster: tc.awsCluster,
24062546
})
24072547
if err != nil {
24082548
t.Fatalf("Failed to create test context: %v", err)

0 commit comments

Comments
 (0)