From 906bbb88b7388618c6736e40120795eb47352af2 Mon Sep 17 00:00:00 2001 From: Hideki Saito Date: Wed, 9 Oct 2024 15:41:37 +0900 Subject: [PATCH] Revert "Revert "Merge pull request #568 from abakanovskii/feature/add_path_option_authorized_key"" This reverts commit 098b5bee701554b0b533eb0d2ef8fca45b8ee456. --- .../fragments/568_update_authorized_key.yml | 3 ++ plugins/modules/authorized_key.py | 23 ++++++++++++- .../targets/authorized_key/defaults/main.yml | 2 ++ .../authorized_key/tasks/check_path.yml | 32 +++++++++++++++++++ .../targets/authorized_key/tasks/main.yml | 3 ++ 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/568_update_authorized_key.yml create mode 100644 tests/integration/targets/authorized_key/tasks/check_path.yml diff --git a/changelogs/fragments/568_update_authorized_key.yml b/changelogs/fragments/568_update_authorized_key.yml new file mode 100644 index 0000000..7efa29c --- /dev/null +++ b/changelogs/fragments/568_update_authorized_key.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - authorized_keys - allow using absolute path to a file as a SSH key(s) source (https://github.com/ansible-collections/ansible.posix/pull/568) diff --git a/plugins/modules/authorized_key.py b/plugins/modules/authorized_key.py index 9fbc610..1d68b4e 100644 --- a/plugins/modules/authorized_key.py +++ b/plugins/modules/authorized_key.py @@ -24,6 +24,7 @@ options: key: description: - The SSH public key(s), as a string or (since Ansible 1.9) url (https://github.com/username.keys). + - You can also use V(file://) prefix to search remote for a file with SSH key(s). type: str required: true path: @@ -96,6 +97,12 @@ EXAMPLES = r''' state: present key: https://github.com/charlie.keys +- name: Set authorized keys taken from path on controller node + ansible.posix.authorized_key: + user: charlie + state: present + key: file:///home/charlie/.ssh/id_rsa.pub + - name: Set authorized keys taken from url using lookup ansible.posix.authorized_key: user: charlie @@ -223,6 +230,7 @@ from operator import itemgetter from ansible.module_utils._text import to_native from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.urls import fetch_url +from ansible.module_utils.six.moves.urllib.parse import urlparse class keydict(dict): @@ -556,7 +564,7 @@ def enforce_state(module, params): follow = params.get('follow', False) error_msg = "Error getting key from: %s" - # if the key is a url, request it and use it as key source + # if the key is a url or file, request it and use it as key source if key.startswith("http"): try: resp, info = fetch_url(module, key) @@ -570,6 +578,19 @@ def enforce_state(module, params): # resp.read gives bytes on python3, convert to native string type key = to_native(key, errors='surrogate_or_strict') + if key.startswith("file"): + # if the key is an absolute path, check for existense and use it as a key source + key_path = urlparse(key).path + if not os.path.exists(key_path): + module.fail_json(msg="Path to a key file not found: %s" % key_path) + if not os.path.isfile(key_path): + module.fail_json(msg="Path to a key is a directory and must be a file: %s" % key_path) + try: + with open(key_path, 'r') as source_fh: + key = source_fh.read() + except OSError as e: + module.fail_json(msg="Failed to read key file %s : %s" % (key_path, to_native(e))) + # extract individual keys into an array, skipping blank lines and comments new_keys = [s for s in key.splitlines() if s and not s.startswith('#')] diff --git a/tests/integration/targets/authorized_key/defaults/main.yml b/tests/integration/targets/authorized_key/defaults/main.yml index 1b60f8c..7ec99ca 100644 --- a/tests/integration/targets/authorized_key/defaults/main.yml +++ b/tests/integration/targets/authorized_key/defaults/main.yml @@ -35,3 +35,5 @@ multiple_keys_comments: | ssh-rsa DATA_BASIC 1@testing # I like adding comments yo-dude-this-is-not-a-key INVALID_DATA 2@testing ecdsa-sha2-nistp521 ECDSA_DATA 4@testing + +key_path: /tmp/id_rsa.pub diff --git a/tests/integration/targets/authorized_key/tasks/check_path.yml b/tests/integration/targets/authorized_key/tasks/check_path.yml new file mode 100644 index 0000000..df5d46e --- /dev/null +++ b/tests/integration/targets/authorized_key/tasks/check_path.yml @@ -0,0 +1,32 @@ +--- +- name: Create key file for test + ansible.builtin.copy: + dest: "{{ key_path }}" + content: "{{ rsa_key_basic }}" + mode: "0600" + +- name: Add key using path + ansible.posix.authorized_key: + user: root + key: file://{{ key_path }} + state: present + path: "{{ output_dir | expanduser }}/authorized_keys" + register: result + +- name: Assert that the key was added + ansible.builtin.assert: + that: + - result.changed == true + +- name: Add key using path again + ansible.posix.authorized_key: + user: root + key: file://{{ key_path }} + state: present + path: "{{ output_dir | expanduser }}/authorized_keys" + register: result + +- name: Assert that no changes were applied + ansible.builtin.assert: + that: + - result.changed == false diff --git a/tests/integration/targets/authorized_key/tasks/main.yml b/tests/integration/targets/authorized_key/tasks/main.yml index 6a22838..d687f17 100644 --- a/tests/integration/targets/authorized_key/tasks/main.yml +++ b/tests/integration/targets/authorized_key/tasks/main.yml @@ -31,3 +31,6 @@ - name: Test for the management of comments with key ansible.builtin.import_tasks: comments.yml + +- name: Test for specifying key as a path + ansible.builtin.import_tasks: check_path.yml