sigs.k8s.io/cluster-api-provider-aws@v1.5.5/pkg/cloud/services/securitygroup/securitygroups.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package securitygroup
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  
    23  	"github.com/aws/aws-sdk-go/aws"
    24  	"github.com/aws/aws-sdk-go/service/ec2"
    25  	"github.com/pkg/errors"
    26  	kerrors "k8s.io/apimachinery/pkg/util/errors"
    27  
    28  	infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1beta1"
    29  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/awserrors"
    30  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/converters"
    31  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/filter"
    32  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services"
    33  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait"
    34  	"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/tags"
    35  	"sigs.k8s.io/cluster-api-provider-aws/pkg/record"
    36  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    37  	"sigs.k8s.io/cluster-api/util/conditions"
    38  )
    39  
    40  const (
    41  	// IPProtocolTCP is how EC2 represents the TCP protocol in ingress rules.
    42  	IPProtocolTCP = "tcp"
    43  
    44  	// IPProtocolUDP is how EC2 represents the UDP protocol in ingress rules.
    45  	IPProtocolUDP = "udp"
    46  
    47  	// IPProtocolICMP is how EC2 represents the ICMP protocol in ingress rules.
    48  	IPProtocolICMP = "icmp"
    49  
    50  	// IPProtocolICMPv6 is how EC2 represents the ICMPv6 protocol in ingress rules.
    51  	IPProtocolICMPv6 = "58"
    52  )
    53  
    54  // ReconcileSecurityGroups will reconcile security groups against the Service object.
    55  func (s *Service) ReconcileSecurityGroups() error {
    56  	s.scope.V(2).Info("Reconciling security groups")
    57  
    58  	if s.scope.Network().SecurityGroups == nil {
    59  		s.scope.Network().SecurityGroups = make(map[infrav1.SecurityGroupRole]infrav1.SecurityGroup)
    60  	}
    61  
    62  	var err error
    63  
    64  	// Security group overrides are mapped by Role rather than their security group name
    65  	// They are copied into the main 'sgs' list by their group name later
    66  	var securityGroupOverrides map[infrav1.SecurityGroupRole]*ec2.SecurityGroup
    67  	securityGroupOverrides, err = s.describeSecurityGroupOverridesByID()
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	// Security group overrides should not be specified for a managed VPC
    73  	// because VPC id should be provided during security group creation
    74  	if securityGroupOverrides != nil && s.scope.VPC().IsManaged(s.scope.Name()) {
    75  		return errors.Errorf("security group overrides provided for managed vpc %q", s.scope.Name())
    76  	}
    77  	sgs, err := s.describeSecurityGroupsByName()
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	// Add security group overrides to known security group map
    83  	for _, securityGroupOverride := range securityGroupOverrides {
    84  		sg := s.ec2SecurityGroupToSecurityGroup(securityGroupOverride)
    85  		sgs[sg.Name] = sg
    86  	}
    87  
    88  	// First iteration makes sure that the security group are valid and fully created.
    89  	for i := range s.roles {
    90  		role := s.roles[i]
    91  		sg := s.getDefaultSecurityGroup(role)
    92  
    93  		// if an override exists for this role use it
    94  		sgOverride, ok := securityGroupOverrides[role]
    95  		if ok {
    96  			s.scope.V(2).Info("Using security group override", "role", role, "security group", sgOverride.GroupName)
    97  			sg = sgOverride
    98  		}
    99  
   100  		existing, ok := sgs[*sg.GroupName]
   101  
   102  		if !ok {
   103  			if err := s.createSecurityGroup(role, sg); err != nil {
   104  				return err
   105  			}
   106  
   107  			s.scope.SecurityGroups()[role] = infrav1.SecurityGroup{
   108  				ID:   *sg.GroupId,
   109  				Name: *sg.GroupName,
   110  			}
   111  			continue
   112  		}
   113  
   114  		// TODO(vincepri): validate / update security group if necessary.
   115  		s.scope.SecurityGroups()[role] = existing
   116  
   117  		if s.isEKSOwned(existing) {
   118  			s.scope.V(2).Info("Security group is EKS owned", "role", role, "security-group", s.scope.SecurityGroups()[role])
   119  			continue
   120  		}
   121  
   122  		if !s.securityGroupIsOverridden(existing.ID) {
   123  			// Make sure tags are up to date.
   124  			if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
   125  				buildParams := s.getSecurityGroupTagParams(existing.Name, existing.ID, role)
   126  				tagsBuilder := tags.New(&buildParams, tags.WithEC2(s.EC2Client))
   127  				if err := tagsBuilder.Ensure(existing.Tags); err != nil {
   128  					return false, err
   129  				}
   130  				return true, nil
   131  			}, awserrors.GroupNotFound); err != nil {
   132  				return errors.Wrapf(err, "failed to ensure tags on security group %q", existing.ID)
   133  			}
   134  		}
   135  	}
   136  
   137  	// Second iteration creates or updates all permissions on the security group to match
   138  	// the specified ingress rules.
   139  	for i := range s.scope.SecurityGroups() {
   140  		sg := s.scope.SecurityGroups()[i]
   141  		s.scope.V(2).Info("second pass security group reconciliation", "group-id", sg.ID, "name", sg.Name, "role", i)
   142  
   143  		if s.securityGroupIsOverridden(sg.ID) {
   144  			// skip rule/tag reconciliation on security groups that are overridden, assuming they're managed by another process
   145  			continue
   146  		}
   147  
   148  		if sg.Tags.HasAWSCloudProviderOwned(s.scope.Name()) || s.isEKSOwned(sg) {
   149  			// skip rule reconciliation, as we expect the in-cluster cloud integration to manage them
   150  			continue
   151  		}
   152  		current := sg.IngressRules
   153  
   154  		want, err := s.getSecurityGroupIngressRules(i)
   155  		if err != nil {
   156  			return err
   157  		}
   158  
   159  		toRevoke := current.Difference(want)
   160  		if len(toRevoke) > 0 {
   161  			if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
   162  				if err := s.revokeSecurityGroupIngressRules(sg.ID, toRevoke); err != nil {
   163  					return false, err
   164  				}
   165  				return true, nil
   166  			}, awserrors.GroupNotFound); err != nil {
   167  				return errors.Wrapf(err, "failed to revoke security group ingress rules for %q", sg.ID)
   168  			}
   169  
   170  			s.scope.V(2).Info("Revoked ingress rules from security group", "revoked-ingress-rules", toRevoke, "security-group-id", sg.ID)
   171  		}
   172  
   173  		toAuthorize := want.Difference(current)
   174  		if len(toAuthorize) > 0 {
   175  			if err := wait.WaitForWithRetryable(wait.NewBackoff(), func() (bool, error) {
   176  				if err := s.authorizeSecurityGroupIngressRules(sg.ID, toAuthorize); err != nil {
   177  					return false, err
   178  				}
   179  				return true, nil
   180  			}, awserrors.GroupNotFound); err != nil {
   181  				return err
   182  			}
   183  
   184  			s.scope.V(2).Info("Authorized ingress rules in security group", "authorized-ingress-rules", toAuthorize, "security-group-id", sg.ID)
   185  		}
   186  	}
   187  	conditions.MarkTrue(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition)
   188  	return nil
   189  }
   190  
   191  func (s *Service) securityGroupIsOverridden(securityGroupID string) bool {
   192  	for _, overrideID := range s.scope.SecurityGroupOverrides() {
   193  		if overrideID == securityGroupID {
   194  			return true
   195  		}
   196  	}
   197  	return false
   198  }
   199  
   200  func (s *Service) describeSecurityGroupOverridesByID() (map[infrav1.SecurityGroupRole]*ec2.SecurityGroup, error) {
   201  	securityGroupIds := map[infrav1.SecurityGroupRole]*string{}
   202  	input := &ec2.DescribeSecurityGroupsInput{}
   203  
   204  	overrides := s.scope.SecurityGroupOverrides()
   205  
   206  	// return if no security group overrides have been provided
   207  	if len(overrides) == 0 {
   208  		return nil, nil
   209  	}
   210  
   211  	if len(overrides) > 0 {
   212  		for _, role := range s.roles {
   213  			securityGroupID, ok := s.scope.SecurityGroupOverrides()[role]
   214  			if ok {
   215  				securityGroupIds[role] = aws.String(securityGroupID)
   216  				input.GroupIds = append(input.GroupIds, aws.String(securityGroupID))
   217  			}
   218  		}
   219  	}
   220  
   221  	out, err := s.EC2Client.DescribeSecurityGroups(input)
   222  	if err != nil {
   223  		return nil, errors.Wrapf(err, "failed to describe security groups in vpc %q", s.scope.VPC().ID)
   224  	}
   225  
   226  	res := make(map[infrav1.SecurityGroupRole]*ec2.SecurityGroup, len(out.SecurityGroups))
   227  	for _, role := range s.roles {
   228  		for _, ec2sg := range out.SecurityGroups {
   229  			if securityGroupIds[role] == nil {
   230  				continue
   231  			}
   232  			if *ec2sg.GroupId == *securityGroupIds[role] {
   233  				s.scope.V(2).Info("found security group override", "role", role, "security group", *ec2sg.GroupName)
   234  
   235  				res[role] = ec2sg
   236  				break
   237  			}
   238  		}
   239  	}
   240  
   241  	return res, nil
   242  }
   243  
   244  func (s *Service) ec2SecurityGroupToSecurityGroup(ec2SecurityGroup *ec2.SecurityGroup) infrav1.SecurityGroup {
   245  	sg := makeInfraSecurityGroup(ec2SecurityGroup)
   246  
   247  	for _, ec2rule := range ec2SecurityGroup.IpPermissions {
   248  		sg.IngressRules = append(sg.IngressRules, ingressRulesFromSDKType(ec2rule)...)
   249  	}
   250  	return sg
   251  }
   252  
   253  // DeleteSecurityGroups will delete a service's security groups.
   254  func (s *Service) DeleteSecurityGroups() error {
   255  	if s.scope.VPC().ID == "" {
   256  		s.scope.V(2).Info("Skipping security group deletion, vpc-id is nil", "vpc-id", s.scope.VPC().ID)
   257  		conditions.MarkFalse(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition, clusterv1.DeletedReason, clusterv1.ConditionSeverityInfo, "")
   258  		return nil
   259  	}
   260  
   261  	clusterGroups, err := s.describeClusterOwnedSecurityGroups()
   262  	if err != nil {
   263  		return err
   264  	}
   265  
   266  	// Security groups already deleted, exit early
   267  	if len(clusterGroups) == 0 {
   268  		return nil
   269  	}
   270  
   271  	conditions.MarkFalse(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition, clusterv1.DeletingReason, clusterv1.ConditionSeverityInfo, "")
   272  	if err := s.scope.PatchObject(); err != nil {
   273  		return err
   274  	}
   275  
   276  	for i := range clusterGroups {
   277  		sg := clusterGroups[i]
   278  		current := sg.IngressRules
   279  		if err := s.revokeAllSecurityGroupIngressRules(sg.ID); awserrors.IsIgnorableSecurityGroupError(err) != nil {
   280  			conditions.MarkFalse(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition, "DeletingFailed", clusterv1.ConditionSeverityWarning, err.Error())
   281  			return err
   282  		}
   283  
   284  		s.scope.V(2).Info("Revoked ingress rules from security group", "revoked-ingress-rules", current, "security-group-id", sg.ID)
   285  
   286  		if deleteErr := s.deleteSecurityGroup(&sg, "cluster managed"); deleteErr != nil {
   287  			err = kerrors.NewAggregate([]error{err, deleteErr})
   288  		}
   289  	}
   290  
   291  	if err != nil {
   292  		conditions.MarkFalse(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition, "DeletingFailed", clusterv1.ConditionSeverityWarning, err.Error())
   293  		return err
   294  	}
   295  	conditions.MarkFalse(s.scope.InfraCluster(), infrav1.ClusterSecurityGroupsReadyCondition, clusterv1.DeletedReason, clusterv1.ConditionSeverityInfo, "")
   296  
   297  	return nil
   298  }
   299  
   300  func (s *Service) deleteSecurityGroup(sg *infrav1.SecurityGroup, typ string) error {
   301  	input := &ec2.DeleteSecurityGroupInput{
   302  		GroupId: aws.String(sg.ID),
   303  	}
   304  
   305  	if _, err := s.EC2Client.DeleteSecurityGroup(input); awserrors.IsIgnorableSecurityGroupError(err) != nil {
   306  		record.Warnf(s.scope.InfraCluster(), "FailedDeleteSecurityGroup", "Failed to delete %s SecurityGroup %q: %v", typ, sg.ID, err)
   307  		return errors.Wrapf(err, "failed to delete security group %q", sg.ID)
   308  	}
   309  
   310  	record.Eventf(s.scope.InfraCluster(), "SuccessfulDeleteSecurityGroup", "Deleted %s SecurityGroup %q", typ, sg.ID)
   311  	s.scope.Info("Deleted security group", "security-group-id", sg.ID, "kind", typ)
   312  
   313  	return nil
   314  }
   315  
   316  func (s *Service) describeClusterOwnedSecurityGroups() ([]infrav1.SecurityGroup, error) {
   317  	input := &ec2.DescribeSecurityGroupsInput{
   318  		Filters: []*ec2.Filter{
   319  			filter.EC2.VPC(s.scope.VPC().ID),
   320  			filter.EC2.ClusterOwned(s.scope.Name()),
   321  		},
   322  	}
   323  
   324  	groups := []infrav1.SecurityGroup{}
   325  
   326  	err := s.EC2Client.DescribeSecurityGroupsPages(input, func(out *ec2.DescribeSecurityGroupsOutput, last bool) bool {
   327  		for _, group := range out.SecurityGroups {
   328  			if group != nil {
   329  				groups = append(groups, makeInfraSecurityGroup(group))
   330  			}
   331  		}
   332  		return true
   333  	})
   334  	if err != nil {
   335  		return nil, errors.Wrapf(err, "failed to describe cluster-owned security groups in vpc %q", s.scope.VPC().ID)
   336  	}
   337  	return groups, nil
   338  }
   339  
   340  func (s *Service) describeSecurityGroupsByName() (map[string]infrav1.SecurityGroup, error) {
   341  	input := &ec2.DescribeSecurityGroupsInput{
   342  		Filters: []*ec2.Filter{
   343  			filter.EC2.VPC(s.scope.VPC().ID),
   344  			filter.EC2.Cluster(s.scope.Name()),
   345  		},
   346  	}
   347  
   348  	out, err := s.EC2Client.DescribeSecurityGroups(input)
   349  	if err != nil {
   350  		return nil, errors.Wrapf(err, "failed to describe security groups in vpc %q", s.scope.VPC().ID)
   351  	}
   352  
   353  	res := make(map[string]infrav1.SecurityGroup, len(out.SecurityGroups))
   354  	for _, ec2sg := range out.SecurityGroups {
   355  		sg := s.ec2SecurityGroupToSecurityGroup(ec2sg)
   356  		res[sg.Name] = sg
   357  	}
   358  
   359  	return res, nil
   360  }
   361  
   362  func makeInfraSecurityGroup(ec2sg *ec2.SecurityGroup) infrav1.SecurityGroup {
   363  	return infrav1.SecurityGroup{
   364  		ID:   *ec2sg.GroupId,
   365  		Name: *ec2sg.GroupName,
   366  		Tags: converters.TagsToMap(ec2sg.Tags),
   367  	}
   368  }
   369  
   370  func (s *Service) createSecurityGroup(role infrav1.SecurityGroupRole, input *ec2.SecurityGroup) error {
   371  	sgTags := s.getSecurityGroupTagParams(aws.StringValue(input.GroupName), services.TemporaryResourceID, role)
   372  	out, err := s.EC2Client.CreateSecurityGroup(&ec2.CreateSecurityGroupInput{
   373  		VpcId:       input.VpcId,
   374  		GroupName:   input.GroupName,
   375  		Description: aws.String(fmt.Sprintf("Kubernetes cluster %s: %s", s.scope.Name(), role)),
   376  		TagSpecifications: []*ec2.TagSpecification{
   377  			tags.BuildParamsToTagSpecification(ec2.ResourceTypeSecurityGroup, sgTags),
   378  		},
   379  	})
   380  	if err != nil {
   381  		record.Warnf(s.scope.InfraCluster(), "FailedCreateSecurityGroup", "Failed to create managed SecurityGroup for Role %q: %v", role, err)
   382  		return errors.Wrapf(err, "failed to create security group %q in vpc %q", role, aws.StringValue(input.VpcId))
   383  	}
   384  
   385  	record.Eventf(s.scope.InfraCluster(), "SuccessfulCreateSecurityGroup", "Created managed SecurityGroup %q for Role %q", aws.StringValue(out.GroupId), role)
   386  	s.scope.Info("Created security group for role", "security-group", aws.StringValue(out.GroupId), "role", role)
   387  
   388  	// Set the group id.
   389  	input.GroupId = out.GroupId
   390  
   391  	return nil
   392  }
   393  
   394  func (s *Service) authorizeSecurityGroupIngressRules(id string, rules infrav1.IngressRules) error {
   395  	input := &ec2.AuthorizeSecurityGroupIngressInput{GroupId: aws.String(id)}
   396  	for i := range rules {
   397  		rule := rules[i]
   398  		input.IpPermissions = append(input.IpPermissions, ingressRuleToSDKType(&rule))
   399  	}
   400  
   401  	if _, err := s.EC2Client.AuthorizeSecurityGroupIngress(input); err != nil {
   402  		record.Warnf(s.scope.InfraCluster(), "FailedAuthorizeSecurityGroupIngressRules", "Failed to authorize security group ingress rules %v for SecurityGroup %q: %v", rules, id, err)
   403  		return errors.Wrapf(err, "failed to authorize security group %q ingress rules: %v", id, rules)
   404  	}
   405  
   406  	record.Eventf(s.scope.InfraCluster(), "SuccessfulAuthorizeSecurityGroupIngressRules", "Authorized security group ingress rules %v for SecurityGroup %q", rules, id)
   407  	return nil
   408  }
   409  
   410  func (s *Service) revokeSecurityGroupIngressRules(id string, rules infrav1.IngressRules) error {
   411  	input := &ec2.RevokeSecurityGroupIngressInput{GroupId: aws.String(id)}
   412  	for i := range rules {
   413  		rule := rules[i]
   414  		input.IpPermissions = append(input.IpPermissions, ingressRuleToSDKType(&rule))
   415  	}
   416  
   417  	if _, err := s.EC2Client.RevokeSecurityGroupIngress(input); err != nil {
   418  		record.Warnf(s.scope.InfraCluster(), "FailedRevokeSecurityGroupIngressRules", "Failed to revoke security group ingress rules %v for SecurityGroup %q: %v", rules, id, err)
   419  		return errors.Wrapf(err, "failed to revoke security group %q ingress rules: %v", id, rules)
   420  	}
   421  
   422  	record.Eventf(s.scope.InfraCluster(), "SuccessfulRevokeSecurityGroupIngressRules", "Revoked security group ingress rules %v for SecurityGroup %q", rules, id)
   423  	return nil
   424  }
   425  
   426  func (s *Service) revokeAllSecurityGroupIngressRules(id string) error {
   427  	describeInput := &ec2.DescribeSecurityGroupsInput{GroupIds: []*string{aws.String(id)}}
   428  
   429  	securityGroups, err := s.EC2Client.DescribeSecurityGroups(describeInput)
   430  	if err != nil {
   431  		return err
   432  	}
   433  
   434  	for _, sg := range securityGroups.SecurityGroups {
   435  		if len(sg.IpPermissions) > 0 {
   436  			revokeInput := &ec2.RevokeSecurityGroupIngressInput{
   437  				GroupId:       aws.String(id),
   438  				IpPermissions: sg.IpPermissions,
   439  			}
   440  			if _, err := s.EC2Client.RevokeSecurityGroupIngress(revokeInput); err != nil {
   441  				record.Warnf(s.scope.InfraCluster(), "FailedRevokeSecurityGroupIngressRules", "Failed to revoke all security group ingress rules for SecurityGroup %q: %v", *sg.GroupId, err)
   442  				return err
   443  			}
   444  			record.Eventf(s.scope.InfraCluster(), "SuccessfulRevokeSecurityGroupIngressRules", "Revoked all security group ingress rules for SecurityGroup %q", *sg.GroupId)
   445  		}
   446  	}
   447  
   448  	return nil
   449  }
   450  
   451  func (s *Service) defaultSSHIngressRule(sourceSecurityGroupID string) infrav1.IngressRule {
   452  	return infrav1.IngressRule{
   453  		Description:            "SSH",
   454  		Protocol:               infrav1.SecurityGroupProtocolTCP,
   455  		FromPort:               22,
   456  		ToPort:                 22,
   457  		SourceSecurityGroupIDs: []string{sourceSecurityGroupID},
   458  	}
   459  }
   460  
   461  func (s *Service) getSecurityGroupIngressRules(role infrav1.SecurityGroupRole) (infrav1.IngressRules, error) {
   462  	// Set source of CNI ingress rules to be control plane and node security groups
   463  	s.scope.V(2).Info("getting security group ingress rules", "role", role)
   464  
   465  	cniRules := make(infrav1.IngressRules, len(s.scope.CNIIngressRules()))
   466  	for i, r := range s.scope.CNIIngressRules() {
   467  		cniRules[i] = infrav1.IngressRule{
   468  			Description: r.Description,
   469  			Protocol:    r.Protocol,
   470  			FromPort:    r.FromPort,
   471  			ToPort:      r.ToPort,
   472  			SourceSecurityGroupIDs: []string{
   473  				s.scope.SecurityGroups()[infrav1.SecurityGroupControlPlane].ID,
   474  				s.scope.SecurityGroups()[infrav1.SecurityGroupNode].ID,
   475  			},
   476  		}
   477  	}
   478  
   479  	switch role {
   480  	case infrav1.SecurityGroupBastion:
   481  		return infrav1.IngressRules{
   482  			{
   483  				Description: "SSH",
   484  				Protocol:    infrav1.SecurityGroupProtocolTCP,
   485  				FromPort:    22,
   486  				ToPort:      22,
   487  				CidrBlocks:  s.scope.Bastion().AllowedCIDRBlocks,
   488  			},
   489  		}, nil
   490  	case infrav1.SecurityGroupControlPlane:
   491  		rules := infrav1.IngressRules{
   492  			{
   493  				Description: "Kubernetes API",
   494  				Protocol:    infrav1.SecurityGroupProtocolTCP,
   495  				FromPort:    6443,
   496  				ToPort:      6443,
   497  				SourceSecurityGroupIDs: []string{
   498  					s.scope.SecurityGroups()[infrav1.SecurityGroupAPIServerLB].ID,
   499  					s.scope.SecurityGroups()[infrav1.SecurityGroupControlPlane].ID,
   500  					s.scope.SecurityGroups()[infrav1.SecurityGroupNode].ID,
   501  				},
   502  			},
   503  			{
   504  				Description:            "etcd",
   505  				Protocol:               infrav1.SecurityGroupProtocolTCP,
   506  				FromPort:               2379,
   507  				ToPort:                 2379,
   508  				SourceSecurityGroupIDs: []string{s.scope.SecurityGroups()[infrav1.SecurityGroupControlPlane].ID},
   509  			},
   510  			{
   511  				Description:            "etcd peer",
   512  				Protocol:               infrav1.SecurityGroupProtocolTCP,
   513  				FromPort:               2380,
   514  				ToPort:                 2380,
   515  				SourceSecurityGroupIDs: []string{s.scope.SecurityGroups()[infrav1.SecurityGroupControlPlane].ID},
   516  			},
   517  		}
   518  		if s.scope.Bastion().Enabled {
   519  			rules = append(rules, s.defaultSSHIngressRule(s.scope.SecurityGroups()[infrav1.SecurityGroupBastion].ID))
   520  		}
   521  		return append(cniRules, rules...), nil
   522  
   523  	case infrav1.SecurityGroupNode:
   524  		rules := infrav1.IngressRules{
   525  			{
   526  				Description: "Node Port Services",
   527  				Protocol:    infrav1.SecurityGroupProtocolTCP,
   528  				FromPort:    30000,
   529  				ToPort:      32767,
   530  				CidrBlocks:  []string{services.AnyIPv4CidrBlock},
   531  			},
   532  			{
   533  				Description: "Kubelet API",
   534  				Protocol:    infrav1.SecurityGroupProtocolTCP,
   535  				FromPort:    10250,
   536  				ToPort:      10250,
   537  				SourceSecurityGroupIDs: []string{
   538  					s.scope.SecurityGroups()[infrav1.SecurityGroupControlPlane].ID,
   539  					// This is needed to support metrics-server deployments
   540  					s.scope.SecurityGroups()[infrav1.SecurityGroupNode].ID,
   541  				},
   542  			},
   543  		}
   544  		if s.scope.Bastion().Enabled {
   545  			rules = append(rules, s.defaultSSHIngressRule(s.scope.SecurityGroups()[infrav1.SecurityGroupBastion].ID))
   546  		}
   547  		return append(cniRules, rules...), nil
   548  	case infrav1.SecurityGroupEKSNodeAdditional:
   549  		if s.scope.Bastion().Enabled {
   550  			return infrav1.IngressRules{
   551  				s.defaultSSHIngressRule(s.scope.SecurityGroups()[infrav1.SecurityGroupBastion].ID),
   552  			}, nil
   553  		}
   554  		return infrav1.IngressRules{}, nil
   555  	case infrav1.SecurityGroupAPIServerLB:
   556  		return infrav1.IngressRules{
   557  			{
   558  				Description: "Kubernetes API",
   559  				Protocol:    infrav1.SecurityGroupProtocolTCP,
   560  				FromPort:    int64(s.scope.APIServerPort()),
   561  				ToPort:      int64(s.scope.APIServerPort()),
   562  				CidrBlocks:  []string{services.AnyIPv4CidrBlock},
   563  			},
   564  		}, nil
   565  	case infrav1.SecurityGroupLB:
   566  		// We hand this group off to the in-cluster cloud provider, so these rules aren't used
   567  		return infrav1.IngressRules{}, nil
   568  	}
   569  
   570  	return nil, errors.Errorf("Cannot determine ingress rules for unknown security group role %q", role)
   571  }
   572  
   573  func (s *Service) getSecurityGroupName(clusterName string, role infrav1.SecurityGroupRole) string {
   574  	groupPrefix := clusterName
   575  	if strings.HasPrefix(clusterName, "sg-") {
   576  		groupPrefix = "@" + clusterName
   577  	}
   578  	return fmt.Sprintf("%s-%v", groupPrefix, role)
   579  }
   580  
   581  func (s *Service) getDefaultSecurityGroup(role infrav1.SecurityGroupRole) *ec2.SecurityGroup {
   582  	name := s.getSecurityGroupName(s.scope.Name(), role)
   583  
   584  	return &ec2.SecurityGroup{
   585  		GroupName: aws.String(name),
   586  		VpcId:     aws.String(s.scope.VPC().ID),
   587  		Tags:      converters.MapToTags(infrav1.Build(s.getSecurityGroupTagParams(name, "", role))),
   588  	}
   589  }
   590  
   591  func (s *Service) getSecurityGroupTagParams(name, id string, role infrav1.SecurityGroupRole) infrav1.BuildParams {
   592  	additional := s.scope.AdditionalTags()
   593  	if role == infrav1.SecurityGroupLB {
   594  		additional[infrav1.ClusterAWSCloudProviderTagKey(s.scope.Name())] = string(infrav1.ResourceLifecycleOwned)
   595  	}
   596  	return infrav1.BuildParams{
   597  		ClusterName: s.scope.Name(),
   598  		Lifecycle:   infrav1.ResourceLifecycleOwned,
   599  		Name:        aws.String(name),
   600  		ResourceID:  id,
   601  		Role:        aws.String(string(role)),
   602  		Additional:  additional,
   603  	}
   604  }
   605  
   606  func (s *Service) isEKSOwned(sg infrav1.SecurityGroup) bool {
   607  	_, ok := sg.Tags["aws:eks:cluster-name"]
   608  	return ok
   609  }
   610  
   611  func ingressRuleToSDKType(i *infrav1.IngressRule) (res *ec2.IpPermission) {
   612  	// AWS seems to ignore the From/To port when set on protocols where it doesn't apply, but
   613  	// we avoid serializing it out for clarity's sake.
   614  	// See: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_IpPermission.html
   615  	switch i.Protocol {
   616  	case infrav1.SecurityGroupProtocolTCP,
   617  		infrav1.SecurityGroupProtocolUDP,
   618  		infrav1.SecurityGroupProtocolICMP,
   619  		infrav1.SecurityGroupProtocolICMPv6:
   620  		res = &ec2.IpPermission{
   621  			IpProtocol: aws.String(string(i.Protocol)),
   622  			FromPort:   aws.Int64(i.FromPort),
   623  			ToPort:     aws.Int64(i.ToPort),
   624  		}
   625  	case infrav1.SecurityGroupProtocolAll, infrav1.SecurityGroupProtocolIPinIP:
   626  		res = &ec2.IpPermission{
   627  			IpProtocol: aws.String(string(i.Protocol)),
   628  		}
   629  	}
   630  
   631  	for _, cidr := range i.CidrBlocks {
   632  		ipRange := &ec2.IpRange{
   633  			CidrIp: aws.String(cidr),
   634  		}
   635  
   636  		if i.Description != "" {
   637  			ipRange.Description = aws.String(i.Description)
   638  		}
   639  
   640  		res.IpRanges = append(res.IpRanges, ipRange)
   641  	}
   642  
   643  	for _, groupID := range i.SourceSecurityGroupIDs {
   644  		userIDGroupPair := &ec2.UserIdGroupPair{
   645  			GroupId: aws.String(groupID),
   646  		}
   647  
   648  		if i.Description != "" {
   649  			userIDGroupPair.Description = aws.String(i.Description)
   650  		}
   651  
   652  		res.UserIdGroupPairs = append(res.UserIdGroupPairs, userIDGroupPair)
   653  	}
   654  
   655  	return res
   656  }
   657  
   658  func ingressRulesFromSDKType(v *ec2.IpPermission) (res infrav1.IngressRules) {
   659  	// Ports are only well-defined for TCP and UDP protocols, but EC2 overloads the port range
   660  	// in the case of ICMP(v6) traffic to indicate which codes are allowed. For all other protocols,
   661  	// including the custom "-1" All Traffic protocol, FromPort and ToPort are omitted from the response.
   662  	// See: https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_IpPermission.html
   663  	var ir infrav1.IngressRule
   664  	switch *v.IpProtocol {
   665  	case IPProtocolTCP,
   666  		IPProtocolUDP,
   667  		IPProtocolICMP,
   668  		IPProtocolICMPv6:
   669  		ir = infrav1.IngressRule{
   670  			Protocol: infrav1.SecurityGroupProtocol(*v.IpProtocol),
   671  			FromPort: *v.FromPort,
   672  			ToPort:   *v.ToPort,
   673  		}
   674  	default:
   675  		ir = infrav1.IngressRule{
   676  			Protocol: infrav1.SecurityGroupProtocol(*v.IpProtocol),
   677  		}
   678  	}
   679  
   680  	if len(v.IpRanges) > 0 {
   681  		r1 := ir
   682  		for _, ec2range := range v.IpRanges {
   683  			if ec2range.Description != nil && *ec2range.Description != "" {
   684  				r1.Description = *ec2range.Description
   685  			}
   686  
   687  			r1.CidrBlocks = append(r1.CidrBlocks, *ec2range.CidrIp)
   688  		}
   689  		res = append(res, r1)
   690  	}
   691  
   692  	if len(v.UserIdGroupPairs) > 0 {
   693  		r2 := ir
   694  		for _, pair := range v.UserIdGroupPairs {
   695  			if pair.GroupId == nil {
   696  				continue
   697  			}
   698  
   699  			if pair.Description != nil && *pair.Description != "" {
   700  				r2.Description = *pair.Description
   701  			}
   702  
   703  			r2.SourceSecurityGroupIDs = append(r2.SourceSecurityGroupIDs, *pair.GroupId)
   704  		}
   705  		res = append(res, r2)
   706  	}
   707  
   708  	return res
   709  }