diff --git a/CHANGELOG.md b/CHANGELOG.md index 434f790ea..42e753943 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -95,6 +95,8 @@ BUG FIXES: - providers/virtualbox: Show more descriptive error if VirtualBox is reporting an empty version. [GH-4657] - provisioners/ansible: Force `ssh` (OpenSSH) connection by default [GH-3396] + - provisioners/ansible: Don't use or modify `~/.ssh/known_hosts` file by default, + similarly to native vagrant commands [GH-3900] - provisioners/docker: Get GPG key over SSL. [GH-4597] - provisioners/docker: Search for docker binary in multiple places. [GH-4580] - provisioners/salt: Highstate works properly with a master. [GH-4471] diff --git a/plugins/provisioners/ansible/provisioner.rb b/plugins/provisioners/ansible/provisioner.rb index bb6b25ce1..e403b561f 100644 --- a/plugins/provisioners/ansible/provisioner.rb +++ b/plugins/provisioners/ansible/provisioner.rb @@ -183,9 +183,14 @@ module VagrantPlugins @ansible_ssh_args ||= get_ansible_ssh_args end + # Use ANSIBLE_SSH_ARGS to pass some OpenSSH options that are not wrapped by + # an ad-hoc Ansible option. Last update corresponds to Ansible 1.8 def get_ansible_ssh_args ssh_options = [] + # Don't access user's known_hosts file, except when host_key_checking is enabled. + ssh_options << "-o UserKnownHostsFile=/dev/null" unless config.host_key_checking + # Multiple Private Keys @ssh_info[:private_key_path].drop(1).each do |key| ssh_options << "-o IdentityFile=#{key}" diff --git a/test/unit/plugins/provisioners/ansible/provisioner_test.rb b/test/unit/plugins/provisioners/ansible/provisioner_test.rb index e666b51a4..756f95769 100644 --- a/test/unit/plugins/provisioners/ansible/provisioner_test.rb +++ b/test/unit/plugins/provisioners/ansible/provisioner_test.rb @@ -63,7 +63,7 @@ VF # def self.it_should_set_arguments_and_environment_variables( - expected_args_count = 6, expected_vars_count = 3, expected_host_key_checking = false, expected_transport_mode = "ssh") + expected_args_count = 6, expected_vars_count = 4, expected_host_key_checking = false, expected_transport_mode = "ssh") it "sets implicit arguments in a specific order" do expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args| @@ -101,6 +101,12 @@ VF it "exports environment variables" do expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args| cmd_opts = args.last + + if expected_host_key_checking + expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to be_nil unless config.raw_arguments + else + expect(cmd_opts[:env]['ANSIBLE_SSH_ARGS']).to include("-o UserKnownHostsFile=/dev/null") + end expect(cmd_opts[:env]['ANSIBLE_FORCE_COLOR']).to eql("true") expect(cmd_opts[:env]['ANSIBLE_HOST_KEY_CHECKING']).to eql(expected_host_key_checking.to_s) expect(cmd_opts[:env]['PYTHONUNBUFFERED']).to eql(1) @@ -305,7 +311,7 @@ VF "--new-arg=yeah"] end - it_should_set_arguments_and_environment_variables 17, 3, false, "paramiko" + it_should_set_arguments_and_environment_variables 17, 4, false, "paramiko" it "sets all raw arguments" do expect(Vagrant::Util::Subprocess).to receive(:execute).with { |*args| @@ -459,7 +465,7 @@ VF it "shows the ansible-playbook command" do expect(machine.env.ui).to receive(:detail).with { |full_command| - expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml") + expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} playbook.yml") } end end @@ -474,7 +480,7 @@ VF it "shows the ansible-playbook command" do expect(machine.env.ui).to receive(:detail).with { |full_command| - expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml") + expect(full_command).to eq("PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ANSIBLE_HOST_KEY_CHECKING=false ANSIBLE_SSH_ARGS='-o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s' ansible-playbook --private-key=/path/to/my/key --user=testuser --connection=ssh --limit='machine1' --inventory-file=#{generated_inventory_dir} -v playbook.yml") } end end diff --git a/website/docs/source/v2/provisioning/ansible.html.md b/website/docs/source/v2/provisioning/ansible.html.md index 6c79721e1..9301e0fb8 100644 --- a/website/docs/source/v2/provisioning/ansible.html.md +++ b/website/docs/source/v2/provisioning/ansible.html.md @@ -198,7 +198,7 @@ by the sudo command. * `ansible.start_at_task` can be set to a string corresponding to the task name where the playbook provision will start. * `ansible.raw_arguments` can be set to an array of strings corresponding to a list of `ansible-playbook` arguments (e.g. `['--check', '-M /my/modules']`). It is an *unsafe wildcard* that can be used to apply Ansible options that are not (yet) supported by this Vagrant provisioner. As of Vagrant 1.7, `raw_arguments` has the highest priority and its values can potentially override or break other Vagrant settings. * `ansible.raw_ssh_args` can be set to an array of strings corresponding to a list of OpenSSH client parameters (e.g. `['-o ControlMaster=no']`). It is an *unsafe wildcard* that can be used to pass additional SSH settings to Ansible via `ANSIBLE_SSH_ARGS` environment variable. -* `ansible.host_key_checking` can be set to `true` which will enable host key checking. As Vagrant 1.5, the default value is `false`, to avoid connection problems when creating new virtual machines. +* `ansible.host_key_checking` can be set to `true` which will enable host key checking. As of Vagrant 1.5, the default value is `false` and as of Vagrant 1.7 the user kownn host file (e.g. `~/.ssh/known_hosts`) is no longer read nor modified. In other words: by default, the Ansible provisioner behaves the same as Vagrant native commands (e.g `vagrant ssh`). ## Tips and Tricks