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 }