k8s_cluster_api/v1beta1/infrastructure/aws/
network.rs

1use super::*;
2
3mod impls;
4
5/// NetworkSpec encapsulates all things related to AWS network.
6#[skip_serializing_none]
7#[derive(Clone, Debug, Default, Serialize, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct NetworkSpec {
10    /// VPC configuration.
11    // +optional
12    pub vpc: Option<VPCSpec>, // `json:"vpc,omitempty"`
13
14    /// Subnets configuration.
15    // +optional
16    pub subnets: Option<Subnets>, // `json:"subnets,omitempty"`
17
18    /// CNI configuration
19    // +optional
20    pub cni: Option<CNISpec>, // `json:"cni,omitempty"`
21
22    /// SecurityGroupOverrides is an optional set of security groups to use for cluster instances
23    /// This is optional - if not provided new security groups will be created for the cluster
24    // +optional
25    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
26    pub security_group_overrides: BTreeMap<SecurityGroupRole, String>, // `json:"securityGroupOverrides,omitempty"`
27}
28
29/// VPCSpec configures an AWS VPC.
30#[skip_serializing_none]
31#[derive(Clone, Debug, Default, Serialize, Deserialize)]
32#[serde(rename_all = "camelCase")]
33pub struct VPCSpec {
34    /// ID is the vpc-id of the VPC this provider should use to create resources.
35    pub id: Option<String>, // `json:"id,omitempty"`
36
37    /// CidrBlock is the CIDR block to be used when the provider creates a managed VPC.
38    /// Defaults to 10.0.0.0/16.
39    pub cidr_block: Option<String>, // `json:"cidrBlock,omitempty"`
40
41    /// InternetGatewayID is the id of the internet gateway associated with the VPC.
42    // +optional
43    pub internet_gateway_id: Option<String>, // `json:"internetGatewayId,omitempty"`
44
45    /// Tags is a collection of tags describing the resource.
46    #[serde(default, skip_serializing_if = "Tags::is_empty")]
47    pub tags: Tags, // `json:"tags,omitempty"`
48
49    // AvailabilityZoneUsageLimit specifies the maximum number of availability zones (AZ) that
50    // should be used in a region when automatically creating subnets. If a region has more
51    // than this number of AZs then this number of AZs will be picked randomly when creating
52    // default subnets. Defaults to 3
53    // +kubebuilder:default=3
54    // +kubebuilder:validation:Minimum=1
55    pub availability_zone_usage_limit: Option<i64>, // `json:"availabilityZoneUsageLimit,omitempty"`
56
57    // AvailabilityZoneSelection specifies how AZs should be selected if there are more AZs
58    // in a region than specified by AvailabilityZoneUsageLimit. There are 2 selection schemes:
59    // Ordered - selects based on alphabetical order
60    // Random - selects AZs randomly in a region
61    // Defaults to Ordered
62    // +kubebuilder:default=Ordered
63    // +kubebuilder:validation:Enum=Ordered;Random
64    pub availability_zone_selection: Option<AZSelectionScheme>, // `json:"availabilityZoneSelection,omitempty"`
65}
66
67/// NetworkStatus encapsulates AWS networking resources.
68#[skip_serializing_none]
69#[derive(Clone, Debug, Serialize, Deserialize)]
70#[serde(rename_all = "camelCase")]
71pub struct NetworkStatus {
72    /// SecurityGroups is a map from the role/kind of the security group to its unique name, if any.
73    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
74    pub security_groups: BTreeMap<SecurityGroupRole, SecurityGroup>, // `json:"securityGroups,omitempty"`
75
76    /// APIServerELB is the Kubernetes api server classic load balancer.
77    pub api_server_elb: Option<ClassicELB>, // `json:"apiServerElb,omitempty"`
78}
79
80/// ClassicELBScheme defines the scheme of a classic load balancer.
81#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
82pub enum ClassicELBScheme {
83    /// ClassicELBSchemeInternetFacing defines an internet-facing, publicly
84    /// accessible AWS Classic ELB scheme.
85    #[serde(rename = "internet-facing")]
86    InternetFacing,
87
88    /// ClassicELBSchemeInternal defines an internal-only facing
89    /// load balancer internal to an ELB.
90    #[serde(rename = "internal")]
91    Internal,
92
93    /// ClassicELBSchemeIncorrectInternetFacing was inaccurately used to define an internet-facing LB in v0.6 releases > v0.6.6 and v0.7.0 release.
94    #[serde(rename = "Internet-facing")]
95    IncorrectInternetFacing,
96}
97
98/// Subnets is a slice of Subnet.
99#[derive(Clone, Debug, Default, Serialize, Deserialize)]
100pub struct Subnets(pub Vec<SubnetSpec>);
101
102/// SubnetSpec configures an AWS Subnet.
103#[skip_serializing_none]
104#[derive(Clone, Debug, Default, Serialize, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct SubnetSpec {
107    /// ID defines a unique identifier to reference this resource.
108    pub id: Option<String>, // `json:"id,omitempty"`
109
110    /// CidrBlock is the CIDR block to be used when the provider creates a managed VPC.
111    pub cidr_block: Option<String>, // `json:"cidrBlock,omitempty"`
112
113    /// AvailabilityZone defines the availability zone to use for this subnet in the cluster's region.
114    pub availability_zone: Option<String>, // `json:"availabilityZone,omitempty"`
115
116    /// IsPublic defines the subnet as a public subnet. A subnet is public when it is associated with a route table that has a route to an internet gateway.
117    // +optional
118    pub is_public: Option<bool>, // `json:"isPublic"`
119
120    /// RouteTableID is the routing table id associated with the subnet.
121    // +optional
122    pub route_table_id: Option<String>, // `json:"routeTableId,omitempty"`
123
124    /// NatGatewayID is the NAT gateway id associated with the subnet.
125    /// Ignored unless the subnet is managed by the provider, in which case this is set on the public subnet where the NAT gateway resides. It is then used to determine routes for private subnets in the same AZ as the public subnet.
126    // +optional
127    pub nat_gateway_id: Option<String>, // `json:"natGatewayId,omitempty"`
128
129    /// Tags is a collection of tags describing the resource.
130    #[serde(default, skip_serializing_if = "Tags::is_empty")]
131    pub tags: Tags, // `json:"tags,omitempty"`
132}
133
134/// CNISpec defines configuration for CNI.
135#[skip_serializing_none]
136#[derive(Clone, Debug, Default, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct CNISpec {
139    /// CNIIngressRules specify rules to apply to control plane and worker node security groups.
140    /// The source for the rule will be set to control plane and worker security group IDs.
141    #[serde(default, skip_serializing_if = "Vec::is_empty")]
142    pub cni_ingress_rules: Vec<CNIIngressRule>, // `json:"cniIngressRules,omitempty"`
143}
144
145/// CNIIngressRule defines an AWS ingress rule for CNI requirements.
146#[skip_serializing_none]
147#[derive(Clone, Debug, Serialize, Deserialize)]
148#[serde(rename_all = "camelCase")]
149pub struct CNIIngressRule {
150    pub description: String,             //                `json:"description"`
151    pub protocol: SecurityGroupProtocol, // `json:"protocol"`
152    pub from_port: i64,                  //                 `json:"fromPort"`
153    pub to_port: i64,                    //                 `json:"toPort"`
154}
155
156// SecurityGroupProtocol defines the protocol type for a security group rule.
157#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
158pub enum SecurityGroupProtocol {
159    /// SecurityGroupProtocolAll is a wildcard for all IP protocols.
160    #[serde(rename = "-1")]
161    All,
162
163    /// SecurityGroupProtocolIPinIP represents the IP in IP protocol in ingress rules.
164    #[serde(rename = "4")]
165    IPinIP,
166
167    /// SecurityGroupProtocolTCP represents the TCP protocol in ingress rules.
168    #[serde(rename = "tcp")]
169    Tcp,
170
171    /// SecurityGroupProtocolUDP represents the UDP protocol in ingress rules.
172    #[serde(rename = "udp")]
173    Udp,
174
175    /// SecurityGroupProtocolICMP represents the ICMP protocol in ingress rules.
176    #[serde(rename = "icmp")]
177    Icmp,
178
179    /// SecurityGroupProtocolICMPv6 represents the ICMPv6 protocol in ingress rules.
180    #[serde(rename = "58")]
181    Icmpv6,
182}
183
184/// SecurityGroupRole defines the unique role of a security group.
185#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
186pub enum SecurityGroupRole {
187    /// SecurityGroupBastion defines an SSH bastion role.
188    #[serde(rename = "bastion")]
189    Bastion,
190    /// SecurityGroupNode defines a Kubernetes workload node role.
191    #[serde(rename = "node")]
192    Node,
193    /// SecurityGroupEKSNodeAdditional defines an extra node group from eks nodes.
194    #[serde(rename = "node-eks-additional")]
195    EKSNodeAdditional,
196    /// SecurityGroupControlPlane defines a Kubernetes control plane node role.
197    #[serde(rename = "controlplane")]
198    ControlPlane,
199    /// SecurityGroupAPIServerLB defines a Kubernetes API Server Load Balancer role.
200    #[serde(rename = "apiserver-lb")]
201    APIServerLB,
202    /// SecurityGroupLB defines a container for the cloud provider to inject its load balancer ingress rules.
203    #[serde(rename = "lb")]
204    LB,
205}
206
207/// SecurityGroup defines an AWS security group.
208#[skip_serializing_none]
209#[derive(Clone, Debug, Serialize, Deserialize)]
210#[serde(rename_all = "camelCase")]
211pub struct SecurityGroup {
212    /// ID is a unique identifier.
213    pub id: String, // `json:"id"`
214
215    /// Name is the security group name.
216    pub name: String, // `json:"name"`
217
218    /// IngressRules is the inbound rules associated with the security group.
219    // +optional
220    pub ingress_rule: Option<Vec<IngressRule>>, // `json:"ingressRule,omitempty"`
221
222    /// Tags is a map of tags associated with the security group.
223    #[serde(default, skip_serializing_if = "Tags::is_empty")]
224    pub tags: Tags, // `json:"tags,omitempty"`
225}
226
227/// IngressRule defines an AWS ingress rule for security groups.
228#[skip_serializing_none]
229#[derive(Clone, Debug, Serialize, Deserialize)]
230#[serde(rename_all = "camelCase")]
231pub struct IngressRule {
232    pub description: String,             //                `json:"description"`
233    pub protocol: SecurityGroupProtocol, // `json:"protocol"`
234    pub from_port: i64,                  //                 `json:"fromPort"`
235    pub to_port: i64,                    //                 `json:"toPort"`
236
237    /// List of CIDR blocks to allow access from. Cannot be specified with SourceSecurityGroupID.
238    // +optional
239    pub cidr_blocks: Option<Vec<String>>, // `json:"cidrBlocks,omitempty"`
240
241    /// The security group id to allow access from. Cannot be specified with CidrBlocks.
242    // +optional
243    pub source_security_group_ids: Option<Vec<String>>, // `json:"sourceSecurityGroupIds,omitempty"`
244}
245
246// ClassicELB defines an AWS classic load balancer.
247#[skip_serializing_none]
248#[derive(Clone, Debug, Serialize, Deserialize)]
249#[serde(rename_all = "camelCase")]
250pub struct ClassicELB {
251    /// The name of the load balancer. It must be unique within the set of load balancers
252    /// defined in the region. It also serves as identifier.
253    pub name: Option<String>, // `json:"name,omitempty"`
254
255    /// DNSName is the dns name of the load balancer.
256    pub dns_name: Option<String>, // `json:"dnsName,omitempty"`
257
258    /// Scheme is the load balancer scheme, either internet-facing or private.
259    pub scheme: Option<ClassicELBScheme>, // `json:"scheme,omitempty"`
260
261    /// AvailabilityZones is an array of availability zones in the VPC attached to the load balancer.
262    #[serde(default, skip_serializing_if = "Vec::is_empty")]
263    pub availability_zones: Vec<String>, // `json:"availabilityZones,omitempty"`
264
265    /// SubnetIDs is an array of subnets in the VPC attached to the load balancer.
266    #[serde(default, skip_serializing_if = "Vec::is_empty")]
267    pub subnet_ids: Vec<String>, // `json:"subnetIds,omitempty"`
268
269    /// SecurityGroupIDs is an array of security groups assigned to the load balancer.
270    #[serde(default, skip_serializing_if = "Vec::is_empty")]
271    pub security_group_ids: Vec<String>, // `json:"securityGroupIds,omitempty"`
272
273    /// Listeners is an array of classic elb listeners associated with the load balancer. There must be at least one.
274    #[serde(default, skip_serializing_if = "Vec::is_empty")]
275    pub listeners: Vec<ClassicELBListener>, // `json:"listeners,omitempty"`
276
277    /// HealthCheck is the classic elb health check associated with the load balancer.
278    pub health_check: Option<ClassicELBHealthCheck>, // `json:"healthChecks,omitempty"`
279
280    /// Attributes defines extra attributes associated with the load balancer.
281    pub attributes: Option<ClassicELBAttributes>, // `json:"attributes,omitempty"`
282
283    /// Tags is a map of tags associated with the load balancer.
284    #[serde(default, skip_serializing_if = "Tags::is_empty")]
285    pub tags: Tags, // `json:"tags,omitempty"`
286}
287
288/// ClassicELBListener defines an AWS classic load balancer listener.
289#[skip_serializing_none]
290#[derive(Clone, Debug, Serialize, Deserialize)]
291#[serde(rename_all = "camelCase")]
292pub struct ClassicELBListener {
293    pub protocol: ClassicELBProtocol,          // `json:"protocol"`
294    pub port: i64,                             //              `json:"port"`
295    pub instance_protocol: ClassicELBProtocol, // `json:"instanceProtocol"`
296    pub instance_port: i64,                    //             `json:"instancePort"`
297}
298
299/// ClassicELBProtocol defines listener protocols for a classic load balancer.
300#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd, Eq, Ord, Serialize, Deserialize)]
301pub enum ClassicELBProtocol {
302    /// ClassicELBProtocolTCP defines the ELB API string representing the TCP protocol.
303    #[serde(rename = "TCP")]
304    Tcp,
305    /// ClassicELBProtocolSSL defines the ELB API string representing the TLS protocol.
306    #[serde(rename = "SSL")]
307    Ssl,
308    /// ClassicELBProtocolHTTP defines the ELB API string representing the HTTP protocol at L7.
309    #[serde(rename = "HTTP")]
310    Http,
311    /// ClassicELBProtocolHTTPS defines the ELB API string representing the HTTPS protocol at L7.
312    #[serde(rename = "HTTPS")]
313    Https,
314}
315
316/// ClassicELBHealthCheck defines an AWS classic load balancer health check.
317#[serde_as]
318#[skip_serializing_none]
319#[derive(Clone, Debug, Serialize, Deserialize)]
320#[serde(rename_all = "camelCase")]
321pub struct ClassicELBHealthCheck {
322    pub target: String, //       `json:"target"`
323    #[serde_as(as = "serde_with::DurationSeconds<i64>")]
324    pub interval: chrono::Duration, // `json:"interval"`
325    #[serde_as(as = "serde_with::DurationSeconds<i64>")]
326    pub timeout: chrono::Duration, // `json:"timeout"`
327    pub healthy_threshold: i64, //         `json:"healthyThreshold"`
328    pub unhealthy_threshold: i64, //         `json:"unhealthyThreshold"`
329}
330
331/// ClassicELBAttributes defines extra attributes associated with a classic load balancer.
332// #[serde_as]
333#[skip_serializing_none]
334#[derive(Clone, Debug, Serialize, Deserialize)]
335#[serde(rename_all = "camelCase")]
336pub struct ClassicELBAttributes {
337    /// IdleTimeout is time that the connection is allowed to be idle (no data
338    /// has been sent over the connection) before it is closed by the load balancer.
339    // #[serde_as(as = "serde_with::DurationSeconds<i64>")]
340    pub idle_timeout: Option<i64>, // `json:"idleTimeout,omitempty"`
341
342    /// CrossZoneLoadBalancing enables the classic load balancer load balancing.
343    // +optional
344    pub cross_zone_load_balancing: Option<bool>, // `json:"crossZoneLoadBalancing,omitempty"`
345}
346
347/*  ============================================================================
348package v1beta1
349
350import (
351    "fmt"
352    "sort"
353    "time"
354)
355
356
357func (e ClassicELBScheme) String() string {
358    return string(e)
359}
360
361// IsUnmanaged returns true if the Classic ELB is unmanaged.
362func (b *ClassicELB) IsUnmanaged(clusterName string) bool {
363    return b.Name != "" && !Tags(b.Tags).HasOwned(clusterName)
364}
365
366// IsManaged returns true if Classic ELB is managed.
367func (b *ClassicELB) IsManaged(clusterName string) bool {
368    return !b.IsUnmanaged(clusterName)
369}
370
371
372
373// String returns a string representation of the VPC.
374func (v *VPCSpec) String() string {
375    return fmt.Sprintf("id=%s", v.ID)
376}
377
378// IsUnmanaged returns true if the VPC is unmanaged.
379func (v *VPCSpec) IsUnmanaged(clusterName string) bool {
380    return v.ID != "" && !v.Tags.HasOwned(clusterName)
381}
382
383// IsManaged returns true if VPC is managed.
384func (v *VPCSpec) IsManaged(clusterName string) bool {
385    return !v.IsUnmanaged(clusterName)
386}
387
388
389// String returns a string representation of the subnet.
390func (s *SubnetSpec) String() string {
391    return fmt.Sprintf("id=%s/az=%s/public=%v", s.ID, s.AvailabilityZone, s.IsPublic)
392}
393
394// ToMap returns a map from id to subnet.
395func (s Subnets) ToMap() map[string]*SubnetSpec {
396    res := make(map[string]*SubnetSpec)
397    for i := range s {
398        x := s[i]
399        res[x.ID] = &x
400    }
401    return res
402}
403
404// IDs returns a slice of the subnet ids.
405func (s Subnets) IDs() []string {
406    res := []string{}
407    for _, subnet := range s {
408        res = append(res, subnet.ID)
409    }
410    return res
411}
412
413// FindByID returns a single subnet matching the given id or nil.
414func (s Subnets) FindByID(id string) *SubnetSpec {
415    for _, x := range s {
416        if x.ID == id {
417            return &x
418        }
419    }
420
421    return nil
422}
423
424// FindEqual returns a subnet spec that is equal to the one passed in.
425// Two subnets are defined equal to each other if their id is equal
426// or if they are in the same vpc and the cidr block is the same.
427func (s Subnets) FindEqual(spec *SubnetSpec) *SubnetSpec {
428    for _, x := range s {
429        if (spec.ID != "" && x.ID == spec.ID) || (spec.CidrBlock == x.CidrBlock) {
430            return &x
431        }
432    }
433    return nil
434}
435
436// FilterPrivate returns a slice containing all subnets marked as private.
437func (s Subnets) FilterPrivate() (res Subnets) {
438    for _, x := range s {
439        if !x.IsPublic {
440            res = append(res, x)
441        }
442    }
443    return
444}
445
446// FilterPublic returns a slice containing all subnets marked as public.
447func (s Subnets) FilterPublic() (res Subnets) {
448    for _, x := range s {
449        if x.IsPublic {
450            res = append(res, x)
451        }
452    }
453    return
454}
455
456// FilterByZone returns a slice containing all subnets that live in the availability zone specified.
457func (s Subnets) FilterByZone(zone string) (res Subnets) {
458    for _, x := range s {
459        if x.AvailabilityZone == zone {
460            res = append(res, x)
461        }
462    }
463    return
464}
465
466// GetUniqueZones returns a slice containing the unique zones of the subnets.
467func (s Subnets) GetUniqueZones() []string {
468    keys := make(map[string]bool)
469    zones := []string{}
470    for _, x := range s {
471        if _, value := keys[x.AvailabilityZone]; !value {
472            keys[x.AvailabilityZone] = true
473            zones = append(zones, x.AvailabilityZone)
474        }
475    }
476    return zones
477}
478
479// RouteTable defines an AWS routing table.
480type RouteTable struct {
481    ID string `json:"id"`
482}
483
484
485// String returns a string representation of the security group.
486func (s *SecurityGroup) String() string {
487    return fmt.Sprintf("id=%s/name=%s", s.ID, s.Name)
488}
489
490
491
492// String returns a string representation of the ingress rule.
493func (i *IngressRule) String() string {
494    return fmt.Sprintf("protocol=%s/range=[%d-%d]/description=%s", i.Protocol, i.FromPort, i.ToPort, i.Description)
495}
496
497// IngressRules is a slice of AWS ingress rules for security groups.
498type IngressRules []IngressRule
499
500// Difference returns the difference between this slice and the other slice.
501func (i IngressRules) Difference(o IngressRules) (out IngressRules) {
502    for index := range i {
503        x := i[index]
504        found := false
505        for oIndex := range o {
506            y := o[oIndex]
507            if x.Equals(&y) {
508                found = true
509                break
510            }
511        }
512
513        if !found {
514            out = append(out, x)
515        }
516    }
517
518    return
519}
520
521// Equals returns true if two IngressRule are equal.
522func (i *IngressRule) Equals(o *IngressRule) bool {
523    if len(i.CidrBlocks) != len(o.CidrBlocks) {
524        return false
525    }
526
527    sort.Strings(i.CidrBlocks)
528    sort.Strings(o.CidrBlocks)
529
530    for i, v := range i.CidrBlocks {
531        if v != o.CidrBlocks[i] {
532            return false
533        }
534    }
535
536    if len(i.SourceSecurityGroupIDs) != len(o.SourceSecurityGroupIDs) {
537        return false
538    }
539
540    sort.Strings(i.SourceSecurityGroupIDs)
541    sort.Strings(o.SourceSecurityGroupIDs)
542
543    for i, v := range i.SourceSecurityGroupIDs {
544        if v != o.SourceSecurityGroupIDs[i] {
545            return false
546        }
547    }
548
549    if i.Description != o.Description || i.Protocol != o.Protocol {
550        return false
551    }
552
553    // AWS seems to ignore the From/To port when set on protocols where it doesn't apply, but
554    // we avoid serializing it out for clarity's sake.
555    // See: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_IpPermission.html
556    switch i.Protocol {
557    case SecurityGroupProtocolTCP,
558        SecurityGroupProtocolUDP,
559        SecurityGroupProtocolICMP,
560        SecurityGroupProtocolICMPv6:
561        return i.FromPort == o.FromPort && i.ToPort == o.ToPort
562    case SecurityGroupProtocolAll, SecurityGroupProtocolIPinIP:
563        // FromPort / ToPort are not applicable
564    }
565
566    return true
567}
568 ============================================================================ */