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

openssh_keypair module fails to read private key if mode is set to "0644" #564

Open
noonedeadpunk opened this issue Jan 18, 2023 · 4 comments
Labels
bug Something isn't working

Comments

@noonedeadpunk
Copy link

SUMMARY

In case you chmod ssh private key to mode 644 or define mode to '0644' for the module, it fails to read the private key

ISSUE TYPE
  • Bug Report
COMPONENT NAME

openssh_keypair

ANSIBLE VERSION
root@aio1:/home/ubuntu# ansible --version
ansible [core 2.13.4]
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /opt/ansible-runtime/lib/python3.10/site-packages/ansible
  ansible collection location = /etc/ansible
  executable location = /opt/ansible-runtime/bin/ansible
  python version = 3.10.6 (main, Nov 14 2022, 16:10:14) [GCC 11.3.0]
  jinja version = 3.1.2
  libyaml = True
root@aio1:/home/ubuntu# 
COLLECTION VERSION
root@aio1:/home/ubuntu# ansible-galaxy collection list community.crypto 

# /etc/ansible/ansible_collections
Collection       Version
---------------- -------
community.crypto 2.7.0  
root@aio1:/home/ubuntu#
CONFIGURATION
root@aio1:/home/ubuntu# ansible-config dump --only-changed
COLLECTIONS_PATHS(env: ANSIBLE_COLLECTIONS_PATH) = ['/etc/ansible']
root@aio1:/home/ubuntu# 
OS / ENVIRONMENT

Ubuntu 22.04, Python 3.10

STEPS TO REPRODUCE

Assuming you have a task:

---
- hosts: localhost
  tasks:
    - name: generate keypair
      community.crypto.openssh_keypair:
        comment: "{{ kp.comment | default(omit) }}"
        passphrase: "{{ kp.passphrase | default(omit) }}"
        regenerate: "{{ kp.regenerate | default(omit) }}"
        size: "{{ kp.size | default(omit) }}"
        type: "{{ kp.type | default(omit) }}"
        path: "{{ kp.path }}"
        mode: "{{ kp.mode | default(omit) }}"
      loop:
        - path: /home/ubuntu/Ansible-SSH-Signing-Key
          type: rsa
          mode: '0644'
      loop_control:
        loop_var: kp

Then run the task couple of times

EXPECTED RESULTS

Module passes in idempotent manner, preserving mode 644 for files and being able to re-run without failures.

ACTUAL RESULTS
root@aio1:/home/ubuntu# ansible-playbook test.yml 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ***************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [generate keypair] ********************************************************************************************************************************************************************************************************************
changed: [localhost] => (item={'path': '/home/ubuntu/Ansible-SSH-Signing-Key', 'type': 'rsa', 'mode': '0644'})

PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


EXIT NOTICE [Playbook execution success] **************************************
===============================================================================
root@aio1:/home/ubuntu# stat /home/ubuntu/Ansible-SSH-Signing-Key
  File: /home/ubuntu/Ansible-SSH-Signing-Key
  Size: 3357            Blocks: 8          IO Block: 4096   regular file
Device: fc01h/64513d    Inode: 259916      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-01-18 18:10:13.771070714 +0000
Modify: 2023-01-18 18:10:13.735069467 +0000
Change: 2023-01-18 18:10:13.771070714 +0000
 Birth: 2023-01-18 18:10:13.735069467 +0000
root@aio1:/home/ubuntu# ansible-playbook test.yml 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ***************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [generate keypair] ********************************************************************************************************************************************************************************************************************
failed: [localhost] (item={'path': '/home/ubuntu/Ansible-SSH-Signing-Key', 'type': 'rsa', 'mode': '0644'}) => {"ansible_loop_var": "kp", "changed": false, "kp": {"mode": "0644", "path": "/home/ubuntu/Ansible-SSH-Signing-Key", "type": "rsa"}, "msg": "Unable to read the key. The key is protected with a passphrase or broken. Will not proceed. To force regeneration, call the module with `generate` set to `full_idempotence` or `always`, or with `force=true`."}

PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   


EXIT NOTICE [Playbook execution failure] **************************************
===============================================================================
root@aio1:/home/ubuntu# chmod 600 /home/ubuntu/Ansible-SSH-Signing-Key
root@aio1:/home/ubuntu# stat /home/ubuntu/Ansible-SSH-Signing-Key
  File: /home/ubuntu/Ansible-SSH-Signing-Key
  Size: 3357            Blocks: 8          IO Block: 4096   regular file
Device: fc01h/64513d    Inode: 259916      Links: 1
Access: (0600/-rw-------)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-01-18 18:10:29.295608544 +0000
Modify: 2023-01-18 18:10:13.735069467 +0000
Change: 2023-01-18 18:10:49.992325558 +0000
 Birth: 2023-01-18 18:10:13.735069467 +0000
root@aio1:/home/ubuntu# ansible-playbook test.yml 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ***************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [generate keypair] ********************************************************************************************************************************************************************************************************************
changed: [localhost] => (item={'path': '/home/ubuntu/Ansible-SSH-Signing-Key', 'type': 'rsa', 'mode': '0644'})

PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   


EXIT NOTICE [Playbook execution success] **************************************
===============================================================================
root@aio1:/home/ubuntu# stat /home/ubuntu/Ansible-SSH-Signing-Key
  File: /home/ubuntu/Ansible-SSH-Signing-Key
  Size: 3357            Blocks: 8          IO Block: 4096   regular file
Device: fc01h/64513d    Inode: 259916      Links: 1
Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
Access: 2023-01-18 18:11:02.860771371 +0000
Modify: 2023-01-18 18:10:13.735069467 +0000
Change: 2023-01-18 18:11:02.904772896 +0000
 Birth: 2023-01-18 18:10:13.735069467 +0000
root@aio1:/home/ubuntu# ansible-playbook test.yml 
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] ***************************************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [generate keypair] ********************************************************************************************************************************************************************************************************************
failed: [localhost] (item={'path': '/home/ubuntu/Ansible-SSH-Signing-Key', 'type': 'rsa', 'mode': '0644'}) => {"ansible_loop_var": "kp", "changed": false, "kp": {"mode": "0644", "path": "/home/ubuntu/Ansible-SSH-Signing-Key", "type": "rsa"}, "msg": "Unable to read the key. The key is protected with a passphrase or broken. Will not proceed. To force regeneration, call the module with `generate` set to `full_idempotence` or `always`, or with `force=true`."}

PLAY RECAP *********************************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   


EXIT NOTICE [Playbook execution failure] **************************************
===============================================================================
root@aio1:/home/ubuntu#
@felixfontein felixfontein added the bug Something isn't working label Jan 18, 2023
@Ajpantuso
Copy link
Collaborator

This is the nature of the ssh-keygen binary.
It refuses to load world readable private keys with a message like:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for 'test' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "test": bad permissions

using backend: cryptography should permit reading keys with perms like 0644.

@noonedeadpunk
Copy link
Author

Yes, that helps, thank you.

I wonder if it's worth to fix documentation to mention usage of cryptography backend with mode, or make auto use cryptograpy not only when passphrase is set, but also switch to it when mode defined.

Or well, is there any good reason why cryptography is not picked by default and opensshbin is first choice for auto backend?

As even if mode is not set for module, but attributes for file were somehow changed (ie keypair is stored in git which doesn't preserve attributes) error that key can't be decrypted is very confusing.

@Ajpantuso
Copy link
Collaborator

Ajpantuso commented Jan 18, 2023

cryptography and the concept of backends were added to this module more recently so we default to whatever options will not break older playbooks which have not adapted to using cryptography.

@felixfontein
Copy link
Contributor

We could switch the default backend for 3.0.0 (see #559).

openstack-mirroring pushed a commit to openstack/openstack-ansible-plugins that referenced this issue Jan 25, 2023
With default "auto" backend, opensshbin is first pick, which fails
to read a key in case of insecure permissions. This makes task fail
in case private key in topic has mode different from 0600, even if
different mode specified for the module itself [1].

Along with switching backend we also adding mode key to be supported

[1] ansible-collections/community.crypto#564
Change-Id: I9444ef832136783bde1eff5425e4cd369f905a5c
openstack-mirroring pushed a commit to openstack/openstack that referenced this issue Jan 25, 2023
* Update openstack-ansible-plugins from branch 'master'
  to 1dbc2985d39fae7c73c741a95a486d9014aa036b
  - Use cryptography backend for openssh_keypair
    
    With default "auto" backend, opensshbin is first pick, which fails
    to read a key in case of insecure permissions. This makes task fail
    in case private key in topic has mode different from 0600, even if
    different mode specified for the module itself [1].
    
    Along with switching backend we also adding mode key to be supported
    
    [1] ansible-collections/community.crypto#564
    Change-Id: I9444ef832136783bde1eff5425e4cd369f905a5c
openstack-mirroring pushed a commit to openstack/openstack-ansible-plugins that referenced this issue Jul 25, 2023
With default "auto" backend, opensshbin is first pick, which fails
to read a key in case of insecure permissions. This makes task fail
in case private key in topic has mode different from 0600, even if
different mode specified for the module itself [1].

Along with switching backend we also adding mode key to be supported

Depends-On: https://review.opendev.org/c/openstack/openstack-ansible/+/888437

[1] ansible-collections/community.crypto#564
Change-Id: I9444ef832136783bde1eff5425e4cd369f905a5c
(cherry picked from commit 1dbc298)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants