Comment générer des clés SSH hôte via ansible?

11

J'essaie de recréer des clés d'hôte ssh sur une poignée de serveurs distants via ansible (et ssh-keygen), mais les fichiers ne semblent pas apparaître. Le playbook fonctionne correctement, mais les fichiers de la télécommande ne sont pas modifiés.

J'ai besoin de recourir au echo -epiratage, car ces télécommandes fonctionnent sous Ubuntu 14.04 et n'ont pas la version correcte de la version python-pexpectdisponible (selon ansible).

Qu'est-ce que je rate? Mon playbook et ma sortie sont ci-dessous:

playbook

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
    - name: Generate /etc/ssh/ RSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

    - name: Generate /etc/ssh/ DSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

    - name: Generate /etc/ssh/ ECDSA host key
      command : echo -e 'y\n'|ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
      register: output
    - debug: var=output.stdout_lines

production

$ ansible-playbook ./playbooks/ssh-hostkeys.yml -l myhost.mydom.com, 
SUDO password: 

PLAY [all] **********************************************************************************************

TASK [Generate /etc/ssh/ RSA host key] ******************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C  -N "
    ]
}

TASK [Generate /etc/ssh/ DSA host key] ******************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C  -N "
    ]
}

TASK [Generate /etc/ssh/ ECDSA host key] ****************************************************************
changed: [myhost.mydom.com]

TASK [debug] ********************************************************************************************
ok: [myhost.mydom.com] => {
    "output.stdout_lines": [
        "y", 
        "|ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C  -N "
    ]
}

PLAY RECAP **********************************************************************************************
myhost.mydom.com : ok=6    changed=3    unreachable=0    failed=0  
Défaillance du serveur
la source

Réponses:

14

Pour autant que je sache, la seule raison pour laquelle vous auriez besoin de diriger un «y» vers ssh-keygen, c'est si votre commande remplace un fichier existant. À mon avis, ce n'est pas un bon moyen de faire quelque chose à partir d'un outil de gestion de configuration.

Vous devez ajuster vos tâches pour les rendre idempotentes. Plus précisément, si vous ajoutez le creates: filenameà votre commande, les nouvelles clés ne seront créées que lorsqu'elles n'existent pas déjà, au lieu d'être remplacées chaque fois que vous exécutez ce playbook.

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
  - name: Generate /etc/ssh/ RSA host key
    command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_rsa_key

  - name: Generate /etc/ssh/ DSA host key
    command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_dsa_key

  - name: Generate /etc/ssh/ ECDSA host key
    command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_ecdsa_key

Si, pour une raison quelconque, vous vouliez remplacer ces clés, par exemple, si elles étaient trop anciennes ou si vous souhaitez ajouter une autre tâche pour les supprimer. Voici une simple suppression

- file:
    state: absent:
    path: "{{item}}"
  loop:
  - /etc/ssh/ssh_host_rsa_key
  - /etc/ssh/ssh_host_dsa_key
  - /etc/ssh/ssh_host_ecdsa_key

Si vous souhaitez supprimer des fichiers générés avant une certaine heure, vous pouvez utiliser le module stat pour récupérer des détails sur ces fichiers et configurer les whenconditions pour les supprimer de manière sélective s'ils étaient plus anciens qu'une certaine date ou quelque chose.

Zoredache
la source
Excellent exemple et merci pour les réflexions sur le maintien de l'idempotence. Pour mon cas d'utilisation, je provisionne des machines virtuelles clonées, il y aura donc toujours des clés à écraser. J'ai en quelque sorte besoin de l'option nucléaire pour simplement la retirer et la remplacer.
Défaillance du serveur
Si vous voulez toujours le supprimer, je ferais probablement l' file: state:absent ...approche sur sip-keygen. Bien qu'il n'y ait probablement pas beaucoup de différence.
Zoredache
Ah ok. cela a plus de sens. Je ne savais pas il y absenta quelques jours. En effet, cela supprimera le fichier avant de recréer la clé. C'est une approche beaucoup plus claire. Merci.
Défaillance du serveur
6

Le commandmodule ansible ne transmet pas de commandes via un shell . Cela signifie que vous ne pouvez pas utiliser d'opérateurs shell tels que le tuyau, et c'est pourquoi vous voyez le symbole du tuyau dans la sortie. En ce qui concerne ansible, il a exécuté la commandeecho avec tout le reste de la ligne comme arguments echo.

Si vous avez besoin de la ligne de commande traitée par un shell, utilisezshell plutôt que command.

Et, il devrait y avoir un meilleur moyen de régénérer les clés d'hôte ssh, mais je n'en trouve pas pour le moment ...

Michael Hampton
la source
Merci pour le shell vs astuce de commande (fonctionne très bien maintenant), je ne savais pas - encore assez nouveau pour ansible
Erreur de serveur
Concernant la dernière instruction (au moins sur CentOS / RHEL) si vous supprimez les anciennes clés et redémarrez les clés d'hôte du démon sont régénérées pour vous. Vous devrez quand même redémarrer le service, donc cela semble certainement un peu mieux.
Aaron Copley
@AaronCopley Je parlais plus d'un rôle Ansible que du service de distribution. Je suis conscient que la plupart des principales distributions ont un service systemd qui génère des clés d'hôte ssh. Malheureusement, ce service présente de subtiles différences spécifiques à la distribution (il est même différent entre CentOS et Fedora). Un rôle serait un bon moyen d'encapsuler tout cela, mais je ne peux pas en trouver un tout de suite.
Michael Hampton
Pas de soucis, je pensais juste le mentionner. (Vous le savez peut-être, mais OP peut-être pas.)
Aaron Copley
@AaronCopley - d'ailleurs, c'est ce que j'ai fini par faire. le echo ...bit n'a pas fonctionné après une deuxième exécution (je testais dans /tmp/lequel les clés n'existaient pas la première fois). J'ai eu recours à la suppression des clés d'hôte d'abord, comme vous le mentionnez, et à la génération de nouvelles. En ce qui concerne la régénération automatique des clés, cela dépend de votre distribution, n'est-ce pas? Toutes les distributions Linux n'utilisent pas systemd.
Erreur serveur
2

Utilisez le module spécial pour cette tâche:

- name: Generate an OpenSSH keypair with the default values (4096 bits, rsa)
  openssh_keypair:
    path: /home/youruser/.ssh/id_rsa
    owner: youruser
    group: youruser

- name: Fix owner of the generated pub key
  file:
    path: /home/youruser/.ssh/id_rsa.pub
    owner: youruser
    group: youruser
Jorj
la source
Ce ne sont pas des clés d'hôte ssh
KumZ
1

désolé, mais je ne pouvais pas utiliser "crée" dans une tâche. j'ai obtenu l'erreur suivante:

ERROR! 'creates' is not a valid attribute for a Task

par conséquent, j'utilise les tâches suivantes:

- name: remove existing ssh_host keys
  file: path={{ item }} state=absent
  with_items:
    - "/etc/ssh/ssh_host_rsa_key"
    - "/etc/ssh/ssh_host_dsa_key"
    - "/etc/ssh/ssh_host_ecdsa_key"

- name: Generate /etc/ssh/ RSA host key
  command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""

- name: Generate /etc/ssh/ DSA host key
  command : ssh-keygen -q -t dsa -f /etc/ssh/ssh_host_dsa_key -C "" -N ""

- name: Generate /etc/ssh/ ECDSA host key
  command : ssh-keygen -q -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -C "" -N ""
MaxiReglisse
la source
2
Utilisez une version actuelle d'Ansible.
Michael Hampton
Vous avez raison, ma version Ansible est un peu ancienne: 2.0.0.2 ... (Sur Ubuntu 16.04). Je dois changer !
MaxiReglisse
1

@Zoredache a la bonne réponse mais elle échoue (notée par @MaxiReglisse) pour les versions récentes d'Ansible. Utilisez plutôt le code suivant:

---
- hosts: all
  become: true
  gather_facts: false

  tasks:
  - name: Generate /etc/ssh/ RSA host key
    command : ssh-keygen -q -t rsa -f /etc/ssh/ssh_host_rsa_key -C "" -N ""
    args:
      creates: /etc/ssh/ssh_host_rsa_key
David Weber
la source
1

Une autre option consiste à utiliser le module utilisateur . Le côté positif est que vous aurez une tâche idempotente. Voici un exemple comment générer des clés ssh sur localhost:

- name: Generate ssh keys
  local_action:
    module: "user"
    name: "{{ lookup('env','USER') }}"
    generate_ssh_key: true
    ssh_key_type: "{{ item.0 }}"
    ssh_key_bits: "{{ item.1 }}"
    ssh_key_file: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
  with_together:
  - [ 'rsa', 'dsa' ]
  - [ 2048, 1024 ]
  loop_control:
    label: "{{ item.0 }}_{{ item.1 }}_key"

- name: Copy generated ssh keys to remote machine
  copy:
    src: "{{ playbook_dir }}/{{ item.0 }}_{{ item.1 }}_key"
    dest: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"
  with_nested:
  - [ 'rsa', 'dsa' ]
  - [ '', '.pub' ]
  notify:
  - Restart sshd
  loop_control:
    label: "/etc/ssh/ssh_host_{{ item.0 }}_key{{ item.1 }}"
HeroFromEarth
la source
1
N'est-ce pas pour les clés d'utilisateur, pas les clés d'hôte?
MadHatter
Vous pouvez également l'utiliser pour les clés d'hôte car c'est la même chose en fait. N'oubliez pas de restaurer le contexte selinux si vous utilisez SELinux en mode d'application
HeroFromEarth
D'après la documentation, ce n'est pas clair pour moi. Si vous réécriviez votre réponse afin qu'elle montre explicitement la création des clés d'hôte, je supprimerais mon downvote.
MadHatter
D'accord, ce n'était peut-être pas clair. J'ai ajouté une autre tâche pour expliquer comment copier ces clés sur une machine distante. Et bien sûr, ce n'est que mon cas (j'ai besoin des mêmes clés sur quelques machines pour un cluster, donc je dois les générer sur localhost) et je suis presque sûr que vous pouvez utiliser le module «utilisateur» pour générer des clés pour le serveur ssh sur la machine distante (regardez 'ssh_key_file')
HeroFromEarth
Je ne suis toujours pas sûr que ce soit autre chose qu'un hack (notamment parce qu'il laisse à un utilisateur une copie de la clé privée de l'hôte!) Mais au moins c'est quelque chose qui va maintenant répondre à la question comme demandé, j'ai donc supprimé mon downvote.
MadHatter
0

Utilisez les modules openssh_keypair et authorized_key pour créer et déployer les clés en même temps sans les enregistrer dans votre hôte ansible.

- openssh_keypair:
    group: root
    owner: root
    path: /some/path/in/your/server
    register: ssh_key

- name: Store public key into origin
  delegate_to: central_server_name
  authorized_key:
     key: "{{ssh_key.public_key}}"
     comment: "{{ansible_hostname}}"
     user: any_user_on_central
MUY Belgique
la source