Skip to content

Commit

Permalink
Improve node vsphere node deletion
Browse files Browse the repository at this point in the history
Problem: Vsphere node deletion entirely relies on the local directory to
ensure uniqueness during node deletion. Pratically, this means the name
is the only unique identifier used. This can be an issue when the
local dir is being modified out of the bounds of docker machine.

Solution: The vsphere driver now uses the ssh key fingerprints of the
keys to ensure the node being deleted is the intended node.
  • Loading branch information
daxmc99 committed Aug 20, 2019
1 parent c2da448 commit b2cc2b8
Showing 1 changed file with 69 additions and 17 deletions.
86 changes: 69 additions & 17 deletions drivers/vmwarevsphere/vsphere.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package vmwarevsphere
import (
"archive/tar"
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
"net"
Expand All @@ -21,16 +22,14 @@ import (
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"

"errors"

"github.com/vmware/govmomi"
"github.com/vmware/govmomi/find"
"github.com/vmware/govmomi/guest"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
"github.com/vmware/govmomi/vim25/types"
ssh2 "golang.org/x/crypto/ssh"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -754,8 +753,8 @@ func (d *Driver) Create() error {

auth := AuthFlag{}
flag := FileAttrFlag{}
auth.auth.Username = B2DUser
auth.auth.Password = B2DPass
auth.auth.Username = defaultSSHUser
auth.auth.Password = defaultSSHPass
flag.SetPerms(0, 0, 660)
url, err := fileman.InitiateFileTransferToGuest(ctx, auth.Auth(), "/home/docker/userdata.tar", flag.Attr(), s.Size(), true)
if err != nil {
Expand Down Expand Up @@ -941,14 +940,18 @@ func (d *Driver) Remove() error {
if err != nil {
return err
}
if machineState == state.Running {
if err = d.Kill(); err != nil {
return fmt.Errorf("can't stop VM: %s", err)
}
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

pubKeyBytes, err := ioutil.ReadFile(d.publicSSHKeyPath())
if err != nil {
return err
}
localKeyprint, err := getPublicKeyFingerprint(pubKeyBytes)
if err != nil {
return err
}

c, err := d.vsphereLogin(ctx)
if err != nil {
return err
Expand All @@ -965,6 +968,52 @@ func (d *Driver) Remove() error {

f.SetDatacenter(dc)

vm, err := d.fetchVM(ctx, c, d.MachineName)
if err != nil {
return err
}

// grab /home/docker/.ssh/authorized_keys and compare with id_rsa.pub
opman := guest.NewOperationsManager(c.Client, vm.Reference())

fileman, err := opman.FileManager(ctx)
if err != nil {
return err
}

src := d.ResolveStorePath("auth_keys")
auth := AuthFlag{}
auth.auth.Username = defaultSSHUser
auth.auth.Password = defaultSSHPass
resp, err := fileman.InitiateFileTransferFromGuest(ctx, auth.Auth(), "/home/docker/.ssh/authorized_keys")
if err != nil {
return err
}
u, err := c.Client.ParseURL(resp.Url)
if err != nil {
return err
}
if err = c.Client.DownloadFile(ctx, src, u, nil); err != nil {
return err
}
remoteKeyBytes, err := ioutil.ReadFile(src)
if err != nil {
return err
}
remoteKeyprint, err := getPublicKeyFingerprint(remoteKeyBytes)
if err != nil {
return err
}
if remoteKeyprint != localKeyprint {
return errors.New("local key fingerprint is different than remote key fingerprint")
}

if machineState == state.Running {
if err = d.Kill(); err != nil {

return fmt.Errorf("can't stop VM: %s", err)
}
}
dss, err := f.DatastoreOrDefault(ctx, d.Datastore)
if err != nil {
return err
Expand All @@ -977,19 +1026,13 @@ func (d *Driver) Remove() error {
return err
}

err = task.Wait(ctx)
if err != nil {
if err = task.Wait(ctx); err != nil {
if types.IsFileNotFound(err) {
// Ignore error
return nil
}
}

vm, err := d.fetchVM(ctx, c, d.MachineName)
if err != nil {
return err
}

task, err = vm.Destroy(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -1106,6 +1149,15 @@ func (d *Driver) fetchVM(ctx context.Context, c *govmomi.Client, vmname string)
return vm, nil
}

func getPublicKeyFingerprint(pubKeyBytes []byte) (string, error) {
pubKey, _, _, _, err := ssh2.ParseAuthorizedKey(pubKeyBytes)
if err != nil {
return "", err
}
finger := ssh2.FingerprintLegacyMD5(pubKey)
return finger, nil
}

type AuthFlag struct {
auth types.NamePasswordAuthentication
}
Expand Down

0 comments on commit b2cc2b8

Please sign in to comment.