99 "strings"
1010 "time"
1111
12+ "github.com/Azure/azure-sdk-for-go/sdk/azcore"
1213 "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
14+ "github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
1315 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
1416 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v3"
1517 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4"
@@ -25,6 +27,7 @@ import (
2527 "sigs.k8s.io/controller-runtime/pkg/client"
2628
2729 "github.com/openshift/installer/pkg/asset/ignition/bootstrap"
30+ azconfig "github.com/openshift/installer/pkg/asset/installconfig/azure"
2831 "github.com/openshift/installer/pkg/asset/manifests/capiutils"
2932 "github.com/openshift/installer/pkg/infrastructure/clusterapi"
3033 "github.com/openshift/installer/pkg/rhcos"
@@ -45,14 +48,18 @@ type Provider struct {
4548 StorageAccount * armstorage.Account
4649 StorageClientFactory * armstorage.ClientFactory
4750 StorageAccountKeys []armstorage.AccountKey
48- Tags map [ string ] * string
51+ NetworkClientFactory * armnetwork. ClientFactory
4952 lbBackendAddressPool * armnetwork.BackendAddressPool
53+ CloudConfiguration cloud.Configuration
54+ TokenCredential azcore.TokenCredential
55+ Tags map [string ]* string
5056}
5157
5258var _ clusterapi.PreProvider = (* Provider )(nil )
5359var _ clusterapi.InfraReadyProvider = (* Provider )(nil )
5460var _ clusterapi.PostProvider = (* Provider )(nil )
5561var _ clusterapi.IgnitionProvider = (* Provider )(nil )
62+ var _ clusterapi.PostDestroyer = (* Provider )(nil )
5663
5764// Name returns the name of the provider.
5865func (p * Provider ) Name () string {
@@ -239,7 +246,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
239246 cloudConfiguration := session .CloudConfig
240247
241248 resourceGroupName := p .ResourceGroupName
242- storageAccountName := fmt .Sprintf ("cluster%s " , randomString ( 5 ))
249+ storageAccountName := fmt .Sprintf ("%ssa " , strings . ReplaceAll ( in . InfraID , "-" , "" ))
243250 containerName := "vhd"
244251 blobName := fmt .Sprintf ("rhcos%s.vhd" , randomString (5 ))
245252
@@ -469,7 +476,7 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
469476 }
470477 logrus .Debugf ("created public ip: %s" , * publicIP .ID )
471478
472- loadBalancer , err := updateExternalLoadBalancer (ctx , publicIP , lbInput )
479+ loadBalancer , err := updateOutboundLoadBalancerToAPILoadBalancer (ctx , publicIP , lbInput )
473480 if err != nil {
474481 return fmt .Errorf ("failed to update external load balancer: %w" , err )
475482 }
@@ -484,8 +491,9 @@ func (p *Provider) InfraReady(ctx context.Context, in clusterapi.InfraReadyInput
484491 p .StorageAccountName = storageAccountName
485492 p .StorageURL = storageURL
486493 p .StorageAccount = storageAccount
487- p .StorageClientFactory = storageClientFactory
488494 p .StorageAccountKeys = storageAccountKeys
495+ p .StorageClientFactory = storageClientFactory
496+ p .NetworkClientFactory = networkClientFactory
489497 p .lbBackendAddressPool = lbBap
490498
491499 if err := createDNSEntries (ctx , in , extLBFQDN , resourceGroupName ); err != nil {
@@ -516,16 +524,6 @@ func (p *Provider) PostProvision(ctx context.Context, in clusterapi.PostProvisio
516524 if err != nil {
517525 return fmt .Errorf ("error creating vm client: %w" , err )
518526 }
519- nicClient , err := armnetwork .NewInterfacesClient (ssn .Credentials .SubscriptionID , ssn .TokenCreds ,
520- & arm.ClientOptions {
521- ClientOptions : policy.ClientOptions {
522- Cloud : cloudConfiguration ,
523- },
524- },
525- )
526- if err != nil {
527- return fmt .Errorf ("error creating nic client: %w" , err )
528- }
529527
530528 vmIDs , err := getControlPlaneIDs (in .Client , in .InstallConfig .Config .ControlPlane .Replicas , in .InfraID )
531529 if err != nil {
@@ -536,14 +534,113 @@ func (p *Provider) PostProvision(ctx context.Context, in clusterapi.PostProvisio
536534 infraID : in .InfraID ,
537535 resourceGroup : p .ResourceGroupName ,
538536 vmClient : vmClient ,
539- nicClient : nicClient ,
537+ nicClient : p . NetworkClientFactory . NewInterfacesClient () ,
540538 ids : vmIDs ,
541539 bap : p .lbBackendAddressPool ,
542540 }
543541
544542 if err = associateVMToBackendPool (ctx , * vmInput ); err != nil {
545543 return fmt .Errorf ("failed to associate control plane VMs with external load balancer: %w" , err )
546544 }
545+
546+ if err = addSecurityGroupRule (ctx , & securityGroupInput {
547+ resourceGroupName : p .ResourceGroupName ,
548+ securityGroupName : fmt .Sprintf ("%s-nsg" , in .InfraID ),
549+ securityRuleName : "ssh_in" ,
550+ securityRulePort : "22" ,
551+ securityRulePriority : 220 ,
552+ networkClientFactory : p .NetworkClientFactory ,
553+ }); err != nil {
554+ return fmt .Errorf ("failed to add security rule: %w" , err )
555+ }
556+
557+ loadBalancerName := in .InfraID
558+ frontendIPConfigName := "public-lb-ip-v4"
559+ frontendIPConfigID := fmt .Sprintf ("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/loadBalancers/%s/frontendIPConfigurations/%s" ,
560+ subscriptionID ,
561+ p .ResourceGroupName ,
562+ loadBalancerName ,
563+ frontendIPConfigName ,
564+ )
565+
566+ // Create an inbound nat rule that forwards port 22 on the
567+ // public load balancer to the bootstrap host. This takes 2
568+ // stages to accomplish. First, the nat rule needs to be added
569+ // to the frontend IP configuration on the public load
570+ // balancer. Second, the nat rule needs to be addded to the
571+ // bootstrap interface with the association to the rule on the
572+ // public load balancer.
573+ inboundNatRule , err := addInboundNatRuleToLoadBalancer (ctx , & inboundNatRuleInput {
574+ resourceGroupName : p .ResourceGroupName ,
575+ loadBalancerName : loadBalancerName ,
576+ frontendIPConfigID : frontendIPConfigID ,
577+ inboundNatRuleName : "ssh_in" ,
578+ inboundNatRulePort : 22 ,
579+ networkClientFactory : p .NetworkClientFactory ,
580+ })
581+ if err != nil {
582+ return fmt .Errorf ("failed to create inbound nat rule: %w" , err )
583+ }
584+ _ , err = associateInboundNatRuleToInterface (ctx , & inboundNatRuleInput {
585+ resourceGroupName : p .ResourceGroupName ,
586+ loadBalancerName : loadBalancerName ,
587+ bootstrapNicName : fmt .Sprintf ("%s-bootstrap-nic" , in .InfraID ),
588+ frontendIPConfigID : frontendIPConfigID ,
589+ inboundNatRuleID : * inboundNatRule .ID ,
590+ inboundNatRuleName : "ssh_in" ,
591+ inboundNatRulePort : 22 ,
592+ networkClientFactory : p .NetworkClientFactory ,
593+ })
594+ if err != nil {
595+ return fmt .Errorf ("failed to associate inbound nat rule to interface: %w" , err )
596+ }
597+ }
598+
599+ return nil
600+ }
601+
602+ // PostDestroy removes SSH access from the network security rules and removes
603+ // SSH port forwarding off the public load balancer when the bootstrap machine
604+ // is destroyed.
605+ func (p * Provider ) PostDestroy (ctx context.Context , in clusterapi.PostDestroyerInput ) error {
606+ session , err := azconfig .GetSession (in .Metadata .Azure .CloudName , in .Metadata .Azure .ARMEndpoint )
607+ if err != nil {
608+ return fmt .Errorf ("failed to get session: %w" , err )
609+ }
610+
611+ networkClientFactory , err := armnetwork .NewClientFactory (
612+ session .Credentials .SubscriptionID ,
613+ session .TokenCreds ,
614+ & arm.ClientOptions {
615+ ClientOptions : policy.ClientOptions {
616+ Cloud : session .CloudConfig ,
617+ },
618+ },
619+ )
620+ if err != nil {
621+ return fmt .Errorf ("error creating network client factory: %w" , err )
622+ }
623+
624+ // XXX: why is in.Metadata.Azure.ResourceGroupName empty?
625+ err = deleteSecurityGroupRule (ctx , & securityGroupInput {
626+ resourceGroupName : fmt .Sprintf ("%s-rg" , in .Metadata .InfraID ),
627+ securityGroupName : fmt .Sprintf ("%s-nsg" , in .Metadata .InfraID ),
628+ securityRuleName : "ssh_in" ,
629+ securityRulePort : "22" ,
630+ networkClientFactory : networkClientFactory ,
631+ })
632+ if err != nil {
633+ return fmt .Errorf ("failed to delete security rule: %w" , err )
634+ }
635+
636+ err = deleteInboundNatRule (ctx , & inboundNatRuleInput {
637+ resourceGroupName : fmt .Sprintf ("%s-rg" , in .Metadata .InfraID ),
638+ loadBalancerName : in .Metadata .InfraID ,
639+ inboundNatRuleName : "ssh_in" ,
640+ networkClientFactory : networkClientFactory ,
641+ })
642+ if err != nil {
643+ return fmt .Errorf ("failed to delete inbound nat rule: %w" , err )
547644 }
548645
549646 return nil
0 commit comments