diff --git a/cluster-api/providers/aws/go.mod b/cluster-api/providers/aws/go.mod index 9ebaa05d27c..d05252e5bba 100644 --- a/cluster-api/providers/aws/go.mod +++ b/cluster-api/providers/aws/go.mod @@ -2,7 +2,7 @@ module openshift/installer/cluster-api/providers/aws go 1.21 -require sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 +require sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 require ( github.com/NYTimes/gziphandler v1.1.1 // indirect diff --git a/cluster-api/providers/aws/go.sum b/cluster-api/providers/aws/go.sum index 544db479952..e72411f442f 100644 --- a/cluster-api/providers/aws/go.sum +++ b/cluster-api/providers/aws/go.sum @@ -489,8 +489,8 @@ sigs.k8s.io/aws-iam-authenticator v0.6.13 h1:QSQcAkpt/hF97Ogyoz6sj3WD2twTd2cmxFb sigs.k8s.io/aws-iam-authenticator v0.6.13/go.mod h1:CnvFyzR/xeLHmUY/BD0qW6q0wp6KIwXmFp4eTfrHdP8= sigs.k8s.io/cluster-api v1.7.1 h1:JkMAbAMzBM+WBHxXLTJXTiCisv1PAaHRzld/3qrmLYY= sigs.k8s.io/cluster-api v1.7.1/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0= -sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 h1:B5Fzy3rTSn9sa+9tzwOL67gltATrDFAzEqP4H5YDdcE= -sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0/go.mod h1:1aq1EZbirRW6NC2gYUFCc7cVFwX9PM/vDvoU+2oGPuw= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 h1:me2kmDBuAolDLxG/i2BXq4nRzaxAOtugsmQvghHrh9A= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92/go.mod h1:1aq1EZbirRW6NC2gYUFCc7cVFwX9PM/vDvoU+2oGPuw= sigs.k8s.io/controller-runtime v0.17.3 h1:65QmN7r3FWgTxDMz9fvGnO1kbf2nu+acg9p2R9oYYYk= sigs.k8s.io/controller-runtime v0.17.3/go.mod h1:N0jpP5Lo7lMTF9aL56Z/B2oWBJjey6StQM0jRbKQXtY= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= diff --git a/cluster-api/providers/aws/vendor/modules.txt b/cluster-api/providers/aws/vendor/modules.txt index 6dd34fdceef..3f4d29988df 100644 --- a/cluster-api/providers/aws/vendor/modules.txt +++ b/cluster-api/providers/aws/vendor/modules.txt @@ -1149,7 +1149,7 @@ sigs.k8s.io/cluster-api/util/predicates sigs.k8s.io/cluster-api/util/secret sigs.k8s.io/cluster-api/util/topology sigs.k8s.io/cluster-api/version -# sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 +# sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 ## explicit; go 1.21 sigs.k8s.io/cluster-api-provider-aws/v2 sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1 diff --git a/cluster-api/providers/aws/vendor/sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/elb/loadbalancer.go b/cluster-api/providers/aws/vendor/sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/elb/loadbalancer.go index fa3cb49c090..1768e429225 100644 --- a/cluster-api/providers/aws/vendor/sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/elb/loadbalancer.go +++ b/cluster-api/providers/aws/vendor/sigs.k8s.io/cluster-api-provider-aws/v2/pkg/cloud/services/elb/loadbalancer.go @@ -64,6 +64,9 @@ const apiServerTargetGroupPrefix = "apiserver-target-" // listeners. const additionalTargetGroupPrefix = "additional-listener-" +// cantAttachSGToNLBRegions is a set of regions that do not support Security Groups in NLBs. +var cantAttachSGToNLBRegions = sets.New("us-iso-east-1", "us-iso-west-1", "us-isob-east-1") + // ReconcileLoadbalancers reconciles the load balancers for the given cluster. func (s *Service) ReconcileLoadbalancers() error { s.scope.Debug("Reconciling load balancers") @@ -406,6 +409,11 @@ func (s *Service) createLB(spec *infrav1.LoadBalancer, lbSpec *infrav1.AWSLoadBa input.IpAddressType = aws.String("dualstack") } + // TODO: remove when security groups on NLBs is supported in all regions. + if cantAttachSGToNLBRegions.Has(s.scope.Region()) { + input.SecurityGroups = nil + } + // Allocate custom addresses (Elastic IP) to internet-facing Load Balancers, when defined. // Custom, or BYO, Public IPv4 Pool need to be created prior install, and the Pool ID must be // set in the VpcSpec.ElasticIPPool.PublicIPv4Pool to allow Elastic IP be consumed from @@ -1799,7 +1807,11 @@ func shouldReconcileSGs(scope scope.ELBScope, lb *infrav1.LoadBalancer, specSGs // Once created without a security group, the NLB can never have any added. // (https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-security-groups.html) if lb.LoadBalancerType == infrav1.LoadBalancerTypeNLB && len(lb.SecurityGroupIDs) == 0 { - scope.Info("Pre-existing NLB %s without security groups, cannot reconcile security groups.", lb.Name) + if cantAttachSGToNLBRegions.Has(scope.Region()) { + scope.Info("Region doesn't support NLB security groups, cannot reconcile security groups.", "region", scope.Region(), "elb-name", lb.Name) + } else { + scope.Info("Pre-existing NLB without security groups, cannot reconcile security groups.", "elb-name", lb.Name) + } return false } if !sets.NewString(lb.SecurityGroupIDs...).Equal(sets.NewString(specSGs...)) { diff --git a/go.mod b/go.mod index 4f6cb2c7a6a..3d10665a1f3 100644 --- a/go.mod +++ b/go.mod @@ -116,7 +116,7 @@ require ( k8s.io/utils v0.0.0-20240310230437-4693a0247e57 libvirt.org/go/libvirtxml v1.10002.0 sigs.k8s.io/cluster-api v1.7.1 - sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 + sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 sigs.k8s.io/cluster-api-provider-azure v1.14.2 sigs.k8s.io/cluster-api-provider-gcp v1.6.1-0.20240425114559-a1994e55ab7a sigs.k8s.io/cluster-api-provider-ibmcloud v0.7.0 diff --git a/go.sum b/go.sum index 9f0d0fa18b5..a595bb3ebb2 100644 --- a/go.sum +++ b/go.sum @@ -3059,8 +3059,8 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/cluster-api v1.7.1 h1:JkMAbAMzBM+WBHxXLTJXTiCisv1PAaHRzld/3qrmLYY= sigs.k8s.io/cluster-api v1.7.1/go.mod h1:V9ZhKLvQtsDODwjXOKgbitjyCmC71yMBwDcMyNNIov0= -sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 h1:B5Fzy3rTSn9sa+9tzwOL67gltATrDFAzEqP4H5YDdcE= -sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0/go.mod h1:1aq1EZbirRW6NC2gYUFCc7cVFwX9PM/vDvoU+2oGPuw= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 h1:me2kmDBuAolDLxG/i2BXq4nRzaxAOtugsmQvghHrh9A= +sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92/go.mod h1:1aq1EZbirRW6NC2gYUFCc7cVFwX9PM/vDvoU+2oGPuw= sigs.k8s.io/cluster-api-provider-azure v1.14.2 h1:e36ID51GbHlJKmHVxhM51HNXxf6y/1OczERpgka7MzE= sigs.k8s.io/cluster-api-provider-azure v1.14.2/go.mod h1:CA3u3DKaWi+S2vbOrr3f/dEIIAcI91IMfd36aXZ06F4= sigs.k8s.io/cluster-api-provider-gcp v1.6.1-0.20240425114559-a1994e55ab7a h1:m6O4CUcEWS1paLtSV4Bm1yIeaD6Vr+VqpB7u+tR1DTw= diff --git a/pkg/asset/installconfig/aws/route53.go b/pkg/asset/installconfig/aws/route53.go index acb664a9a42..e7ccf88a561 100644 --- a/pkg/asset/installconfig/aws/route53.go +++ b/pkg/asset/installconfig/aws/route53.go @@ -11,7 +11,6 @@ import ( "github.com/aws/aws-sdk-go/aws/endpoints" awss "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/route53" - "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" @@ -156,67 +155,45 @@ func GetR53ClientCfg(sess *awss.Session, roleARN string) *aws.Config { return &aws.Config{Credentials: creds} } -// CreateOrUpdateRecord Creates or Updates the Route53 Record for the cluster endpoint. -func (c *Client) CreateOrUpdateRecord(ctx context.Context, ic *types.InstallConfig, target string, intTarget string, phzID string, aliasZoneID string) error { - useCNAME := cnameRegions.Has(ic.AWS.Region) - - apiName := fmt.Sprintf("api.%s.", ic.ClusterDomain()) - apiIntName := fmt.Sprintf("api-int.%s.", ic.ClusterDomain()) - - // Create api record in public zone - if ic.Publish == types.ExternalPublishingStrategy { - zone, err := c.GetBaseDomain(ic.BaseDomain) - if err != nil { - return err - } - - svc := route53.New(c.ssn) // we dont want to assume role here - if _, err := createRecord(ctx, svc, aws.StringValue(zone.Id), apiName, target, aliasZoneID, useCNAME); err != nil { - return fmt.Errorf("failed to create records for api: %w", err) - } - logrus.Debugln("Created public API record in public zone") - } - - // Create service with assumed role for PHZ - svc := route53.New(c.ssn, GetR53ClientCfg(c.ssn, ic.AWS.HostedZoneRole)) - - // Create api record in private zone - if _, err := createRecord(ctx, svc, phzID, apiName, intTarget, aliasZoneID, useCNAME); err != nil { - return fmt.Errorf("failed to create records for api: %w", err) - } - logrus.Debugln("Created public API record in private zone") - - // Create api-int record in private zone - if _, err := createRecord(ctx, svc, phzID, apiIntName, intTarget, aliasZoneID, useCNAME); err != nil { - return fmt.Errorf("failed to create records for api-int: %w", err) - } - logrus.Debugln("Created private API record in private zone") - - return nil +// CreateRecordInput collects information for creating a record. +type CreateRecordInput struct { + // Fully qualified record domain name. + Name string + // Cluster Region. + Region string + // Where to route the DNS queries to. + DNSTarget string + // ID of the Hosted Zone. + ZoneID string + // ID of the Hosted Zone for Alias record. + AliasZoneID string + // Role to assume to create the record. Leave empty to not assume role. + HostedZoneRole string } -func createRecord(ctx context.Context, client *route53.Route53, zoneID, name, dnsName, aliasZoneID string, useCNAME bool) (*route53.ChangeInfo, error) { +// CreateOrUpdateRecord Creates or Updates the Route53 Record for the cluster endpoint. +func (c *Client) CreateOrUpdateRecord(ctx context.Context, in *CreateRecordInput) error { recordSet := &route53.ResourceRecordSet{ - Name: aws.String(name), + Name: aws.String(in.Name), } - if useCNAME { + if cnameRegions.Has(in.Region) { recordSet.SetType("CNAME") recordSet.SetTTL(10) recordSet.SetResourceRecords([]*route53.ResourceRecord{ - {Value: aws.String(dnsName)}, + {Value: aws.String(in.DNSTarget)}, }) } else { recordSet.SetType("A") recordSet.SetAliasTarget(&route53.AliasTarget{ - DNSName: aws.String(dnsName), - HostedZoneId: aws.String(aliasZoneID), + DNSName: aws.String(in.DNSTarget), + HostedZoneId: aws.String(in.AliasZoneID), EvaluateTargetHealth: aws.Bool(false), }) } input := &route53.ChangeResourceRecordSetsInput{ - HostedZoneId: aws.String(zoneID), + HostedZoneId: aws.String(in.ZoneID), ChangeBatch: &route53.ChangeBatch{ - Comment: aws.String(fmt.Sprintf("Creating record %s", name)), + Comment: aws.String(fmt.Sprintf("Creating record %s", in.Name)), Changes: []*route53.Change{ { Action: aws.String("UPSERT"), @@ -225,12 +202,12 @@ func createRecord(ctx context.Context, client *route53.Route53, zoneID, name, dn }, }, } - res, err := client.ChangeResourceRecordSetsWithContext(ctx, input) - if err != nil { - return nil, err - } - return res.ChangeInfo, nil + // Create service with assumed role, if set + svc := route53.New(c.ssn, GetR53ClientCfg(c.ssn, in.HostedZoneRole)) + + _, err := svc.ChangeResourceRecordSetsWithContext(ctx, input) + return err } // HostedZoneInput defines the input parameters for hosted zone creation. @@ -277,6 +254,7 @@ func (c *Client) CreateHostedZone(ctx context.Context, input *HostedZoneInput) ( // Tag the hosted zone tags := mergeTags(input.UserTags, map[string]string{ "Name": fmt.Sprintf("%s-int", input.InfraID), + fmt.Sprintf("kubernetes.io/cluster/%s", input.InfraID): "owned", }) _, err = svc.ChangeTagsForResourceWithContext(ctx, &route53.ChangeTagsForResourceInput{ ResourceType: aws.String("hostedzone"), diff --git a/pkg/infrastructure/aws/clusterapi/aws.go b/pkg/infrastructure/aws/clusterapi/aws.go index a296281f73b..93a2ecfc163 100644 --- a/pkg/infrastructure/aws/clusterapi/aws.go +++ b/pkg/infrastructure/aws/clusterapi/aws.go @@ -115,46 +115,88 @@ func (*Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput) } } - tags := map[string]string{ - fmt.Sprintf("kubernetes.io/cluster/%s", in.InfraID): "owned", - } - for k, v := range awsCluster.Spec.AdditionalTags { - tags[k] = v - } - client := awsconfig.NewClient(awsSession) + logrus.Infoln("Creating Route53 records for control plane load balancer") + phzID := in.InstallConfig.Config.AWS.HostedZone if len(phzID) == 0 { - logrus.Infoln("Creating private Hosted Zone") + logrus.Debugln("Creating private Hosted Zone") + res, err := client.CreateHostedZone(ctx, &awsconfig.HostedZoneInput{ InfraID: in.InfraID, VpcID: vpcID, Region: awsCluster.Spec.Region, Name: in.InstallConfig.Config.ClusterDomain(), Role: in.InstallConfig.Config.AWS.HostedZoneRole, - UserTags: tags, + UserTags: awsCluster.Spec.AdditionalTags, }) if err != nil { return fmt.Errorf("failed to create private hosted zone: %w", err) } phzID = aws.StringValue(res.Id) + logrus.Infoln("Created private Hosted Zone") + } + + apiName := fmt.Sprintf("api.%s.", in.InstallConfig.Config.ClusterDomain()) + apiIntName := fmt.Sprintf("api-int.%s.", in.InstallConfig.Config.ClusterDomain()) + + // Create api record in public zone + if in.InstallConfig.Config.PublicAPI() { + zone, err := client.GetBaseDomain(in.InstallConfig.Config.BaseDomain) + if err != nil { + return err + } + + pubLB := awsCluster.Status.Network.SecondaryAPIServerELB + aliasZoneID, err := getHostedZoneIDForNLB(ctx, awsSession, awsCluster.Spec.Region, pubLB.DNSName) + if err != nil { + return fmt.Errorf("failed to find HostedZone ID for NLB: %w", err) + } + + if err := client.CreateOrUpdateRecord(ctx, &awsconfig.CreateRecordInput{ + Name: apiName, + Region: awsCluster.Spec.Region, + DNSTarget: pubLB.DNSName, + ZoneID: aws.StringValue(zone.Id), + AliasZoneID: aliasZoneID, + HostedZoneRole: "", // we dont want to assume role here + }); err != nil { + return fmt.Errorf("failed to create records for api in public zone: %w", err) + } + logrus.Debugln("Created public API record in public zone") } - logrus.Infoln("Creating Route53 records for control plane load balancer") aliasZoneID, err := getHostedZoneIDForNLB(ctx, awsSession, awsCluster.Spec.Region, awsCluster.Status.Network.APIServerELB.Name) if err != nil { return fmt.Errorf("failed to find HostedZone ID for NLB: %w", err) } - apiHost := awsCluster.Status.Network.SecondaryAPIServerELB.DNSName - if awsCluster.Status.Network.APIServerELB.Scheme == capa.ELBSchemeInternetFacing { - apiHost = awsCluster.Status.Network.APIServerELB.DNSName - } - apiIntHost := awsCluster.Spec.ControlPlaneEndpoint.Host - err = client.CreateOrUpdateRecord(ctx, in.InstallConfig.Config, apiHost, apiIntHost, phzID, aliasZoneID) - if err != nil { - return fmt.Errorf("failed to create route53 records: %w", err) - } + + // Create api record in private zone + if err := client.CreateOrUpdateRecord(ctx, &awsconfig.CreateRecordInput{ + Name: apiName, + Region: awsCluster.Spec.Region, + DNSTarget: awsCluster.Spec.ControlPlaneEndpoint.Host, + ZoneID: phzID, + AliasZoneID: aliasZoneID, + HostedZoneRole: in.InstallConfig.Config.AWS.HostedZoneRole, + }); err != nil { + return fmt.Errorf("failed to create records for api in private zone: %w", err) + } + logrus.Debugln("Created public API record in private zone") + + // Create api-int record in private zone + if err := client.CreateOrUpdateRecord(ctx, &awsconfig.CreateRecordInput{ + Name: apiIntName, + Region: awsCluster.Spec.Region, + DNSTarget: awsCluster.Spec.ControlPlaneEndpoint.Host, + ZoneID: phzID, + AliasZoneID: aliasZoneID, + HostedZoneRole: in.InstallConfig.Config.AWS.HostedZoneRole, + }); err != nil { + return fmt.Errorf("failed to create records for api-int in private zone: %w", err) + } + logrus.Debugln("Created private API record in private zone") return nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 82f7497eaf6..04f070a1aa0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -2148,7 +2148,7 @@ sigs.k8s.io/cluster-api/util/kubeconfig sigs.k8s.io/cluster-api/util/labels/format sigs.k8s.io/cluster-api/util/secret sigs.k8s.io/cluster-api/util/topology -# sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20250307190545-2361956824d0 +# sigs.k8s.io/cluster-api-provider-aws/v2 v2.6.2-0.20251023220133-66942942ff92 ## explicit; go 1.21 sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta1 sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2