github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/googlecompute/step_create_windows_password.go (about)

     1  package googlecompute
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/rsa"
     7  	"crypto/x509"
     8  	"encoding/base64"
     9  	"encoding/binary"
    10  	"encoding/pem"
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"time"
    15  
    16  	commonhelper "github.com/hashicorp/packer/helper/common"
    17  	"github.com/hashicorp/packer/helper/multistep"
    18  	"github.com/hashicorp/packer/packer"
    19  )
    20  
    21  // StepCreateWindowsPassword represents a Packer build step that sets the windows password on a Windows GCE instance.
    22  type StepCreateWindowsPassword struct {
    23  	Debug        bool
    24  	DebugKeyPath string
    25  }
    26  
    27  // Run executes the Packer build step that sets the windows password on a Windows GCE instance.
    28  func (s *StepCreateWindowsPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
    29  	ui := state.Get("ui").(packer.Ui)
    30  	d := state.Get("driver").(Driver)
    31  	c := state.Get("config").(*Config)
    32  	name := state.Get("instance_name").(string)
    33  
    34  	if c.Comm.WinRMPassword != "" {
    35  		state.Put("winrm_password", c.Comm.WinRMPassword)
    36  		return multistep.ActionContinue
    37  	}
    38  
    39  	create, ok := state.GetOk("create_windows_password")
    40  
    41  	if !ok || !create.(bool) {
    42  		return multistep.ActionContinue
    43  
    44  	}
    45  	ui.Say("Creating windows user for instance...")
    46  	priv, err := rsa.GenerateKey(rand.Reader, 2048)
    47  	if err != nil {
    48  		err := fmt.Errorf("Error creating temporary key: %s", err)
    49  		state.Put("error", err)
    50  		ui.Error(err.Error())
    51  		return multistep.ActionHalt
    52  	}
    53  
    54  	buf := make([]byte, 4)
    55  	binary.BigEndian.PutUint32(buf, uint32(priv.E))
    56  
    57  	data := WindowsPasswordConfig{
    58  		key:      priv,
    59  		UserName: c.Comm.WinRMUser,
    60  		Modulus:  base64.StdEncoding.EncodeToString(priv.N.Bytes()),
    61  		Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
    62  		Email:    c.Account.ClientEmail,
    63  		ExpireOn: time.Now().Add(time.Minute * 5),
    64  	}
    65  
    66  	if s.Debug {
    67  
    68  		priv_blk := pem.Block{
    69  			Type:    "RSA PRIVATE KEY",
    70  			Headers: nil,
    71  			Bytes:   x509.MarshalPKCS1PrivateKey(priv),
    72  		}
    73  
    74  		ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
    75  		f, err := os.Create(s.DebugKeyPath)
    76  		if err != nil {
    77  			state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
    78  			return multistep.ActionHalt
    79  		}
    80  
    81  		// Write out the key
    82  		err = pem.Encode(f, &priv_blk)
    83  		f.Close()
    84  		if err != nil {
    85  			state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
    86  			return multistep.ActionHalt
    87  		}
    88  	}
    89  
    90  	errCh, err := d.CreateOrResetWindowsPassword(name, c.Zone, &data)
    91  
    92  	if err == nil {
    93  		ui.Message("Waiting for windows password to complete...")
    94  		select {
    95  		case err = <-errCh:
    96  		case <-time.After(c.stateTimeout):
    97  			err = errors.New("time out while waiting for the password to be created")
    98  		}
    99  	}
   100  
   101  	if err != nil {
   102  		err := fmt.Errorf("Error creating windows password: %s", err)
   103  		state.Put("error", err)
   104  		ui.Error(err.Error())
   105  		return multistep.ActionHalt
   106  	}
   107  
   108  	ui.Message("Created password.")
   109  
   110  	if s.Debug {
   111  		ui.Message(fmt.Sprintf(
   112  			"Password (since debug is enabled): %s", data.password))
   113  	}
   114  
   115  	state.Put("winrm_password", data.password)
   116  	commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName)
   117  
   118  	return multistep.ActionContinue
   119  }
   120  
   121  // Nothing to clean up. The windows password is only created on the single instance.
   122  func (s *StepCreateWindowsPassword) Cleanup(state multistep.StateBag) {}