Merge pull request #7703 from chrisroberts/cleanup/ssh_agent_2

ssh-agent interaction fix
This commit is contained in:
Chris Roberts 2016-08-11 13:17:22 -07:00 committed by GitHub
commit 55223e30e5
12 changed files with 169 additions and 21 deletions

1
.gitignore vendored
View File

@ -41,6 +41,7 @@ doc/
# Ruby Managers # Ruby Managers
.rbenv .rbenv
.rbenv-gemsets
.ruby-gemset .ruby-gemset
.ruby-version .ruby-version
.rvmrc .rvmrc

View File

@ -30,7 +30,7 @@ module Vagrant
info[:private_key_path] ||= [] info[:private_key_path] ||= []
if info[:private_key_path].empty? if info[:keys_only] && info[:private_key_path].empty?
raise Errors::SSHRunRequiresKeys raise Errors::SSHRunRequiresKeys
end end

View File

@ -443,6 +443,8 @@ module Vagrant
# provider-returned data. # provider-returned data.
info[:host] = @config.ssh.host if @config.ssh.host info[:host] = @config.ssh.host if @config.ssh.host
info[:port] = @config.ssh.port if @config.ssh.port info[:port] = @config.ssh.port if @config.ssh.port
info[:keys_only] = @config.ssh.keys_only
info[:paranoid] = @config.ssh.paranoid
info[:username] = @config.ssh.username if @config.ssh.username info[:username] = @config.ssh.username if @config.ssh.username
info[:password] = @config.ssh.password if @config.ssh.password info[:password] = @config.ssh.password if @config.ssh.password
@ -462,7 +464,7 @@ module Vagrant
if !info[:private_key_path] && !info[:password] if !info[:private_key_path] && !info[:password]
if @config.ssh.private_key_path if @config.ssh.private_key_path
info[:private_key_path] = @config.ssh.private_key_path info[:private_key_path] = @config.ssh.private_key_path
else elsif info[:keys_only]
info[:private_key_path] = @env.default_private_key_path info[:private_key_path] = @env.default_private_key_path
end end
end end

View File

@ -109,19 +109,25 @@ module Vagrant
"-p", options[:port].to_s, "-p", options[:port].to_s,
"-o", "Compression=yes", "-o", "Compression=yes",
"-o", "DSAAuthentication=yes", "-o", "DSAAuthentication=yes",
"-o", "LogLevel=#{log_level}", "-o", "LogLevel=#{log_level}"]
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null"]
# Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the # Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the
# IdentitiesOnly option. Also, we don't enable it in plain mode so # IdentitiesOnly option. Also, we don't enable it in plain mode or if
# that SSH properly searches our identities and tries to do it itself. # if keys_only is false so that SSH and Net::SSH properly search our identities
if !Platform.solaris? && !plain_mode # and tries to do it itself.
if !Platform.solaris? && !plain_mode && ssh_info[:keys_only]
command_options += ["-o", "IdentitiesOnly=yes"] command_options += ["-o", "IdentitiesOnly=yes"]
end end
# If we're not in plain mode, attach the private key path. # no strict hostkey checking unless paranoid
if !plain_mode if ! ssh_info[:paranoid]
command_options += [
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null"]
end
# If we're not in plain mode and :private_key_path is set attach the private key path(s).
if !plain_mode && options[:private_key_path]
options[:private_key_path].each do |path| options[:private_key_path].each do |path|
command_options += ["-i", path.to_s] command_options += ["-i", path.to_s]
end end

View File

@ -37,7 +37,10 @@ module VagrantPlugins
ssh_host: ssh_info[:host], ssh_host: ssh_info[:host],
ssh_port: ssh_info[:port], ssh_port: ssh_info[:port],
ssh_user: ssh_info[:username], ssh_user: ssh_info[:username],
keys_only: ssh_info[:keys_only],
paranoid: ssh_info[:paranoid],
private_key_path: ssh_info[:private_key_path], private_key_path: ssh_info[:private_key_path],
log_level: ssh_info[:log_level],
forward_agent: ssh_info[:forward_agent], forward_agent: ssh_info[:forward_agent],
forward_x11: ssh_info[:forward_x11], forward_x11: ssh_info[:forward_x11],
proxy_command: ssh_info[:proxy_command], proxy_command: ssh_info[:proxy_command],

View File

@ -334,7 +334,6 @@ module VagrantPlugins
config: false, config: false,
forward_agent: ssh_info[:forward_agent], forward_agent: ssh_info[:forward_agent],
send_env: ssh_info[:forward_env], send_env: ssh_info[:forward_env],
keys: ssh_info[:private_key_path],
keys_only: ssh_info[:keys_only], keys_only: ssh_info[:keys_only],
paranoid: ssh_info[:paranoid], paranoid: ssh_info[:paranoid],
password: ssh_info[:password], password: ssh_info[:password],
@ -375,6 +374,10 @@ module VagrantPlugins
connect_opts = common_connect_opts.dup connect_opts = common_connect_opts.dup
connect_opts[:logger] = ssh_logger connect_opts[:logger] = ssh_logger
if ssh_info[:private_key_path]
connect_opts[:keys] = ssh_info[:private_key_path]
end
if ssh_info[:proxy_command] if ssh_info[:proxy_command]
connect_opts[:proxy] = Net::SSH::Proxy::Command.new(ssh_info[:proxy_command]) connect_opts[:proxy] = Net::SSH::Proxy::Command.new(ssh_info[:proxy_command])
end end
@ -385,6 +388,7 @@ module VagrantPlugins
@logger.info(" - Username: #{ssh_info[:username]}") @logger.info(" - Username: #{ssh_info[:username]}")
@logger.info(" - Password? #{!!ssh_info[:password]}") @logger.info(" - Password? #{!!ssh_info[:password]}")
@logger.info(" - Key Path: #{ssh_info[:private_key_path]}") @logger.info(" - Key Path: #{ssh_info[:private_key_path]}")
@logger.debug(" - connect_opts: #{connect_opts}")
Net::SSH.start(ssh_info[:host], ssh_info[:username], connect_opts) Net::SSH.start(ssh_info[:host], ssh_info[:username], connect_opts)
ensure ensure

View File

@ -63,7 +63,11 @@ module VagrantPlugins
opts[:owner] ||= ssh_info[:username] opts[:owner] ||= ssh_info[:username]
opts[:group] ||= ssh_info[:username] opts[:group] ||= ssh_info[:username]
# set log level
log_level = ssh_info[:log_level] || "FATAL"
# Connection information # Connection information
# make it better match lib/vagrant/util/ssh.rb command_options style and logic
username = ssh_info[:username] username = ssh_info[:username]
host = ssh_info[:host] host = ssh_info[:host]
proxy_command = "" proxy_command = ""
@ -80,15 +84,32 @@ module VagrantPlugins
control_options = "-o ControlMaster=auto -o ControlPath=#{controlpath} -o ControlPersist=10m " control_options = "-o ControlMaster=auto -o ControlPath=#{controlpath} -o ControlPersist=10m "
end end
# rsh cmd option
rsh = [ rsh = [
"ssh -p #{ssh_info[:port]} " + "ssh", "-p", "#{ssh_info[:port]}",
proxy_command + "-o", "LogLevel=#{log_level}",
control_options + proxy_command,
"-o StrictHostKeyChecking=no " + control_options,
"-o IdentitiesOnly=true " + ]
"-o UserKnownHostsFile=/dev/null",
ssh_info[:private_key_path].map { |p| "-i '#{p}'" }, # Solaris/OpenSolaris/Illumos uses SunSSH which doesn't support the
].flatten.join(" ") # IdentitiesOnly option. Also, we don't enable it if keys_only is false
# so that SSH properly searches our identities and tries to do it itself.
if !Vagrant::Util::Platform.solaris? && ssh_info[:keys_only]
rsh += ["-o", "IdentitiesOnly=yes"]
end
# no strict hostkey checking unless paranoid
if ! ssh_info[:paranoid]
rsh += [
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null"]
end
# If specified, attach the private key paths.
if ssh_info[:private_key_path]
rsh += ssh_info[:private_key_path].map { |p| "-i '#{p}'" }
end
# Exclude some files by default, and any that might be configured # Exclude some files by default, and any that might be configured
# by the user. # by the user.
@ -130,7 +151,7 @@ module VagrantPlugins
command = [ command = [
"rsync", "rsync",
args, args,
"-e", rsh, "-e", rsh.flatten.join(" "),
excludes.map { |e| ["--exclude", e] }, excludes.map { |e| ["--exclude", e] },
hostpath, hostpath,
"#{username}@#{host}:#{guestpath}", "#{username}@#{host}:#{guestpath}",

View File

@ -2,9 +2,12 @@ Host <%= host_key %>
HostName <%= ssh_host %> HostName <%= ssh_host %>
User <%= ssh_user %> User <%= ssh_user %>
Port <%= ssh_port %> Port <%= ssh_port %>
<% if ! paranoid -%>
UserKnownHostsFile /dev/null UserKnownHostsFile /dev/null
StrictHostKeyChecking no StrictHostKeyChecking no
<% end -%>
PasswordAuthentication no PasswordAuthentication no
<% if private_key_path -%>
<% private_key_path.each do |path| %> <% private_key_path.each do |path| %>
<% if path.include?(" ") -%> <% if path.include?(" ") -%>
IdentityFile "<%= path %>" IdentityFile "<%= path %>"
@ -12,8 +15,15 @@ Host <%= host_key %>
IdentityFile <%= path %> IdentityFile <%= path %>
<% end -%> <% end -%>
<% end -%> <% end -%>
<% end -%>
<% if keys_only -%>
IdentitiesOnly yes IdentitiesOnly yes
<% end -%>
<% if log_level -%>
LogLevel <%= log_level %>
<% else -%>
LogLevel FATAL LogLevel FATAL
<% end -%>
<% if forward_agent -%> <% if forward_agent -%>
ForwardAgent yes ForwardAgent yes
<% end -%> <% end -%>

View File

@ -22,6 +22,8 @@ describe VagrantPlugins::CommandSSHConfig::Command do
host: "testhost.vagrant.dev", host: "testhost.vagrant.dev",
port: 1234, port: 1234,
username: "testuser", username: "testuser",
keys_only: true,
paranoid: false,
private_key_path: [], private_key_path: [],
forward_agent: false, forward_agent: false,
forward_x11: false forward_x11: false
@ -107,5 +109,32 @@ Host #{machine.name}
expect(output).to include('IdentityFile "with a space"') expect(output).to include('IdentityFile "with a space"')
end end
it "omits IdentitiesOnly when keys_only is false" do
allow(machine).to receive(:ssh_info) { ssh_info.merge(keys_only: false) }
output = ""
allow(subject).to receive(:safe_puts) do |data|
output += data if data
end
subject.execute
expect(output).not_to include('IdentitiesOnly')
end
it "omits StrictHostKeyChecking and UserKnownHostsFile when paranoid is true" do
allow(machine).to receive(:ssh_info) { ssh_info.merge(paranoid: true) }
output = ""
allow(subject).to receive(:safe_puts) do |data|
output += data if data
end
subject.execute
expect(output).not_to include('StrictHostKeyChecking ')
expect(output).not_to include('UserKnownHostsFile ')
end
end end
end end

View File

@ -213,4 +213,59 @@ describe VagrantPlugins::SyncedFolderRSync::RsyncHelper do
end end
end end
end end
describe "#rsync_single with custom ssh_info" do
let(:result) { Vagrant::Util::Subprocess::Result.new(0, "", "") }
let(:ssh_info) {{
:private_key_path => ['/path/to/key'],
:keys_only => true,
:paranoid => false,
}}
let(:opts) {{
hostpath: "/foo",
}}
let(:ui) { machine.ui }
before do
Vagrant::Util::Subprocess.stub(execute: result)
guest.stub(capability?: false)
end
it "includes IdentitiesOnly, StrictHostKeyChecking, and UserKnownHostsFile with defaults" do
expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args|
expect(args[9]).to include('IdentitiesOnly')
expect(args[9]).to include('StrictHostKeyChecking')
expect(args[9]).to include('UserKnownHostsFile')
expect(args[9]).to include("-i '/path/to/key'")
}
subject.rsync_single(machine, ssh_info, opts)
end
it "omits IdentitiesOnly with keys_only = false" do
ssh_info[:keys_only] = false
Vagrant::Util::Subprocess.should_receive(:execute) do |*args|
expect(args[9]).not_to include('IdentitiesOnly')
result
end
subject.rsync_single(machine, ssh_info, opts)
end
it "omits StrictHostKeyChecking and UserKnownHostsFile with paranoid = true" do
ssh_info[:keys_only] = false
Vagrant::Util::Subprocess.should_receive(:execute) do |*args|
expect(args[9]).not_to include('StrictHostKeyChecking ')
expect(args[9]).not_to include('UserKnownHostsFile ')
result
end
subject.rsync_single(machine, ssh_info, opts)
end
end
end end

View File

@ -724,6 +724,23 @@ describe Vagrant::Machine do
expect(instance.ssh_info[:password]).to eql("") expect(instance.ssh_info[:password]).to eql("")
end end
end end
context "with custom ssh_info" do
it "keys_only should be default" do
expect(instance.ssh_info[:keys_only]).to be_true
end
it "paranoid should be default" do
expect(instance.ssh_info[:paranoid]).to be_false
end
it "keys_only should be overridden" do
instance.config.ssh.keys_only = false
expect(instance.ssh_info[:keys_only]).to be_false
end
it "paranoid should be overridden" do
instance.config.ssh.paranoid = true
expect(instance.ssh_info[:paranoid]).to be_true
end
end
end end
end end

View File

@ -68,7 +68,7 @@ any keys stored in ssh-agent). The default value is `true`.`
<hr> <hr>
`config.ssh.paranoid` - Perform strict host-key verification. The default value `config.ssh.paranoid` - Perform strict host-key verification. The default value
is `true`. is `false`.
<hr> <hr>