Skip to content

Commit

Permalink
AWSManagedMachinePool: Make public access to SSH explicit
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbeaumont committed Feb 7, 2021
1 parent 3ac3feb commit c54dd7a
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 10 deletions.
Expand Up @@ -83,8 +83,11 @@ spec:
remoteAccess:
description: RemoteAccess specifies how machines can be accessed remotely
properties:
public:
description: Public specifies whether to open port 22 to the public internet
type: boolean
sourceSecurityGroups:
description: SourceSecurityGroups specifies which security groups are allowed access An empty array opens port 22 to the public internet
description: SourceSecurityGroups specifies which security groups are allowed access
items:
type: string
type: array
Expand Down
6 changes: 6 additions & 0 deletions controlplane/eks/api/v1alpha3/types.go
Expand Up @@ -208,3 +208,9 @@ type AddonIssue struct {
// ResourceIDs is a list of resource ids for the issue
ResourceIDs []*string `json:"resourceIds,omitempty"`
}

const (
// SecurityGroupCluster is the security group for communication between EKS
// control plane and managed node groups
SecurityGroupCluster = infrav1.SecurityGroupRole("cluster")
)
4 changes: 3 additions & 1 deletion exp/api/v1alpha3/awsmanagedmachinepool_types.go
Expand Up @@ -129,8 +129,10 @@ type ManagedRemoteAccess struct {
SSHKeyName *string `json:"sshKeyName,omitempty"`

// SourceSecurityGroups specifies which security groups are allowed access
// An empty array opens port 22 to the public internet
SourceSecurityGroups []string `json:"sourceSecurityGroups,omitempty"`

// Public specifies whether to open port 22 to the public internet
Public bool `json:"public,omitempty"`
}

// AWSManagedMachinePoolStatus defines the observed state of AWSManagedMachinePool
Expand Down
22 changes: 22 additions & 0 deletions exp/api/v1alpha3/awsmanagedmachinepool_webhook.go
Expand Up @@ -74,6 +74,25 @@ func (r *AWSManagedMachinePool) validateScaling() field.ErrorList {
return allErrs
}

func (r *AWSManagedMachinePool) validateRemoteAccess() field.ErrorList {
var allErrs field.ErrorList
if r.Spec.RemoteAccess == nil {
return allErrs
}
remoteAccessPath := field.NewPath("spec", "remoteAccess")
sourceSecurityGroups := r.Spec.RemoteAccess.SourceSecurityGroups
public := r.Spec.RemoteAccess.Public

if public && len(sourceSecurityGroups) > 0 {
allErrs = append(
allErrs,
field.Invalid(remoteAccessPath.Child("sourceSecurityGroups"), sourceSecurityGroups, "must be empty if public is set"),
)
}

return allErrs
}

// ValidateCreate will do any extra validation when creating a AWSManagedMachinePool
func (r *AWSManagedMachinePool) ValidateCreate() error {
mmpLog.Info("AWSManagedMachinePool validate create", "name", r.Name)
Expand All @@ -86,6 +105,9 @@ func (r *AWSManagedMachinePool) ValidateCreate() error {
if errs := r.validateScaling(); errs != nil || len(errs) == 0 {
allErrs = append(allErrs, errs...)
}
if errs := r.validateRemoteAccess(); len(errs) > 0 {
allErrs = append(allErrs, errs...)
}

if len(allErrs) == 0 {
return nil
Expand Down
33 changes: 25 additions & 8 deletions pkg/cloud/services/eks/nodegroup.go
Expand Up @@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/util/version"

infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1alpha3"
controlplanev1exp "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1alpha3"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/services/wait"
"sigs.k8s.io/cluster-api-provider-aws/pkg/record"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha3"
Expand Down Expand Up @@ -119,17 +120,33 @@ func (s *NodegroupService) remoteAccess() (*eks.RemoteAccessConfig, error) {
}

controlPlane := s.scope.ControlPlane
sSGs := pool.RemoteAccess.SourceSecurityGroups

if controlPlane.Spec.Bastion.Enabled {
additionalSG, ok := controlPlane.Status.Network.SecurityGroups[infrav1.SecurityGroupEKSNodeAdditional]
// SourceSecurityGroups is validated to be empty if PublicAccess is true
// but just in case we use an empty list to take advantage of the documented
// API behavior
var sSGs = []string{}

if !pool.RemoteAccess.Public {
sSGs = pool.RemoteAccess.SourceSecurityGroups
// We add the EKS created cluster security group to the allowed security
// groups by default to prevent the API default of 0.0.0.0/0 from taking effect
// in case SourceSecurityGroups is empty
clusterSG, ok := controlPlane.Status.Network.SecurityGroups[controlplanev1exp.SecurityGroupCluster]
if !ok {
return nil, errors.Errorf("%s security group not found on control plane", infrav1.SecurityGroupEKSNodeAdditional)
return nil, errors.Errorf("%s security group not found on control plane", controlplanev1exp.SecurityGroupCluster)
}
sSGs = append(sSGs, clusterSG.ID)

if controlPlane.Spec.Bastion.Enabled {
additionalSG, ok := controlPlane.Status.Network.SecurityGroups[infrav1.SecurityGroupEKSNodeAdditional]
if !ok {
return nil, errors.Errorf("%s security group not found on control plane", infrav1.SecurityGroupEKSNodeAdditional)
}
sSGs = append(
sSGs,
additionalSG.ID,
)
}
sSGs = append(
sSGs,
additionalSG.ID,
)
}

sshKeyName := pool.RemoteAccess.SSHKeyName
Expand Down
18 changes: 18 additions & 0 deletions pkg/cloud/services/eks/securitygroup.go
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/aws/aws-sdk-go/service/eks"

infrav1 "sigs.k8s.io/cluster-api-provider-aws/api/v1alpha3"
ekscontrolplanev1 "sigs.k8s.io/cluster-api-provider-aws/controlplane/eks/api/v1alpha3"
"sigs.k8s.io/cluster-api-provider-aws/pkg/cloud/converters"
)

Expand Down Expand Up @@ -59,5 +60,22 @@ func (s *Service) reconcileSecurityGroups(cluster *eks.Cluster) error {
}
s.scope.ControlPlane.Status.Network.SecurityGroups[infrav1.SecurityGroupNode] = sg

input = &ec2.DescribeSecurityGroupsInput{
GroupIds: []*string{
cluster.ResourcesVpcConfig.ClusterSecurityGroupId,
},
}

output, err = s.EC2Client.DescribeSecurityGroups(input)
if err != nil || len(output.SecurityGroups) == 0 {
return fmt.Errorf("describing EKS cluster security group: %w", err)
}

s.scope.ControlPlane.Status.Network.SecurityGroups[ekscontrolplanev1.SecurityGroupCluster] = infrav1.SecurityGroup{
ID: aws.StringValue(cluster.ResourcesVpcConfig.ClusterSecurityGroupId),
Name: *output.SecurityGroups[0].GroupName,
Tags: converters.TagsToMap(output.SecurityGroups[0].Tags),
}

return nil
}

0 comments on commit c54dd7a

Please sign in to comment.