Ansibleを使用して、複数のUbuntu 22.04サーバーの初期セットアップを自動化する方法

著者は、Write for Donationsプログラムの一環として、寄付を受けるためにフリー&オープンソース基金を選びました。

イントロダクション

Ansibleは、サーバーやアプリケーションのプロビジョニング、設定管理、展開を自動化するために使用されるオープンソースのソフトウェアツールです。Ansibleを使用すると、1つ以上のサーバー上でタスクを自動化したり、複数のサーバー上で分散アプリケーションを実行したりすることができます。マルチサーバーセットアップでは、各サーバーの初期サーバーセットアップを完了するのに時間がかかることがありますが、Ansibleを使用すると自動化プレイブックでプロセスをスピーディに進めることができます。

Ansibleはエージェントレスなので、Ansibleを実行するためにサーバーに任意のAnsibleコンポーネントをインストールする必要はありません。これらのサーバーはAnsibleホストであり、Python 3とOpenSSHが事前にUbuntu 22.04とすべてのLinuxディストリビューションにインストールされている必要があります。Ansibleコントロールノードは自動化を開始するマシンであり、互換性のあるUnix系オペレーティングシステムまたはWindows(Windows Subsystem for Linux(WSL)がインストールされている場合)を実行できます。

このチュートリアルでは、Ansibleを使用して複数のUbuntu 22.04サーバーの初期サーバー設定を自動化します。すべてのサーバーで次の初期設定タスクを実行します。

  • Updating installed packages
  • Adding a non-root user with admin privileges
  • Enabling SSH access for that non-root user
  • Enabling the firewall
  • Changing the port for SSH access and using the firewall to protect against brute-force attacks and boost the overall security of the servers
  • Disabling remote login for the root account
  • Making sure critical services are active
  • Removing package dependencies that are no longer required

ansibleを使用して各タスクを定義する包括的なプレイブックを実行するため、個々のサーバに個別にログインする必要なく、これらのタスクは単一のコマンドで完了されます。最初のサーバー設定後、オプションの2次プレイブックを実行してサーバー管理を自動化することもできます。

前提条件

このチュートリアルを完了するためには、以下のものが必要です:

  • Ansible installed on a machine that will act as your control node, which can be your local machine or a remote Linux server. To install Ansible, follow Step 1 of How To Install and Configure Ansible on Ubuntu 22.04, and you can refer to the official Ansible installation guide as needed for other operating systems.If your control node is a remote Ubuntu 22.04 server, be sure to set it up using the Initial Server Setup and create its SSH key pair as well.
    Git installed on the control node. Follow the How To Install Git tutorials for popular Linux distributions.
    (Optional) In Step 5, you will use Ansible Vault to create an encrypted password file for your hosts’ users. Ansible Vault uses vi as its default editor. If your control node is a Linux machine and you prefer using nano, use the section on Setting the Ansible Vault Editor in the How To Use Ansible Vault tutorial to change the text editor linked to the EDITOR environment shell variable. This tutorial will use nano as the editor for Ansible Vault.
  • Two or more Ubuntu 22.04 servers and the public IPv4 address of each server. No prior setup is required as you’ll use Ansible to automate setup in Step 5, but you must have SSH access to these servers from the Ansible control node mentioned above. If you are using Silicon Cloud vServers, you’ll find the IPv4 address in each server’s Public Network section of the Networking tab in your dashboard.If your control node is a remote Ubuntu 22.04 server, be sure to use ssh-copy-id to connect the key pair to the hosts.

ステップ1 – コントロールノード上のSSHクライアント設定ファイルの変更

このステップでは、制御ノードのSSHクライアント設定ファイルの指示を変更します。この変更を行うと、リモートマシンのSSHキーの指紋を受け入れるようにプロンプトが表示されなくなります。各リモートマシンのSSHキーの指紋を手動で受け入れるのは手間がかかるため、この変更により、複数のサーバーの初期設定を自動化する際のスケーリングの問題が解決されます。

Ansibleのknown_hostsモジュールを使用して、単一のホストのSSHキーの指紋を自動的に受け入れることができますが、このチュートリアルでは複数のホストを扱っているため、制御ノード(通常はローカルマシン)のSSHクライアント設定ファイルを変更する方が効果的です。

最初に、制御ノードで端末アプリケーションを起動し、nanoあるいはお気に入りのテキストエディタを使用して、SSHクライアントの設定ファイルを開きます。

  1. sudo nano /etc/ssh/ssh_config

 

StrictHostKeyCheckingディレクティブが含まれている行を見つけて、コメントを解除し、値を以下のように変更してください。

以下の文を日本語で自然な表現に置き換えてください。1つのオプションの提供で十分です:
/etc/ssh/ssh_config→ SSHの設定ファイルである、/etc/ssh/ssh_config

...
   StrictHostKeyChecking accept-new
...

ファイルを保存して閉じてください。SSHのクライアント設定ファイルのみを変更したため、SSHデーモンを再読み込みや再起動する必要はありません。

Note

注意:もしStrictHostKeyCheckingの値を永久的にaskからaccept-newに変更したくない場合は、ステップ7でプレイブックを実行した後にデフォルトに戻すことができます。値を変更すると、システムが自動的にSSHキーのフィンガープリントを受け入れるようになりますが、フィンガープリントが変更されると、同じホストからの後続の接続は拒否されます。この機能により、accept-newの変更はその指示の値をnoに変更するよりもセキュリティリスクは少なくなります。

SSHディレクティブを更新したので、次はAnsibleの設定を開始します。次の手順で行います。

ステップ2- Ansibleホストファイルの設定

Ansibleのホストファイル(またはインベントリファイル)には、Ansibleホストの情報が含まれています。この情報には、グループ名、エイリアス、ドメイン名、IPアドレスなどが含まれる場合があります。ファイルはデフォルトで/etc/ansibleディレクトリに配置されています。この手順では、事前準備セクションで起動したAnsibleホストのIPアドレスを追加し、Ansible playbookを実行できるようにします。

最初に、nanoまたはお気に入りのテキストエディタを使用してホストファイルを開きます。

  1. sudo nano /etc/ansible/hosts

 

ファイルの冒頭コメントの後に、以下の行を追加してください。

以下の文を日本語で自然に言い換えてください。1つのオプションで構いません。
「/etc/ansible/hosts」
...

host1 ansible_host=host1-public-ip-address
host2 ansible_host=host2-public-ip-address
host3 ansible_host=host3-public-ip-address

[initial]
host1
host2
host3

[ongoing]
host1
host2
host3

ホスト1、ホスト2、ホスト3はそれぞれ初期サーバーの自動設定を行いたいホストに対する別名です。別名を使用することで、他の場所でホストを参照するのが容易になります。ansible_hostはAnsibleの接続変数であり、この場合、ターゲットホストのIPアドレスを指しています。

初期と継続は、Ansibleホストのサンプルグループ名です。ホストが何に使用されるかを簡単に知ることができるようなグループ名を選んでください。このようにホストをグループ化すると、まとまった形で対応することが可能です。ホストは複数のグループに所属することができます。このチュートリアルでは、ふたつの異なるプレイブックで使用されるため、ホストは2つの異なるグループに割り当てられています。ステップ6の初期サーバーセットアップのためには「初期グループ」、ステップ8の後続サーバー管理のためには「継続グループ」として割り当てられています。

hostNのパブリックIPアドレスは、各AnsibleホストのIPアドレスです。host1のパブリックIPアドレスとその後の行は、自動化の一部となるサーバーのIPアドレスに置き換えてください。

ファイルの編集が終わったら、保存して閉じてください。

インベントリファイルでホストを定義することで、Ansibleの自動化でどのホストが設定されるか指定することができます。次のステップでは、複数のサーバーのセットアップを自動化するためのサンプルプレイブックをリポジトリからクローンします。

ステップ3 — Ansible Ubuntuイニシャルサーバーセットアップリポジトリのクローン操作

このステップでは、GitHubからサンプルリポジトリをクローンして、この自動化に必要なファイルを取得します。

このリポジトリには、サンプルのマルチサーバーオートメーションに必要な3つのファイルが含まれています: initial.yml、ongoing.yml、そしてvars/default.ymlです。initial.ymlファイルは、Ansibleホストに対して初期設定のために実行するプレイとタスクが含まれています。ongoing.ymlファイルには、初期サーバーセットアップ後にホストに対して実行するタスクが含まれています。vars/default.ymlファイルには、ステップ6とステップ8の両方で呼び出される変数が含まれています。

リポジトリをクローンするには、次のコマンドを入力してください。

  1. git clone https://github.com/do-community/ansible-ubuntu.git

 

もしご自身のSSHキーをGitHubアカウントに追加している場合は、次のコマンドを使用してリポジトリをクローンすることもできます。

  1. git@github.com:do-community/ansible-ubuntu.git

 

今、あなたの作業ディレクトリにansible-ubuntuという名前のフォルダが作成されました。そのフォルダに移動してください。

  1. cd ansible-ubuntu

 

このチュートリアルの残りの部分では、それがあなたの作業ディレクトリになります。

このステップでは、Ansibleを使用して複数のUbuntu 22.04サーバーを自動化するためのサンプルファイルを取得しました。次に、ホストに合わせた情報を含むvars/default.ymlファイルを更新して、システムと連携させます。

ステップ4 — Ansibleの変数の修正

このプレイブックでは、自動化に関する情報を参照しますが、時間経過に伴い更新が必要な場合があります。その情報を1つの変数ファイルに配置し、プレイブック内で変数を呼び出す方が、プレイブック内で直接コーディングするよりも効率的です。そのため、このステップでは、お好みやセットアップの要件に合わせて変数をvars/default.ymlファイルで変更します。

最初に、ファイルをナノまたはお気に入りのテキストエディタで開きます。

  1. nano vars/default.yml

 

ファイルの内容を確認します。以下の変数が含まれています。

デフォルトの変数を含むvars/default.yml
create_user: sammy

ssh_port: 5995

copy_local_key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"

create_user変数の値は、各ホストに作成されるsudoユーザーの名前である必要があります。この場合は「sammy」ですが、ユーザーの名前は好きなように設定できます。

以下の通り日本語で言い換えることができます。

Ansibleホストに接続するために使用するSSHポートは、ssh_port変数に格納されています。SSHのデフォルトポートは22ですが、変更することで自動化された攻撃がサーバーに対して著しく減少します。この変更は任意ですが、ホストのセキュリティ状態を向上させます。1024から65535の範囲内で、Ansibleホスト上の他のアプリケーションで使用されていないあまり知られていないポートを選択すべきです。この例ではポート5995を使用しています。

Note

注意:コントロールノードがLinuxディストリビューションを実行している場合、1023より大きい番号を選択し、/etc/servicesでそれを検索してください。例えば、grep 5995 /etc/services を実行して、5995が使用されているかどうかを確認します。出力がない場合は、そのポートはそのファイルに存在しないため、変数に割り当てることができます。コントロールノードがLinuxディストリビューションではない場合で、どこでそのシステムの同等な場所を見つけるかわからない場合は、Service Name and Transport Protocol Port Number Registryを参照することができます。

copy_local_keyという変数は、制御ノードのSSH公開鍵ファイルを参照しています。そのファイルの名前がid_rsa.pubであれば、その行に変更を加える必要はありません。それ以外の場合は、制御ノードのSSH公開鍵ファイルと一致するように変更してください。ファイルは制御ノードの~/.sshディレクトリの下にあります。ステップ5でメインのプレイブックを実行し、sudo特権を持つユーザーが作成されると、Ansibleコントローラーは公開鍵ファイルをユーザーのホームディレクトリにコピーします。これにより、初期サーバーのセットアップ後にそのユーザーとしてSSH経由でログインすることができるようになります。

ファイルの編集が完了したら、保存して閉じてください。

「vars/default.yml」に変数に値を割り当てたので、Ansibleはステップ6とステップ8のプレイブック実行中にこれらの変数を呼び出すことができるようになります。次のステップでは、Ansible Vaultを使用して、各ホストに作成されるユーザーのパスワードを作成し、安全に保護します。

ステップ5 — 暗号化されたパスワードファイルを作成するためにAnsible Vaultを使用する

Ansible Vaultは、playbooksで参照されるファイルと変数を作成および暗号化するために使用されます。Ansible Vaultを使用することで、playbookの実行中に機密情報が平文で送信されないことが保証されます。このステップでは、各ホストのsudoユーザーのパスワードを作成するために使用される値を含むファイルを作成し、暗号化します。この方法でAnsible Vaultを使用することで、初期のサーバーセットアップ中およびその後のplaybooks内でパスワードが平文で参照されないことが保証されます。

アンシブル-ウブントゥディレクトリ内にいる状態で、以下のコマンドを使ってボールトファイルを作成し、開いてください。

  1. ansible-vault create secret

 

指示が表示されたら、秘密のファイルを暗号化するために使用されるパスワードを入力して確認してください。これは、保管庫のパスワードです。ステップ6とステップ8でプレイブックを実行する際に、保管庫のパスワードが必要になるため、忘れないようにしてください。

金庫のパスワードを入力し、確認した後、シェルのEDITOR環境変数にリンクされているテキストエディタで秘密ファイルが開きます。以下の行をファイルに追加し、type_a_strong_password_hereとtype_a_salt_hereの値を入力してください。

〜/ansible-ubuntu/secret を日本語で同義の表現に変えると、次のようになります。
〜/ansible-ubuntu/秘密
  1. password: type_a_strong_password_here
  2. password_salt: type_a_salt_here

 

パスワード変数の値は、各ホストに作成するsudoユーザーの実際のパスワードになります。 password_salt変数は、その値に対してソルトを使用します。ソルトは、ハッシュされたパスワードを生成するために使用される長いランダムな値です。アルファベットまたは英数字の文字列を使用することができますが、単独の数字の文字列だけでは機能しない場合があります。ハッシュされたパスワードを生成する際にソルトを追加することで、パスワードを推測したりハッシュを解読することがより困難になります。両変数は、ステップ6およびステップ8でプレイブックを実行する際に呼び出されます。

Note

注意:テストの結果、数字のみで構成された塩がStep 6とStep 8のプレイブック実行に問題を引き起こすことがわかりました。しかし、アルファベットのみで構成された塩は正常に動作しました。また、英数字の塩も動作するはずです。塩を指定する際にはこれを念頭に置いてください。

ファイルの編集が終わったら、保存して閉じてください。 (ファイルのへんしゅうが おわったら、ほぞんして とじてください。)

以下の日本語の表現を参考にしてください:
「ユーザーに関するパスワードを作成するための変数を使って、暗号化されたパスワードファイルを作成しました。次の手順では、メインのAnsibleプレイブックを実行することで、ステップ2で指定したサーバーの初期セットアップを自動化します。」

ステップ6:Ansibleホストに対してメインのプレイブックを実行します。

このステップでは、Ansibleを使用して、インベントリファイルで指定したサーバーの初期セットアップを自動化します。まず、メインのプレイブックで定義されたタスクを確認します。次に、ホストに対してプレイブックを実行します。

Ansibleのプレイブックは、1つまたは複数のプレイと、それぞれのプレイに関連付けられた1つ以上のタスクで構成されています。Ansibleホストに対して実行するサンプルのプレイブックには、合計14のタスクを持つ2つのプレイが含まれています。

プレイブックを実行する前に、セットアッププロセスに関与する各タスクを確認します。開始するには、nanoまたはお気に入りのテキストエディタでファイルを開いてください。

  1. nano initial.yml

 

プレイ1:

ファイルの最初のセクションには、プレイの振る舞いに影響を与える以下のキーワードが含まれています。

initial.ymlの日本語による表現は以下の通りです(1つのオプションのみ):
初期.yml
- name: Initial server setup tasks
  hosts: initial
  remote_user: root
  vars_files:
    - vars/default.yml
    - secret
...

プレイの名前は、プレイが実行される際に端末に表示されるプレイの短い説明です。hostsキーワードは、プレイの対象となるホストを示しています。この場合、キーワードに渡されるパターンは、ステップ2で指定したホストのグループ名です。remote_userキーワードを使用して、Ansibleコントローラーにログインするためのユーザー名を指定します(この場合はroot)。vars_filesキーワードは、タスクを実行する際にプレイが参照する変数が含まれているファイルを指定します。

この設定では、AnsibleコントローラーはSSHポート22を介してルートユーザーとしてホストにログインしようとします。ログインできたホストごとにOKの応答を報告します。それ以外の場合は、サーバーにアクセスできないと報告し、ログインできるホストに対して、プレイのタスクを実行し始めます。手動でこの設定を行っている場合、この自動化によりssh root@ホストのIPアドレスにログインする必要がありません。

キーワードセクションに続いて、順次実行されるタスクのリストがあります。演劇と同様に、各タスクは名前で始まり、そのタスクがどのような目的を果たすかの短い説明が記載されています。

タスク1:キャッシュを更新します。

プレイブックの最初のタスクは、パッケージデータベースの更新です。

最初の.yml
...
- name: update cache
  ansible.builtin.apt:
    update_cache: yes
...

このタスクは、ansible.builtin.apt モジュールを使用してパッケージデータベースを更新するために定義されているため、update_cache: yes と定義されています。このタスクは、しばしばインストールされたすべてのパッケージを更新する前に、Ubuntu サーバーにログインし sudo apt update と入力するのと同じことを実現します。

課題2:インストールされているすべてのパッケージを更新します。

プレイブックの2つ目のタスクはパッケージの更新です。

最初の.yml
...
- name: Update all installed packages
  ansible.builtin.apt:
    name: "*"
    state: latest
...

最初のタスクと同様に、このタスクでもansible.builtin.aptモジュールを呼び出します。ここでは、ワイルドカード(name: “*”)とstate: latestを使用して、インストールされているすべてのパッケージが最新であることを確認します。これは、サーバーにログインしてsudo apt upgrade -yコマンドを実行するのと同等です。

タスク3: NTPサービスが正常に動作していることを確認してください。 (Tasuku 3: NTP sābisu ga seikō ni dōsa shite iru koto o kakunin shite kudasai.)

プレイブックの第3のタスクは、ネットワークタイムプロトコル(NTP)デーモンがアクティブになっていることを確認します。

最初の.yml
...
- name: Make sure NTP service is running
  ansible.builtin.systemd:
    state: started
    name: systemd-timesyncd
...

このタスクでは、ansible.builtin.systemdモジュールを呼び出して、systemd-timesyncdというNTPデーモンが実行されているか確認します(状態:開始)。サーバー間で同じ時刻を維持するために、分散アプリケーションを運用する際にこのようなタスクを実行します。

タスク4: sudoグループがあることを確認してください。

プレイブックの4番目のタスクでは、sudoグループが存在するかどうかを確認します。

最初の.yml
...
- name: Make sure we have a 'sudo' group
  ansible.builtin.group:
    name: sudo
    state: present
...

このタスクでは、ansible.builtin.groupモジュールを呼び出して、ホスト上にsudoという名前のグループが存在するかを確認します(状態:present)。次のタスクはホスト上にsudoグループが存在することに依存しているため、このタスクではsudoグループが存在するかを確認し、次のタスクが失敗しないことを確認します。

タスク5:sudo特権を持つユーザーを作成してください。

プレイブックの第5のタスクでは、sudo権限を持つ非ルートユーザーを作成します。

最初の.yml
...
- name: Create a user with sudo privileges
  ansible.builtin.user:
    name: "{{ create_user }}"
    state: present
    groups: sudo
    append: true
    create_home: true
    shell: /bin/bash
    password: "{{ password | password_hash('sha512', password_salt) }}"
    update_password: on_create
...

ここでは、ansible.builtin.userモジュールを呼び出し、ユーザーごとにユーザーを作成し、ユーザーのグループにsudoグループを追加します。ユーザー名はvars/default.ymlで指定したcreate_user変数の値から派生します。このタスクでは、ユーザーのためにホームディレクトリが作成され、適切なシェルで割り当てられることも確認されます。

ステップ5で設定したパスワードとソルトの組み合わせを使用して、パスワードパラメータと組み合わせた関数がSHA-512の暗号ハッシュアルゴリズムを呼び出し、ユーザーのパスワードをハッシュ化します。秘密の保管庫ファイルとペアになっているため、パスワードは平文でコントローラーに渡されることはありません。update_passwordを使用することで、ハッシュ化されたパスワードがユーザーが作成された最初の時点でのみ設定されることを保証します。もしプレイブックを再実行しても、パスワードは再生成されません。

タスク6:リモートユーザーの認証キーを設定する。

プレイブックの第6のタスクは、ユーザーの鍵を設定します。

初期.yml
...
- name: Set authorized key for remote user
  ansible.posix.authorized_key:
    user: "{{ create_user }}"
    state: present
    key: "{{ copy_local_key }}"
...

このタスクでは、ansible.posix.authorized_keyを呼び出すことで公開SSHキーをホストにコピーします。userの値は、前のタスクでホストに作成されたユーザーの名前であり、keyはコピーするキーを指します。両方の変数はvar/default.ymlファイルで定義されています。このタスクは、ssh-copy-idコマンドを手動で実行するのと同じ効果があります。

タスク7:rootのリモートログインを無効にする

プレイブックの7番目のタスクでは、rootユーザーに対するリモートログインを無効にします。

最初の.yml
...
- name: Disable remote login for root
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    state: present
    regexp: '^PermitRootLogin yes'
    line: 'PermitRootLogin no'
...

次に、ansible.builtin.lineinfileモジュールを呼び出します。このタスクでは、正規表現(regexp)を使用して、/etc/ssh/sshd_configファイル内のPermitRootLoginで始まる行を検索し、それをlineの値で置換します。このタスクにより、このプレイブックの実行後、rootアカウントを使用したリモートログインが失敗することが保証されます。タスク6で作成されたユーザーアカウントでのみリモートログインが成功します。リモートルートログインを無効にすることで、通常sudoと呼ばれる特権昇格の方法が必要となり、一般のユーザーのみがログインでき、管理者特権を取得するために必要となります。

課題8: SSHポートの変更

プレイブックの8番目のタスクでは、SSHのポートを変更します。

最初の.yml
...
- name: Change the SSH port
  ansible.builtin.lineinfile:
    path: /etc/ssh/sshd_config
    state: present
    regexp: '^#Port 22'
    line: 'Port "{{ ssh_port }}"'
...

SSHが一般的なポート22で待ち受けているため、そのポートを狙った自動攻撃にさらされやすい傾向があります。SSHが待ち受けるポートを変更することで、ホストに対する自動攻撃の数を減らすことができます。このタスクでは、ansible.builtin.lineinfileモジュールを使用して、SSHデーモンの設定ファイルで正規表現で始まる行を検索し、その値をlineパラメータの値に変更します。SSHが待ち受ける新しいポート番号は、ステップ4でssh_port変数に割り当てたポート番号になります。このプレイの最後でホストを再起動した後、ポート22経由でホストにログインすることはできません。

タスク9: UFW – SSH接続を許可する

プレイブックの9番目のタスクでは、SSHトラフィックを許可します。

初期の.yml
...
- name: UFW - Allow SSH connections
  community.general.ufw:
    rule: allow
    port: "{{ ssh_port }}"
...

ここでは、コミュニティ全体のufwモジュールを呼び出し、ファイアウォールを介してSSHトラフィックを許可します。SSHのポート番号は22ではなく、ステップ4のvars/default.ymlファイルで指定したカスタムポート番号です。このタスクは、ufw allow 5995/tcpコマンドを手動で実行するのと同等です。

タスク10:SSHの総当たり攻撃からの保護

第十のタスクは、総当たり攻撃から守るための対策です。

初めの.yml
...
- name: Brute-force attempt protection for SSH
  community.general.ufw:
    rule: limit
    port: "{{ ssh_port }}"
    proto: tcp
...

community.general.ufwモジュールを再度呼び出し、このタスクではレート制限ルールを使用して、30秒以内にSSHポートへの接続試行が6回以上失敗したIPアドレスのログインアクセスを拒否します。プロトパラメータは対象のプロトコルを指定します(この場合、TCP)。

タスク11:UFW – 他の着信トラフィックを拒否し、UFWを有効化する

11番目のタスクでは、ファイアウォールを有効にします。 (Jūichi-banme no tasuku de wa, faiawōru o yūkō ni shimasu.)

初期.yml
...
- name: UFW - Deny other incoming traffic and enable UFW
  community.general.ufw:
    state: enabled
    policy: deny
    direction: incoming
...

このタスクでは、まだ community.general.ufw モジュールに依存しており、ファイアウォールを有効にして(状態:有効)、すべての受信トラフィックを拒否するデフォルトポリシーを設定します。

タスク12:不要な依存関係を削除してください。

このプレイの第12のタスクは、パッケージの依存関係をクリーニングすることです。

最初の.yml
...
- name: Remove dependencies that are no longer required
  ansible.builtin.apt:
    autoremove: yes
...

ansible.builtin.aptモジュールを再度呼び出すことにより、このタスクはサーバ上で不要になったパッケージの依存関係を削除します。これは、手動でsudo apt autoremoveコマンドを実行するのと同等です。

タスク13: SSHデーモンを再起動してください。

このプレイブックの13番目のタスクでは、SSHを再起動します。

初期.yml
...
- name: Restart the SSH daemon
  ansible.builtin.systemd:
    state: restarted
    name: ssh

最後のタスクでは、ansible.builtin.systemdモジュールを使用して、SSHデーモンを再起動します。この再起動は、デーモンの設定ファイルの変更が有効になるために行われる必要があります。このタスクは、sudo systemctl restart sshコマンドを使用してデーモンを再起動するのと同じ効果があります。

ホストとの最初の接続は、ポート22を経由してrootとして行われましたが、以前のタスクでポート番号が変更され、リモートrootログインが無効化されたため、このステージではSSHデーモンを再起動する必要があります。2番目の操作では、接続の認証情報が異なります(rootではなくユーザー名を使用し、ポート番号も22以外の新しく定義された番号です)。

プレイ2: 初期設定後にホストを再起動します。

プレイ1の最後のタスクが成功裏に終了した後に、このプレイが開始されます。以下のキーワードに影響を受けます。

最初の.ymlファイル
...
- name: Rebooting hosts after initial setup
  hosts: initial
  port: "{{ ssh_port }}"
  remote_user: "{{ create_user }}"
  become: true
  vars_files:
    - vars/default.yml
    - ~/secret
  vars:
    ansible_become_pass: "{{ password }}"
...

ステップ2で指定された初期グループ名は/etc/ansible/hostsファイルに渡されるパターンです。デフォルトのSSHポート22を使用してホストにログインすることはできなくなるため、ステップ4で設定されたカスタムSSHポートをportキーワードで指定します。

最初のプレイでは、Ansible コントローラーはホストに root ユーザーとしてログインしました。最初のプレイでリモート root ログインが無効化されたため、Ansible コントローラーがログインするユーザーを指定する必要があります。remote_user キーワードは、Ansible コントローラーが最初のプレイのタスク 5 で作成された sudo ユーザーとして各ホストにログインするように指示します。

「become」キーワードは、指定されたホストでのタスクの実行に特権昇格を使用することを指定します。このキーワードは、必要な場合にタスクの実行に対してAnsibleコントローラーがroot権限を仮定するように指示します。この場合、コントローラーはsudoを使用してroot権限を仮定します。「ansible_become_pass」キーワードは、特権昇格パスワードを設定します。これは、root権限を仮定するために使用されるパスワードです。この場合、Ansible Vaultで設定したパスワードを指す変数を示しています。

vars/default.ymlファイルを指定するだけでなく、vars_filesキーワードはステップ5で設定したシークレットファイルも指します。これにより、Ansibleコントローラーがパスワード変数を見つける場所がわかります。

キーワードセクションの後には、この演劇で実行される唯一のタスクがあります。

タスク14:全てのホストを再起動する

Note

注意:これは2番目のプレイの最初のタスクですが、Ansibleコントローラーはこれをプレイ2のタスク1と見なすのではなく、プレイブックのタスク14として見ています。

プレイブックの最終タスクは、すべてのホストを再起動します。

最初の.yml
...
- name: Reboot all hosts
  ansible.builtin.reboot:

最初のプレイでのタスクが完了した後、ホストを再起動することで、カーネルやライブラリの更新がアプリケーションのインストール前に有効になります。

完全なプレイブックファイルは次のようになります。

最初の.yml
- name: Initial server setup tasks
  hosts: initial
  remote_user: root
  vars_files:
    - vars/default.yml
    - secret

  tasks:
    - name: update cache
      ansible.builtin.apt:
        update_cache: yes

    - name: Update all installed packages
      ansible.builtin.apt:
        name: "*"
        state: latest

    - name: Make sure NTP service is running
      ansible.builtin.systemd:
        state: started
        name: systemd-timesyncd

    - name: Make sure we have a 'sudo' group
      ansible.builtin.group:
        name: sudo
        state: present

    - name: Create a user with sudo privileges
      ansible.builtin.user:
        name: "{{ create_user }}"
        state: present
        groups: sudo
        append: true
        create_home: true
        shell: /bin/bash
        password: "{{ password | password_hash('sha512', password_salt) }}"
        update_password: on_create

    - name: Set authorized key for remote user
      ansible.builtin.authorized_key:
        user: "{{ create_user }}"
        state: present
        key: "{{ copy_local_key }}"

    - name: Disable remote login for root
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        state: present
        regexp: '^PermitRootLogin yes'
        line: 'PermitRootLogin no'

    - name: Change the SSH port
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        state: present
        regexp: '^#Port 22'
        line: 'Port "{{ ssh_port }}"'

    - name: UFW - Allow SSH connections
      community.general.ufw:
        rule: allow
        port: "{{ ssh_port }}"

    - name: Brute-force attempt protection for SSH
      community.general.ufw:
        rule: limit
        port: "{{ ssh_port }}"
        proto: tcp

    - name: UFW - Deny other incoming traffic and enable UFW
      community.general.ufw:
        state: enabled
        policy: deny
        direction: incoming

    - name: Remove dependencies that are no longer required
      ansible.builtin.apt:
        autoremove: yes

    - name: Restart the SSH daemon
      ansible.builtin.systemd:
        state: restarted
        name: ssh

- name: Rebooting hosts after initial setup
  hosts: initial
  port: "{{ ssh_port }}"
  remote_user: "{{ create_user }}"
  become: true
  vars_files:
    - vars/default.yml
    - secret
  vars:
    ansible_become_pass: "{{ password }}"

  tasks:
    - name: Reboot all hosts
      ansible.builtin.reboot:

ファイルの内容を確認し終えたら、保存して閉じてください。

Note

注意:プレイブックに新しいタスクを追加したり、既存のタスクを変更することができます。ただし、YAMLファイルを変更すると、スペースに敏感なYAMLが破損する可能性があるため、ファイルのどの部分を編集するかに注意してください。Ansibleのプレイブックの作成方法については、弊社のシリーズ「Ansibleプレイブックの作成方法」を参照してください。

今、プレイブックを実行することができます。まず、構文を確認してください。

  1. ansible-playbook –syntax-check –ask-vault-pass initial.yml

 

ステップ5で作成した保管庫のパスワードを入力するように求められます。認証が成功した後にYAML構文にエラーがなければ、出力は次の通りです。

Output

playbook: initial.yml

以下のコマンドを使用して、ファイルを実行することができます。

  1. ansible-playbook –ask-vault-pass initial.yml

 

バルトのパスワードが再度要求されます。認証が成功すると、Ansibleコントローラは各ホストにrootユーザーとしてログインし、プレイブック内のすべてのタスクを実行します。個々のサーバーでssh root@node-ip-addressのコマンドを実行する代わりに、Ansibleは/etc/ansible/hostsで指定されたすべてのノードに接続し、その後、プレイブック内のタスクを実行します。

このチュートリアルのサンプルホストでは、Ansibleは3つのホスト間でタスクを完了するのに約3分かかりました。タスクが完了したら、以下のような出力が表示されます。

Output

PLAY RECAP ***************************************************************************************************** host1 : ok=16 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 host2 : ok=16 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 host3 : ok=16 changed=11 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

成功裁定された各タスクとプレイのキーワードセクションは、OK列の数に加算されます。2つのプレイで14のタスクがあり、すべての評価が成功した場合、その数は16になります。評価されたタスクの中で、サーバー上で変更が行われたのは11個だけであり、それは変更列で表されています。

到達不能なホストの数は、Ansibleコントローラーがログインできなかったホストの数を示しています。どのタスクも失敗していないため、失敗した数は0です。

タスクは、タスクに指定された条件が満たされない場合にスキップされます(通常はwhenパラメーターを使用します)。この場合、タスクはスキップされませんが、ステップ8では適用されます。

最後の2つの列(救助されたものと無視されたもの)は、演劇またはタスクのために指定されたエラーハンドリングに関連しています。

あなたは現在、Ansibleを使用してUbuntu 22.04サーバーの初期セットアップを複数のサーバーに自動化し、プレイブックで指定されたすべてのタスクを完了する1つのコマンドを実行することに成功しました。

期待通りにすべてが動作しているかを確認するために、次にホストのログインを行い、セットアップを検証します。

(任意)ステップ7 — サーバーの設定を手動で確認する

前の手順の最後にあるプレイの要約の出力を確認するために、事前に設定された資格情報を使用してホストの1つにログインすることができます。これらのアクションは学習の目的のために任意のものです。なぜなら、Ansibleの要約レポートが正確な完了を報告しているからです。

次のコマンドを使用して、ホストの1つにログインしてください。

  1. ssh -p 5995 sammy@host1-public-ip-address

 

Step 4で設定したSSHのカスタムポート番号(5995)を指定するために、-pオプションを使用し、Step 6で作成したユーザーであるsammyを使います。そのポート経由でそのユーザーとしてホストにログインできれば、Ansibleはそれらのタスクを成功裏に完了したということがわかります。

ログイン後、パッケージデータベースを更新できるかどうか確認してください。

  1. sudo apt update

 

パスワードの入力を求められ、ステップ5で設定したユーザーのパスワードで認証できる場合、Ansibleがユーザーの作成とパスワードの設定のタスクを正常に完了したことを確認することができます。

計画書が意図通りに機能したことを確認したら、継続的なメンテナンスのために第二の計画書を実行することができます。

(オプション)ステップ8- ホストの継続的なメンテナンスにはAnsibleを使用します。

ステップ6で実行された最初のサーバー設定のプレイブックは、希望するだけの数のサーバーにスケーリングできますが、その初期設定の後にホストを管理することはできません。各ホストに個別にログインしてコマンドを実行することはできますが、それは複数のサーバーで同時に作業するためにスケーリングされません。ステップ3の一環として、継続的なメンテナンスに使用できるongoing.ymlのプレイブックも取り込みました。このステップでは、ongoing.ymlプレイブックを実行して、チュートリアルで設定したホストの継続的なメンテナンスを自動化します。

プレイブックを実行する前に、各タスクを確認します。始める前に、nanoやお気に入りのテキストエディタでファイルを開いてください。

  1. nano ongoing.yml

 

最初のセットアップのプレイブックとは異なり、メンテナンスのプレイブックには1つのプレイと少ないタスクしか含まれていません。

プレイ1:

ファイルの最初のセクションにある以下のキーワードは、プレイの動作に影響を与えます。

進行中のもの.yml
- hosts: ongoing
  port: "{{ ssh_port }}"
  remote_user: "{{ create_user }}"
  become: true
  vars_files:
    - vars/default.yml
    - secret
  vars:
    ansible_become_pass: "{{ password }}"
...

ホストキーワードに渡されるグループ以外は、セットアッププレイブックの2番目のプレイで使用されるキーワードと同じです。

キーワードの後には、順番に実行するタスクのリストがあります。セットアップのプレイブックと同様に、メンテナンスのプレイブックの各タスクは、タスクが達成する目的を短く説明する名前で始まります。

タスク1:キャッシュを更新する。

最初のタスクはパッケージデータベースの更新です。

現在進行中のもの。
...
- name: update cache
  ansible.builtin.apt:
    update_cache: yes
...

このタスクでは、ansible.builtin.aptモジュールを使用してパッケージデータベースを更新します。そのため、update_cache: yesとして定義されています。このタスクは、しばしばパッケージのインストールやすべてのインストール済みパッケージの更新の前に、Ubuntuサーバーにログインしてsudo apt updateと入力するのと同じことを行います。

タスク2:すべてのインストール済みパッケージを更新してください。

第二のタスクはパッケージのアップデートを行います。

継続中です。
...
- name: Update all installed packages
  ansible.builtin.apt:
    name: "*"
    state: latest
...

最初のタスクのように、このタスクでもansible.builtin.aptモジュールを呼び出します。ここでは、パッケージを指定するためにワイルドカード(name: “*”)とstate: latestを使用して、インストール済みのすべてのパッケージが最新であることを確認します。これは、サーバーにログインしてsudo apt upgrade -yコマンドを実行するのと同等です。

タスク3: NTPサービスが実行されていることを確認してください。

プレイブックの第三のタスクでは、NTPデーモンのセットアップが確実に行われます。

進行中です。
...
- name: Make sure NTP service is running
  ansible.builtin.systemd:
    state: started
    name: systemd-timesyncd
...

サーバー上のアクティブなサービスがさまざまな理由で失敗する可能性があるため、そのようなサービスが引き続きアクティブであることを確認したいです。このタスクでは、systemd-timesyncdというNTPデーモンがアクティブな状態(started)であることを保証するために、ansible.builtin.systemdモジュールを呼び出します。

タスク4:UFW – 実行中ですか?

第四のタスクはUFWファイアウォールの状態を確認します。

以下の文を日本語で表現する(オプション1つだけ):

進行中のもの.yml

...
- name: UFW - Is it running?
  ansible.builtin.command: ufw status
    register: ufw_status
...

UbuntuのUFWファイアウォールの状態は、sudo ufw statusコマンドで確認できます。出力の最初の行には、Status: activeまたはStatus: inactiveと表示されます。このタスクでは、ansible.builtin.commandモジュールを使用して同じコマンドを実行し、出力をufw_status変数に保存(登録)します。その変数の値は、次のタスクでクエリされます。

タスク5:UFW – UFWを有効にし、着信トラフィックを拒否する

もしUFWファイアウォールが停止されている場合は、第五のタスクで再度有効になります。

現在進行中の.ymlファイル
...
- name: UFW - Enable UFW and deny incoming traffic
  community.general.ufw:
    state: enabled
  when: "'inactive' in ufw_status.stdout"
...

このタスクは、ufw_status変数の出力にinactiveという用語が現れた場合にのみ、community.general.ufwモジュールを呼び出してファイアウォールを有効にします。ファイアウォールがアクティブな場合、when条件が満たされないため、タスクはスキップされます。

タスク6:必要なくなった依存関係を削除する。

このプレイブックの6番目のタスクは、パッケージの依存関係を整理することです。

ongoing.ymlを日本語で自然に言い換える :
進行中の.yml
...
- name: Remove dependencies that are no longer required
  ansible.builtin.apt:
    autoremove: yes
...

このタスクは、ansible.builtin.aptモジュールを呼び出すことで、サーバー上で不要になったパッケージの依存関係を削除します。これは、sudo apt autoremoveコマンドを実行するのと同等です。

課題7:再起動が必要かどうかを確認する。

第7のタスクは、再起動が必要かどうかをチェックします。

続行中です。
...
- name: Check if reboot required
  ansible.builtin.stat:
    path: /var/run/reboot-required
  register: reboot_required
...

Ubuntuで新しくインストールされたパッケージやアップグレードによって導入された変更を有効にするには、再起動が必要であることを示すために、/var/run/reboot-required ファイルが作成されます。このファイルが存在するかどうかは、stat /var/run/reboot-required コマンドを使用して確認できます。このタスクでは、同じことを行うためにansible.builtin.statモジュールを呼び出し、その出力をreboot_required変数に保存(登録)します。その変数の値は、次のタスクでクエリされます。

タスク8: 必要なら再起動する

必要に応じて、8番目のタスクがサーバーを再起動します。

進行中です。
...
- name: Reboot if required
  ansible.builtin.reboot:
  when: reboot_required.stat.exists == true

以下のタスクは、タスク7からreboot_required変数をクエリし、/var/run/reboot-requiredが存在する場合にのみ、ansible.builtin.rebootモジュールを使用してホストを再起動します。再起動が必要で、ホストが再起動された場合、タスクは変更されたとしてマークされます。それ以外の場合、Ansibleは再生の概要でスキップされたとマークします。

継続的な保守作業のための完全なプレイブックファイルは以下のとおりです:

最初の.yml
- hosts: ongoing
  port: "{{ ssh_port }}"
  remote_user: "{{ create_user }}"
  become: true
  vars_files:
    - vars/default.yml
    - secret
  vars:
    ansible_become_pass: "{{ password }}"

  tasks:
    - name: update cache
      ansible.builtin.apt:
        update_cache: yes

    - name: Update all installed packages
      ansible.builtin.apt:
        name: "*"
        state: latest

    - name: Make sure NTP service is running
      ansible.builtin.systemd:
        state: started
        name: systemd-timesyncd

    - name: UFW - Is it running?
      ansible.builtin.command: ufw status
      register: ufw_status
      
    - name: UFW - Enable UFW and deny incoming traffic
      community.general.ufw:
        state: enabled
      when: "'inactive' in ufw_status.stdout"

    - name: Remove dependencies that are no longer required
      ansible.builtin.apt:
        autoremove: yes

    - name: Check if reboot required
      ansible.builtin.stat:
        path: /var/run/reboot-required
      register: reboot_required

    - name: Reboot if required
      ansible.builtin.reboot:
      when: reboot_required.stat.exists == true

ファイルの確認が終わったら、保存して閉じてください。

Note

注意:プレイブックに新しいタスクを追加したり、既存のタスクを変更することができます。ただし、YAMLファイルを変更すると破損する可能性があります。YAMLはスペースに敏感ですので、ファイルのどの部分を編集するかに注意してください。Ansibleプレイブックの作成に関する詳細は、弊社の「Ansibleプレイブックの書き方」シリーズをご覧ください。

今、そのファイルを実行できます。最初に、構文をチェックしてください。

  1. ansible-playbook –syntax-check –ask-vault-pass ongoing.yml

 

ステップ5で作成した保管庫のパスワードを入力するように促されます。認証が成功した後、YAML構文にエラーがなければ、以下の結果が表示されます。

Output

playbook: ongoing.yml

以下のコマンドで、ファイルを実行することができます。

  1. ansible-playbook –ask-vault-pass ongoing.yml

 

ボールトのパスワードが求められます。認証が成功した後、Ansibleコントローラはプレイブックのタスクを実行するために、各ホストにsammy(または指定したユーザー名)としてログインします。個々のサーバーでssh -p 5995 sammy @ host_ip_addressコマンドを実行する代わりに、Ansibleは/etc/ansible/hostsの進行中のグループで指定されたノードに接続し、その後でプレイブックのタスクを実行します。

もしコマンドが成功したら、以下の出力が表示されます。

Output

PLAY RECAP ***************************************************************************************************** host1 : ok=7 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 host2 : ok=7 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0 host3 : ok=7 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

最初のサーバーセットアップの場合とは異なり、このプレイリストの要約では、whenパラメータで設定された条件に合わなかったため、2つのタスクがスキップされたことが記録されています。

各ホストに個別にログインせずに、このプレイブックを使用してホストのメンテナンスができます。ホスト上にアプリケーションを構築・インストールする際に、プレイブックにタスクを追加することでAnsibleでこれらのアプリケーションも管理できます。

結論 – Ketsuron

このチュートリアルでは、Ansibleを使用して複数のUbuntu 22.04サーバーの初期セットアップを自動化しました。さらに、それらのサーバーの定期的なメンテナンスのためにセカンダリプレイブックも実行しました。分散またはクラスターモードでCassandraやMinIOのようなアプリケーションをセットアップする必要がある場合、Ansibleの自動化は時間の節約になる便利なツールです。

公式のAnsibleドキュメンテーションサイトでさらなる情報を入手することができます。プレイブックをさらにカスタマイズするためには、構成管理の基礎として「アンサイブルプレイブックの作成」と「構成管理101: アンサイブルプレイブックの書き方」を参考にしてください。

コメントを残す 0

Your email address will not be published. Required fields are marked *