diff --git a/changelogs/fragments/7456-add-ssh-control-master.yml b/changelogs/fragments/7456-add-ssh-control-master.yml new file mode 100644 index 0000000000..de6399e2bd --- /dev/null +++ b/changelogs/fragments/7456-add-ssh-control-master.yml @@ -0,0 +1,2 @@ +minor_changes: + - ssh_config - adds ``controlmaster``, ``controlpath`` and ``controlpersist`` parameters (https://github.com/ansible-collections/community.general/pull/7456). diff --git a/plugins/modules/ssh_config.py b/plugins/modules/ssh_config.py index 3e03ebc275..90be40512e 100644 --- a/plugins/modules/ssh_config.py +++ b/plugins/modules/ssh_config.py @@ -108,6 +108,22 @@ options: - Sets the C(HostKeyAlgorithms) option. type: str version_added: 6.1.0 + controlmaster: + description: + - Sets the C(ControlMaster) option. + choices: [ 'yes', 'no', 'ask', 'auto', 'autoask' ] + type: str + version_added: 8.1.0 + controlpath: + description: + - Sets the C(ControlPath) option. + type: str + version_added: 8.1.0 + controlpersist: + description: + - Sets the C(ControlPersist) option. + type: str + version_added: 8.1.0 requirements: - paramiko ''' @@ -177,6 +193,22 @@ from ansible_collections.community.general.plugins.module_utils._stormssh import from ansible_collections.community.general.plugins.module_utils.ssh import determine_config_file +def convert_bool(value): + if value is True: + return 'yes' + if value is False: + return 'no' + return None + + +def fix_bool_str(value): + if value == 'True': + return 'yes' + if value == 'False': + return 'no' + return value + + class SSHConfig(object): def __init__(self, module): self.module = module @@ -219,14 +251,12 @@ class SSHConfig(object): proxycommand=self.params.get('proxycommand'), proxyjump=self.params.get('proxyjump'), host_key_algorithms=self.params.get('host_key_algorithms'), + forward_agent=convert_bool(self.params.get('forward_agent')), + controlmaster=self.params.get('controlmaster'), + controlpath=self.params.get('controlpath'), + controlpersist=fix_bool_str(self.params.get('controlpersist')), ) - # Convert True / False to 'yes' / 'no' for usage in ssh_config - if self.params['forward_agent'] is True: - args['forward_agent'] = 'yes' - if self.params['forward_agent'] is False: - args['forward_agent'] = 'no' - config_changed = False hosts_changed = [] hosts_change_diff = [] @@ -320,9 +350,13 @@ def main(): ssh_config_file=dict(default=None, type='path'), state=dict(type='str', default='present', choices=['present', 'absent']), strict_host_key_checking=dict( + type='str', default=None, choices=['yes', 'no', 'ask'] ), + controlmaster=dict(type='str', default=None, choices=['yes', 'no', 'ask', 'auto', 'autoask']), + controlpath=dict(type='str', default=None), + controlpersist=dict(type='str', default=None), user=dict(default=None, type='str'), user_known_hosts_file=dict(type='str', default=None), ), diff --git a/tests/integration/targets/ssh_config/tasks/options.yml b/tests/integration/targets/ssh_config/tasks/options.yml index df12675947..946b1fc78c 100644 --- a/tests/integration/targets/ssh_config/tasks/options.yml +++ b/tests/integration/targets/ssh_config/tasks/options.yml @@ -16,6 +16,9 @@ proxycommand: "ssh jumphost.example.com -W %h:%p" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add check_mode: true @@ -45,6 +48,9 @@ proxycommand: "ssh jumphost.example.com -W %h:%p" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add @@ -63,6 +69,9 @@ proxycommand: "ssh jumphost.example.com -W %h:%p" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add_again @@ -85,6 +94,9 @@ - "'proxycommand ssh jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" - "'forwardagent yes' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-rsa' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster auto' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist yes' in slurp_ssh_config['content'] | b64decode" - name: Options - Update host community.general.ssh_config: @@ -93,6 +105,9 @@ proxycommand: "ssh new-jumphost.example.com -W %h:%p" forward_agent: false host_key_algorithms: "+ssh-ed25519" + controlmaster: no + controlpath: "~/.ssh/new-sockets/%r@%h-%p" + controlpersist: "600" state: present register: options_update @@ -113,6 +128,9 @@ proxycommand: "ssh new-jumphost.example.com -W %h:%p" forward_agent: false host_key_algorithms: "+ssh-ed25519" + controlmaster: no + controlpath: "~/.ssh/new-sockets/%r@%h-%p" + controlpersist: "600" state: present register: options_update @@ -136,6 +154,9 @@ - "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster no' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode" - name: Options - Ensure no update in case option exist in ssh_config file but wasn't defined in playbook community.general.ssh_config: @@ -164,6 +185,9 @@ - "'proxycommand ssh new-jumphost.example.com -W %h:%p' in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster no' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode" - name: Debug debug: @@ -210,6 +234,9 @@ - "'proxycommand ssh new-jumphost.example.com -W %h:%p' not in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' not in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' not in slurp_ssh_config['content'] | b64decode" + - "'controlmaster auto' not in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/sockets/%r@%h-%p' not in slurp_ssh_config['content'] | b64decode" + - "'controlpersist yes' not in slurp_ssh_config['content'] | b64decode" # Proxycommand and ProxyJump are mutually exclusive. # Reset ssh_config before testing options with proxyjump @@ -226,6 +253,9 @@ proxyjump: "jumphost.example.com" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add check_mode: true @@ -255,6 +285,9 @@ proxyjump: "jumphost.example.com" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add @@ -273,6 +306,9 @@ proxyjump: "jumphost.example.com" forward_agent: true host_key_algorithms: "+ssh-rsa" + controlmaster: "auto" + controlpath: "~/.ssh/sockets/%r@%h-%p" + controlpersist: yes state: present register: options_add_again @@ -295,6 +331,9 @@ - "'proxyjump jumphost.example.com' in slurp_ssh_config['content'] | b64decode" - "'forwardagent yes' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-rsa' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster auto' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist yes' in slurp_ssh_config['content'] | b64decode" - name: Options - Update host community.general.ssh_config: @@ -303,6 +342,9 @@ proxyjump: "new-jumphost.example.com" forward_agent: false host_key_algorithms: "+ssh-ed25519" + controlmaster: no + controlpath: "~/.ssh/new-sockets/%r@%h-%p" + controlpersist: "600" state: present register: options_update @@ -323,6 +365,9 @@ proxyjump: "new-jumphost.example.com" forward_agent: false host_key_algorithms: "+ssh-ed25519" + controlmaster: no + controlpath: "~/.ssh/new-sockets/%r@%h-%p" + controlpersist: "600" state: present register: options_update @@ -346,6 +391,9 @@ - "'proxyjump new-jumphost.example.com' in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster no' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode" - name: Options - Ensure no update in case option exist in ssh_config file but wasn't defined in playbook community.general.ssh_config: @@ -374,6 +422,9 @@ - "'proxyjump new-jumphost.example.com' in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' in slurp_ssh_config['content'] | b64decode" + - "'controlmaster no' in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/new-sockets/%r@%h-%p' in slurp_ssh_config['content'] | b64decode" + - "'controlpersist 600' in slurp_ssh_config['content'] | b64decode" - name: Debug debug: @@ -420,3 +471,6 @@ - "'proxyjump new-jumphost.example.com' not in slurp_ssh_config['content'] | b64decode" - "'forwardagent no' not in slurp_ssh_config['content'] | b64decode" - "'hostkeyalgorithms +ssh-ed25519' not in slurp_ssh_config['content'] | b64decode" + - "'controlmaster auto' not in slurp_ssh_config['content'] | b64decode" + - "'controlpath ~/.ssh/sockets/%r@%h-%p' not in slurp_ssh_config['content'] | b64decode" + - "'controlpersist yes' not in slurp_ssh_config['content'] | b64decode"