diff --git a/bootstrap/eks/controllers/eksconfig_controller.go b/bootstrap/eks/controllers/eksconfig_controller.go index c982c90980..a0c4e7fed1 100644 --- a/bootstrap/eks/controllers/eksconfig_controller.go +++ b/bootstrap/eks/controllers/eksconfig_controller.go @@ -20,27 +20,20 @@ package controllers import ( "bytes" "context" + "encoding/base64" "fmt" "os" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/eks" "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" "k8s.io/utils/ptr" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller" - "sigs.k8s.io/controller-runtime/pkg/handler" - "sigs.k8s.io/controller-runtime/pkg/source" - eksbootstrapv1 "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/api/v1beta2" "sigs.k8s.io/cluster-api-provider-aws/v2/bootstrap/eks/internal/userdata" ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/v2/controlplane/eks/api/v1beta2" @@ -53,8 +46,14 @@ import ( "sigs.k8s.io/cluster-api/feature" "sigs.k8s.io/cluster-api/util" "sigs.k8s.io/cluster-api/util/conditions" + kubeconfigutil "sigs.k8s.io/cluster-api/util/kubeconfig" "sigs.k8s.io/cluster-api/util/patch" "sigs.k8s.io/cluster-api/util/predicates" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/source" ) const ( @@ -323,36 +322,19 @@ func (r *EKSConfigReconciler) joinWorker(ctx context.Context, cluster *clusterv1 log.Info("Using mock CA certificate for test environment") nodeInput.CACert = "mock-ca-certificate-for-testing" } else { - // Fetch CA cert from EKS API - sess, err := session.NewSession(&aws.Config{Region: aws.String(controlPlane.Spec.Region)}) - if err != nil { - log.Error(err, "Failed to create AWS session for EKS API") - conditions.MarkFalse(config, eksbootstrapv1.DataSecretAvailableCondition, - eksbootstrapv1.DataSecretGenerationFailedReason, - clusterv1.ConditionSeverityWarning, - "Failed to create AWS session: %v", err) - return ctrl.Result{}, err + // Fetch CA cert from KubeConfig secret + // We already have the cluster object passed to this function + obj := client.ObjectKey{ + Namespace: cluster.Namespace, + Name: cluster.Name, } - eksClient := eks.New(sess) - describeInput := &eks.DescribeClusterInput{Name: aws.String(controlPlane.Spec.EKSClusterName)} - clusterOut, err := eksClient.DescribeCluster(describeInput) + ca, err := r.extractCAFromSecret(ctx, obj) if err != nil { - log.Error(err, "Failed to describe EKS cluster for CA cert fetch") - conditions.MarkFalse(config, eksbootstrapv1.DataSecretAvailableCondition, - eksbootstrapv1.DataSecretGenerationFailedReason, - clusterv1.ConditionSeverityWarning, - "Failed to describe EKS cluster: %v", err) + log.Error(err, "Failed to extract CA from kubeconfig secret") + conditions.MarkFalse(config, eksbootstrapv1.DataSecretAvailableCondition, eksbootstrapv1.DataSecretGenerationFailedReason, clusterv1.ConditionSeverityWarning, "Failed to extract CA from kubeconfig secret: %v", err) return ctrl.Result{}, err - } else if clusterOut.Cluster != nil && clusterOut.Cluster.CertificateAuthority != nil && clusterOut.Cluster.CertificateAuthority.Data != nil { - nodeInput.CACert = *clusterOut.Cluster.CertificateAuthority.Data - } else { - log.Error(nil, "CA certificate not found in EKS cluster response") - conditions.MarkFalse(config, eksbootstrapv1.DataSecretAvailableCondition, - eksbootstrapv1.DataSecretGenerationFailedReason, - clusterv1.ConditionSeverityWarning, - "CA certificate not found in EKS cluster response") - return ctrl.Result{}, fmt.Errorf("CA certificate not found in EKS cluster response") } + nodeInput.CACert = ca } // Get AMI ID from AWSManagedMachinePool's launch template if specified @@ -377,9 +359,7 @@ func (r *EKSConfigReconciler) joinWorker(ctx context.Context, cluster *clusterv1 } } - log.Info("Generating AL2023 userdata", - "cluster", controlPlane.Spec.EKSClusterName, - "endpoint", nodeInput.APIServerEndpoint) + log.Info("Generating AL2023 userdata", "cluster", controlPlane.Spec.EKSClusterName, "endpoint", nodeInput.APIServerEndpoint) } else { nodeInput.AMIFamilyType = userdata.AMIFamilyAL2 log.Info("Generating standard userdata for node type", "type", config.Spec.NodeType) @@ -581,3 +561,23 @@ func (r *EKSConfigReconciler) updateBootstrapSecret(ctx context.Context, secret } return false, nil } + +func (r *EKSConfigReconciler) extractCAFromSecret(ctx context.Context, obj client.ObjectKey) (string, error) { + data, err := kubeconfigutil.FromSecret(ctx, r.Client, obj) + if err != nil { + return "", errors.Wrapf(err, "failed to get kubeconfig secret %s", obj.Name) + } + config, err := clientcmd.Load(data) + if err != nil { + return "", errors.Wrapf(err, "failed to parse kubeconfig data from secret %s", obj.Name) + } + + // Iterate through all clusters in the kubeconfig and use the first one with CA data + for _, cluster := range config.Clusters { + if len(cluster.CertificateAuthorityData) > 0 { + return base64.StdEncoding.EncodeToString(cluster.CertificateAuthorityData), nil + } + } + + return "", fmt.Errorf("no cluster with CA data found in kubeconfig") +}