ansibleを介してホストSSHキーを生成する方法は?


11

ansible(およびssh-keygen)を介して少数のリモートサーバーでSSHホストキーを再生成しようとしていますが、ファイルが表示されないようです。プレイブックは正常に実行されますが、リモートのファイルは変更されません。

echo -eこれらのリモートはUbuntu 14.04を実行していて、python-pexpect使用可能なバージョンのバージョンが(ansibleによると)ないため、ハッカーに頼る必要があります。

何が欠けていますか?私のプレイブックと出力は以下の通りです:

プレイブック

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

出力

$ 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  

回答:


14

私が知っている限り、ssh-keygenに「y」をパイプする必要がある唯一の理由は、コマンドが既存のファイルを置き換える場合です。私の意見では、これは構成管理ツールから何かを行うための良い方法ではありません。

タスクをべき等になるように調整する必要があります。具体的creates: filenameには、コマンドにを追加した場合、新しいキーは、そのプレイブックを実行するたびに置き換えられるのではなく、存在しない場合にのみ作成されます。

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

なんらかの理由でそれらのキーを交換したい場合(例えば、キーが古すぎた場合など)、別のタスクを追加してそれらを削除することができます。これは簡単な削除です

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

特定の時間より前に生成されたファイルを削除したい場合は、statモジュールを使用してこのファイルの詳細を取得し、when条件を設定して、特定の日付よりも古い場合にそれらを選択的に削除できます。


べき等を維持することについての考えに対する素晴らしい例と感謝。私の使用例では、クローン仮想マシンをプロビジョニングしているため、上書きするキーは常に存在します。取り外して交換するだけの核のオプションが必要です。
サーバー障害

常にそれを削除したい場合は、おそらくfile: state:absent ...ssh-keygenにパイプすることでアプローチを行うでしょう。おそらくそれほど大きな違いはありませんが。
Zoredache

あ、そう。それはもっと理にかなっています。absent数日前は知りませんでした。事実上、キーを再生成する前にファイルが削除されます。これはより明確なアプローチです。ありがとう。
サーバー障害、

6

ansible commandモジュール は、シェルを介してコマンドを渡しません。つまり、パイプなどのシェルオペレーターは使用できません。そのため、出力にパイプシンボルが表示されます。ansibleに関する限り、それはecho行の残りすべてをへの引数としてコマンドを実行しましたecho

シェルでコマンドラインを処理する必要がある場合は、の代わりに使用してくださいshellcommand

そして、sshホストキーを再生成するためのより良い方法があるはずですが、今は見つかりません...


シェル対コマンド先端をありがとう(現在正常に動作します)私は知りませんでした- ansibleにまだかなり新しい
サーバー障害

最後のステートメント(少なくともCentOS / RHELでは)について、古いキーを削除してデーモンを再起動すると、ホストキーが再生成されます。とにかくサービスを再起動する必要があるので、これは間違いなく多少良くなるようです。
アーロンコプリー

@AaronCopley私は、ディストリビューションサービスというより、Ansibleの役割について言及していました。ほとんどの主要なディストリビューションには、sshホストキーを生成するsystemdサービスがあることがわかっています。残念ながら、このサービスにはディストリビューション固有の微妙な違いがあります(CentOSとFedoraの間でも違いがあります)。役割は、これらすべてをカプセル化するための優れた方法ですが、私は1つの手がかりを見つけることができません。
マイケルハンプトン

心配する必要はありません。(あなたは知っているかもしれませんが、OPはそうでないかもしれません。)
アーロン・コプリ

@AaronCopley-ちなみに、これは私がやったことです。echo ...2回目の実行後、ビットは機能しませんでした(私は/tmp/、最初にキーが存在しないことをテストしていました)。先に述べたように、最初にホストキーを削除し、新しいキーを生成することに頼りました。キーが自動的に再生成される限り、これはディストリビューションに依存しますよね?すべてのLinuxディストリビューションがsystemdを使用するわけではありません。
サーバー障害

2

このタスクには特別なモジュールを使用します。

- 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

これらはSSHホストキーではありません
KumZ

1

申し訳ありませんが、タスクで「作成」を使用できませんでした。次のエラーが発生しました:

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

結果として、私は次のタスクを使用します。

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

2
現在のバージョンのAnsibleを使用します。
マイケルハンプトン

そうです、私のAnsibleバージョンは少し古いです:2.0.0.2 ...(Ubuntu 16.04)。変わらなきゃ!
MaxiReglisse 2018

1

@Zoredacheは正しい答えを持っていますが、Ansibleの最近のバージョンでは失敗します(@MaxiReglisseで示されます)。代わりに次のコードを使用してください。

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

1

別のオプションは、ユーザーモジュールを使用することです。これの良い面は、べき等のタスクを取得することです。ローカルホストでSSH鍵を生成する方法の例を次に示します。

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

1
ホストキーではなく、ユーザーキーのことではありませんか?
MadHatter

実際には同じものなので、ホストキーにも使用できます。強制モードでSELinuxを使用する場合は、selinuxコンテキストを復元することを忘れないでください
HeroFromEarth

あなたができるドキュメントから私には明確ではありません。作成中のホストキーが明示的に表示されるように回答を書き換える場合は、反対票を削除します。
MadHatter

わかりました、多分それは不明確でした。これらのキーをリモートマシンにコピーする方法を説明する別のタスクを追加しました。そしてもちろんそれは私のケースだけです(私はクラスターのいくつかのマシンで同じキーが必要なのでlocalhostでそれらを生成する必要があります)そして 'user'モジュールを使用してsshサーバーのキーを生成できると確信していますリモートマシン( 'ssh_key_file'を見てください)
HeroFromEarth

それでもハッキング以外のことは確かではありません(特に、1人のユーザーにホストの秘密鍵のコピーが残るためです!)少なくとも、要求されたとおりに質問に答えられるものなので、削除しました反対票。
MadHatter

0

openssh_keypairおよびauthorized_keyモジュールを使用して、キーを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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.