Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.12] Add accept_newhostkey option to git module #73819

Merged
merged 5 commits into from
Apr 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelogs/fragments/73819-git-accept_new_host_key.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- git - Add ``accept_newhostkey`` option (https://github.com/ansible/ansible/issues/69846).
40 changes: 38 additions & 2 deletions lib/ansible/modules/git.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@
type: bool
default: 'no'
version_added: "1.5"
accept_newhostkey:
description:
- As of OpenSSH 7.5, "-o StrictHostKeyChecking=accept-new" can be
used which is safer and will only accepts host keys which are
not present or are the same. if C(yes), ensure that
"-o StrictHostKeyChecking=accept-new" is present as an ssh option.
type: bool
default: 'no'
version_added: "2.12"
ssh_opts:
description:
- Creates a wrapper script and exports the path as GIT_SSH
Expand Down Expand Up @@ -317,6 +326,7 @@
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.six import b, string_types
from ansible.module_utils._text import to_native, to_text
from ansible.module_utils.common.process import get_bin_path


def relocate_repo(module, result, repo_dir, old_repo_dir, worktree_dir):
Expand Down Expand Up @@ -462,6 +472,21 @@ def get_version(module, git_path, dest, ref="HEAD"):
return sha


def ssh_supports_acceptnewhostkey(module):
try:
ssh_path = get_bin_path('ssh')
except ValueError as err:
module.fail_json(
msg='Remote host is missing ssh command, so you cannot '
'use acceptnewhostkey option.', details=to_text(err))
supports_acceptnewhostkey = True
cmd = [ssh_path, '-o', 'StrictHostKeyChecking=accept-new', '-V']
rc, stdout, stderr = module.run_command(cmd)
if rc != 0:
supports_acceptnewhostkey = False
return supports_acceptnewhostkey


def get_submodule_versions(git_path, module, dest, version='HEAD'):
cmd = [git_path, 'submodule', 'foreach', git_path, 'rev-parse', version]
(rc, out, err) = module.run_command(cmd, cwd=dest)
Expand Down Expand Up @@ -1107,6 +1132,7 @@ def main():
verify_commit=dict(default='no', type='bool'),
gpg_whitelist=dict(default=[], type='list', elements='str'),
accept_hostkey=dict(default='no', type='bool'),
accept_newhostkey=dict(default='no', type='bool'),
key_file=dict(default=None, type='path', required=False),
ssh_opts=dict(default=None, required=False),
executable=dict(default=None, type='path'),
Expand All @@ -1119,7 +1145,7 @@ def main():
archive_prefix=dict(),
separate_git_dir=dict(type='path'),
),
mutually_exclusive=[('separate_git_dir', 'bare')],
mutually_exclusive=[('separate_git_dir', 'bare'), ('accept_hostkey', 'accept_newhostkey')],
required_by={'archive_prefix': ['archive']},
supports_check_mode=True
)
Expand Down Expand Up @@ -1150,11 +1176,21 @@ def main():

if module.params['accept_hostkey']:
if ssh_opts is not None:
if "-o StrictHostKeyChecking=no" not in ssh_opts:
if ("-o StrictHostKeyChecking=no" not in ssh_opts) and ("-o StrictHostKeyChecking=accept-new" not in ssh_opts):
ssh_opts += " -o StrictHostKeyChecking=no"
else:
ssh_opts = "-o StrictHostKeyChecking=no"

if module.params['accept_newhostkey']:
if not ssh_supports_acceptnewhostkey(module):
module.warn("Your ssh client does not support accept_newhostkey option, therefore it cannot be used.")
else:
if ssh_opts is not None:
if ("-o StrictHostKeyChecking=no" not in ssh_opts) and ("-o StrictHostKeyChecking=accept-new" not in ssh_opts):
ssh_opts += " -o StrictHostKeyChecking=accept-new"
else:
ssh_opts = "-o StrictHostKeyChecking=accept-new"

# evaluate and set the umask before doing anything else
if umask is not None:
if not isinstance(umask, string_types):
Expand Down
1 change: 1 addition & 0 deletions test/integration/targets/git/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

- import_tasks: formats.yml
- import_tasks: missing_hostkey.yml
- import_tasks: missing_hostkey_acceptnew.yml
- import_tasks: no-destination.yml
- import_tasks: specific-revision.yml
- import_tasks: submodules.yml
Expand Down
13 changes: 13 additions & 0 deletions test/integration/targets/git/tasks/missing_hostkey.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,16 @@
that:
- git_result is changed
when: github_ssh_private_key is defined

- name: MISSING-HOSTEKY | Remove github.com hostkey from known_hosts
lineinfile:
dest: '{{ output_dir }}/known_hosts'
regexp: "github.com"
state: absent
when: github_ssh_private_key is defined

- name: MISSING-HOSTKEY | clear checkout_dir
file:
state: absent
path: '{{ checkout_dir }}'
when: github_ssh_private_key is defined
78 changes: 78 additions & 0 deletions test/integration/targets/git/tasks/missing_hostkey_acceptnew.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
- name: MISSING-HOSTKEY | check accept_newhostkey support
shell: ssh -o StrictHostKeyChecking=accept-new -V
register: ssh_supports_accept_newhostkey
ignore_errors: true

- block:
- name: MISSING-HOSTKEY | accept_newhostkey when ssh does not support the option
git:
repo: '{{ repo_format2 }}'
dest: '{{ checkout_dir }}'
accept_newhostkey: true
ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts'
register: git_result
ignore_errors: true

- assert:
that:
- git_result is failed
- git_result.warnings is search("does not support")

when: ssh_supports_accept_newhostkey.rc != 0

- name: MISSING-HOSTKEY | checkout ssh://git@github.com repo without accept_newhostkey (expected fail)
git:
repo: '{{ repo_format2 }}'
dest: '{{ checkout_dir }}'
ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts'
register: git_result
ignore_errors: true

- assert:
that:
- git_result is failed

- block:
- name: MISSING-HOSTKEY | checkout git@github.com repo with accept_newhostkey (expected pass)
git:
repo: '{{ repo_format2 }}'
dest: '{{ checkout_dir }}'
accept_newhostkey: true
key_file: '{{ github_ssh_private_key }}'
ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts'
register: git_result

- assert:
that:
- git_result is changed

- name: MISSING-HOSTKEY | clear checkout_dir
file:
state: absent
path: '{{ checkout_dir }}'

- name: MISSING-HOSTKEY | checkout ssh://git@github.com repo with accept_newhostkey (expected pass)
git:
repo: '{{ repo_format3 }}'
dest: '{{ checkout_dir }}'
version: 'master'
accept_newhostkey: false # should already have been accepted
key_file: '{{ github_ssh_private_key }}'
ssh_opts: '-o UserKnownHostsFile={{ output_dir }}/known_hosts'
register: git_result

- assert:
that:
- git_result is changed

- name: MISSING-HOSTEKY | Remove github.com hostkey from known_hosts
lineinfile:
dest: '{{ output_dir }}/known_hosts'
regexp: "github.com"
state: absent

- name: MISSING-HOSTKEY | clear checkout_dir
file:
state: absent
path: '{{ checkout_dir }}'
when: github_ssh_private_key is defined and ssh_supports_accept_newhostkey.rc == 0