in gke-windows-builder/builder/builder/gce.go [471:561]
func (s *Server) resetWindowsPassword(username string) (string, error) {
//Create random key and encode
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Printf("Failed to generate random RSA key: %v", err)
return "", err
}
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(key.E))
wpc := WindowsPasswordConfig{
key: key,
UserName: username,
Modulus: base64.StdEncoding.EncodeToString(key.N.Bytes()),
Exponent: base64.StdEncoding.EncodeToString(buf[1:]),
Email: "nobody@nowhere.com",
ExpireOn: time.Now().Add(time.Minute * 5),
}
data, err := json.Marshal(wpc)
dstring := string(data)
if err != nil {
log.Printf("Failed to marshal JSON: %v", err)
return "", err
}
//Write key to instance metadata and wait for op to complete
log.Print("Writing Windows instance metadata for password reset")
var found bool
for _, mdi := range s.instance.Metadata.Items {
if mdi.Key == "windows-keys" {
log.Print("Altering current key")
mdi.Value = &dstring
found = true
break
}
}
if !found {
s.instance.Metadata.Items = append(s.instance.Metadata.Items, &compute.MetadataItems{Key: "windows-keys", Value: &dstring})
}
op, err := s.service.Instances.SetMetadata(s.projectID, s.zone, s.instance.Name, &compute.Metadata{
Fingerprint: s.instance.Metadata.Fingerprint,
Items: s.instance.Metadata.Items,
}).Do()
if err != nil {
log.Printf("Failed to set instance metadata: %v", err)
return "", err
}
err = s.waitForComputeOperation(op)
if err != nil {
log.Printf("Compute operation timed out")
return "", err
}
//Read and decode password
log.Print("Waiting for Windows password response")
timeout := time.Now().Add(time.Minute * 5)
hash := sha1.New()
for time.Now().Before(timeout) {
output, err := s.service.Instances.GetSerialPortOutput(s.projectID, s.zone, s.instance.Name).Port(4).Do()
if err != nil {
log.Printf("Unable to get serial port output: %v", err)
return "", err
}
responses := strings.Split(output.Contents, "\n")
for _, response := range responses {
var wpr WindowsPasswordResponse
if err := json.Unmarshal([]byte(response), &wpr); err != nil {
log.Printf("Cannot Unmarshal password: %v", err)
continue
}
if wpr.Modulus == wpc.Modulus {
decodedPassword, err := base64.StdEncoding.DecodeString(wpr.EncryptedPassword)
if err != nil {
log.Printf("Cannot Base64 decode password: %v", err)
return "", err
}
password, err := rsa.DecryptOAEP(hash, rand.Reader, wpc.key, decodedPassword, nil)
if err != nil {
log.Printf("Cannot decrypt password response: %v", err)
return "", err
}
return string(password), nil
}
}
time.Sleep(2 * time.Second)
}
err = errors.New("Could not retrieve password before timeout")
return "", err
}