github.phpd.cn/hashicorp/packer@v1.3.2/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  		packer.LogSecretFilter.Set(c.Comm.WinRMPassword)
    37  		return multistep.ActionContinue
    38  	}
    39  
    40  	create, ok := state.GetOk("create_windows_password")
    41  
    42  	if !ok || !create.(bool) {
    43  		return multistep.ActionContinue
    44  
    45  	}
    46  	ui.Say("Creating windows user for instance...")
    47  	priv, err := rsa.GenerateKey(rand.Reader, 2048)
    48  	if err != nil {
    49  		err := fmt.Errorf("Error creating temporary key: %s", err)
    50  		state.Put("error", err)
    51  		ui.Error(err.Error())
    52  		return multistep.ActionHalt
    53  	}
    54  
    55  	buf := make([]byte, 4)
    56  	binary.BigEndian.PutUint32(buf, uint32(priv.E))
    57  
    58  	data := WindowsPasswordConfig{
    59  		key:      priv,
    60  		UserName: c.Comm.WinRMUser,
    61  		Modulus:  base64.StdEncoding.EncodeToString(priv.N.Bytes()),
    62  		Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
    63  		Email:    c.Account.ClientEmail,
    64  		ExpireOn: time.Now().Add(time.Minute * 5),
    65  	}
    66  
    67  	if s.Debug {
    68  
    69  		priv_blk := pem.Block{
    70  			Type:    "RSA PRIVATE KEY",
    71  			Headers: nil,
    72  			Bytes:   x509.MarshalPKCS1PrivateKey(priv),
    73  		}
    74  
    75  		ui.Message(fmt.Sprintf("Saving key for debug purposes: %s", s.DebugKeyPath))
    76  		f, err := os.Create(s.DebugKeyPath)
    77  		if err != nil {
    78  			state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
    79  			return multistep.ActionHalt
    80  		}
    81  
    82  		// Write out the key
    83  		err = pem.Encode(f, &priv_blk)
    84  		f.Close()
    85  		if err != nil {
    86  			state.Put("error", fmt.Errorf("Error saving debug key: %s", err))
    87  			return multistep.ActionHalt
    88  		}
    89  	}
    90  
    91  	errCh, err := d.CreateOrResetWindowsPassword(name, c.Zone, &data)
    92  
    93  	if err == nil {
    94  		ui.Message("Waiting for windows password to complete...")
    95  		select {
    96  		case err = <-errCh:
    97  		case <-time.After(c.stateTimeout):
    98  			err = errors.New("time out while waiting for the password to be created")
    99  		}
   100  	}
   101  
   102  	if err != nil {
   103  		err := fmt.Errorf("Error creating windows password: %s", err)
   104  		state.Put("error", err)
   105  		ui.Error(err.Error())
   106  		return multistep.ActionHalt
   107  	}
   108  
   109  	ui.Message("Created password.")
   110  
   111  	if s.Debug {
   112  		ui.Message(fmt.Sprintf(
   113  			"Password (since debug is enabled): %s", data.password))
   114  	}
   115  
   116  	state.Put("winrm_password", data.password)
   117  	commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName)
   118  	packer.LogSecretFilter.Set(data.password)
   119  
   120  	return multistep.ActionContinue
   121  }
   122  
   123  // Nothing to clean up. The windows password is only created on the single instance.
   124  func (s *StepCreateWindowsPassword) Cleanup(state multistep.StateBag) {}