Skip to content

Commit a36545f

Browse files
committed
capi aws: delete bootstrap ssh rule
Deletes the SSH bootstrap rule by updating the ingress rule in the cluster spec.
1 parent 2cecf17 commit a36545f

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

pkg/asset/manifests/aws/cluster.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import (
1717
"github.com/openshift/installer/pkg/types"
1818
)
1919

20+
// BootstrapSSHDescription is the description for the
21+
// ingress rule that provides SSH access to the bootstrap node
22+
// & identifies the rule for removal during bootstrap destroy.
23+
const BootstrapSSHDescription = "Bootstrap SSH Access"
24+
2025
// GenerateClusterAssets generates the manifests for the cluster-api.
2126
func GenerateClusterAssets(ic *installconfig.InstallConfig, clusterID *installconfig.ClusterID) (*capiutils.GenerateClusterAssetsOutput, error) {
2227
manifests := []*asset.RuntimeFile{}
@@ -133,7 +138,7 @@ func GenerateClusterAssets(ic *installconfig.InstallConfig, clusterID *installco
133138
SourceSecurityGroupRoles: []capa.SecurityGroupRole{"controlplane", "node"},
134139
},
135140
{
136-
Description: "SSH everyone",
141+
Description: BootstrapSSHDescription,
137142
Protocol: capa.SecurityGroupProtocolTCP,
138143
FromPort: 22,
139144
ToPort: 22,

pkg/infrastructure/aws/clusterapi/aws.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,22 @@ import (
44
"context"
55
"errors"
66
"fmt"
7+
"strings"
8+
"time"
79

810
"github.com/aws/aws-sdk-go/aws"
911
"github.com/aws/aws-sdk-go/aws/awserr"
1012
"github.com/aws/aws-sdk-go/aws/session"
1113
"github.com/aws/aws-sdk-go/service/ec2"
1214
"github.com/aws/aws-sdk-go/service/elbv2"
1315
"github.com/sirupsen/logrus"
16+
"k8s.io/apimachinery/pkg/util/wait"
1417
"k8s.io/utils/ptr"
1518
capa "sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
1619
k8sClient "sigs.k8s.io/controller-runtime/pkg/client"
1720

1821
awsconfig "github.com/openshift/installer/pkg/asset/installconfig/aws"
22+
awsmanifest "github.com/openshift/installer/pkg/asset/manifests/aws"
1923
"github.com/openshift/installer/pkg/asset/manifests/capiutils"
2024
"github.com/openshift/installer/pkg/infrastructure/clusterapi"
2125
awstypes "github.com/openshift/installer/pkg/types/aws"
@@ -192,3 +196,77 @@ func getHostedZoneIDForNLB(ctx context.Context, awsSession *session.Session, reg
192196

193197
return "", errNotFound
194198
}
199+
200+
// DestroyBootstrap removes aws bootstrap resources not handled
201+
// by the deletion of the bootstrap machine by the capi controllers.
202+
func (*Provider) DestroyBootstrap(ctx context.Context, in clusterapi.BootstrapDestroyInput) error {
203+
if err := removeSSHRule(ctx, in.Client, in.Metadata.InfraID); err != nil {
204+
return fmt.Errorf("failed to remove bootstrap SSH rule: %w", err)
205+
}
206+
return nil
207+
}
208+
209+
// removeSSHRule removes the SSH rule for accessing the bootstrap node
210+
// by removing the rule from the cluster spec and updating the object.
211+
func removeSSHRule(ctx context.Context, cl k8sClient.Client, infraID string) error {
212+
awsCluster := &capa.AWSCluster{}
213+
key := k8sClient.ObjectKey{
214+
Name: infraID,
215+
Namespace: capiutils.Namespace,
216+
}
217+
if err := cl.Get(ctx, key, awsCluster); err != nil {
218+
return fmt.Errorf("failed to get AWSCluster: %w", err)
219+
}
220+
221+
postBootstrapRules := []capa.IngressRule{}
222+
for _, rule := range awsCluster.Spec.NetworkSpec.AdditionalControlPlaneIngressRules {
223+
if strings.EqualFold(rule.Description, awsmanifest.BootstrapSSHDescription) {
224+
continue
225+
}
226+
postBootstrapRules = append(postBootstrapRules, rule)
227+
}
228+
229+
awsCluster.Spec.NetworkSpec.AdditionalControlPlaneIngressRules = postBootstrapRules
230+
231+
if err := cl.Update(ctx, awsCluster); err != nil {
232+
return fmt.Errorf("failed to update AWSCluster during bootstrap destroy: %w", err)
233+
}
234+
logrus.Debug("Updated AWSCluster to remove bootstrap SSH rule")
235+
236+
timeout := 5 * time.Minute
237+
untilTime := time.Now().Add(timeout)
238+
timezone, _ := untilTime.Zone()
239+
logrus.Infof("Waiting up to %v (until %v %s) for bootstrap SSH rule to be destroyed...", timeout, untilTime.Format(time.Kitchen), timezone)
240+
if err := wait.ExponentialBackoffWithContext(ctx, wait.Backoff{
241+
Duration: time.Second * 10,
242+
Factor: float64(1.5),
243+
Steps: 32,
244+
Cap: timeout,
245+
}, func(ctx context.Context) (bool, error) {
246+
c := &capa.AWSCluster{}
247+
if err := cl.Get(ctx, key, c); err != nil {
248+
return false, err
249+
}
250+
if sg, ok := c.Status.Network.SecurityGroups[capa.SecurityGroupControlPlane]; ok {
251+
for _, r := range sg.IngressRules {
252+
if r.Description == awsmanifest.BootstrapSSHDescription {
253+
return false, nil
254+
}
255+
}
256+
return true, nil
257+
}
258+
// This shouldn't happen, but if control plane SG is not found, return an error.
259+
keys := make([]capa.SecurityGroupRole, 0, len(c.Status.Network.SecurityGroups))
260+
for sgr := range c.Status.Network.SecurityGroups {
261+
keys = append(keys, sgr)
262+
}
263+
return false, fmt.Errorf("controlplane not found in cluster security groups: %v", keys)
264+
}); err != nil {
265+
if wait.Interrupted(err) {
266+
return fmt.Errorf("bootstrap ssh rule was not removed within %v: %w", timeout, err)
267+
}
268+
return fmt.Errorf("unable to remove bootstrap ssh rule: %w", err)
269+
}
270+
271+
return nil
272+
}

0 commit comments

Comments
 (0)