自作PCの組み立て方　ベアメタルで構築するKali Linux【構築編】

# はじめに
[自作PCの組み立て方　ベアメタルで構築する俺のKALI【PC組み立て編】](https://qiita.com/Brutus/items/4d6da6a989f2a64ec9a2)では自作PCの組み立て及び、Kaliのインストールを行いました。

本記事はAnsibleを用いてベアメタルで構築した[Kali Linux](https://ja.wikipedia.org/wiki/Kali_Linux)（以降、Kali）の構築を自動化する方法について記載しています。Ansibleを使用して構築手順をコード化することで冪等性を担保し、構成管理を容易にします。

Ansibleについて知りたい方は以前書いた[Ansibleとは何か　構成管理ツールの目的〜Ansible導入まで最速で理解する](https://qiita.com/Brutus/items/1894629105d61f4854bc)を参照。

## 構築作業
構築作業として必要なパッケージのインストール及び、インストールした各種ソフトウェアのセットアップを行います。

リモートデスクトップ接続を実現するために[VNC](https://ja.wikipedia.org/wiki/Virtual_Network_Computing)を利用した[TightVNC](https://en.wikipedia.org/wiki/TightVNC)、無料のウイルス対策ソフトウェアとして[Clam AntiVirus](https://ja.wikipedia.org/wiki/Clam_AntiVirus)、その他、リモートでPCを起動するために[Wake-on-LAN](https://ja.wikipedia.org/wiki/Wake-on-LAN)等をインストールします。また、これら新規に導入するソフトウェアに対して設定ファイルの編集や、対話的入力などセットアップ作業を行います。

Ansibleでは上記のようなプロセスについても、Playbookを活用することで**オーケストレーション**可能です。
Playbookを使用してシステムの望ましい状態を定義します。

:::note
公式ドキュメントの[Kali In The Browser (noVNC)](https://www.kali.org/docs/general-use/novnc-kali-in-browser/)より、ブラウザからGUIで接続する方法も紹介されています。
:::

### 準備作業
本記事では以下の資材を用意します。
同様のものを[kali-linux-setup](https://github.com/Brutus03/kali-linux-setup)リポジトリにアップロードしています。

```text
.
|-- README.md
|-- hosts
`-- material
    |-- tightvnc
|-- playbook.yml
```

また、前提として管理するPC側にはAnsibleと、VNCクライアントが必要です。
VNCクライアントは[REALVNC](https://www.realvnc.com/en/connect/download/viewer/)のサイトからダウンロードできます。

後述するWake-on-LAN（Wol）についても管理側PCからコマンドなどで実行するための仕組みが必要です。
本記事ではこちらの[wakeonlan](https://github.com/jpoliv/wakeonlan)を使用しています。
使い方は簡単でスクリプトの引数に対象となるPCのMACアドレスを指定してコマンドを実行するだけです。
Macの場合、aliasコマンドや、Automatorなどと組み合わせて使用するのがお勧めです。

留意事項としてKaliインストール直後の状態の場合、sshサービスが起動していないため、初回のみKaliにログインしてsshサービスを起動します。

環境によってはAnsibleのコマンド実行時に以下のようなsshpassに関するメッセージが出力される場合があります。

```console
TASK [shell] ****************************************************************************************************************************************
fatal: [192.168.x.x]: FAILED! => {"msg": "to use the 'ssh' connection type with passwords or pkcs11_provider, you must install the sshpass program"}
```

本記事ではMac環境となり、対応としてsshpassをインストールします。

[SourceForge.net](https://ja.wikipedia.org/wiki/SourceForge.net)の[Non-interactive ssh password auth](https://sourceforge.net/projects/sshpass/)からsshpassの資材をダウンロードし、`opt`ディレクトリに移動して展開します。

- sshpassの展開
`$ cd /opt/`
`$ sudo mv /Users/hoge/Downloads/sshpass-1.08.tar.gz ./`
`$ sudo tar -xvf sshpass-1.08.tar.gz `
`$ cd sshpass-1.08`

以下のコマンドを実行し、インストールします。

- sshpassのインストール
`$ sudo ./configure`
`$ sudo make`
`$ sudo make install`

以下のコマンドを実行し、パスが通っていることを確認します。

`$ which sshpass` -> `/usr/local/bin/sshpass`

:::note warn
本記事で紹介しているsshの接続方法はパスワード認証を使用しています。実際のシステム運用では公開鍵認証を使用するなど、セキュリティを確保することが重要です。
:::

### Playbook作成
構築作業を実施するためのPlaybookを作成していきます。
以下、TASK毎の解説です。

#### パッケージ管理
パッケージ管理の操作は**apt**モジュールを使用します。
アップデートは一つのタスクにまとめることできますが、本記事ではタスクを分けています。

- Documentation：[ansible.builtin.apt module – Manages apt-packages](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html)

##### package update (apt-get update)

`apt-get update`に相当し、パッケージのリストを更新します。なお、デフォルトの場合、更新されません。

```yaml
    - name: package update (apt-get update) 
      apt:
        update_cache: yes
```

##### package installation
`name`の値にインストールしたいパッケージを記載することで複数のパッケージをインストールします。

VNCを使用するためにXfceとxfce4-goodiesパッケージをインストールします。これには、デスクトップ環境のいくつかの拡張機能が含まれています。

```yaml
    - name: package installation
      apt:
        name:
          - ethtool
          - xfce4 
          - xfce4-goodies 
          - tightvncserver
          - autocutsel
          - clamav
          - clamav-daemon           
          - gobuster
```

##### package upgrade (apt-get dist-upgrade)

`apt-get dist-upgrade`に相当し、パッケージのアップグレードを行います。
依存関係を考慮し、一部のパッケージは削除されます。

```yaml
    - name: package upgrade (apt-get dist-upgrade)
      apt:
        upgrade: dist
```

#### systemctlの設定
新規にインストールしたパッケージについて**systemctl**モジュールを使用して各サービスの起動及び、自動起動を有効にします。

- Documentation：[ansible.builtin.systemd module – Manage systemd units Note](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_module.html)

##### clamav-daemon.service setting
`clamav-daemon`のサービスを設定します。

```yaml
    - name: clamav-daemon.service setting
      systemd:
        name: clamav-daemon.service
        state: started
        enabled: yes
```

##### clamav-freshclam.service setting
`clamav-freshclam`のサービスを設定します。

```yaml
    - name: clamav-freshclam.service setting
      systemd:
        name: clamav-freshclam.service
        state: started
        enabled: yes
```

##### ssh.service setting
`ssh`のサービスを設定します。

```yaml
    - name: ssh.service setting
      systemd:
        name: ssh.service
        state: started
        enabled: yes
```

#### ethtoolの設定 
[ethtool](https://en.wikipedia.org/wiki/Ethtool)はNetwork Interface Cards (NICs) 設定を行うためのユーティリティです。

##### ethtool setting (enable wol feature for driver)
`ethtool`コマンドを実行し、`wol`オプションの値に`g`を付与して[Wake-on-LAN（WoL）](https://ja.wikipedia.org/wiki/Wake-on-LAN)を有効にします。magic packetの受信ができるようになるため、リモートで機器の電源管理を行うことができます。なお、`-s`の値はインターフェース名によって異なります。

```yaml
    - name: ethtool setting (enable wol feature for driver)
      changed_when: False
      command: ethtool -s eth0 wol g
```

##### ethtool auto start setting ("@reboot /usr/sbin/ethtool")
OS再起動後もethtoolの設定を有効にするため、**cron**モジュールを使用して設定します。
@rebootは起動時に1度だけ実行される指定方法です。

- Documentation：[ansible.builtin.cron module – Manage cron.d and crontab entries](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/cron_module.html)

```yaml
    - name: ethtool auto start setting ("@reboot /usr/sbin/ethtool")
      ansible.builtin.cron:
        name: "a job for reboot"
        special_time: reboot
        job: "/usr/sbin/ethtool -s eth0 wol g"
```

#### tightvncserverの設定
tightvncserverの設定を行います。

##### tightvncserver check (passwd)
**stat**モジュールを使用してパスワードファイルを指定し、ファイルの存在有無についてチェックを行います。

- Documentation：[ansible.builtin.stat module – Retrieve file or file system status](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/stat_module.html)

```yaml
    - name: tightvncserver check (passwd)
      stat: path=/home/kali/.vnc/passwd 
      register: result
```

##### tightvncserver start (interactive input)
対話的入力は**expect**モジュールを使用して制御します。
以下の例では`when`でパスワードファイルが存在しない場合は設定を行うように記述しています。
パスワードはハードコーディングしているため、ご注意ください。

- Documentation：[ansible.builtin.expect module – Executes a command and responds to prompts](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/expect_module.html)

```yaml
    - name: tightvncserver start (interactive input)
      become: yes
      become_user: kali
      expect:
        command: tightvncserver :1 -geometry 1280x800 -depth 24
        responses:
          "Password:": "********"
          "Verify:": "********"
          "Would you like to enter a view-only password (y/n)?": "n"
      when: not result.stat.exists 
```

##### script deployment (tightvncserver)
**copy**モジュールを使用してansibleの管理マシンから接続先ホストの指定したディレクトリに起動スクリプトをコピーします。
以下の例では管理マシン内の`/etc/ansible/material/tightvnc`を接続先ホストとなる、`/etc/init.d/`にコピーする例になります。

- Documentation：[ansible.builtin.copy module – Copy files to remote locations](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html)

```yaml
    - name: script deployment (tightvncserver)
      copy:
        src: /etc/ansible/material/tightvnc
        dest: /etc/init.d/
        owner: root
        group: root
        mode: 0755
```

##### script auto start setting (tightvncserver)
スクリプトの自動起動を有効にします。
Playbookを繰り返し実行した場合でもchangedで記録されるため、`changed_when False`を指定しています。

```yaml
    - name: script auto start setting (tightvncserver)
      changed_when: False
      command: update-rc.d tightvnc defaults
```

##### autocutsel setting (edit file)
VNC接続時に操作するPCと、リモート接続するKali間でクリップボードの共有を行うためには別途、設定が必要です。
**shell**モジュールを使用して、`/home/kali/.vnc/xstartup`ファイルを設定します。

- Documentation：[ansible.builtin.shell module – Execute shell commands on targets](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/shell_module.html)

```yaml
    - name: autocutsel setting (edit file)
      changed_when: False
      shell: |
        cat /home/kali/.vnc/xstartup | grep 'autocutsel -fork'
        if [ $? != 0 ]; then sed -i '8i autocutsel -fork' /home/kali/.vnc/xstartup;else :;fi
      args:
        executable: /bin/bash
```

#### rockyouの展開
Kaliインストール後、`rockyou.txt`ファイルは圧縮されているため、**shell**モジュールを使用して展開します。

##### uncompress compressed rockyou files
rockyouは`/usr/share/wordlists`配下に存在しています。ファイルの存在有無を確認して展開しています。

```yaml
    - name: uncompress compressed rockyou files
      changed_when: False
      shell: |
        cd /usr/share/wordlists
        if [ -e rockyou.txt.gz ]; then gunzip -d rockyou.txt.gz;else :;fi
```

#### clamavの設定
clamavの設定を行います。

##### excluded directory settings (clamav)
**cron**モジュールを使用してclamavの自動スキャンを設定します。

```yaml
    - name: clamav schedule scan setting ("0 0 * * * /usr/bin/clamdscan/clamdscan -m --fdpass /")
      ansible.builtin.cron:
        name: "clamav schedule scan"
        minute: "0"
        hour: "0"
        job: /usr/bin/clamdscan -m --fdpass /
```

##### clamav schedule scan setting ("0 0 * * * /usr/bin/clamdscan/clamdscan -m --fdpass /")

**shell**モジュールを使用して、clamavの除外ディレクトリを設定します。

```yaml
    - name: excluded directory settings (clamav)
      changed_when: False
      shell: |
        cat /etc/clamav/clamd.conf  | grep 'ExcludePath'
        if [ $? != 0 ]; then sed -i '$a ExcludePath /usr/lib\nExcludePath /usr/share\nExcludePath /var/lib ' /etc/clamav/clamd.conf;else :;fi
      args:
        executable: /bin/bash
```

### Ansible Playbook
`ansible-playbook`コマンドを実行します。
コマンド実行後、sshのパスワードを入力します。

<details><summary>出力例</summary>

```console
hoge@MacBook-Pro:/etc/ansible$ ansible-playbook -i hosts -k -K playbook_kali.yml 
SSH password: 
BECOME password[defaults to SSH password]: 

PLAY [kali linux setting] *********************************************************************************************************************************

TASK [package update (apt-get update)] ********************************************************************************************************************
[WARNING]: Platform linux on host 192.168.x.x is using the discovered Python interpreter at /usr/bin/python3.10, but future installation of another
Python interpreter could change the meaning of that path. See https://docs.ansible.com/ansible-core/2.12/reference_appendices/interpreter_discovery.html
for more information.
ok: [192.168.x.x]

TASK [package installation] *******************************************************************************************************************************
changed: [192.168.x.x]

TASK [package upgrade (apt-get dist-upgrade)] *************************************************************************************************************
changed: [192.168.x.x]

TASK [clamav-daemon.service setting] **********************************************************************************************************************
changed: [192.168.x.x]

TASK [clamav-freshclam.service setting] *******************************************************************************************************************
changed: [192.168.x.x]

TASK [ssh.service setting] ********************************************************************************************************************************
changed: [192.168.x.x]

TASK [ethtool setting (enable wol feature for driver)] ****************************************************************************************************
ok: [192.168.x.x]

TASK [ethtool auto start setting ("@reboot /usr/sbin/ethtool")] *******************************************************************************************
changed: [192.168.x.x]

TASK [tightvncserver check (passwd)] **********************************************************************************************************************
ok: [192.168.x.x]

TASK [tightvncserver start (interactive input)] ***********************************************************************************************************
changed: [192.168.x.x]

TASK [script deployment (tightvncserver)] *****************************************************************************************************************
changed: [192.168.x.x]

TASK [script auto start setting (tightvncserver)] *********************************************************************************************************
ok: [192.168.x.x]

TASK [autocutsel setting (edit file)] *********************************************************************************************************************
ok: [192.168.x.x]

TASK [uncompress compressed rockyou files] ****************************************************************************************************************
ok: [192.168.x.x]

TASK [clamav schedule scan setting ("0 0 * * * /usr/bin/clamdscan/clamdscan -m --fdpass /")] **************************************************************
changed: [192.168.x.x]

TASK [excluded directory settings (clamav)] ***************************************************************************************************************
ok: [192.168.x.x]

PLAY RECAP ************************************************************************************************************************************************
192.168.x.x              : ok=16   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
```
</details>

`ansible-playbook`コマンド実行後、**failed**がないことを確認し、OS再起動を行います。

OS再起動後、PCからVNCでKaliに接続できます。

![スクリーンショット 2022-05-23 0.32.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/8e8f7c73-2554-93cc-11cd-c90c045ed43d.png)

以下はVNCで接続できなかった場合のキャプチャです。
OS再起動することで上記のようにログインできます。

![スクリーンショット 2022-05-23 0.28.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/ce8806bc-d70a-13a2-ba03-5ad54bba6ad5.png)

# おわりに
Ansibleを活用することで、PCが壊れた場合でも同じ環境を簡単に再現することができます。

Wolも凄い便利なユーティリティです。
わざわざ物理的に電源ボタンを押すことなく、仮想マシンのように手元からPCのシャットダウンができます。

## 参考
- [Ansible の基本を学ぶ](https://www.redhat.com/ja/topics/automation/learning-ansible-tutorial)
- [Wake-on-LAN](https://wiki.archlinux.jp/index.php/Wake-on-LAN)