Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 86 additions & 2 deletions bootstrap/eks/controllers/eksconfig_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,12 @@ import (
"bytes"
"context"
"encoding/base64"
"encoding/binary"
"fmt"
"math/big"
"net"
"os"
"strings"
"time"

"github.com/pkg/errors"
Expand Down Expand Up @@ -176,6 +180,76 @@ func (r *EKSConfigReconciler) resolveFiles(ctx context.Context, cfg *eksbootstra
return collected, nil
}

// determineClusterCIDR prefers the Cluster's service CIDR (from Spectro pack) and falls back to the VPC CIDR.
func determineClusterCIDR(cluster *clusterv1.Cluster, controlPlane *ekscontrolplanev1.AWSManagedControlPlane) string {
if cluster != nil &&
cluster.Spec.ClusterNetwork != nil &&
cluster.Spec.ClusterNetwork.Services != nil &&
len(cluster.Spec.ClusterNetwork.Services.CIDRBlocks) > 0 {
if cidr := strings.TrimSpace(cluster.Spec.ClusterNetwork.Services.CIDRBlocks[0]); cidr != "" {
return cidr
}
}

if controlPlane != nil && controlPlane.Spec.NetworkSpec.VPC.CidrBlock != "" {
return controlPlane.Spec.NetworkSpec.VPC.CidrBlock
}

return ""
}

// deriveDNSFromCIDR returns the 10th IP inside the provided CIDR.
func deriveDNSFromCIDR(cidr string) (string, error) {
if strings.TrimSpace(cidr) == "" {
return "", nil
}

_, network, err := net.ParseCIDR(strings.TrimSpace(cidr))
if err != nil {
return "", err
}

const dnsOffset = 10

if baseIPv4 := network.IP.To4(); baseIPv4 != nil {
base := binary.BigEndian.Uint32(baseIPv4)
dns := base + dnsOffset

out := make([]byte, 4)
binary.BigEndian.PutUint32(out, dns)
ip := net.IP(out)

if !network.Contains(ip) {
return "", fmt.Errorf("calculated IPv4 DNS IP %s is outside CIDR %s", ip.String(), cidr)
}
return ip.String(), nil
}

baseIPv6 := network.IP.To16()
if baseIPv6 == nil {
return "", fmt.Errorf("invalid CIDR %s", cidr)
}

baseInt := new(big.Int).SetBytes(baseIPv6)
dnsInt := new(big.Int).Add(baseInt, big.NewInt(dnsOffset))

ipBytes := dnsInt.Bytes()
if len(ipBytes) > net.IPv6len {
return "", fmt.Errorf("calculated IPv6 DNS IP exceeds address space for CIDR %s", cidr)
}
if len(ipBytes) < net.IPv6len {
padded := make([]byte, net.IPv6len)
copy(padded[net.IPv6len-len(ipBytes):], ipBytes)
ipBytes = padded
}

ip := net.IP(ipBytes)
if !network.Contains(ip) {
return "", fmt.Errorf("calculated IPv6 DNS IP %s is outside CIDR %s", ip.String(), cidr)
}
return ip.String(), nil
}

func (r *EKSConfigReconciler) resolveSecretFileContent(ctx context.Context, ns string, source eksbootstrapv1.File) ([]byte, error) {
secret := &corev1.Secret{}
key := types.NamespacedName{Namespace: ns, Name: source.ContentFrom.Secret.Name}
Expand Down Expand Up @@ -271,11 +345,21 @@ func (r *EKSConfigReconciler) joinWorker(ctx context.Context, cluster *clusterv1
}

// Create unified NodeInput for both AL2 and AL2023
clusterCIDR := determineClusterCIDR(cluster, controlPlane)
dnsClusterIP := config.Spec.DNSClusterIP
if (dnsClusterIP == nil || strings.TrimSpace(*dnsClusterIP) == "") && clusterCIDR != "" {
if derivedDNS, err := deriveDNSFromCIDR(clusterCIDR); err != nil {
log.Info("failed to derive DNS IP from service CIDR", "cidr", clusterCIDR, "error", err.Error())
} else if derivedDNS != "" {
dnsClusterIP = ptr.To(derivedDNS)
}
}

nodeInput := &userdata.NodeInput{
ClusterName: controlPlane.Spec.EKSClusterName,
KubeletExtraArgs: config.Spec.KubeletExtraArgs,
ContainerRuntime: config.Spec.ContainerRuntime,
DNSClusterIP: config.Spec.DNSClusterIP,
DNSClusterIP: dnsClusterIP,
DockerConfigJSON: config.Spec.DockerConfigJSON,
APIRetryAttempts: config.Spec.APIRetryAttempts,
UseMaxPods: config.Spec.UseMaxPods,
Expand All @@ -287,7 +371,7 @@ func (r *EKSConfigReconciler) joinWorker(ctx context.Context, cluster *clusterv1
DiskSetup: config.Spec.DiskSetup,
Mounts: config.Spec.Mounts,
Files: files,
ClusterCIDR: controlPlane.Spec.NetworkSpec.VPC.CidrBlock,
ClusterCIDR: clusterCIDR,
}

if config.Spec.PauseContainer != nil {
Expand Down
38 changes: 38 additions & 0 deletions bootstrap/eks/controllers/eksconfig_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"

ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2"
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
bsutil "sigs.k8s.io/cluster-api/bootstrap/util"
)
Expand Down Expand Up @@ -71,6 +72,43 @@ func TestEKSConfigReconcilerReturnEarlyIfClusterControlPlaneNotInitialized(t *te
}).Should(Succeed())
}

func TestDetermineClusterCIDR(t *testing.T) {
g := NewWithT(t)

cluster := newCluster("service-cidr-cluster")
controlPlane := newAMCP("service-cidr-cluster")
controlPlane.Spec.NetworkSpec.VPC.CidrBlock = "10.0.0.0/16"

cluster.Spec.ClusterNetwork = &clusterv1.ClusterNetwork{
Services: &clusterv1.NetworkRanges{
CIDRBlocks: []string{"192.168.0.0/16"},
},
}

g.Expect(determineClusterCIDR(cluster, controlPlane)).To(Equal("192.168.0.0/16"))

cluster.Spec.ClusterNetwork.Services.CIDRBlocks = nil
g.Expect(determineClusterCIDR(cluster, controlPlane)).To(Equal("10.0.0.0/16"))

controlPlane.Spec.NetworkSpec.VPC.CidrBlock = ""
g.Expect(determineClusterCIDR(&clusterv1.Cluster{}, &ekscontrolplanev1.AWSManagedControlPlane{})).To(Equal(""))
}

func TestDeriveDNSFromCIDR(t *testing.T) {
g := NewWithT(t)

ip, err := deriveDNSFromCIDR("192.168.0.0/16")
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ip).To(Equal("192.168.0.10"))

ip, err = deriveDNSFromCIDR("fd00::/112")
g.Expect(err).ToNot(HaveOccurred())
g.Expect(ip).To(Equal("fd00::a"))

_, err = deriveDNSFromCIDR("not-a-cidr")
g.Expect(err).To(HaveOccurred())
}

func configOwner(kind string) *bsutil.ConfigOwner {
unstructuredOwner := unstructured.Unstructured{
Object: map[string]interface{}{"kind": kind},
Expand Down
Loading