func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") keyFactory := func(pubKeyFile string, privKeyFile string) (*Keys, error) { var public ssh.PublicKey var private ssh.Signer var filename string = "" var generated bool = false if len(pubKeyFile) > 0 { pubKeyBytes, err := ioutil.ReadFile(pubKeyFile) if err != nil { return nil, errors.New("Failed to read public key") } public, _, _, _, err = ssh.ParseAuthorizedKey(pubKeyBytes) if err != nil { return nil, errors.New("Failed to parse authorized key") } } else { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, errors.New("Failed to generate key pair") } public, err = ssh.NewPublicKey(key.Public()) if err != nil { return nil, errors.New("Failed to extract public key from generated key pair") } // To support Ansible calling back to us we need to write // this file down privateKeyDer := x509.MarshalPKCS1PrivateKey(key) privateKeyBlock := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, Bytes: privateKeyDer, } tf, err := ioutil.TempFile("", "ansible-key") if err != nil { return nil, errors.New("failed to create temp file for generated key") } _, err = tf.Write(pem.EncodeToMemory(&privateKeyBlock)) if err != nil { return nil, errors.New("failed to write private key to temp file") } err = tf.Close() if err != nil { return nil, errors.New("failed to close private key temp file") } filename = tf.Name() } if len(privKeyFile) > 0 { privateBytes, err := ioutil.ReadFile(privKeyFile) if err != nil { return nil, errors.New("Failed to load private host key") } private, err = ssh.ParsePrivateKey(privateBytes) if err != nil { return nil, errors.New("Failed to parse private host key") } } else { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, errors.New("Failed to generate server key pair") } private, err = ssh.NewSignerFromKey(key) if err != nil { return nil, errors.New("Failed to extract private key from generated key pair") } generated = true } return &Keys{public, filename, private, generated}, nil } k, err := keyFactory(p.config.SSHAuthorizedKeyFile, p.config.SSHHostKeyFile) if err != nil { return err } // Remove the private key file if len(k.filename) > 0 { defer os.Remove(k.filename) } keyChecker := ssh.CertChecker{ UserKeyFallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) { if user := conn.User(); user != "packer-ansible" { ui.Say(fmt.Sprintf("%s is not a valid user", user)) return nil, errors.New("authentication failed") } if !bytes.Equal(k.public.Marshal(), pubKey.Marshal()) { ui.Say("unauthorized key") return nil, errors.New("authentication failed") } return nil, nil }, } config := &ssh.ServerConfig{ AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) { ui.Say(fmt.Sprintf("authentication attempt from %s to %s as %s using %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User(), method)) }, PublicKeyCallback: keyChecker.Authenticate, //NoClientAuth: true, } config.AddHostKey(k.private) localListener, err := func() (net.Listener, error) { port, err := strconv.ParseUint(p.config.LocalPort, 10, 16) if err != nil { return nil, err } tries := 1 if port != 0 { tries = 10 } for i := 0; i < tries; i++ { l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) port++ if err != nil { ui.Say(err.Error()) continue } _, p.config.LocalPort, err = net.SplitHostPort(l.Addr().String()) if err != nil { ui.Say(err.Error()) continue } return l, nil } return nil, errors.New("Error setting up SSH proxy connection") }() if err != nil { return err } ui = newUi(ui) p.adapter = newAdapter(p.done, localListener, config, p.config.SFTPCmd, ui, comm) defer func() { ui.Say("shutting down the SSH proxy") close(p.done) p.adapter.Shutdown() }() go p.adapter.Serve() if len(p.config.inventoryFile) == 0 { tf, err := ioutil.TempFile("", "packer-provisioner-ansible") if err != nil { return fmt.Errorf("Error preparing inventory file: %s", err) } defer os.Remove(tf.Name()) inv := fmt.Sprintf("default ansible_ssh_host=127.0.0.1 ansible_ssh_user=packer-ansible ansible_ssh_port=%s", p.config.LocalPort) _, err = tf.Write([]byte(inv)) if err != nil { tf.Close() return fmt.Errorf("Error preparing inventory file: %s", err) } tf.Close() p.config.inventoryFile = tf.Name() defer func() { p.config.inventoryFile = "" }() } if err := p.executeAnsible(ui, comm, k.filename, k.generated); err != nil { return fmt.Errorf("Error executing Ansible: %s", err) } return nil }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") k, err := newUserKey(p.config.SSHAuthorizedKeyFile) if err != nil { return err } hostSigner, err := newSigner(p.config.SSHHostKeyFile) // Remove the private key file if len(k.privKeyFile) > 0 { defer os.Remove(k.privKeyFile) } keyChecker := ssh.CertChecker{ UserKeyFallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) { if user := conn.User(); user != p.config.User { ui.Say(fmt.Sprintf("%s is not a valid user", user)) return nil, errors.New("authentication failed") } if !bytes.Equal(k.Marshal(), pubKey.Marshal()) { ui.Say("unauthorized key") return nil, errors.New("authentication failed") } return nil, nil }, } config := &ssh.ServerConfig{ AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) { ui.Say(fmt.Sprintf("authentication attempt from %s to %s as %s using %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User(), method)) }, PublicKeyCallback: keyChecker.Authenticate, //NoClientAuth: true, } config.AddHostKey(hostSigner) localListener, err := func() (net.Listener, error) { port, err := strconv.ParseUint(p.config.LocalPort, 10, 16) if err != nil { return nil, err } tries := 1 if port != 0 { tries = 10 } for i := 0; i < tries; i++ { l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) port++ if err != nil { ui.Say(err.Error()) continue } _, p.config.LocalPort, err = net.SplitHostPort(l.Addr().String()) if err != nil { ui.Say(err.Error()) continue } return l, nil } return nil, errors.New("Error setting up SSH proxy connection") }() if err != nil { return err } ui = newUi(ui) p.adapter = newAdapter(p.done, localListener, config, p.config.SFTPCmd, ui, comm) defer func() { ui.Say("shutting down the SSH proxy") close(p.done) p.adapter.Shutdown() }() go p.adapter.Serve() if len(p.config.inventoryFile) == 0 { tf, err := ioutil.TempFile("", "packer-provisioner-ansible") if err != nil { return fmt.Errorf("Error preparing inventory file: %s", err) } defer os.Remove(tf.Name()) host := fmt.Sprintf("%s ansible_host=127.0.0.1 ansible_user=%s ansible_port=%s\n", p.config.HostAlias, p.config.User, p.config.LocalPort) if p.ansibleMajVersion < 2 { host = fmt.Sprintf("%s ansible_ssh_host=127.0.0.1 ansible_ssh_user=%s ansible_ssh_port=%s\n", p.config.HostAlias, p.config.User, p.config.LocalPort) } w := bufio.NewWriter(tf) w.WriteString(host) for _, group := range p.config.Groups { fmt.Fprintf(w, "[%s]\n%s", group, host) } for _, group := range p.config.EmptyGroups { fmt.Fprintf(w, "[%s]\n", group) } if err := w.Flush(); err != nil { tf.Close() return fmt.Errorf("Error preparing inventory file: %s", err) } tf.Close() p.config.inventoryFile = tf.Name() defer func() { p.config.inventoryFile = "" }() } if err := p.executeAnsible(ui, comm, k.privKeyFile, !hostSigner.generated); err != nil { return fmt.Errorf("Error executing Ansible: %s", err) } return nil }
func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say("Provisioning with Ansible...") pubKeyBytes, err := ioutil.ReadFile(p.config.SSHAuthorizedKeyFile) if err != nil { return errors.New("Failed to load authorized key file") } public, _, _, _, err := ssh.ParseAuthorizedKey(pubKeyBytes) if err != nil { return errors.New("Failed to parse authorized key") } keyChecker := ssh.CertChecker{ UserKeyFallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) { if user := conn.User(); user != "packer-ansible" { ui.Say(fmt.Sprintf("%s is not a valid user", user)) return nil, errors.New("authentication failed") } if !bytes.Equal(public.Marshal(), pubKey.Marshal()) { ui.Say("unauthorized key") return nil, errors.New("authentication failed") } return nil, nil }, } config := &ssh.ServerConfig{ AuthLogCallback: func(conn ssh.ConnMetadata, method string, err error) { ui.Say(fmt.Sprintf("authentication attempt from %s to %s as %s using %s", conn.RemoteAddr(), conn.LocalAddr(), conn.User(), method)) }, PublicKeyCallback: keyChecker.Authenticate, //NoClientAuth: true, } privateBytes, err := ioutil.ReadFile(p.config.SSHHostKeyFile) if err != nil { return errors.New("Failed to load private host key") } private, err := ssh.ParsePrivateKey(privateBytes) if err != nil { return errors.New("Failed to parse private host key") } config.AddHostKey(private) localListener, err := func() (net.Listener, error) { port, _ := strconv.ParseUint(p.config.LocalPort, 10, 16) if port == 0 { port = 2200 } for i := 0; i < 10; i++ { port++ l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port)) if err == nil { p.config.LocalPort = strconv.FormatUint(port, 10) return l, nil } ui.Say(err.Error()) } return nil, errors.New("Error setting up SSH proxy connection") }() if err != nil { return err } ui = newUi(ui) p.adapter = newAdapter(p.done, localListener, config, p.config.SFTPCmd, ui, comm) defer func() { ui.Say("shutting down the SSH proxy") close(p.done) p.adapter.Shutdown() }() go p.adapter.Serve() if len(p.config.inventoryFile) == 0 { tf, err := ioutil.TempFile("", "packer-provisioner-ansible") if err != nil { return fmt.Errorf("Error preparing inventory file: %s", err) } defer os.Remove(tf.Name()) inv := fmt.Sprintf("default ansible_ssh_host=127.0.0.1 ansible_ssh_user=packer-ansible ansible_ssh_port=%s", p.config.LocalPort) _, err = tf.Write([]byte(inv)) if err != nil { tf.Close() return fmt.Errorf("Error preparing inventory file: %s", err) } tf.Close() p.config.inventoryFile = tf.Name() defer func() { p.config.inventoryFile = "" }() } if err := p.executeAnsible(ui); err != nil { return fmt.Errorf("Error executing Ansible: %s", err) } return nil }