Wie generiere ich Host-SSH-Schlüssel über ansible?

11

Ich versuche, SSH-Hostschlüssel auf einer Handvoll Remote-Servern über ansible (und ssh-keygen) neu zu generieren , aber die Dateien scheinen nicht angezeigt zu werden. Das Playbook läuft in Ordnung, aber die Dateien auf der Fernbedienung werden nicht geändert.

Ich muss auf das echo -eHackery zurückgreifen, da auf diesen Fernbedienungen Ubuntu 14.04 ausgeführt wird und nicht die richtige Version der python-pexpectverfügbaren (laut ansible) vorhanden ist.

Was vermisse ich? Mein Playbook und meine Ausgabe sind unten:

Spielbuch

---
- 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

Ausgabe

$ 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  
Serverfehler
quelle

Antworten:

14

Soweit ich weiß, ist der einzige Grund, warum Sie ein 'y' an ssh-keygen weiterleiten müssten, wenn Ihr Befehl eine vorhandene Datei ersetzt. Meiner Meinung nach ist dies kein guter Weg, um etwas mit einem Konfigurationsmanagement-Tool zu tun.

Sie sollten Ihre Aufgaben anpassen, um sie idempotent zu machen. Insbesondere wenn Sie das creates: filenamezu Ihrem Befehl hinzufügen , werden die neuen Schlüssel nur erstellt, wenn sie noch nicht vorhanden sind, anstatt jedes Mal ersetzt zu werden, wenn Sie dieses Playbook ausführen.

---
- 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

Wenn Sie diese Schlüssel aus irgendeinem Grund ersetzen möchten, z. B. wenn sie zu alt sind oder etwas anderes, möchten Sie möglicherweise eine weitere Aufgabe hinzufügen, um sie zu entfernen. Hier ist ein einfaches Löschen

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

Wenn Sie Dateien löschen möchten, die vor einer bestimmten Zeit erstellt wurden, können Sie das stat-Modul verwenden, um Details zu diesen Dateien abzurufen, und whenBedingungen einrichten, um sie selektiv zu entfernen, wenn sie älter als ein bestimmtes Datum oder etwas anderes sind.

Zoredache
quelle
Tolles Beispiel und vielen Dank für die Gedanken zur Aufrechterhaltung der Idempotenz. Für meinen Anwendungsfall stelle ich geklonte virtuelle Maschinen bereit, sodass immer Schlüssel zum Überschreiben vorhanden sind. Ich brauche die nukleare Option, um sie einfach zu entfernen und zu ersetzen.
Serverfehler
Wenn Sie immer möchten, dass es entfernt wird, würde ich wahrscheinlich den file: state:absent ...Ansatz für das Weiterleiten von Inhalten an ssh-keygen ausführen. Obwohl es wahrscheinlich keinen so großen Unterschied gibt.
Zoredache
Ah, ok. das macht mehr Sinn. Ich wusste es vor absentein paar Tagen nicht. Dadurch wird die Datei effektiv gelöscht, bevor der Schlüssel erneut generiert wird. Es ist ein viel klarerer Ansatz. Vielen Dank.
Serverfehler
6

Das ansible- commandModul leitet keine Befehle durch eine Shell . Dies bedeutet, dass Sie keine Shell-Operatoren wie die Pipe verwenden können. Aus diesem Grund wird das Pipe-Symbol in der Ausgabe angezeigt. Was ansible betrifft, hat es den Befehl echomit dem gesamten Rest der Zeile als Argumente für ausgeführt echo.

Wenn Sie die von einer Shell verarbeitete Befehlszeile benötigen, verwenden Sieshell anstelle von command.

Und es sollte einen besseren Weg geben, SSH-Hostschlüssel neu zu generieren, aber ich kann momentan keinen finden ...

Michael Hampton
quelle
Vielen Dank für die Shell vs. Befehl Spitze (funktioniert jetzt) Ich wusste nicht , - noch ziemlich neu in ansible
Server Fehler
In Bezug auf die letzte Anweisung (zumindest unter CentOS / RHEL) werden die Daemon-Hostschlüssel für Sie neu generiert, wenn Sie die alten Schlüssel entfernen und neu starten. Sie müssen den Dienst trotzdem neu starten, damit dies definitiv etwas besser erscheint.
Aaron Copley
@ AaronCopley Ich bezog mich eher auf eine Ansible-Rolle als auf den Distributionsdienst. Mir ist bekannt, dass die meisten großen Distributionen einen systemd-Dienst haben, der SSH-Hostschlüssel generiert. Leider weist dieser Dienst subtile distro-spezifische Unterschiede auf (er unterscheidet sich sogar zwischen CentOS und Fedora). Eine Rolle wäre ein guter Weg, um all das zusammenzufassen, aber ich kann nicht ohne weiteres eine finden.
Michael Hampton
Keine Sorge, ich dachte nur, ich würde es erwähnen. (Sie können wissen, aber OP möglicherweise nicht.)
Aaron Copley
@ AaronCopley - übrigens, das habe ich letztendlich getan. Das echo ...Bit funktionierte nach einem zweiten Durchlauf nicht (ich habe getestet, bei /tmp/dem die Schlüssel beim ersten Mal nicht vorhanden waren). Wie Sie bereits erwähnt haben, habe ich zuerst die Host-Schlüssel entfernt und neue generiert. Soweit die Schlüssel automatisch neu generiert werden, hängt dies von Ihrer Verteilung ab, richtig? Nicht alle Linux-Distributionen verwenden systemd.
Server Fehler
2

Verwenden Sie für diese Aufgabe das Spezialmodul:

- 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
quelle
Das sind keine
SSH-Hostschlüssel
1

Entschuldigung, aber das konnte ich nicht "erstellt" in einer Aufgabe verwenden. Ich habe den folgenden Fehler erhalten:

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

konsequent benutze ich die folgenden aufgaben:

- 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
quelle
2
Verwenden Sie eine aktuelle Version von Ansible.
Michael Hampton
Sie haben Recht, meine Ansible-Version ist etwas alt: 2.0.0.2 ... (unter Ubuntu 16.04). Ich muss wechseln !
MaxiReglisse
1

@Zoredache hat die richtige Antwort, schlägt jedoch für neuere Versionen von Ansible fehl (von @MaxiReglisse notiert). Verwenden Sie stattdessen den folgenden Code:

---
- 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
quelle
1

Eine weitere Option ist die Verwendung des Benutzermoduls . Positiv ist, dass Sie eine idempotente Aufgabe bekommen. Hier ist ein Beispiel zum Generieren von SSH-Schlüsseln auf 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
quelle
1
Gilt das nicht für Benutzerschlüssel, nicht für Hostschlüssel?
MadHatter
Sie können es auch für Hostschlüssel verwenden, da es tatsächlich dasselbe ist. Vergessen Sie nicht, den Selinux-Kontext wiederherzustellen, wenn Sie SELinux im Erzwingungsmodus verwenden
HeroFromEarth
Aus der Dokumentation geht mir nicht hervor, dass Sie das können. Wenn Sie Ihre Antwort so umschreiben würden, dass explizit angezeigt wird, dass Hostschlüssel erstellt werden, würde ich meine Ablehnung entfernen.
MadHatter
Okay, vielleicht war es unklar. Ich habe eine weitere Aufgabe hinzugefügt, um zu erklären, wie diese Schlüssel auf einem Remotecomputer kopiert werden. Und natürlich ist es nur mein Fall (ich benötige die gleichen Schlüssel auf einigen Computern für einen Cluster, also muss ich sie auf localhost generieren) und ich bin mir ziemlich sicher, dass Sie das 'Benutzer'-Modul verwenden können, um Schlüssel für den SSH-Server zu generieren die entfernte Maschine (siehe 'ssh_key_file')
HeroFromEarth
Ich bin mir immer noch nicht sicher, ob es etwas anderes als ein Hack ist (nicht zuletzt, weil ein Benutzer eine Kopie des privaten Hostschlüssels hat!), Aber zumindest ist es etwas, das jetzt die gestellte Frage beantwortet, also habe ich meine entfernt abstimmen.
MadHatter
0

Verwenden Sie das Modul openssh_keypair und authorized_key, um die Schlüssel gleichzeitig zu erstellen und bereitzustellen, ohne sie auf Ihrem ansible Host zu speichern.

- 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 Belgien
quelle