Merge pull request #2754 from mitchellh/f-insert-private-key
Support password-based SSH, automatically insert insecure key
This commit is contained in:
commit
0f989ce554
|
@ -28,11 +28,15 @@ module Vagrant
|
|||
# not yet ready for SSH, so we raise this exception.
|
||||
raise Errors::SSHNotReady if info.nil?
|
||||
|
||||
if info[:private_key_path]
|
||||
# Check SSH key permissions
|
||||
info[:private_key_path].each do |path|
|
||||
SSH.check_key_permissions(Pathname.new(path))
|
||||
end
|
||||
info[:private_key_path] ||= []
|
||||
|
||||
# Check SSH key permissions
|
||||
info[:private_key_path].each do |path|
|
||||
SSH.check_key_permissions(Pathname.new(path))
|
||||
end
|
||||
|
||||
if info[:private_key_path].empty? && info[:password]
|
||||
env[:ui].warn(I18n.t("vagrant.ssh_exec_password"))
|
||||
end
|
||||
|
||||
# Exec!
|
||||
|
|
|
@ -26,11 +26,15 @@ module Vagrant
|
|||
# not yet ready for SSH, so we raise this exception.
|
||||
raise Errors::SSHNotReady if info.nil?
|
||||
|
||||
if info[:private_key_path]
|
||||
# Check SSH key permissions
|
||||
info[:private_key_path].each do |path|
|
||||
SSH.check_key_permissions(Pathname.new(path))
|
||||
end
|
||||
info[:private_key_path] ||= []
|
||||
|
||||
# Check SSH key permissions
|
||||
info[:private_key_path].each do |path|
|
||||
SSH.check_key_permissions(Pathname.new(path))
|
||||
end
|
||||
|
||||
if info[:private_key_path].empty?
|
||||
raise Errors::SSHRunRequiresKeys
|
||||
end
|
||||
|
||||
# Get the command and wrap it in a login shell
|
||||
|
|
|
@ -56,6 +56,10 @@ module Vagrant
|
|||
return if env[:interrupted]
|
||||
end
|
||||
|
||||
# Join so that they can raise exceptions if there were any
|
||||
ready_thr.join if !ready_thr.alive?
|
||||
states_thr.join if !states_thr.alive?
|
||||
|
||||
# If it went into a bad state, then raise an error
|
||||
if !states_thr[:result]
|
||||
raise Errors::VMBootBadState,
|
||||
|
|
|
@ -532,6 +532,10 @@ module Vagrant
|
|||
error_key(:ssh_port_not_detected)
|
||||
end
|
||||
|
||||
class SSHRunRequiresKeys < VagrantError
|
||||
error_key(:ssh_run_requires_keys)
|
||||
end
|
||||
|
||||
class SSHUnavailable < VagrantError
|
||||
error_key(:ssh_unavailable)
|
||||
end
|
||||
|
|
|
@ -280,6 +280,7 @@ module Vagrant
|
|||
info[:host] = @config.ssh.host if @config.ssh.host
|
||||
info[:port] = @config.ssh.port if @config.ssh.port
|
||||
info[:username] = @config.ssh.username if @config.ssh.username
|
||||
info[:password] = @config.ssh.password if @config.ssh.password
|
||||
|
||||
# We also set some fields that are purely controlled by Varant
|
||||
info[:forward_agent] = @config.ssh.forward_agent
|
||||
|
@ -291,7 +292,7 @@ module Vagrant
|
|||
# Set the private key path. If a specific private key is given in
|
||||
# the Vagrantfile we set that. Otherwise, we use the default (insecure)
|
||||
# private key, but only if the provider didn't give us one.
|
||||
if !info[:private_key_path]
|
||||
if !info[:private_key_path] && !info[:password]
|
||||
if @config.ssh.private_key_path
|
||||
info[:private_key_path] = @config.ssh.private_key_path
|
||||
else
|
||||
|
@ -299,7 +300,14 @@ module Vagrant
|
|||
end
|
||||
end
|
||||
|
||||
# If we have a private key in our data dir, then use that
|
||||
data_private_key = @data_dir.join("private_key")
|
||||
if data_private_key.file?
|
||||
info[:private_key_path] = [data_private_key.to_s]
|
||||
end
|
||||
|
||||
# Setup the keys
|
||||
info[:private_key_path] ||= []
|
||||
if !info[:private_key_path].is_a?(Array)
|
||||
info[:private_key_path] = [info[:private_key_path]]
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'logger'
|
||||
require 'pathname'
|
||||
require 'stringio'
|
||||
require 'thread'
|
||||
require 'timeout'
|
||||
|
||||
require 'log4r'
|
||||
|
@ -27,25 +28,58 @@ module VagrantPlugins
|
|||
end
|
||||
|
||||
def initialize(machine)
|
||||
@lock = Mutex.new
|
||||
@machine = machine
|
||||
@logger = Log4r::Logger.new("vagrant::communication::ssh")
|
||||
@connection = nil
|
||||
@inserted_key = false
|
||||
end
|
||||
|
||||
def ready?
|
||||
@logger.debug("Checking whether SSH is ready...")
|
||||
|
||||
# Attempt to connect. This will raise an exception if it fails.
|
||||
connect
|
||||
begin
|
||||
connect
|
||||
@logger.info("SSH is ready!")
|
||||
rescue Vagrant::Errors::VagrantError => e
|
||||
# We catch a `VagrantError` which would signal that something went
|
||||
# wrong expectedly in the `connect`, which means we didn't connect.
|
||||
@logger.info("SSH not up: #{e.inspect}")
|
||||
return false
|
||||
end
|
||||
|
||||
# If we're already attempting to switch out the SSH key, then
|
||||
# just return that we're ready (for Machine#guest).
|
||||
@lock.synchronize do
|
||||
return true if @inserted_key || !@machine.config.ssh.insert_key
|
||||
@inserted_key = true
|
||||
end
|
||||
|
||||
# If we used a password, then insert the insecure key
|
||||
ssh_info = @machine.ssh_info
|
||||
if ssh_info[:password] && ssh_info[:private_key_path].empty?
|
||||
@logger.info("Inserting insecure key to avoid password")
|
||||
@machine.ui.info(I18n.t("vagrant.inserting_insecure_key"))
|
||||
@machine.guest.capability(
|
||||
:insert_public_key,
|
||||
Vagrant.source_root.join("keys", "vagrant.pub").read)
|
||||
|
||||
# Write out the private key in the data dir so that the
|
||||
# machine automatically picks it up.
|
||||
@machine.data_dir.join("private_key").open("w+") do |f|
|
||||
f.write(Vagrant.source_root.join("keys", "vagrant").read)
|
||||
end
|
||||
|
||||
@machine.ui.info(I18n.t("vagrant.inserted_key"))
|
||||
@connection.close
|
||||
@connection = nil
|
||||
|
||||
return ready?
|
||||
end
|
||||
|
||||
# If we reached this point then we successfully connected
|
||||
@logger.info("SSH is ready!")
|
||||
true
|
||||
rescue Vagrant::Errors::VagrantError => e
|
||||
# We catch a `VagrantError` which would signal that something went
|
||||
# wrong expectedly in the `connect`, which means we didn't connect.
|
||||
@logger.info("SSH not up: #{e.inspect}")
|
||||
return false
|
||||
end
|
||||
|
||||
def execute(command, opts=nil, &block)
|
||||
|
@ -170,6 +204,7 @@ module VagrantPlugins
|
|||
:keys => ssh_info[:private_key_path],
|
||||
:keys_only => true,
|
||||
:paranoid => false,
|
||||
:password => ssh_info[:password],
|
||||
:port => ssh_info[:port],
|
||||
:user_known_hosts_file => []
|
||||
}
|
||||
|
@ -222,6 +257,7 @@ module VagrantPlugins
|
|||
@logger.info(" - Host: #{ssh_info[:host]}")
|
||||
@logger.info(" - Port: #{ssh_info[:port]}")
|
||||
@logger.info(" - Username: #{ssh_info[:username]}")
|
||||
@logger.info(" - Password? #{!!ssh_info[:password]}")
|
||||
@logger.info(" - Key Path: #{ssh_info[:private_key_path]}")
|
||||
|
||||
Net::SSH.start(ssh_info[:host], ssh_info[:username], connect_opts)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
module VagrantPlugins
|
||||
module GuestLinux
|
||||
module Cap
|
||||
class InsertPublicKey
|
||||
def self.insert_public_key(machine, contents)
|
||||
machine.communicate.tap do |comm|
|
||||
comm.execute("echo #{contents} > /tmp/key.pub")
|
||||
comm.execute("mkdir -p ~/.ssh")
|
||||
comm.execute("chmod 0700 ~/.ssh")
|
||||
comm.execute("cat /tmp/key.pub >> ~/.ssh/authorized_keys")
|
||||
comm.execute("chmod 0600 ~/.ssh/authorized_keys")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -16,6 +16,11 @@ module VagrantPlugins
|
|||
Cap::Halt
|
||||
end
|
||||
|
||||
guest_capability("linux", "insert_public_key") do
|
||||
require_relative "cap/insert_public_key"
|
||||
Cap::InsertPublicKey
|
||||
end
|
||||
|
||||
guest_capability("linux", "shell_expand_guest_path") do
|
||||
require_relative "cap/shell_expand_guest_path"
|
||||
Cap::ShellExpandGuestPath
|
||||
|
|
|
@ -5,12 +5,16 @@ module VagrantPlugins
|
|||
attr_accessor :port
|
||||
attr_accessor :private_key_path
|
||||
attr_accessor :username
|
||||
attr_accessor :password
|
||||
attr_accessor :insert_key
|
||||
|
||||
def initialize
|
||||
@host = UNSET_VALUE
|
||||
@port = UNSET_VALUE
|
||||
@private_key_path = UNSET_VALUE
|
||||
@username = UNSET_VALUE
|
||||
@password = UNSET_VALUE
|
||||
@insert_key = UNSET_VALUE
|
||||
end
|
||||
|
||||
def finalize!
|
||||
|
@ -18,6 +22,8 @@ module VagrantPlugins
|
|||
@port = nil if @port == UNSET_VALUE
|
||||
@private_key_path = nil if @private_key_path == UNSET_VALUE
|
||||
@username = nil if @username == UNSET_VALUE
|
||||
@password = nil if @password == UNSET_VALUE
|
||||
@insert_key = true if @insert_key == UNSET_VALUE
|
||||
|
||||
if @private_key_path && !@private_key_path.is_a?(Array)
|
||||
@private_key_path = [@private_key_path]
|
||||
|
|
|
@ -58,6 +58,10 @@ en:
|
|||
docker_install_with_version_not_supported: |-
|
||||
Vagrant is not capable of installing an specific version of Docker
|
||||
onto the guest machine and the latest version will be installed.
|
||||
inserted_key: |-
|
||||
Key inserted! Disconnecting and reconnecting using new SSH key...
|
||||
inserting_insecure_key: |-
|
||||
Inserting Vagrant public key within guest...
|
||||
plugin_needs_reinstall: |-
|
||||
The following plugins were installed with a version of Vagrant
|
||||
that had different versions of underlying components. Because
|
||||
|
@ -77,6 +81,11 @@ en:
|
|||
%{names}
|
||||
provisioner_cleanup: |-
|
||||
Running cleanup tasks for '%{name}' provisioner...
|
||||
ssh_exec_password: |-
|
||||
The machine you're attempting to SSH into is configured to use
|
||||
password-based authentication. Vagrant can't script entering the
|
||||
password for you. If you're prompted for a password, please enter
|
||||
the same password you have configured in the Vagrantfile.
|
||||
|
||||
cfengine_config:
|
||||
classes_array: |-
|
||||
|
@ -641,6 +650,15 @@ en:
|
|||
|
||||
Please make sure that you have a forwarded port that goes to the configured
|
||||
guest port value, or specify an explicit SSH port with `config.ssh.port`.
|
||||
ssh_run_requires_keys: |-
|
||||
Using `vagrant ssh -c` requires key-based SSH authentication, but your
|
||||
Vagrant environmet is configured to use only password-based authentication.
|
||||
Please configure your Vagrantfile with a private key to use this
|
||||
feature.
|
||||
|
||||
Note that Vagrant can automatically insert a keypair and use that
|
||||
keypair for you. Just set `config.ssh.insert_key = true` in your
|
||||
Vagrantfile.
|
||||
ssh_unavailable: "`ssh` binary could not be found. Is an SSH client installed?"
|
||||
ssh_unavailable_windows: |-
|
||||
`ssh` executable not found in any directories in the %PATH% variable. Is an
|
||||
|
|
|
@ -279,7 +279,7 @@ describe Vagrant::Machine do
|
|||
let(:provider_ssh_info) { {} }
|
||||
|
||||
before(:each) do
|
||||
provider.should_receive(:ssh_info).and_return(provider_ssh_info)
|
||||
provider.stub(:ssh_info).and_return(provider_ssh_info)
|
||||
end
|
||||
|
||||
[:host, :port, :username].each do |type|
|
||||
|
@ -373,6 +373,29 @@ describe Vagrant::Machine do
|
|||
instance.ssh_info[:private_key_path].should ==
|
||||
[instance.env.default_private_key_path.to_s]
|
||||
end
|
||||
|
||||
it "should not set any default private keys if a password is specified" do
|
||||
provider_ssh_info[:private_key_path] = nil
|
||||
instance.config.ssh.private_key_path = nil
|
||||
instance.config.ssh.password = ""
|
||||
|
||||
expect(instance.ssh_info[:private_key_path]).to be_empty
|
||||
expect(instance.ssh_info[:password]).to eql("")
|
||||
end
|
||||
|
||||
it "should return the private key in the data dir above all else" do
|
||||
provider_ssh_info[:private_key_path] = nil
|
||||
instance.config.ssh.private_key_path = nil
|
||||
instance.config.ssh.password = ""
|
||||
|
||||
instance.data_dir.join("private_key").open("w+") do |f|
|
||||
f.write("hey")
|
||||
end
|
||||
|
||||
expect(instance.ssh_info[:private_key_path]).to eql(
|
||||
[instance.data_dir.join("private_key").to_s])
|
||||
expect(instance.ssh_info[:password]).to eql("")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -20,6 +20,14 @@ public boxes are made as.
|
|||
|
||||
<hr>
|
||||
|
||||
`config.ssh.password` - This sets a password that Vagrant will use to
|
||||
authenticate the SSH user. Note that Vagrant recommends you use key-based
|
||||
authentiation rather than a password (see `private_key_path`) below. If
|
||||
you use a password, Vagrant will automatically insert a keypair if
|
||||
`insert_key` is true.
|
||||
|
||||
<hr>
|
||||
|
||||
`config.ssh.host` - The hostname or IP to SSH into. By default this is
|
||||
empty, because the provider usually figures this out for you.
|
||||
|
||||
|
@ -59,6 +67,12 @@ is enabled. Defaults to false.
|
|||
|
||||
<hr>
|
||||
|
||||
`config.ssh.insert_key` - If `true`, Vagrant will automatically insert
|
||||
an insecure keypair to use for SSH. By default, this is true. This only
|
||||
has an effect if you don't already use private keys for authentication.
|
||||
|
||||
<hr>
|
||||
|
||||
`config.ssh.shell` - The shell to use when executing SSH commands from
|
||||
Vagrant. By default this is `bash -l`. Note that this has no effect on
|
||||
the shell you get when you run `vagrant ssh`. This configuration option
|
||||
|
|
Loading…
Reference in New Issue