예제 #1
0
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

}
예제 #2
0
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
}
예제 #3
0
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
}