From 4656743c229735d2892bc9bb0b652fa16f3a68b2 Mon Sep 17 00:00:00 2001 From: Ciprian Hacman Date: Fri, 7 Jul 2023 13:15:51 +0300 Subject: [PATCH] gce: Add support for bastions --- pkg/model/gcemodel/autoscalinggroup.go | 11 ++++++++--- pkg/model/gcemodel/external_access.go | 25 +++++++++++++++++++++++++ pkg/model/gcemodel/firewall.go | 26 +++++++++++++++----------- 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/pkg/model/gcemodel/autoscalinggroup.go b/pkg/model/gcemodel/autoscalinggroup.go index 1c7ee2bd94..211ad9fcac 100644 --- a/pkg/model/gcemodel/autoscalinggroup.go +++ b/pkg/model/gcemodel/autoscalinggroup.go @@ -96,7 +96,7 @@ func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.CloudupModelB Preemptible: fi.PtrTo(fi.ValueOf(ig.Spec.GCPProvisioningModel) == "SPOT"), GCPProvisioningModel: ig.Spec.GCPProvisioningModel, - HasExternalIP: fi.PtrTo(subnet.Type == kops.SubnetTypePublic || subnet.Type == kops.SubnetTypeUtility), + HasExternalIP: fi.PtrTo(subnet.Type == kops.SubnetTypePublic || subnet.Type == kops.SubnetTypeUtility || ig.IsBastion()), Scopes: []string{ "compute-rw", @@ -104,13 +104,15 @@ func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.CloudupModelB "logging-write", }, Metadata: map[string]fi.Resource{ - "startup-script": startupScript, - //"config": resources/config.yaml $nodeset.Name gcemetadata.MetadataKeyClusterName: fi.NewStringResource(b.ClusterName()), nodeidentitygce.MetadataKeyInstanceGroupName: fi.NewStringResource(ig.Name), }, } + if startupScript != nil { + t.Metadata["startup-script"] = startupScript + } + if ig.Spec.Role == kops.InstanceGroupRoleNode { autoscalerEnvVars := "os_distribution=ubuntu;arch=amd64;os=linux" if strings.HasPrefix(ig.Spec.Image, "cos-cloud/") { @@ -168,6 +170,9 @@ func (b *AutoscalingGroupModelBuilder) buildInstanceTemplate(c *fi.CloudupModelB case kops.InstanceGroupRoleNode: t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleNode)) + + case kops.InstanceGroupRoleBastion: + t.Tags = append(t.Tags, b.GCETagForRole(kops.InstanceGroupRoleBastion)) } roleLabel := gce.GceLabelNameRolePrefix + ig.Spec.Role.ToLowerString() t.Labels = map[string]string{ diff --git a/pkg/model/gcemodel/external_access.go b/pkg/model/gcemodel/external_access.go index 4ad010e288..cb5835e258 100644 --- a/pkg/model/gcemodel/external_access.go +++ b/pkg/model/gcemodel/external_access.go @@ -51,6 +51,31 @@ func (b *ExternalAccessModelBuilder) Build(c *fi.CloudupModelBuilderContext) err // This is admittedly a little odd... adding a bastion shuts down direct access to the masters/nodes // But I think we can always add more permissions in this case later, but we can't easily take them away klog.V(2).Infof("bastion is in use; won't configure SSH access to control-plane / worker node instances") + network, err := b.LinkToNetwork() + if err != nil { + return err + } + b.AddFirewallRulesTasks(c, "ssh-external-to-bastion", &gcetasks.FirewallRule{ + Lifecycle: b.Lifecycle, + TargetTags: []string{b.GCETagForRole(kops.InstanceGroupRoleBastion)}, + Allowed: []string{"tcp:22"}, + SourceRanges: b.Cluster.Spec.SSHAccess, + Network: network, + }) + b.AddFirewallRulesTasks(c, "bastion-to-master", &gcetasks.FirewallRule{ + Lifecycle: b.Lifecycle, + TargetTags: []string{b.GCETagForRole(kops.InstanceGroupRoleControlPlane), b.GCETagForRole("Master")}, + Allowed: []string{"tcp:22"}, + SourceTags: []string{b.GCETagForRole(kops.InstanceGroupRoleBastion)}, + Network: network, + }) + b.AddFirewallRulesTasks(c, "bastion-to-node", &gcetasks.FirewallRule{ + Lifecycle: b.Lifecycle, + TargetTags: []string{b.GCETagForRole(kops.InstanceGroupRoleNode)}, + Allowed: []string{"tcp:22"}, + SourceTags: []string{b.GCETagForRole(kops.InstanceGroupRoleBastion)}, + Network: network, + }) } else { network, err := b.LinkToNetwork() if err != nil { diff --git a/pkg/model/gcemodel/firewall.go b/pkg/model/gcemodel/firewall.go index d4f31864fd..70b1789720 100644 --- a/pkg/model/gcemodel/firewall.go +++ b/pkg/model/gcemodel/firewall.go @@ -180,23 +180,27 @@ func (b *GCEModelContext) AddFirewallRulesTasks(c *fi.CloudupModelBuilderContext ipv4 := *rule ipv4.Name = s(b.NameForFirewallRule(name)) ipv4.Family = gcetasks.AddressFamilyIPv4 - ipv4.SourceRanges = ipv4SourceRanges - if len(ipv4.SourceRanges) == 0 { - // This is helpful because empty SourceRanges and SourceTags are interpreted as allow everything, - // but the intent is usually to block everything, which can be achieved with Disabled=true. - ipv4.Disabled = true - ipv4.SourceRanges = []string{"0.0.0.0/0"} + if len(ipv4.SourceTags) == 0 { + ipv4.SourceRanges = ipv4SourceRanges + if len(ipv4.SourceRanges) == 0 { + // This is helpful because empty SourceRanges and SourceTags are interpreted as allow everything, + // but the intent is usually to block everything, which can be achieved with Disabled=true. + ipv4.Disabled = true + ipv4.SourceRanges = []string{"0.0.0.0/0"} + } } c.AddTask(&ipv4) ipv6 := *rule ipv6.Name = s(b.NameForFirewallRule(name + "-ipv6")) ipv6.Family = gcetasks.AddressFamilyIPv6 - ipv6.SourceRanges = ipv6SourceRanges - if len(ipv6.SourceRanges) == 0 { - // We specify explicitly so the rule is in IPv6 mode - ipv6.Disabled = true - ipv6.SourceRanges = []string{"::/0"} + if len(ipv6.SourceTags) == 0 { + ipv6.SourceRanges = ipv6SourceRanges + if len(ipv6.SourceRanges) == 0 { + // We specify explicitly so the rule is in IPv6 mode + ipv6.Disabled = true + ipv6.SourceRanges = []string{"::/0"} + } } var ipv6Allowed []string for _, allowed := range ipv6.Allowed {