晴耕雨読

working in the fields on fine days and reading books on rainy days

[Ansible] SSH公開鍵認証からプレイブック実行までの流れ

Ansibleの使い方について、簡単に説明します。

Ansibleはリモートでコマンドを実行するために、sshでサーバに接続します。 Ansibleを使うためには、まずSSHの公開鍵認証でサーバに接続できるようにします。

秘密鍵と公開鍵の生成

ssh-keygen コマンドを利用して、秘密鍵と公開鍵の生成します。 ここでは、鍵の生成にSSH認証において最強の鍵である楕円曲線暗号 ed25519 を使用しています。 すでに鍵を作成済みの場合、再作成する必要はありません

$ ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519

接続先情報の設定

SSHでサーバに接続する際の情報を ~/.ssh/config に追加します。各設定項目は以下の通りです。

  • Host : サーバ名(HostNameを指定する場合は識別子)
    • HostName : サーバのIP(省略可)
    • User : サーバログイン時に使用するユーザ名
    • IdentityFile : サーバログイン時に使用する

~/.ssh/config には以下のように設定を追加します。この場合、ssh centos8ssh mako@192.168.11.102 で接続できるようになります。

Host centos8
  HostName 192.168.11.102
  User mako
  IdentityFile ~/.ssh/id_ed25519

サーバに公開鍵を登録する

ssh-copy-id コマンドを利用して、生成した公開鍵をサーバの ~/.ssh/authorized_keys に追加します。 このコマンドを使わない方法もありますが、ssh-copy-id の使用を推奨します 1

$ ssh-copy-id -i ~/.ssh/id_ed25519 centos8

公開鍵認証の確認

サーバに登録した公開鍵でログインできることを以下のコマンドで確認します。

$ ssh centos8

または

$ ssh mako@192.168.11.102

Ansibleの疎通確認

インベントリは、ターゲットノードの接続情報を記載したファイルです。 接続先のサーバ情報をインベントリファイル「inventory.ini」に書いて、新規ファイルとして保存します。

[linuxservers]
centos8 ansible_host=192.168.11.102

以下の ansible コマンドを実行し、ping モジュールによる疎通を確認します。

$ ansible all -i inventory.ini -m ping

結果は json 形式で表示されます。SUCCESS であれば疎通できていることが確認できます。

centos8 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    },
    "changed": false,
    "ping": "pong"
}

Ansibleによるコマンドの実行

Ansibleでは、プレイブックにYAML形式で自動化する内容を記述します。 ここでは、ファイル mytest.yml に以下の内容を書き、/etc/os-release の内容を表示するプレイブックを作成します。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Get OS version
      command: cat /etc/os-release
      register: res_command

    - name: Show Result
      debug:
        msg: "{{ res_command['stdout_lines'] }}"

以下の ansible-playbook コマンドでプレイブックを実行します。

$ ansible-playbook -i inventory.ini mytest.yml

実行結果:

PLAY [linuxservers] *****************************************************************

TASK [Get OS version] ***************************************************************
changed: [centos8]

TASK [Show Result] ******************************************************************
ok: [centos8] => {
    "msg": [
        "NAME=\"CentOS Stream\"",
        "VERSION=\"8\"",
        "ID=\"centos\"",
        "ID_LIKE=\"rhel fedora\"",
        "VERSION_ID=\"8\"",
        "PLATFORM_ID=\"platform:el8\"",
        "PRETTY_NAME=\"CentOS Stream 8\"",
        "ANSI_COLOR=\"0;31\"",
        "CPE_NAME=\"cpe:/o:centos:centos:8\"",
        "HOME_URL=\"https://centos.org/\"",
        "BUG_REPORT_URL=\"https://bugzilla.redhat.com/\"",
        "REDHAT_SUPPORT_PRODUCT=\"Red Hat Enterprise Linux 8\"",
        "REDHAT_SUPPORT_PRODUCT_VERSION=\"CentOS Stream\""
    ]
}

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

Ansibleによるサービス起動

サービス起動を定義したプレイブック mytest2.yml を以下の内容で作成します。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Start httpd service
      service:
        name: httpd
        state: started
      become: true

ansible-playbook コマンドでプレイブックを実行します。 今回は root に昇格する必要があるため、become で root ユーザに sudo で昇格するときのパスワードを入力するためのオプション –ask-become-pass を追加します。

$ ansible-playbook -i inventory.ini mytest3.yml --ask-become-pass

実行結果:

BECOME password: rootパスワードを入力

PLAY [linuxservers] *****************************************************************

TASK [Start httpd service] **********************************************************
changed: [centos8]

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

Ansibleによるファイアウォール管理

HTTPのポートをファイアウォールで開く方法を定義したプレイブック mytest3.yml を以下の内容で作成します。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Permit traffic for http service
      firewalld:
        service: http
        permanent: true
        state: enabled
      become: true

ansible-playbook コマンドでプレイブックを実行します。

$ ansible-playbook -i inventory.ini mytest3.yml --ask-become-pass

Ansibleによるユーザ管理

ユーザのパスワードを設定するプレイブック mytest4.yml を以下の内容で作成します。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Create user
      user:
        name: testuser
        password: testuser123
      become: true

ansible-playbook コマンドでプレイブックを実行します。

$ ansible-playbook -i inventory.ini mytest4.yml --ask-become-pass

条件の設定 (when)

特定のホストで特定の処理をスキップしたいときは、whenステートメントを使用します。 ansible_facts という変数には、接続先のホストの情報が格納されており、whenを使って条件を満たすときのみ処理を実行するということを実現します。

---
- hosts: linuxservers

  tasks:
    - name: shut down CentOS 7 systems
      command: /sbin/shutdown -t now
      when: ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "7"

ループ文 (loop)

処理を繰り返したいときは、loopを使用します。繰り返しでリストに参照する際の変数名は「item」です。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Add Users
      user:
        name: "{{ item }}"
        state: present
      loop:
        - testuser1
        - testuser2
      become: true

リストの要素は、文字列だけでなくハッシュ(連想配列)にすることも可能です。

---
- hosts: linuxservers
  gather_facts: false

  tasks:
    - name: Add Users
      user:
        name: "{{ item.name }}"
        state: present
        groups: "{{ item.groups }}"
      loop:
        - { name: 'testuser1', groups: 'wheel' }
        - { name: 'testuser2', groups: 'root' }
      become: true

以上です。

参考文献


  1. ssh-copy-id コマンドを利用しないでサーバに公開鍵を登録するには、以下のコマンドを実行します。

    $ cat ~/.ssh/id_ed25519.pub | ssh ホスト名 'mkdir -p ~/.ssh; chmod 700 ~/.ssh; cat >> ~/.ssh/authorized_keys; chmod 600 ~/.ssh/authorized_keys'