From c72f25d84cf5e048368f740ed332027761c79369 Mon Sep 17 00:00:00 2001
From: Nolan Brubaker
Date: Mon, 9 Oct 2023 17:23:19 -0400
Subject: [PATCH] Support a secondary control plane load balancer
* A secondary control plane load balancer can be added.
* It will be a network load balancer.
* Its scheme must not match that of the ControlPlaneLoadBalancer.
Previously, NLBs could not have security groups attached. This has now
changed, and an NLB can have a security group attached at creation. If a
security group is _not_ present at creation, then the NLB can never have
security groups added.
---
api/v1beta1/awscluster_conversion.go | 22 +
api/v1beta1/zz_generated.conversion.go | 2 +
api/v1beta2/awscluster_types.go | 8 +
api/v1beta2/awscluster_webhook.go | 136 ++++--
api/v1beta2/defaults.go | 8 +
api/v1beta2/network_types.go | 3 +
api/v1beta2/zz_generated.deepcopy.go | 6 +
...ster.x-k8s.io_awsmanagedcontrolplanes.yaml | 418 ++++++++++++++++
...tructure.cluster.x-k8s.io_awsclusters.yaml | 390 +++++++++++++++
....cluster.x-k8s.io_awsclustertemplates.yaml | 189 ++++++++
controllers/awsmachine_controller.go | 53 +-
controllers/helpers_test.go | 4 +
docs/book/src/SUMMARY_PREFIX.md | 2 +
docs/book/src/crd/index.md | 456 ++++++++++++++++++
.../network-load-balancer-with-awscluster.md | 13 +-
.../src/topics/secondary-load-balancer.md | 36 ++
.../20220712-garbage-collection-delete.svg | 6 +-
docs/proposal/IPv6 Sequence Diagram.svg | 53 ++
pkg/cloud/scope/cluster.go | 7 +
pkg/cloud/scope/elb.go | 5 +
pkg/cloud/services/elb/loadbalancer.go | 145 +++---
pkg/cloud/services/elb/loadbalancer_test.go | 257 ++++++++--
pkg/cloud/services/interfaces.go | 4 +-
.../mock_services/elb_interface_mock.go | 16 +-
24 files changed, 2052 insertions(+), 187 deletions(-)
create mode 100644 docs/book/src/topics/secondary-load-balancer.md
create mode 100644 docs/proposal/IPv6 Sequence Diagram.svg
diff --git a/api/v1beta1/awscluster_conversion.go b/api/v1beta1/awscluster_conversion.go
index ca199770ec..5761b39e67 100644
--- a/api/v1beta1/awscluster_conversion.go
+++ b/api/v1beta1/awscluster_conversion.go
@@ -44,6 +44,14 @@ func (src *AWSCluster) ConvertTo(dstRaw conversion.Hub) error {
}
restoreControlPlaneLoadBalancerStatus(&restored.Status.Network.APIServerELB, &dst.Status.Network.APIServerELB)
+ if restored.Spec.SecondaryControlPlaneLoadBalancer != nil {
+ if dst.Spec.SecondaryControlPlaneLoadBalancer == nil {
+ dst.Spec.SecondaryControlPlaneLoadBalancer = &infrav2.AWSLoadBalancerSpec{}
+ }
+ restoreControlPlaneLoadBalancer(restored.Spec.SecondaryControlPlaneLoadBalancer, dst.Spec.SecondaryControlPlaneLoadBalancer)
+ }
+ restoreControlPlaneLoadBalancerStatus(&restored.Status.Network.SecondaryAPIServerELB, &dst.Status.Network.SecondaryAPIServerELB)
+
dst.Spec.S3Bucket = restored.Spec.S3Bucket
if restored.Status.Bastion != nil {
dst.Status.Bastion.InstanceMetadataOptions = restored.Status.Bastion.InstanceMetadataOptions
@@ -115,6 +123,16 @@ func restoreControlPlaneLoadBalancerStatus(restored, dst *infrav2.LoadBalancer)
dst.LoadBalancerType = restored.LoadBalancerType
dst.ELBAttributes = restored.ELBAttributes
dst.ELBListeners = restored.ELBListeners
+ dst.Name = restored.Name
+ dst.DNSName = restored.DNSName
+ dst.Scheme = restored.Scheme
+ dst.SubnetIDs = restored.SubnetIDs
+ dst.SecurityGroupIDs = restored.SecurityGroupIDs
+ dst.HealthCheck = restored.HealthCheck
+ dst.ClassicElbAttributes = restored.ClassicElbAttributes
+ dst.Tags = restored.Tags
+ dst.ClassicELBListeners = restored.ClassicELBListeners
+ dst.AvailabilityZones = restored.AvailabilityZones
}
// restoreIPAMPool manually restores the ipam pool data.
@@ -135,6 +153,10 @@ func restoreControlPlaneLoadBalancer(restored, dst *infrav2.AWSLoadBalancerSpec)
dst.PreserveClientIP = restored.PreserveClientIP
dst.IngressRules = restored.IngressRules
dst.AdditionalListeners = restored.AdditionalListeners
+ dst.AdditionalSecurityGroups = restored.AdditionalSecurityGroups
+ dst.Scheme = restored.Scheme
+ dst.CrossZoneLoadBalancing = restored.CrossZoneLoadBalancing
+ dst.Subnets = restored.Subnets
}
// ConvertFrom converts the v1beta1 AWSCluster receiver to a v1beta1 AWSCluster.
diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go
index 347e67fd35..45567bd837 100644
--- a/api/v1beta1/zz_generated.conversion.go
+++ b/api/v1beta1/zz_generated.conversion.go
@@ -932,6 +932,7 @@ func autoConvert_v1beta2_AWSClusterSpec_To_v1beta1_AWSClusterSpec(in *v1beta2.AW
} else {
out.ControlPlaneLoadBalancer = nil
}
+ // WARNING: in.SecondaryControlPlaneLoadBalancer requires manual conversion: does not exist in peer-type
out.ImageLookupFormat = in.ImageLookupFormat
out.ImageLookupOrg = in.ImageLookupOrg
out.ImageLookupBaseOS = in.ImageLookupBaseOS
@@ -2101,6 +2102,7 @@ func autoConvert_v1beta2_NetworkStatus_To_v1beta1_NetworkStatus(in *v1beta2.Netw
if err := Convert_v1beta2_LoadBalancer_To_v1beta1_ClassicELB(&in.APIServerELB, &out.APIServerELB, s); err != nil {
return err
}
+ // WARNING: in.SecondaryAPIServerELB requires manual conversion: does not exist in peer-type
// WARNING: in.NatGatewaysIPs requires manual conversion: does not exist in peer-type
return nil
}
diff --git a/api/v1beta2/awscluster_types.go b/api/v1beta2/awscluster_types.go
index 0a1bdafbfc..05b3887b2d 100644
--- a/api/v1beta2/awscluster_types.go
+++ b/api/v1beta2/awscluster_types.go
@@ -60,6 +60,14 @@ type AWSClusterSpec struct {
// +optional
ControlPlaneLoadBalancer *AWSLoadBalancerSpec `json:"controlPlaneLoadBalancer,omitempty"`
+ // SecondaryControlPlaneLoadBalancer is an additional load balancer that can be used for the control plane.
+ //
+ // An example use case is to have a separate internal load balancer for internal traffic,
+ // and a separate external load balancer for external traffic.
+ //
+ // +optional
+ SecondaryControlPlaneLoadBalancer *AWSLoadBalancerSpec `json:"secondaryControlPlaneLoadBalancer,omitempty"`
+
// ImageLookupFormat is the AMI naming format to look up machine images when
// a machine does not specify an AMI. When set, this will be used for all
// cluster machines unless a machine specifies a different ImageLookupOrg.
diff --git a/api/v1beta2/awscluster_webhook.go b/api/v1beta2/awscluster_webhook.go
index 3ffdfaa707..bbc3eb6a8f 100644
--- a/api/v1beta2/awscluster_webhook.go
+++ b/api/v1beta2/awscluster_webhook.go
@@ -58,7 +58,7 @@ func (r *AWSCluster) ValidateCreate() (admission.Warnings, error) {
allErrs = append(allErrs, r.Spec.AdditionalTags.Validate()...)
allErrs = append(allErrs, r.Spec.S3Bucket.Validate()...)
allErrs = append(allErrs, r.validateNetwork()...)
- allErrs = append(allErrs, r.validateControlPlaneLB()...)
+ allErrs = append(allErrs, r.validateControlPlaneLBs()...)
return nil, aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
}
@@ -85,51 +85,18 @@ func (r *AWSCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, err
)
}
- newLoadBalancer := &AWSLoadBalancerSpec{}
- existingLoadBalancer := &AWSLoadBalancerSpec{}
-
- if r.Spec.ControlPlaneLoadBalancer != nil {
- newLoadBalancer = r.Spec.ControlPlaneLoadBalancer.DeepCopy()
+ // Validate the control plane load balancers.
+ lbs := map[*AWSLoadBalancerSpec]*AWSLoadBalancerSpec{
+ oldC.Spec.ControlPlaneLoadBalancer: r.Spec.ControlPlaneLoadBalancer,
+ oldC.Spec.SecondaryControlPlaneLoadBalancer: r.Spec.SecondaryControlPlaneLoadBalancer,
}
- if oldC.Spec.ControlPlaneLoadBalancer != nil {
- existingLoadBalancer = oldC.Spec.ControlPlaneLoadBalancer.DeepCopy()
- }
- if oldC.Spec.ControlPlaneLoadBalancer == nil {
- // If old scheme was nil, the only value accepted here is the default value: internet-facing
- if newLoadBalancer.Scheme != nil && newLoadBalancer.Scheme.String() != ELBSchemeInternetFacing.String() {
- allErrs = append(allErrs,
- field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "scheme"),
- r.Spec.ControlPlaneLoadBalancer.Scheme, "field is immutable, default value was set to internet-facing"),
- )
- }
- } else {
- // If old scheme was not nil, the new scheme should be the same.
- if !cmp.Equal(existingLoadBalancer.Scheme, newLoadBalancer.Scheme) {
- allErrs = append(allErrs,
- field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "scheme"),
- r.Spec.ControlPlaneLoadBalancer.Scheme, "field is immutable"),
- )
- }
- // The name must be defined when the AWSCluster is created. If it is not defined,
- // then the controller generates a default name at runtime, but does not store it,
- // so the name remains nil. In either case, the name cannot be changed.
- if !cmp.Equal(existingLoadBalancer.Name, newLoadBalancer.Name) {
- allErrs = append(allErrs,
- field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "name"),
- r.Spec.ControlPlaneLoadBalancer.Name, "field is immutable"),
- )
+ for oldLB, newLB := range lbs {
+ if oldLB == nil && newLB == nil {
+ continue
}
- }
- // Block the update for Protocol :
- // - if it was not set in old spec but added in new spec
- // - if it was set in old spec but changed in new spec
- if !cmp.Equal(newLoadBalancer.HealthCheckProtocol, existingLoadBalancer.HealthCheckProtocol) {
- allErrs = append(allErrs,
- field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "healthCheckProtocol"),
- newLoadBalancer.HealthCheckProtocol, "field is immutable once set"),
- )
+ allErrs = append(allErrs, r.validateControlPlaneLoadBalancerUpdate(oldLB, newLB)...)
}
if !cmp.Equal(oldC.Spec.ControlPlaneEndpoint, clusterv1.APIEndpoint{}) &&
@@ -174,6 +141,49 @@ func (r *AWSCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, err
return nil, aggregateObjErrors(r.GroupVersionKind().GroupKind(), r.Name, allErrs)
}
+func (r *AWSCluster) validateControlPlaneLoadBalancerUpdate(oldlb, newlb *AWSLoadBalancerSpec) field.ErrorList {
+ var allErrs field.ErrorList
+
+ if oldlb == nil {
+ // If old scheme was nil, the only value accepted here is the default value: internet-facing
+ if newlb.Scheme != nil && newlb.Scheme.String() != ELBSchemeInternetFacing.String() {
+ allErrs = append(allErrs,
+ field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "scheme"),
+ newlb.Scheme, "field is immutable, default value was set to internet-facing"),
+ )
+ }
+ } else {
+ // If old scheme was not nil, the new scheme should be the same.
+ if !cmp.Equal(oldlb.Scheme, newlb.Scheme) {
+ allErrs = append(allErrs,
+ field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "scheme"),
+ newlb.Scheme, "field is immutable"),
+ )
+ }
+ // The name must be defined when the AWSCluster is created. If it is not defined,
+ // then the controller generates a default name at runtime, but does not store it,
+ // so the name remains nil. In either case, the name cannot be changed.
+ if !cmp.Equal(oldlb.Name, newlb.Name) {
+ allErrs = append(allErrs,
+ field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "name"),
+ newlb.Name, "field is immutable"),
+ )
+ }
+ }
+
+ // Block the update for Protocol :
+ // - if it was not set in old spec but added in new spec
+ // - if it was set in old spec but changed in new spec
+ if !cmp.Equal(newlb.HealthCheckProtocol, oldlb.HealthCheckProtocol) {
+ allErrs = append(allErrs,
+ field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "healthCheckProtocol"),
+ newlb.HealthCheckProtocol, "field is immutable once set"),
+ )
+ }
+
+ return allErrs
+}
+
// Default satisfies the defaulting webhook interface.
func (r *AWSCluster) Default() {
SetObjectDefaults_AWSCluster(r)
@@ -243,26 +253,48 @@ func (r *AWSCluster) validateNetwork() field.ErrorList {
allErrs = append(allErrs, field.Invalid(field.NewPath("additionalControlPlaneIngressRules"), r.Spec.NetworkSpec.AdditionalControlPlaneIngressRules, "CIDR blocks and security group IDs or security group roles cannot be used together"))
}
}
+
return allErrs
}
-func (r *AWSCluster) validateControlPlaneLB() field.ErrorList {
+func (r *AWSCluster) validateControlPlaneLBs() field.ErrorList {
var allErrs field.ErrorList
- if r.Spec.ControlPlaneLoadBalancer == nil {
- return allErrs
+ // If the secondary is defined, check that the name is not empty and different from the primary.
+ // Also, ensure that the secondary load balancer is an NLB
+ if r.Spec.SecondaryControlPlaneLoadBalancer != nil {
+ if r.Spec.SecondaryControlPlaneLoadBalancer.Name == nil || *r.Spec.SecondaryControlPlaneLoadBalancer.Name == "" {
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "secondaryControlPlaneLoadBalancer", "name"), r.Spec.SecondaryControlPlaneLoadBalancer.Name, "secondary controlPlaneLoadBalancer.name cannot be empty"))
+ }
+
+ if r.Spec.SecondaryControlPlaneLoadBalancer.Name == r.Spec.ControlPlaneLoadBalancer.Name {
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "secondaryControlPlaneLoadBalancer", "name"), r.Spec.SecondaryControlPlaneLoadBalancer.Name, "field must be different from controlPlaneLoadBalancer.name"))
+ }
+
+ if r.Spec.SecondaryControlPlaneLoadBalancer.Scheme.Equals(r.Spec.ControlPlaneLoadBalancer.Scheme) {
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "secondaryControlPlaneLoadBalancer", "scheme"), r.Spec.SecondaryControlPlaneLoadBalancer.Scheme, "control plane load balancers must have different schemes"))
+ }
+
+ if r.Spec.SecondaryControlPlaneLoadBalancer.LoadBalancerType != LoadBalancerTypeNLB {
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "secondaryControlPlaneLoadBalancer", "loadBalancerType"), r.Spec.SecondaryControlPlaneLoadBalancer.LoadBalancerType, "secondary control plane load balancer must be a Network Load Balancer"))
+ }
}
// Additional listeners are only supported for NLBs.
- if len(r.Spec.ControlPlaneLoadBalancer.AdditionalListeners) > 0 {
- if r.Spec.ControlPlaneLoadBalancer.LoadBalancerType != LoadBalancerTypeNLB {
- allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "additionalListeners"), r.Spec.ControlPlaneLoadBalancer.AdditionalListeners, "additional listeners are only supported for NLB load balancers"))
- }
+ // Validate the control plane load balancers.
+ loadBalancers := []*AWSLoadBalancerSpec{
+ r.Spec.ControlPlaneLoadBalancer,
+ r.Spec.SecondaryControlPlaneLoadBalancer,
}
+ for _, cp := range loadBalancers {
+ if cp == nil {
+ continue
+ }
- for _, rule := range r.Spec.ControlPlaneLoadBalancer.IngressRules {
- if (rule.CidrBlocks != nil || rule.IPv6CidrBlocks != nil) && (rule.SourceSecurityGroupIDs != nil || rule.SourceSecurityGroupRoles != nil) {
- allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "ingressRules"), r.Spec.ControlPlaneLoadBalancer.IngressRules, "CIDR blocks and security group IDs or security group roles cannot be used together"))
+ for _, rule := range cp.IngressRules {
+ if (rule.CidrBlocks != nil || rule.IPv6CidrBlocks != nil) && (rule.SourceSecurityGroupIDs != nil || rule.SourceSecurityGroupRoles != nil) {
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "controlPlaneLoadBalancer", "ingressRules"), r.Spec.ControlPlaneLoadBalancer.IngressRules, "CIDR blocks and security group IDs or security group roles cannot be used together"))
+ }
}
}
diff --git a/api/v1beta2/defaults.go b/api/v1beta2/defaults.go
index 50a917df37..f10bb895c1 100644
--- a/api/v1beta2/defaults.go
+++ b/api/v1beta2/defaults.go
@@ -69,6 +69,14 @@ func SetDefaults_AWSClusterSpec(s *AWSClusterSpec) { //nolint:golint,stylecheck
if s.ControlPlaneLoadBalancer.LoadBalancerType == "" {
s.ControlPlaneLoadBalancer.LoadBalancerType = LoadBalancerTypeClassic
}
+ if s.SecondaryControlPlaneLoadBalancer != nil {
+ if s.SecondaryControlPlaneLoadBalancer.LoadBalancerType == "" {
+ s.SecondaryControlPlaneLoadBalancer.LoadBalancerType = LoadBalancerTypeNLB
+ }
+ if s.SecondaryControlPlaneLoadBalancer.Scheme == nil {
+ s.SecondaryControlPlaneLoadBalancer.Scheme = &ELBSchemeInternal
+ }
+ }
}
// SetDefaults_Labels is used to default cluster scope resources for clusterctl move.
diff --git a/api/v1beta2/network_types.go b/api/v1beta2/network_types.go
index 8b4ba3ac4e..df5f13fea9 100644
--- a/api/v1beta2/network_types.go
+++ b/api/v1beta2/network_types.go
@@ -37,6 +37,9 @@ type NetworkStatus struct {
// APIServerELB is the Kubernetes api server load balancer.
APIServerELB LoadBalancer `json:"apiServerElb,omitempty"`
+ // SecondaryAPIServerELB is the secondary Kubernetes api server load balancer.
+ SecondaryAPIServerELB LoadBalancer `json:"secondaryAPIServerELB,omitempty"`
+
// NatGatewaysIPs contains the public IPs of the NAT Gateways
NatGatewaysIPs []string `json:"natGatewaysIPs,omitempty"`
}
diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go
index cd5ba0a0f9..a037772772 100644
--- a/api/v1beta2/zz_generated.deepcopy.go
+++ b/api/v1beta2/zz_generated.deepcopy.go
@@ -308,6 +308,11 @@ func (in *AWSClusterSpec) DeepCopyInto(out *AWSClusterSpec) {
*out = new(AWSLoadBalancerSpec)
(*in).DeepCopyInto(*out)
}
+ if in.SecondaryControlPlaneLoadBalancer != nil {
+ in, out := &in.SecondaryControlPlaneLoadBalancer, &out.SecondaryControlPlaneLoadBalancer
+ *out = new(AWSLoadBalancerSpec)
+ (*in).DeepCopyInto(*out)
+ }
in.Bastion.DeepCopyInto(&out.Bastion)
if in.IdentityRef != nil {
in, out := &in.IdentityRef, &out.IdentityRef
@@ -1632,6 +1637,7 @@ func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) {
}
}
in.APIServerELB.DeepCopyInto(&out.APIServerELB)
+ in.SecondaryAPIServerELB.DeepCopyInto(&out.SecondaryAPIServerELB)
if in.NatGatewaysIPs != nil {
in, out := &in.NatGatewaysIPs, &out.NatGatewaysIPs
*out = make([]string, len(*in))
diff --git a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml
index 8c9cdd638a..3c30e1f660 100644
--- a/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml
+++ b/config/crd/bases/controlplane.cluster.x-k8s.io_awsmanagedcontrolplanes.yaml
@@ -1500,6 +1500,215 @@ spec:
items:
type: string
type: array
+ secondaryAPIServerELB:
+ description: SecondaryAPIServerELB is the secondary Kubernetes
+ api server load balancer.
+ properties:
+ arn:
+ description: ARN of the load balancer. Unlike the ClassicLB,
+ ARN is used mostly to define and get it.
+ type: string
+ attributes:
+ description: ClassicElbAttributes defines extra attributes
+ associated with the load balancer.
+ properties:
+ crossZoneLoadBalancing:
+ description: CrossZoneLoadBalancing enables the classic
+ load balancer load balancing.
+ type: boolean
+ idleTimeout:
+ description: IdleTimeout is time that the connection is
+ allowed to be idle (no data has been sent over the connection)
+ before it is closed by the load balancer.
+ format: int64
+ type: integer
+ type: object
+ availabilityZones:
+ description: AvailabilityZones is an array of availability
+ zones in the VPC attached to the load balancer.
+ items:
+ type: string
+ type: array
+ dnsName:
+ description: DNSName is the dns name of the load balancer.
+ type: string
+ elbAttributes:
+ additionalProperties:
+ type: string
+ description: ELBAttributes defines extra attributes associated
+ with v2 load balancers.
+ type: object
+ elbListeners:
+ description: ELBListeners is an array of listeners associated
+ with the load balancer. There must be at least one.
+ items:
+ description: Listener defines an AWS network load balancer
+ listener.
+ properties:
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ targetGroup:
+ description: TargetGroupSpec specifies target group
+ settings for a given listener. This is created first,
+ and the ARN is then passed to the listener.
+ properties:
+ name:
+ description: Name of the TargetGroup. Must be unique
+ over the same group of listeners.
+ type: string
+ port:
+ description: Port is the exposed port
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ enum:
+ - tcp
+ - tls
+ - udp
+ - TCP
+ - TLS
+ - UDP
+ type: string
+ targetGroupHealthCheck:
+ description: HealthCheck is the elb health check
+ associated with the load balancer.
+ properties:
+ intervalSeconds:
+ format: int64
+ type: integer
+ path:
+ type: string
+ port:
+ type: string
+ protocol:
+ type: string
+ thresholdCount:
+ format: int64
+ type: integer
+ timeoutSeconds:
+ format: int64
+ type: integer
+ type: object
+ vpcId:
+ type: string
+ required:
+ - name
+ - port
+ - protocol
+ - vpcId
+ type: object
+ required:
+ - port
+ - protocol
+ - targetGroup
+ type: object
+ type: array
+ healthChecks:
+ description: HealthCheck is the classic elb health check associated
+ with the load balancer.
+ properties:
+ healthyThreshold:
+ format: int64
+ type: integer
+ interval:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ target:
+ type: string
+ timeout:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ unhealthyThreshold:
+ format: int64
+ type: integer
+ required:
+ - healthyThreshold
+ - interval
+ - target
+ - timeout
+ - unhealthyThreshold
+ type: object
+ listeners:
+ description: ClassicELBListeners is an array of classic elb
+ listeners associated with the load balancer. There must
+ be at least one.
+ items:
+ description: ClassicELBListener defines an AWS classic load
+ balancer listener.
+ properties:
+ instancePort:
+ format: int64
+ type: integer
+ instanceProtocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ required:
+ - instancePort
+ - instanceProtocol
+ - port
+ - protocol
+ type: object
+ type: array
+ loadBalancerType:
+ description: LoadBalancerType sets the type for a load balancer.
+ The default type is classic.
+ enum:
+ - classic
+ - elb
+ - alb
+ - nlb
+ type: string
+ name:
+ description: The name of the load balancer. It must be unique
+ within the set of load balancers defined in the region.
+ It also serves as identifier.
+ type: string
+ scheme:
+ description: Scheme is the load balancer scheme, either internet-facing
+ or private.
+ type: string
+ securityGroupIds:
+ description: SecurityGroupIDs is an array of security groups
+ assigned to the load balancer.
+ items:
+ type: string
+ type: array
+ subnetIds:
+ description: SubnetIDs is an array of subnets in the VPC attached
+ to the load balancer.
+ items:
+ type: string
+ type: array
+ tags:
+ additionalProperties:
+ type: string
+ description: Tags is a map of tags associated with the load
+ balancer.
+ type: object
+ type: object
securityGroups:
additionalProperties:
description: SecurityGroup defines an AWS security group.
@@ -3110,6 +3319,215 @@ spec:
items:
type: string
type: array
+ secondaryAPIServerELB:
+ description: SecondaryAPIServerELB is the secondary Kubernetes
+ api server load balancer.
+ properties:
+ arn:
+ description: ARN of the load balancer. Unlike the ClassicLB,
+ ARN is used mostly to define and get it.
+ type: string
+ attributes:
+ description: ClassicElbAttributes defines extra attributes
+ associated with the load balancer.
+ properties:
+ crossZoneLoadBalancing:
+ description: CrossZoneLoadBalancing enables the classic
+ load balancer load balancing.
+ type: boolean
+ idleTimeout:
+ description: IdleTimeout is time that the connection is
+ allowed to be idle (no data has been sent over the connection)
+ before it is closed by the load balancer.
+ format: int64
+ type: integer
+ type: object
+ availabilityZones:
+ description: AvailabilityZones is an array of availability
+ zones in the VPC attached to the load balancer.
+ items:
+ type: string
+ type: array
+ dnsName:
+ description: DNSName is the dns name of the load balancer.
+ type: string
+ elbAttributes:
+ additionalProperties:
+ type: string
+ description: ELBAttributes defines extra attributes associated
+ with v2 load balancers.
+ type: object
+ elbListeners:
+ description: ELBListeners is an array of listeners associated
+ with the load balancer. There must be at least one.
+ items:
+ description: Listener defines an AWS network load balancer
+ listener.
+ properties:
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ targetGroup:
+ description: TargetGroupSpec specifies target group
+ settings for a given listener. This is created first,
+ and the ARN is then passed to the listener.
+ properties:
+ name:
+ description: Name of the TargetGroup. Must be unique
+ over the same group of listeners.
+ type: string
+ port:
+ description: Port is the exposed port
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ enum:
+ - tcp
+ - tls
+ - udp
+ - TCP
+ - TLS
+ - UDP
+ type: string
+ targetGroupHealthCheck:
+ description: HealthCheck is the elb health check
+ associated with the load balancer.
+ properties:
+ intervalSeconds:
+ format: int64
+ type: integer
+ path:
+ type: string
+ port:
+ type: string
+ protocol:
+ type: string
+ thresholdCount:
+ format: int64
+ type: integer
+ timeoutSeconds:
+ format: int64
+ type: integer
+ type: object
+ vpcId:
+ type: string
+ required:
+ - name
+ - port
+ - protocol
+ - vpcId
+ type: object
+ required:
+ - port
+ - protocol
+ - targetGroup
+ type: object
+ type: array
+ healthChecks:
+ description: HealthCheck is the classic elb health check associated
+ with the load balancer.
+ properties:
+ healthyThreshold:
+ format: int64
+ type: integer
+ interval:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ target:
+ type: string
+ timeout:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ unhealthyThreshold:
+ format: int64
+ type: integer
+ required:
+ - healthyThreshold
+ - interval
+ - target
+ - timeout
+ - unhealthyThreshold
+ type: object
+ listeners:
+ description: ClassicELBListeners is an array of classic elb
+ listeners associated with the load balancer. There must
+ be at least one.
+ items:
+ description: ClassicELBListener defines an AWS classic load
+ balancer listener.
+ properties:
+ instancePort:
+ format: int64
+ type: integer
+ instanceProtocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ required:
+ - instancePort
+ - instanceProtocol
+ - port
+ - protocol
+ type: object
+ type: array
+ loadBalancerType:
+ description: LoadBalancerType sets the type for a load balancer.
+ The default type is classic.
+ enum:
+ - classic
+ - elb
+ - alb
+ - nlb
+ type: string
+ name:
+ description: The name of the load balancer. It must be unique
+ within the set of load balancers defined in the region.
+ It also serves as identifier.
+ type: string
+ scheme:
+ description: Scheme is the load balancer scheme, either internet-facing
+ or private.
+ type: string
+ securityGroupIds:
+ description: SecurityGroupIDs is an array of security groups
+ assigned to the load balancer.
+ items:
+ type: string
+ type: array
+ subnetIds:
+ description: SubnetIDs is an array of subnets in the VPC attached
+ to the load balancer.
+ items:
+ type: string
+ type: array
+ tags:
+ additionalProperties:
+ type: string
+ description: Tags is a map of tags associated with the load
+ balancer.
+ type: object
+ type: object
securityGroups:
additionalProperties:
description: SecurityGroup defines an AWS security group.
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml
index b30f43b245..b8ff27e9a7 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclusters.yaml
@@ -1527,6 +1527,187 @@ spec:
required:
- name
type: object
+ secondaryControlPlaneLoadBalancer:
+ description: "SecondaryControlPlaneLoadBalancer is an additional load
+ balancer that can be used for the control plane. \n An example use
+ case is to have a separate internal load balancer for internal traffic,
+ and a separate external load balancer for external traffic."
+ properties:
+ additionalListeners:
+ description: AdditionalListeners sets the additional listeners
+ for the control plane load balancer. This is only applicable
+ to Network Load Balancer (NLB) types for the time being.
+ items:
+ description: AdditionalListenerSpec defines the desired state
+ of an additional listener on an AWS load balancer.
+ properties:
+ port:
+ description: Port sets the port for the additional listener.
+ format: int64
+ maximum: 65535
+ minimum: 1
+ type: integer
+ protocol:
+ default: TCP
+ description: Protocol sets the protocol for the additional
+ listener. Currently only TCP is supported.
+ enum:
+ - TCP
+ type: string
+ required:
+ - port
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - port
+ x-kubernetes-list-type: map
+ additionalSecurityGroups:
+ description: AdditionalSecurityGroups sets the security groups
+ used by the load balancer. Expected to be security group IDs
+ This is optional - if not provided new security groups will
+ be created for the load balancer
+ items:
+ type: string
+ type: array
+ crossZoneLoadBalancing:
+ description: "CrossZoneLoadBalancing enables the classic ELB cross
+ availability zone balancing. \n With cross-zone load balancing,
+ each load balancer node for your Classic Load Balancer distributes
+ requests evenly across the registered instances in all enabled
+ Availability Zones. If cross-zone load balancing is disabled,
+ each load balancer node distributes requests evenly across the
+ registered instances in its Availability Zone only. \n Defaults
+ to false."
+ type: boolean
+ disableHostsRewrite:
+ description: DisableHostsRewrite disabled the hair pinning issue
+ solution that adds the NLB's address as 127.0.0.1 to the hosts
+ file of each instance. This is by default, false.
+ type: boolean
+ healthCheckProtocol:
+ description: HealthCheckProtocol sets the protocol type for ELB
+ health check target default value is ELBProtocolSSL
+ enum:
+ - TCP
+ - SSL
+ - HTTP
+ - HTTPS
+ - TLS
+ - UDP
+ type: string
+ ingressRules:
+ description: IngressRules sets the ingress rules for the control
+ plane load balancer.
+ items:
+ description: IngressRule defines an AWS ingress rule for security
+ groups.
+ properties:
+ cidrBlocks:
+ description: List of CIDR blocks to allow access from. Cannot
+ be specified with SourceSecurityGroupID.
+ items:
+ type: string
+ type: array
+ description:
+ description: Description provides extended information about
+ the ingress rule.
+ type: string
+ fromPort:
+ description: FromPort is the start of port range.
+ format: int64
+ type: integer
+ ipv6CidrBlocks:
+ description: List of IPv6 CIDR blocks to allow access from.
+ Cannot be specified with SourceSecurityGroupID.
+ items:
+ type: string
+ type: array
+ protocol:
+ description: Protocol is the protocol for the ingress rule.
+ Accepted values are "-1" (all), "4" (IP in IP),"tcp",
+ "udp", "icmp", and "58" (ICMPv6), "50" (ESP).
+ enum:
+ - "-1"
+ - "4"
+ - tcp
+ - udp
+ - icmp
+ - "58"
+ - "50"
+ type: string
+ sourceSecurityGroupIds:
+ description: The security group id to allow access from.
+ Cannot be specified with CidrBlocks.
+ items:
+ type: string
+ type: array
+ sourceSecurityGroupRoles:
+ description: The security group role to allow access from.
+ Cannot be specified with CidrBlocks. The field will be
+ combined with source security group IDs if specified.
+ items:
+ description: SecurityGroupRole defines the unique role
+ of a security group.
+ enum:
+ - bastion
+ - node
+ - controlplane
+ - apiserver-lb
+ - lb
+ - node-eks-additional
+ type: string
+ type: array
+ toPort:
+ description: ToPort is the end of port range.
+ format: int64
+ type: integer
+ required:
+ - description
+ - fromPort
+ - protocol
+ - toPort
+ type: object
+ type: array
+ loadBalancerType:
+ default: classic
+ description: LoadBalancerType sets the type for a load balancer.
+ The default type is classic.
+ enum:
+ - classic
+ - elb
+ - alb
+ - nlb
+ type: string
+ name:
+ description: Name sets the name of the classic ELB load balancer.
+ As per AWS, the name must be unique within your set of load
+ balancers for the region, must have a maximum of 32 characters,
+ must contain only alphanumeric characters or hyphens, and cannot
+ begin or end with a hyphen. Once set, the value cannot be changed.
+ maxLength: 32
+ pattern: ^[A-Za-z0-9]([A-Za-z0-9]{0,31}|[-A-Za-z0-9]{0,30}[A-Za-z0-9])$
+ type: string
+ preserveClientIP:
+ description: PreserveClientIP lets the user control if preservation
+ of client ips must be retained or not. If this is enabled 6443
+ will be opened to 0.0.0.0/0.
+ type: boolean
+ scheme:
+ default: internet-facing
+ description: Scheme sets the scheme of the load balancer (defaults
+ to internet-facing)
+ enum:
+ - internet-facing
+ - internal
+ type: string
+ subnets:
+ description: Subnets sets the subnets that should be applied to
+ the control plane load balancer (defaults to discovered subnets
+ for managed VPCs or an empty set for unmanaged VPCs)
+ items:
+ type: string
+ type: array
+ type: object
sshKeyName:
description: SSHKeyName is the name of the ssh key to attach to the
bastion host. Valid values are empty string (do not use SSH keys),
@@ -2063,6 +2244,215 @@ spec:
items:
type: string
type: array
+ secondaryAPIServerELB:
+ description: SecondaryAPIServerELB is the secondary Kubernetes
+ api server load balancer.
+ properties:
+ arn:
+ description: ARN of the load balancer. Unlike the ClassicLB,
+ ARN is used mostly to define and get it.
+ type: string
+ attributes:
+ description: ClassicElbAttributes defines extra attributes
+ associated with the load balancer.
+ properties:
+ crossZoneLoadBalancing:
+ description: CrossZoneLoadBalancing enables the classic
+ load balancer load balancing.
+ type: boolean
+ idleTimeout:
+ description: IdleTimeout is time that the connection is
+ allowed to be idle (no data has been sent over the connection)
+ before it is closed by the load balancer.
+ format: int64
+ type: integer
+ type: object
+ availabilityZones:
+ description: AvailabilityZones is an array of availability
+ zones in the VPC attached to the load balancer.
+ items:
+ type: string
+ type: array
+ dnsName:
+ description: DNSName is the dns name of the load balancer.
+ type: string
+ elbAttributes:
+ additionalProperties:
+ type: string
+ description: ELBAttributes defines extra attributes associated
+ with v2 load balancers.
+ type: object
+ elbListeners:
+ description: ELBListeners is an array of listeners associated
+ with the load balancer. There must be at least one.
+ items:
+ description: Listener defines an AWS network load balancer
+ listener.
+ properties:
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ targetGroup:
+ description: TargetGroupSpec specifies target group
+ settings for a given listener. This is created first,
+ and the ARN is then passed to the listener.
+ properties:
+ name:
+ description: Name of the TargetGroup. Must be unique
+ over the same group of listeners.
+ type: string
+ port:
+ description: Port is the exposed port
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ enum:
+ - tcp
+ - tls
+ - udp
+ - TCP
+ - TLS
+ - UDP
+ type: string
+ targetGroupHealthCheck:
+ description: HealthCheck is the elb health check
+ associated with the load balancer.
+ properties:
+ intervalSeconds:
+ format: int64
+ type: integer
+ path:
+ type: string
+ port:
+ type: string
+ protocol:
+ type: string
+ thresholdCount:
+ format: int64
+ type: integer
+ timeoutSeconds:
+ format: int64
+ type: integer
+ type: object
+ vpcId:
+ type: string
+ required:
+ - name
+ - port
+ - protocol
+ - vpcId
+ type: object
+ required:
+ - port
+ - protocol
+ - targetGroup
+ type: object
+ type: array
+ healthChecks:
+ description: HealthCheck is the classic elb health check associated
+ with the load balancer.
+ properties:
+ healthyThreshold:
+ format: int64
+ type: integer
+ interval:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ target:
+ type: string
+ timeout:
+ description: A Duration represents the elapsed time between
+ two instants as an int64 nanosecond count. The representation
+ limits the largest representable duration to approximately
+ 290 years.
+ format: int64
+ type: integer
+ unhealthyThreshold:
+ format: int64
+ type: integer
+ required:
+ - healthyThreshold
+ - interval
+ - target
+ - timeout
+ - unhealthyThreshold
+ type: object
+ listeners:
+ description: ClassicELBListeners is an array of classic elb
+ listeners associated with the load balancer. There must
+ be at least one.
+ items:
+ description: ClassicELBListener defines an AWS classic load
+ balancer listener.
+ properties:
+ instancePort:
+ format: int64
+ type: integer
+ instanceProtocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ port:
+ format: int64
+ type: integer
+ protocol:
+ description: ELBProtocol defines listener protocols
+ for a load balancer.
+ type: string
+ required:
+ - instancePort
+ - instanceProtocol
+ - port
+ - protocol
+ type: object
+ type: array
+ loadBalancerType:
+ description: LoadBalancerType sets the type for a load balancer.
+ The default type is classic.
+ enum:
+ - classic
+ - elb
+ - alb
+ - nlb
+ type: string
+ name:
+ description: The name of the load balancer. It must be unique
+ within the set of load balancers defined in the region.
+ It also serves as identifier.
+ type: string
+ scheme:
+ description: Scheme is the load balancer scheme, either internet-facing
+ or private.
+ type: string
+ securityGroupIds:
+ description: SecurityGroupIDs is an array of security groups
+ assigned to the load balancer.
+ items:
+ type: string
+ type: array
+ subnetIds:
+ description: SubnetIDs is an array of subnets in the VPC attached
+ to the load balancer.
+ items:
+ type: string
+ type: array
+ tags:
+ additionalProperties:
+ type: string
+ description: Tags is a map of tags associated with the load
+ balancer.
+ type: object
+ type: object
securityGroups:
additionalProperties:
description: SecurityGroup defines an AWS security group.
diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml
index a8dbe5cbb1..0da685658a 100644
--- a/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml
+++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_awsclustertemplates.yaml
@@ -1148,6 +1148,195 @@ spec:
required:
- name
type: object
+ secondaryControlPlaneLoadBalancer:
+ description: "SecondaryControlPlaneLoadBalancer is an additional
+ load balancer that can be used for the control plane. \n
+ An example use case is to have a separate internal load
+ balancer for internal traffic, and a separate external load
+ balancer for external traffic."
+ properties:
+ additionalListeners:
+ description: AdditionalListeners sets the additional listeners
+ for the control plane load balancer. This is only applicable
+ to Network Load Balancer (NLB) types for the time being.
+ items:
+ description: AdditionalListenerSpec defines the desired
+ state of an additional listener on an AWS load balancer.
+ properties:
+ port:
+ description: Port sets the port for the additional
+ listener.
+ format: int64
+ maximum: 65535
+ minimum: 1
+ type: integer
+ protocol:
+ default: TCP
+ description: Protocol sets the protocol for the
+ additional listener. Currently only TCP is supported.
+ enum:
+ - TCP
+ type: string
+ required:
+ - port
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - port
+ x-kubernetes-list-type: map
+ additionalSecurityGroups:
+ description: AdditionalSecurityGroups sets the security
+ groups used by the load balancer. Expected to be security
+ group IDs This is optional - if not provided new security
+ groups will be created for the load balancer
+ items:
+ type: string
+ type: array
+ crossZoneLoadBalancing:
+ description: "CrossZoneLoadBalancing enables the classic
+ ELB cross availability zone balancing. \n With cross-zone
+ load balancing, each load balancer node for your Classic
+ Load Balancer distributes requests evenly across the
+ registered instances in all enabled Availability Zones.
+ If cross-zone load balancing is disabled, each load
+ balancer node distributes requests evenly across the
+ registered instances in its Availability Zone only.
+ \n Defaults to false."
+ type: boolean
+ disableHostsRewrite:
+ description: DisableHostsRewrite disabled the hair pinning
+ issue solution that adds the NLB's address as 127.0.0.1
+ to the hosts file of each instance. This is by default,
+ false.
+ type: boolean
+ healthCheckProtocol:
+ description: HealthCheckProtocol sets the protocol type
+ for ELB health check target default value is ELBProtocolSSL
+ enum:
+ - TCP
+ - SSL
+ - HTTP
+ - HTTPS
+ - TLS
+ - UDP
+ type: string
+ ingressRules:
+ description: IngressRules sets the ingress rules for the
+ control plane load balancer.
+ items:
+ description: IngressRule defines an AWS ingress rule
+ for security groups.
+ properties:
+ cidrBlocks:
+ description: List of CIDR blocks to allow access
+ from. Cannot be specified with SourceSecurityGroupID.
+ items:
+ type: string
+ type: array
+ description:
+ description: Description provides extended information
+ about the ingress rule.
+ type: string
+ fromPort:
+ description: FromPort is the start of port range.
+ format: int64
+ type: integer
+ ipv6CidrBlocks:
+ description: List of IPv6 CIDR blocks to allow access
+ from. Cannot be specified with SourceSecurityGroupID.
+ items:
+ type: string
+ type: array
+ protocol:
+ description: Protocol is the protocol for the ingress
+ rule. Accepted values are "-1" (all), "4" (IP
+ in IP),"tcp", "udp", "icmp", and "58" (ICMPv6),
+ "50" (ESP).
+ enum:
+ - "-1"
+ - "4"
+ - tcp
+ - udp
+ - icmp
+ - "58"
+ - "50"
+ type: string
+ sourceSecurityGroupIds:
+ description: The security group id to allow access
+ from. Cannot be specified with CidrBlocks.
+ items:
+ type: string
+ type: array
+ sourceSecurityGroupRoles:
+ description: The security group role to allow access
+ from. Cannot be specified with CidrBlocks. The
+ field will be combined with source security group
+ IDs if specified.
+ items:
+ description: SecurityGroupRole defines the unique
+ role of a security group.
+ enum:
+ - bastion
+ - node
+ - controlplane
+ - apiserver-lb
+ - lb
+ - node-eks-additional
+ type: string
+ type: array
+ toPort:
+ description: ToPort is the end of port range.
+ format: int64
+ type: integer
+ required:
+ - description
+ - fromPort
+ - protocol
+ - toPort
+ type: object
+ type: array
+ loadBalancerType:
+ default: classic
+ description: LoadBalancerType sets the type for a load
+ balancer. The default type is classic.
+ enum:
+ - classic
+ - elb
+ - alb
+ - nlb
+ type: string
+ name:
+ description: Name sets the name of the classic ELB load
+ balancer. As per AWS, the name must be unique within
+ your set of load balancers for the region, must have
+ a maximum of 32 characters, must contain only alphanumeric
+ characters or hyphens, and cannot begin or end with
+ a hyphen. Once set, the value cannot be changed.
+ maxLength: 32
+ pattern: ^[A-Za-z0-9]([A-Za-z0-9]{0,31}|[-A-Za-z0-9]{0,30}[A-Za-z0-9])$
+ type: string
+ preserveClientIP:
+ description: PreserveClientIP lets the user control if
+ preservation of client ips must be retained or not.
+ If this is enabled 6443 will be opened to 0.0.0.0/0.
+ type: boolean
+ scheme:
+ default: internet-facing
+ description: Scheme sets the scheme of the load balancer
+ (defaults to internet-facing)
+ enum:
+ - internet-facing
+ - internal
+ type: string
+ subnets:
+ description: Subnets sets the subnets that should be applied
+ to the control plane load balancer (defaults to discovered
+ subnets for managed VPCs or an empty set for unmanaged
+ VPCs)
+ items:
+ type: string
+ type: array
+ type: object
sshKeyName:
description: SSHKeyName is the name of the ssh key to attach
to the bastion host. Valid values are empty string (do not
diff --git a/controllers/awsmachine_controller.go b/controllers/awsmachine_controller.go
index 20d3832c0d..32a0863cdb 100644
--- a/controllers/awsmachine_controller.go
+++ b/controllers/awsmachine_controller.go
@@ -32,6 +32,7 @@ import (
"github.com/pkg/errors"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
+ kerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
"k8s.io/utils/ptr"
@@ -331,7 +332,8 @@ func (r *AWSMachineReconciler) reconcileDelete(machineScope *scope.MachineScope,
if err := r.reconcileLBAttachment(machineScope, elbScope, instance); err != nil {
// We are tolerating AccessDenied error, so this won't block for users with older version of IAM;
// all the other errors are blocking.
- if !elb.IsAccessDenied(err) && !elb.IsNotFound(err) {
+ // Because we are reconciling all load balancers, attempt to treat the error as a list of errors.
+ if err = kerrors.FilterOut(err, elb.IsAccessDenied, elb.IsNotFound); err != nil {
conditions.MarkFalse(machineScope.AWSMachine, infrav1.ELBAttachedCondition, "DeletingFailed", clusterv1.ConditionSeverityWarning, err.Error())
return ctrl.Result{}, errors.Errorf("failed to reconcile LB attachment: %+v", err)
}
@@ -853,6 +855,8 @@ func (r *AWSMachineReconciler) deleteIgnitionBootstrapDataFromS3(machineScope *s
return nil
}
+// reconcileLBAttachment reconciles attachment to _all_ defined load balancers.
+// Callers are expected to filter out known-good errors out of the aggregate error list.
func (r *AWSMachineReconciler) reconcileLBAttachment(machineScope *scope.MachineScope, elbScope scope.ELBScope, i *infrav1.Instance) error {
if !machineScope.IsControlPlane() {
return nil
@@ -860,18 +864,33 @@ func (r *AWSMachineReconciler) reconcileLBAttachment(machineScope *scope.Machine
elbsvc := r.getELBService(elbScope)
- // In order to prevent sending request to a "not-ready" control plane machines, it is required to remove the machine
- // from the ELB as soon as the machine or infra machine gets deleted or when the machine is in a not running state.
- if machineScope.AWSMachineIsDeleted() || machineScope.MachineIsDeleted() || !machineScope.InstanceIsRunning() {
- if elbScope.ControlPlaneLoadBalancer().LoadBalancerType == infrav1.LoadBalancerTypeClassic {
- machineScope.Debug("deregistering from classic load balancer")
- return r.deregisterInstanceFromClassicLB(machineScope, elbsvc, i)
+ errs := []error{}
+ for _, lbSpec := range elbScope.ControlPlaneLoadBalancers() {
+ if lbSpec == nil {
+ continue
+ }
+ // In order to prevent sending request to a "not-ready" control plane machines, it is required to remove the machine
+ // from the ELB as soon as the machine or infra machine gets deleted or when the machine is in a not running state.
+ if machineScope.AWSMachineIsDeleted() || machineScope.MachineIsDeleted() || !machineScope.InstanceIsRunning() {
+ if lbSpec.LoadBalancerType == infrav1.LoadBalancerTypeClassic {
+ machineScope.Debug("deregistering from classic load balancer")
+ return r.deregisterInstanceFromClassicLB(machineScope, elbsvc, i)
+ }
+ machineScope.Debug("deregistering from v2 load balancer")
+ errs = append(errs, r.deregisterInstanceFromV2LB(machineScope, elbsvc, i, lbSpec))
+ continue
+ }
+
+ if err := r.registerInstanceToLBs(machineScope, elbsvc, i, lbSpec); err != nil {
+ errs = append(errs, errors.Wrapf(err, "could not register machine to load balancer"))
}
- machineScope.Debug("deregistering from v2 load balancer")
- return r.deregisterInstanceFromV2LB(machineScope, elbsvc, i)
}
- switch elbScope.ControlPlaneLoadBalancer().LoadBalancerType {
+ return kerrors.NewAggregate(errs)
+}
+
+func (r *AWSMachineReconciler) registerInstanceToLBs(machineScope *scope.MachineScope, elbsvc services.ELBInterface, i *infrav1.Instance, lb *infrav1.AWSLoadBalancerSpec) error {
+ switch lb.LoadBalancerType {
case infrav1.LoadBalancerTypeClassic:
fallthrough
case "":
@@ -884,10 +903,10 @@ func (r *AWSMachineReconciler) reconcileLBAttachment(machineScope *scope.Machine
fallthrough
case infrav1.LoadBalancerTypeNLB:
machineScope.Debug("registering to v2 load balancer")
- return r.registerInstanceToV2LB(machineScope, elbsvc, i)
+ return r.registerInstanceToV2LB(machineScope, elbsvc, i, lb)
}
- return errors.Errorf("unknown load balancer type %q", elbScope.ControlPlaneLoadBalancer().LoadBalancerType)
+ return errors.Errorf("unknown load balancer type %q", lb.LoadBalancerType)
}
func (r *AWSMachineReconciler) registerInstanceToClassicLB(machineScope *scope.MachineScope, elbsvc services.ELBInterface, i *infrav1.Instance) error {
@@ -914,8 +933,8 @@ func (r *AWSMachineReconciler) registerInstanceToClassicLB(machineScope *scope.M
return nil
}
-func (r *AWSMachineReconciler) registerInstanceToV2LB(machineScope *scope.MachineScope, elbsvc services.ELBInterface, instance *infrav1.Instance) error {
- _, registered, err := elbsvc.IsInstanceRegisteredWithAPIServerLB(instance)
+func (r *AWSMachineReconciler) registerInstanceToV2LB(machineScope *scope.MachineScope, elbsvc services.ELBInterface, instance *infrav1.Instance, lb *infrav1.AWSLoadBalancerSpec) error {
+ _, registered, err := elbsvc.IsInstanceRegisteredWithAPIServerLB(instance, lb)
if err != nil {
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeWarning, "FailedAttachControlPlaneELB",
"Failed to register control plane instance %q with load balancer: failed to determine registration status: %v", instance.ID, err)
@@ -926,7 +945,7 @@ func (r *AWSMachineReconciler) registerInstanceToV2LB(machineScope *scope.Machin
return nil
}
- if err := elbsvc.RegisterInstanceWithAPIServerLB(instance); err != nil {
+ if err := elbsvc.RegisterInstanceWithAPIServerLB(instance, lb); err != nil {
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeWarning, "FailedAttachControlPlaneELB",
"Failed to register control plane instance %q with load balancer: %v", instance.ID, err)
conditions.MarkFalse(machineScope.AWSMachine, infrav1.ELBAttachedCondition, infrav1.ELBAttachFailedReason, clusterv1.ConditionSeverityError, err.Error())
@@ -962,8 +981,8 @@ func (r *AWSMachineReconciler) deregisterInstanceFromClassicLB(machineScope *sco
return nil
}
-func (r *AWSMachineReconciler) deregisterInstanceFromV2LB(machineScope *scope.MachineScope, elbsvc services.ELBInterface, i *infrav1.Instance) error {
- targetGroupARNs, registered, err := elbsvc.IsInstanceRegisteredWithAPIServerLB(i)
+func (r *AWSMachineReconciler) deregisterInstanceFromV2LB(machineScope *scope.MachineScope, elbsvc services.ELBInterface, i *infrav1.Instance, lb *infrav1.AWSLoadBalancerSpec) error {
+ targetGroupARNs, registered, err := elbsvc.IsInstanceRegisteredWithAPIServerLB(i, lb)
if err != nil {
r.Recorder.Eventf(machineScope.AWSMachine, corev1.EventTypeWarning, "FailedDetachControlPlaneELB",
"Failed to deregister control plane instance %q from load balancer: failed to determine registration status: %v", i.ID, err)
diff --git a/controllers/helpers_test.go b/controllers/helpers_test.go
index e998ff06e5..f4511e9508 100644
--- a/controllers/helpers_test.go
+++ b/controllers/helpers_test.go
@@ -285,6 +285,10 @@ func mockedCreateLBV2Calls(t *testing.T, m *mocks.MockELBV2APIMockRecorder) {
ResourceArns: []*string{lbArn},
TagKeys: []*string{aws.String("sigs.k8s.io/cluster-api-provider-aws/cluster/test-cluster-apiserver")},
})).MaxTimes(1)
+ m.SetSecurityGroups(gomock.Eq(&elbv2.SetSecurityGroupsInput{
+ LoadBalancerArn: lbArn,
+ SecurityGroups: aws.StringSlice([]string{"sg-apiserver-lb"}),
+ })).MaxTimes(1)
}
func mockedDeleteLBCalls(expectV2Call bool, mv2 *mocks.MockELBV2APIMockRecorder, m *mocks.MockELBAPIMockRecorder) {
diff --git a/docs/book/src/SUMMARY_PREFIX.md b/docs/book/src/SUMMARY_PREFIX.md
index 765c63312b..55a3083769 100644
--- a/docs/book/src/SUMMARY_PREFIX.md
+++ b/docs/book/src/SUMMARY_PREFIX.md
@@ -38,3 +38,5 @@
- [Ignition support](./topics/ignition-support.md)
- [External Resource Garbage Collection](./topics/external-resource-gc.md)
- [Instance Metadata](./topics/instance-metadata.md)
+ - [Network Load Balancers](./topics/network-load-balancer-with-awscluster.md)
+ - [Secondary Control Plane Load Balancer](./topics/secondary-load-balancer.md)
diff --git a/docs/book/src/crd/index.md b/docs/book/src/crd/index.md
index 71dccd1323..9ee3ff5135 100644
--- a/docs/book/src/crd/index.md
+++ b/docs/book/src/crd/index.md
@@ -15653,6 +15653,22 @@ AWSLoadBalancerSpec
SecondaryAPIServerELB is the secondary Kubernetes api server load balancer.
+
+
+
+
natGatewaysIPs
[]string
@@ -21101,6 +21162,23 @@ Random - selects AZs randomly in a region
Defaults to Ordered
+
+
+emptyRoutesDefaultVPCSecurityGroup
+
+bool
+
+
+
+(Optional)
+
EmptyRoutesDefaultVPCSecurityGroup specifies whether the default VPC security group ingress
+and egress rules should be removed.
+
By default, when creating a VPC, AWS creates a security group called default with ingress and egress
+rules that allow traffic from anywhere. The group could be used as a potential surface attack and
+it’s generally suggested that the group rules are removed or modified appropriately.
+
NOTE: This only applies when the VPC is managed by the Cluster API AWS controller.
+
+
Volume
@@ -23982,6 +24060,162 @@ Cluster API api/v1beta1.FailureDomains
+
ROSAMachinePool
+
+
+
ROSAMachinePool is the Schema for the rosamachinepools API.
NodePoolName specifies the name of the nodepool in Rosa
+must be a valid DNS-1035 label, so it must consist of lower case alphanumeric and have a max length of 15 characters.
+
+
+
+
+availabilityZone
+
+string
+
+
+
+(Optional)
+
AvailabilityZone is an optinal field specifying the availability zone where instances of this machine pool should run
+For Multi-AZ clusters, you can create a machine pool in a Single-AZ of your choice.
+
+
+
+
+subnet
+
+string
+
+
+
+(Optional)
+
+
+
+
+labels
+
+map[string]string
+
+
+
+(Optional)
+
Labels specifies labels for the Kubernetes node objects
+
+
+
+
+autoRepair
+
+bool
+
+
+
+(Optional)
+
AutoRepair specifies whether health checks should be enabled for machines
+in the NodePool. The default is false.
RosaMachinePoolSpec defines the desired state of RosaMachinePool.
+
+
+
+
+
Field
+
Description
+
+
+
+
+
+nodePoolName
+
+string
+
+
+
+
NodePoolName specifies the name of the nodepool in Rosa
+must be a valid DNS-1035 label, so it must consist of lower case alphanumeric and have a max length of 15 characters.
+
+
+
+
+availabilityZone
+
+string
+
+
+
+(Optional)
+
AvailabilityZone is an optinal field specifying the availability zone where instances of this machine pool should run
+For Multi-AZ clusters, you can create a machine pool in a Single-AZ of your choice.
+
+
+
+
+subnet
+
+string
+
+
+
+(Optional)
+
+
+
+
+labels
+
+map[string]string
+
+
+
+(Optional)
+
Labels specifies labels for the Kubernetes node objects
+
+
+
+
+autoRepair
+
+bool
+
+
+
+(Optional)
+
AutoRepair specifies whether health checks should be enabled for machines
+in the NodePool. The default is false.