From e4c6130a111fddc8a0334997c6d7cfa5b5e5cf32 Mon Sep 17 00:00:00 2001 From: Pradip Dhara Date: Wed, 21 Jul 2021 14:24:14 -0700 Subject: [PATCH] Adding support for multiple ssh keys --- api/v1alpha3/azurestackhcimachine_types.go | 2 ++ .../azurestackhcivirtualmachine_types.go | 2 ++ api/v1alpha3/zz_generated.deepcopy.go | 17 +++++++++++ .../virtualmachines/virtualmachines.go | 29 +++++++++---------- ...luster.x-k8s.io_azurestackhcimachines.yaml | 4 +++ ...-k8s.io_azurestackhcimachinetemplates.yaml | 4 +++ ...x-k8s.io_azurestackhcivirtualmachines.yaml | 4 +++ .../azurestackhcimachine_controller.go | 1 + .../azurestackhcivirtualmachine_reconciler.go | 12 +++++++- 9 files changed, 59 insertions(+), 16 deletions(-) diff --git a/api/v1alpha3/azurestackhcimachine_types.go b/api/v1alpha3/azurestackhcimachine_types.go index 7b9c904a..70170b20 100644 --- a/api/v1alpha3/azurestackhcimachine_types.go +++ b/api/v1alpha3/azurestackhcimachine_types.go @@ -51,6 +51,8 @@ type AzureStackHCIMachineSpec struct { // AllocatePublicIP allows the ability to create dynamic public ips for machines where this value is true. // +optional AllocatePublicIP bool `json:"allocatePublicIP,omitempty"` + + AdditionalSSHKeys []string `json:"additionalSSHKeys,omitempty"` } // AzureStackHCIMachineStatus defines the observed state of AzureStackHCIMachine diff --git a/api/v1alpha3/azurestackhcivirtualmachine_types.go b/api/v1alpha3/azurestackhcivirtualmachine_types.go index a9b69152..a55eb059 100644 --- a/api/v1alpha3/azurestackhcivirtualmachine_types.go +++ b/api/v1alpha3/azurestackhcivirtualmachine_types.go @@ -47,6 +47,8 @@ type AzureStackHCIVirtualMachineSpec struct { ClusterName string `json:"clusterName"` SubnetName string `json:"subnetName"` BackendPoolNames []string `json:"backendPoolNames,omitempty"` + + AdditionalSSHKeys []string `json:"additionalSSHKeys,omitempty"` } // AzureStackHCIVirtualMachineStatus defines the observed state of AzureStackHCIVirtualMachine diff --git a/api/v1alpha3/zz_generated.deepcopy.go b/api/v1alpha3/zz_generated.deepcopy.go index 079c0055..fd4f2fce 100644 --- a/api/v1alpha3/zz_generated.deepcopy.go +++ b/api/v1alpha3/zz_generated.deepcopy.go @@ -361,6 +361,11 @@ func (in *AzureStackHCIMachineSpec) DeepCopyInto(out *AzureStackHCIMachineSpec) in.AvailabilityZone.DeepCopyInto(&out.AvailabilityZone) in.Image.DeepCopyInto(&out.Image) out.OSDisk = in.OSDisk + if in.AdditionalSSHKeys != nil { + in, out := &in.AdditionalSSHKeys, &out.AdditionalSSHKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureStackHCIMachineSpec. @@ -386,6 +391,13 @@ func (in *AzureStackHCIMachineStatus) DeepCopyInto(out *AzureStackHCIMachineStat *out = new(VMState) **out = **in } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(apiv1alpha3.Conditions, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.FailureReason != nil { in, out := &in.FailureReason, &out.FailureReason *out = new(errors.MachineStatusError) @@ -593,6 +605,11 @@ func (in *AzureStackHCIVirtualMachineSpec) DeepCopyInto(out *AzureStackHCIVirtua *out = make([]string, len(*in)) copy(*out, *in) } + if in.AdditionalSSHKeys != nil { + in, out := &in.AdditionalSSHKeys, &out.AdditionalSSHKeys + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureStackHCIVirtualMachineSpec. diff --git a/cloud/services/virtualmachines/virtualmachines.go b/cloud/services/virtualmachines/virtualmachines.go index d0b6cde3..1f8a40a6 100644 --- a/cloud/services/virtualmachines/virtualmachines.go +++ b/cloud/services/virtualmachines/virtualmachines.go @@ -46,7 +46,7 @@ const ( type Spec struct { Name string NICName string - SSHKeyData string + SSHKeyData []string Size string Zone string Image infrav1.Image @@ -99,7 +99,7 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { klog.V(2).Infof("creating vm %s : %v", vmSpec.Name, vmSpec) sshKeyData := vmSpec.SSHKeyData - if sshKeyData == "" { + if len(sshKeyData) == 0 { privateKey, perr := rsa.GenerateKey(rand.Reader, 2048) if perr != nil { return errors.Wrap(perr, "Failed to generate private key") @@ -109,7 +109,16 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { if perr != nil { return errors.Wrap(perr, "Failed to generate public key") } - sshKeyData = string(ssh.MarshalAuthorizedKey(publicRsaKey)) + sshKeyData = []string{string(ssh.MarshalAuthorizedKey(publicRsaKey))} + } + + sshPublicKeys := []compute.SSHPublicKey{} + sshKeyPath := fmt.Sprintf("/home/%s/.ssh/authorized_keys", azurestackhci.DefaultUserName) + for i := 0; i < len(sshKeyData); i++ { + sshPublicKeys = append(sshPublicKeys, compute.SSHPublicKey{ + Path: &sshKeyPath, + KeyData: &sshKeyData[i], + }) } randomPassword, err := GenerateRandomString(32) @@ -131,12 +140,7 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { OsType: compute.OperatingSystemTypes(vmSpec.OSDisk.OSType), LinuxConfiguration: &compute.LinuxConfiguration{ SSH: &compute.SSHConfiguration{ - PublicKeys: &[]compute.SSHPublicKey{ - { - Path: to.StringPtr(fmt.Sprintf("/home/%s/.ssh/authorized_keys", azurestackhci.DefaultUserName)), - KeyData: to.StringPtr(sshKeyData), - }, - }, + PublicKeys: &sshPublicKeys, }, DisablePasswordAuthentication: to.BoolPtr(false), }, @@ -164,12 +168,7 @@ func (s *Service) Reconcile(ctx context.Context, spec interface{}) error { virtualMachine.OsProfile.WindowsConfiguration = &compute.WindowsConfiguration{ SSH: &compute.SSHConfiguration{ - PublicKeys: &[]compute.SSHPublicKey{ - { - Path: to.StringPtr(fmt.Sprintf("/users/%s/.ssh/authorized_keys", azurestackhci.DefaultUserName)), - KeyData: to.StringPtr(sshKeyData), - }, - }, + PublicKeys: &sshPublicKeys, }, } } diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachines.yaml index 8427f2d2..1328b5ab 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachines.yaml @@ -39,6 +39,10 @@ spec: spec: description: AzureStackHCIMachineSpec defines the desired state of AzureStackHCIMachine properties: + additionalSSHKeys: + items: + type: string + type: array allocatePublicIP: description: AllocatePublicIP allows the ability to create dynamic public ips for machines where this value is true. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachinetemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachinetemplates.yaml index dc69b494..d322148f 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachinetemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcimachinetemplates.yaml @@ -48,6 +48,10 @@ spec: description: Spec is the specification of the desired behavior of the machine. properties: + additionalSSHKeys: + items: + type: string + type: array allocatePublicIP: description: AllocatePublicIP allows the ability to create dynamic public ips for machines where this value is true. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcivirtualmachines.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcivirtualmachines.yaml index 0495e7da..ca6f50fa 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcivirtualmachines.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azurestackhcivirtualmachines.yaml @@ -40,6 +40,10 @@ spec: description: AzureStackHCIVirtualMachineSpec defines the desired state of AzureStackHCIVirtualMachine properties: + additionalSSHKeys: + items: + type: string + type: array availabilityZone: properties: enabled: diff --git a/controllers/azurestackhcimachine_controller.go b/controllers/azurestackhcimachine_controller.go index 2d6f6003..4036389a 100644 --- a/controllers/azurestackhcimachine_controller.go +++ b/controllers/azurestackhcimachine_controller.go @@ -305,6 +305,7 @@ func (r *AzureStackHCIMachineReconciler) reconcileVirtualMachineNormal(machineSc vm.Spec.Location = machineScope.AzureStackHCIMachine.Spec.Location vm.Spec.SSHPublicKey = machineScope.AzureStackHCIMachine.Spec.SSHPublicKey vm.Spec.BootstrapData = &bootstrapData + vm.Spec.AdditionalSSHKeys = machineScope.AzureStackHCIMachine.Spec.AdditionalSSHKeys return nil } diff --git a/controllers/azurestackhcivirtualmachine_reconciler.go b/controllers/azurestackhcivirtualmachine_reconciler.go index 0624f66e..17bfc908 100644 --- a/controllers/azurestackhcivirtualmachine_reconciler.go +++ b/controllers/azurestackhcivirtualmachine_reconciler.go @@ -164,10 +164,20 @@ func (s *azureStackHCIVirtualMachineService) reconcileNetworkInterface(nicName s func (s *azureStackHCIVirtualMachineService) createVirtualMachine(nicName string) (*infrav1.VM, error) { var vm *infrav1.VM + decodedKeys := []string{} decoded, err := base64.StdEncoding.DecodeString(s.vmScope.AzureStackHCIVirtualMachine.Spec.SSHPublicKey) if err != nil { return nil, errors.Wrapf(err, "failed to decode ssh public key") } + decodedKeys = append(decodedKeys, string(decoded)) + + for _, key := range s.vmScope.AzureStackHCIVirtualMachine.Spec.AdditionalSSHKeys { + decoded, err = base64.StdEncoding.DecodeString(key) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode an additional ssh public key") + } + decodedKeys = append(decodedKeys, string(decoded)) + } vmSpec := &virtualmachines.Spec{ Name: s.vmScope.Name(), @@ -205,7 +215,7 @@ func (s *azureStackHCIVirtualMachineService) createVirtualMachine(nicName string vmSpec = &virtualmachines.Spec{ Name: s.vmScope.Name(), NICName: nicName, - SSHKeyData: string(decoded), + SSHKeyData: decodedKeys, Size: s.vmScope.AzureStackHCIVirtualMachine.Spec.VMSize, OSDisk: s.vmScope.AzureStackHCIVirtualMachine.Spec.OSDisk, Image: s.vmScope.AzureStackHCIVirtualMachine.Spec.Image,