Adds password protection for VNC on VMWare

This commit is contained in:
Israel Shirk 2015-06-26 02:29:33 -06:00 committed by Rickard von Essen
parent 9489c83f0f
commit f961ce701b
8 changed files with 128 additions and 9 deletions

View File

@ -30,7 +30,7 @@ type VNCAddressFinder interface {
VNCAddress(string, uint, uint) (string, uint, error)
// UpdateVMX, sets driver specific VNC values to VMX data.
UpdateVMX(vncAddress string, vncPort uint, vmxData map[string]string)
UpdateVMX(vncAddress, vncPassword string, vncPort uint, vmxData map[string]string)
}
func (StepConfigureVNC) VNCAddress(vncBindAddress string, portMin, portMax uint) (string, uint, error) {
@ -56,6 +56,21 @@ func (StepConfigureVNC) VNCAddress(vncBindAddress string, portMin, portMax uint)
return vncBindAddress, vncPort, nil
}
func VNCPassword() string {
length := int(8)
charSet := []byte("1234567890-=qwertyuiop[]asdfghjkl;zxcvbnm,./!@#%^*()_+QWERTYUIOP{}|ASDFGHJKL:XCVBNM<>?")
charSetLength := len(charSet)
password := make([]byte, length)
for i := 0; i < length; i++ {
password[i] = charSet[rand.Intn(charSetLength)]
}
return string(password)
}
func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
@ -91,10 +106,12 @@ func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
return multistep.ActionHalt
}
vncPassword := VNCPassword()
log.Printf("Found available VNC port: %d", vncPort)
vmxData := ParseVMX(string(vmxBytes))
vncFinder.UpdateVMX(vncBindAddress, vncPort, vmxData)
vncFinder.UpdateVMX(vncBindAddress, vncPassword, vncPort, vmxData)
if err := WriteVMX(vmxPath, vmxData); err != nil {
err := fmt.Errorf("Error writing VMX data: %s", err)
@ -105,14 +122,16 @@ func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
state.Put("vnc_port", vncPort)
state.Put("vnc_ip", vncBindAddress)
state.Put("vnc_password", vncPassword)
return multistep.ActionContinue
}
func (StepConfigureVNC) UpdateVMX(address string, port uint, data map[string]string) {
func (StepConfigureVNC) UpdateVMX(address, password string, port uint, data map[string]string) {
data["remotedisplay.vnc.enabled"] = "TRUE"
data["remotedisplay.vnc.port"] = fmt.Sprintf("%d", port)
data["remotedisplay.vnc.ip"] = address
data["remotedisplay.vnc.password"] = password
}
func (StepConfigureVNC) Cleanup(multistep.StateBag) {

View File

@ -0,0 +1,46 @@
diff a/builder/vmware/common/step_configure_vnc.go b/builder/vmware/common/step_configure_vnc.go (rejected hunks)
@@ -52,6 +52,21 @@ func (StepConfigureVNC) VNCAddress(portMin, portMax uint) (string, uint, error)
return "127.0.0.1", vncPort, nil
}
+func VNCPassword() (string) {
+ length := int(8)
+
+ charSet := []byte("1234567890-=qwertyuiop[]asdfghjkl;zxcvbnm,./!@#%^*()_+QWERTYUIOP{}|ASDFGHJKL:XCVBNM<>?")
+ charSetLength := len(charSet)
+
+ password := make([]byte, length)
+
+ for i := 0; i < length; i++ {
+ password[i] = charSet[ rand.Intn(charSetLength) ]
+ }
+
+ return string(password)
+}
+
func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
driver := state.Get("driver").(Driver)
ui := state.Get("ui").(packer.Ui)
@@ -86,12 +101,14 @@ func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
ui.Error(err.Error())
return multistep.ActionHalt
}
+ vncPassword := VNCPassword()
log.Printf("Found available VNC port: %d", vncPort)
vmxData := ParseVMX(string(vmxBytes))
vmxData["remotedisplay.vnc.enabled"] = "TRUE"
vmxData["remotedisplay.vnc.port"] = fmt.Sprintf("%d", vncPort)
+ vmxData["remotedisplay.vnc.password"] = vncPassword
if err := WriteVMX(vmxPath, vmxData); err != nil {
err := fmt.Errorf("Error writing VMX data: %s", err)
@@ -102,6 +119,7 @@ func (s *StepConfigureVNC) Run(state multistep.StateBag) multistep.StepAction {
state.Put("vnc_port", vncPort)
state.Put("vnc_ip", vncIp)
+ state.Put("vnc_password", vncPassword)
return multistep.ActionContinue
}

View File

@ -12,7 +12,7 @@ func TestStepConfigureVNC_implVNCAddressFinder(t *testing.T) {
func TestStepConfigureVNC_UpdateVMX(t *testing.T) {
var s StepConfigureVNC
data := make(map[string]string)
s.UpdateVMX("0.0.0.0", 5900, data)
s.UpdateVMX("0.0.0.0", "", 5900, data)
if ip := data["remotedisplay.vnc.ip"]; ip != "0.0.0.0" {
t.Errorf("bad VMX data for key remotedisplay.vnc.ip: %v", ip)
}

View File

@ -38,15 +38,17 @@ func (s *StepRun) Run(state multistep.StateBag) multistep.StepAction {
if s.Headless {
vncIpRaw, vncIpOk := state.GetOk("vnc_ip")
vncPortRaw, vncPortOk := state.GetOk("vnc_port")
vncPasswordRaw, vncPasswordOk := state.GetOk("vnc_password")
if vncIpOk && vncPortOk {
if vncIpOk && vncPortOk && vncPasswordOk {
vncIp := vncIpRaw.(string)
vncPort := vncPortRaw.(uint)
vncPassword := vncPasswordRaw.(string)
ui.Message(fmt.Sprintf(
"The VM will be run headless, without a GUI. If you want to\n"+
"view the screen of the VM, connect via VNC without a password to\n"+
"%s:%d", vncIp, vncPort))
"view the screen of the VM, connect via VNC with the password %s to\n"+
"%s:%d", vncPassword, vncIp, vncPort))
} else {
ui.Message("The VM will be run headless, without a GUI, as configured.\n" +
"If the run isn't succeeding as you expect, please enable the GUI\n" +

View File

@ -46,6 +46,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
ui := state.Get("ui").(packer.Ui)
vncIp := state.Get("vnc_ip").(string)
vncPort := state.Get("vnc_port").(uint)
vncPassword := state.Get("vnc_password")
var pauseFn multistep.DebugPauseFn
if debug {
@ -63,7 +64,15 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
}
defer nc.Close()
c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: false})
var auth []vnc.ClientAuth
if vncPassword != nil {
auth = []vnc.ClientAuth{&vnc.PasswordAuth{Password: vncPassword.(string)}}
} else {
auth = []vnc.ClientAuth{}
}
c, err := vnc.Client(nc, &vnc.ClientConfig{Auth: auth, Exclusive: true})
if err != nil {
err := fmt.Errorf("Error handshaking with VNC: %s", err)
state.Put("error", err)

View File

@ -0,0 +1,26 @@
diff a/builder/vmware/common/step_type_boot_command.go b/builder/vmware/common/step_type_boot_command.go (rejected hunks)
@@ -45,6 +45,7 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
ui := state.Get("ui").(packer.Ui)
vncIp := state.Get("vnc_ip").(string)
vncPort := state.Get("vnc_port").(uint)
+ vncPassword := state.Get("vnc_password")
// Connect to VNC
ui.Say("Connecting to VM via VNC")
@@ -57,7 +58,15 @@ func (s *StepTypeBootCommand) Run(state multistep.StateBag) multistep.StepAction
}
defer nc.Close()
- c, err := vnc.Client(nc, &vnc.ClientConfig{Exclusive: true})
+ var auth []vnc.ClientAuth
+
+ if vncPassword != nil {
+ auth = []vnc.ClientAuth{&vnc.PasswordAuth{Password: vncPassword.(string)}}
+ } else {
+ auth = []vnc.ClientAuth{}
+ }
+
+ c, err := vnc.Client(nc, &vnc.ClientConfig{Auth: auth, Exclusive: true})
if err != nil {
err := fmt.Errorf("Error handshaking with VNC: %s", err)
state.Put("error", err)

View File

@ -231,10 +231,11 @@ func (d *ESX5Driver) VNCAddress(_ string, portMin, portMax uint) (string, uint,
}
// UpdateVMX, adds the VNC port to the VMX data.
func (ESX5Driver) UpdateVMX(_ string, port uint, data map[string]string) {
func (ESX5Driver) UpdateVMX(_, password string, port uint, data map[string]string) {
// Do not set remotedisplay.vnc.ip - this breaks ESXi.
data["remotedisplay.vnc.enabled"] = "TRUE"
data["remotedisplay.vnc.port"] = fmt.Sprintf("%d", port)
data["remotedisplay.vnc.password"] = password
}
func (d *ESX5Driver) CommHost(state multistep.StateBag) (string, error) {

View File

@ -13,6 +13,22 @@ func TestESX5Driver_implDriver(t *testing.T) {
var _ vmwcommon.Driver = new(ESX5Driver)
}
func TestESX5Driver_UpdateVMX(t *testing.T) {
var driver ESX5Driver
data := make(map[string]string)
driver.UpdateVMX("0.0.0.0", "", 5900, data)
if _, ok := data["remotedisplay.vnc.ip"]; ok {
// Do not add the remotedisplay.vnc.ip on ESXi
t.Fatal("invalid VMX data key: remotedisplay.vnc.ip")
}
if enabled := data["remotedisplay.vnc.enabled"]; enabled != "TRUE" {
t.Errorf("bad VMX data for key remotedisplay.vnc.enabled: %v", enabled)
}
if port := data["remotedisplay.vnc.port"]; port != fmt.Sprint(port) {
t.Errorf("bad VMX data for key remotedisplay.vnc.port: %v", port)
}
}
func TestESX5Driver_implOutputDir(t *testing.T) {
var _ vmwcommon.OutputDir = new(ESX5Driver)
}