`vagrant ssh` will automatically fix permissions on the private key if necessary

This commit is contained in:
Mitchell Hashimoto 2010-03-19 01:15:42 -07:00
parent a7652244d5
commit b80a08ce8e
3 changed files with 103 additions and 2 deletions

View File

@ -9,6 +9,7 @@ module Vagrant
options[param] = opts[param] || Vagrant.config.ssh.send(param) options[param] = opts[param] || Vagrant.config.ssh.send(param)
end end
check_key_permissions(options[:private_key_path])
Kernel.exec "ssh -p #{port(opts)} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{options[:private_key_path]} #{options[:username]}@#{options[:host]}".strip Kernel.exec "ssh -p #{port(opts)} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i #{options[:private_key_path]} #{options[:username]}@#{options[:host]}".strip
end end
@ -49,6 +50,28 @@ module Vagrant
def port(opts={}) def port(opts={})
opts[:port] || Vagrant.config.vm.forwarded_ports[Vagrant.config.ssh.forwarded_port_key][:hostport] opts[:port] || Vagrant.config.vm.forwarded_ports[Vagrant.config.ssh.forwarded_port_key][:hostport]
end end
def check_key_permissions(key_path)
# TODO: This only works on unix based systems for now. Windows
# systems will need to be investigated further.
stat = File.stat(key_path)
if stat.owned? && file_perms(key_path) != "600"
logger.info "Permissions on private key incorrect, fixing..."
File.chmod(0600, key_path)
error_and_exit(:ssh_bad_permissions, :key_path => key_path) if file_perms(key_path) != "600"
end
rescue Errno::EPERM
# This shouldn't happen since we verify we own the file, but just
# in case.
error_and_exit(:ssh_bad_permissions, :key_path => key_path)
end
def file_perms(path)
perms = sprintf("%o", File.stat(path).mode)
perms.reverse[0..2].reverse
end
end end
end end
end end

View File

@ -52,6 +52,12 @@
\nsince it describes the expected environment that vagrant is supposed \nsince it describes the expected environment that vagrant is supposed
\nto manage. Please create a `<%= Vagrant::Env::ROOTFILE_NAME %>` and place it in your project \nto manage. Please create a `<%= Vagrant::Env::ROOTFILE_NAME %>` and place it in your project
\nroot." \nroot."
:ssh_bad_permissions: "The private key to connect to this box via SSH has invalid permissions
\nset on it. The permissions of the private key should be set to 0600, otherwise SSH will
\nignore the key. Vagrant tried to do this automatically for you but failed. Please set the
\npermissions on the following file to 0600 and then try running this command again:
\n<%= key_path %>"
:virtualbox_import_failure: "The VM import failed! Try running `VBoxManage import` on the box file manually for more verbose error output." :virtualbox_import_failure: "The VM import failed! Try running `VBoxManage import` on the box file manually for more verbose error output."
:virtualbox_invalid_version: "Vagrant has detected that you have VirtualBox version <%= version %> installed! :virtualbox_invalid_version: "Vagrant has detected that you have VirtualBox version <%= version %> installed!
\nVagrant requires that you use at least VirtualBox version 3.1. Please install \nVagrant requires that you use at least VirtualBox version 3.1. Please install

View File

@ -6,7 +6,18 @@ class SshTest < Test::Unit::TestCase
end end
context "connecting to SSH" do context "connecting to SSH" do
test "should call exec with defaults when no options are supplied" do setup do
Vagrant::SSH.stubs(:check_key_permissions)
end
should "check key permissions prior to exec" do
exec_seq = sequence("exec_seq")
Vagrant::SSH.expects(:check_key_permissions).with(Vagrant.config.ssh.private_key_path).once.in_sequence(exec_seq)
Kernel.expects(:exec).in_sequence(exec_seq)
Vagrant::SSH.connect
end
should "call exec with defaults when no options are supplied" do
ssh = Vagrant.config.ssh ssh = Vagrant.config.ssh
ssh_exec_expect(Vagrant::SSH.port, ssh_exec_expect(Vagrant::SSH.port,
Vagrant.config.ssh.private_key_path, Vagrant.config.ssh.private_key_path,
@ -15,7 +26,7 @@ class SshTest < Test::Unit::TestCase
Vagrant::SSH.connect Vagrant::SSH.connect
end end
test "should call exec with supplied params" do should "call exec with supplied params" do
args = {:username => 'bar', :private_key_path => 'baz', :host => 'bak', :port => 'bag'} args = {:username => 'bar', :private_key_path => 'baz', :host => 'bak', :port => 'bag'}
ssh_exec_expect(args[:port], args[:private_key_path], args[:username], args[:host]) ssh_exec_expect(args[:port], args[:private_key_path], args[:username], args[:host])
Vagrant::SSH.connect(args) Vagrant::SSH.connect(args)
@ -121,4 +132,65 @@ class SshTest < Test::Unit::TestCase
assert_equal "47", Vagrant::SSH.port({ :port => "47" }) assert_equal "47", Vagrant::SSH.port({ :port => "47" })
end end
end end
context "checking key permissions" do
setup do
@key_path = "foo"
Vagrant::SSH.stubs(:file_perms)
@stat = mock("stat")
@stat.stubs(:owned?).returns(true)
File.stubs(:stat).returns(@stat)
end
should "do nothing if the user is not the owner" do
@stat.expects(:owned?).returns(false)
File.expects(:chmod).never
Vagrant::SSH.check_key_permissions(@key_path)
end
should "do nothing if the file perms equal 600" do
Vagrant::SSH.expects(:file_perms).with(@key_path).returns("600")
File.expects(:chmod).never
Vagrant::SSH.check_key_permissions(@key_path)
end
should "chmod the file if the file perms aren't 600" do
perm_sequence = sequence("perm_seq")
Vagrant::SSH.expects(:file_perms).returns("900").in_sequence(perm_sequence)
File.expects(:chmod).with(0600, @key_path).once.in_sequence(perm_sequence)
Vagrant::SSH.expects(:file_perms).returns("600").in_sequence(perm_sequence)
Vagrant::SSH.expects(:error_and_exit).never
Vagrant::SSH.check_key_permissions(@key_path)
end
should "error and exit if the resulting chmod doesn't work" do
perm_sequence = sequence("perm_seq")
Vagrant::SSH.expects(:file_perms).returns("900").in_sequence(perm_sequence)
File.expects(:chmod).with(0600, @key_path).once.in_sequence(perm_sequence)
Vagrant::SSH.expects(:file_perms).returns("900").in_sequence(perm_sequence)
Vagrant::SSH.expects(:error_and_exit).once.with(:ssh_bad_permissions, :key_path => @key_path).in_sequence(perm_sequence)
Vagrant::SSH.check_key_permissions(@key_path)
end
should "error and exit if a bad file perm is raised" do
Vagrant::SSH.expects(:file_perms).with(@key_path).returns("900")
File.expects(:chmod).raises(Errno::EPERM)
Vagrant::SSH.expects(:error_and_exit).once.with(:ssh_bad_permissions, :key_path => @key_path)
Vagrant::SSH.check_key_permissions(@key_path)
end
end
context "getting file permissions" do
should "return the last 3 characters of the file mode" do
path = "foo"
mode = "10000foo"
stat = mock("stat")
File.expects(:stat).with(path).returns(stat)
stat.expects(:mode).returns(mode)
Vagrant::SSH.expects(:sprintf).with("%o", mode).returns(mode)
assert_equal path, Vagrant::SSH.file_perms(path)
end
end
end end