Apple Silicon Mac(M1 Mac)で徳丸本の実習用仮想マシンを動かす

改訂履歴
2022.12.05 公式実習環境に誘導する記述を追加。あとどこかのタイミングで色々な記載がCTF本の記事とごっちゃになってたので修正(滝汗)。
2022.08.19 仮想NICデバイス名の誤記を修正
2022.05.29 UTMのアップデートに伴い、スクリーンショットおよびパラメータ設定を修正

# はじめに
「安全なWebアプリケーションの作り方 第2版」(以降、徳丸本)の実習環境はx86_64アーキテクチャを前提とした構成となっており、アーキテクチャが異なるApple Silicon Macではそのまま動かすことができません。
...この手の実習系はASM民辛いですね。
今回、Mac向けの仮想化環境である[UTM](https://mac.getutm.app)を使って何とか動かすことができましたので、備忘として公開します。

<font color="#ff0000">2022.12.05追記 [徳丸本公式サポートページ](http://wasbook.org)でDockerコンテナ版実習環境の提供が始まりました。あえてUTMを弄りたい方以外は公式コンテナ版をお使いください。</font>

# 想定する読者
  - 徳丸本を買って実習しようとワクテカしてたけど、Apple Silicon Macしか持ってなくてつまづいてしまった方

# なぜ動かない?
徳丸本の実習環境はx86_64アーキテクチャのVirtualBox環境を前提としていますが、Apple SiliconのCPUはARMアーキテクチャであり**互換性がない**ためです。

# 使うもの
<dl>
  <dt>Apple Silicon Mac</dt>
  <dd>言わずもがなですね。本記事の執筆にあたってはMacBook Air(M1, 2020)で確認しています。</dd>
</dl>
<dl>
  <dt><a href="https://brew.sh/index_ja">Homebrew</a></dt>
  <dd>サードパーティのパッケージマネージャーです。UTMおよびQEMUを導入するのに使用します。</dd>
</dl>
<dl>
  <dt><a href="https://mac.getutm.app">UTM</a></dt>
  <dd>Mac向けの仮想化環境ソフトウェアです。同一アーキテクチャのハイパーバイザーに加えて、<b>異なるアーキテクチャのエミュレーションにも対応</b>しています。遅くなりますが。<br>実態としてはQEMUにGUIのフロントエンドが付いたものです。本記事ではHomebrew経由でインストールしますが、App Storeの有償版(App Storeから更新できる以外には機能差異無し)や、サイト上のdmgイメージからの導入でもOKです。</dd>
</dl>

# 手順1. 各種ソフトウェアの導入
まずはHomebrewをインストールします。ターミナル上でHomebrewのトップページに記載されているインストールコマンドを実行します。

```shell
# Homebrewインストールコマンドの実行
% /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
==> Checking for `sudo` access (which may request your password).
Password: (パスワードを入力)
==> This script will install:
/opt/homebrew/bin/brew
/opt/homebrew/share/doc/homebrew
/opt/homebrew/share/man/man1/brew.1
/opt/homebrew/share/zsh/site-functions/_brew
/opt/homebrew/etc/bash_completion.d/brew
/opt/homebrew
==> The following new directories will be created:
/opt/homebrew/Cellar
/opt/homebrew/Caskroom

Press RETURN to continue or any other key to abort (Enterを入力)
==> /usr/bin/sudo /bin/mkdir -p /opt/homebrew/Cellar /opt/homebrew/Caskroom

(中略)

==> Installation successful!

==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
Read the analytics documentation (and how to opt-out) here:
  https://docs.brew.sh/Analytics
No analytics data has been sent yet (or will be during this `install` run).

==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
  https://github.com/Homebrew/brew#donations

==> Next steps:
- Run these two commands in your terminal to add Homebrew to your PATH:
    echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/kumaneko/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv)"
- Run `brew help` to get started
- Further documentation: 
    https://docs.brew.sh
%
# Next stepsとして指示されたコマンドを実行
% echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/kumaneko/.zprofile
% eval "$(/opt/homebrew/bin/brew shellenv)"
% rehash        
```

続いてUTMをインストールします。

```shell
% brew install UTM
(中略)
% rehash
```

これで必要なソフトウェアのインストールは完了しました。

# 手順2. 仮想マシンの作成

実習用環境は.ova形式の仮想マシンとして配布されていますが、UTMではこのまま仮想マシンをインポートすることはできません。
そこで、.ova形式のファイルから仮想ディスクを抜き出してUTM(QEMU)に対応した形式に変換します。

```shell
# wasbook.ovaの中身を確認
% tar tf wasbook.ova
wasbook.ovf
wasbook-disk001.vmdk
# wasbook.ovaより仮想ディスクイメージwasbook-disk001.vmdkを抽出
% tar xf wasbook.ova wasbook-disk001.vmdk
# 仮想ディスクイメージをvmdk形式からqcow2形式に変換
% qemu-img convert -f vmdk -O qcow2 wasbook-disk001.vmdk wasbook-disk001.qcow2
```
wasbook-disk001.vmdkはこの先の手順では不要ですので、削除しても結構です。

# 手順3. 仮想マシンの作成

アプリケーションにUTM.appが導入されていますので、これを起動します。
![スクリーンショット 2022-05-29 8.50.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/e56141a7-a039-36f1-7019-3085d50c8caa.png)
ウィンドウ上部の「＋」をクリックし、続いて[Emulate]をクリックします。
![スクリーンショット 2022-05-29 8.53.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/acedc930-7e52-2a72-a0e0-9b1e2d926653.png)
Operating Systemでは[Other]をクリックします。
![スクリーンショット 2022-05-29 8.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/5ff9c8d6-27a4-3c33-16f8-fa98f3363f35.png)
Otherでは[Skip ISO boot]のチェックを入れて[Continue]をクリックします。
![スクリーンショット 2022-05-29 8.57.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/a2e37c57-b16f-6f6e-4abd-a78a471e8142.png)
Hardwareでは、配布ovaファイルの構成に倣ってMemoryを512MB、CPU Coresを1にし、[Continue]をクリックします。
![スクリーンショット 2022-05-29 8.59.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/62ffe0e4-f4dc-c727-c04a-f06ace33021d.png)
Storageではそのまま[Continue]をクリックします。
![スクリーンショット 2022-05-29 8.59.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/a6651283-0777-5667-e818-85f6a1c0ff72.png)
Shared Dirctoryもそのまま[Continue]をクリックします。
![スクリーンショット 2022-05-29 9.00.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/5a9b923e-17a9-71ce-dfc2-c78050761b34.png)
SummaryではNameをwasbookとして、[Open VM Settings]のチェックを入れて[Save]をクリックします。
![スクリーンショット 2022-05-29 9.01.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/134b954d-0632-80ac-d2dd-59dfb11fa183.png)

続いて仮想マシンの編集画面が開きます。
まずIDE Driveで[Delete Drive]をクリックし、既定で作成された仮想ディスクを削除します。
![スクリーンショット 2022-05-29 9.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/7363a37b-d064-246f-c89b-763f8c408d8b.png)
次にNew Driveをクリックし、続いて[Import]をクリックして、先ほど変換した.qcow2ファイルを指定します。
![スクリーンショット 2022-05-29 9.06.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/616f01bc-fa49-b396-ace9-19b488c1e5c4.png)
次はNetworkを確認しておきます。Shared Networkで構成されていることを確認しMAC Addressをメモしておきます(後で使います)。
![スクリーンショット 2022-05-29 9.08.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/3aedda68-b0de-2bde-9a2a-f292a7a9f588.png)
最後にQEMUに移ります。まずは[UEFI Boot]のチェックを外します。
![スクリーンショット 2022-05-29 9.10.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/47220dfa-8973-a1be-ab3f-52a5fb109648.png)
次に下方にスクロールし、1つめの仮想NICの設定を確認しておきます。-device「e1000,mac=(仮想NICのMACアドレス),netdev=net0」および-netdev「vmnet-shared,id=net0」の部分です。
![スクリーンショット 2022-05-29 9.12.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/6a9659f3-e368-e676-5558-6e30d872470f.png)
次にウィンドウの最下部に移動し、[New...]となっている欄に「-device e1000,mac=(2つめの仮想NICのMACアドレス),netdev=net1」と入力します。MACアドレスは1つめの仮想NICのものを参考に、16進数下2桁を少し変えたようなものにしておきます。入力したらEnterを入力します。
![スクリーンショット 2022-05-29 9.45.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/24f733b5-ffa8-3c83-a545-bcd4ebde4a07.png)
続いて[New...]となっている欄に「-netdev vmnet-host,id=net1」(+Enter)と入力します。
![スクリーンショット 2022-05-29 9.45.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/4dbcadcb-0c6a-d4ea-04a1-96edc15fc75d.png)
入力が終わりましたら[Save]をクリックします。
vmdkから変換して生成したqcow2ファイルは以後の手順では使用しないので、削除して結構です。

# 手順4. ネットワーク設定の調整

それではUTM上で仮想マシンの再生ボタンをクリックして、仮想マシンを起動します
![スクリーンショット 2022-05-29 9.20.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/6c781cdf-cad4-c3cb-88f7-99b61c9df946.png)

無事起動すればログインプロンプトが表示されますので、徳丸本記載のアカウントでログインします。また、指定したMACアドレスを持つ仮想NICが確かに2つ存在しているか、`ip addr`で確認しておきましょう。MACアドレスから判別するに、この例ではenp0s7がShared、enp0s10がHost Onlyの仮想NICとなっています。 
![スクリーンショット 2022-05-29 9.24.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2043976/c1e2a912-f02e-0f58-3aab-5cc231451adb.png)

ここから先は、仮想マシン側では仮想NICに合わせてネットワーク設定を調整し、ホスト(Mac)側では仮想マシン側のネットワークに合わせてbridgeインターフェイスのIPアドレスを調整します。

```shell:仮想マシン側
# 認識している仮想NICデバイス名に合わせて/etc/network/interfacesを書き換える
#   enp0s3をSharedの仮想NICデバイス(前述の例ではenp0s7)に変更
#   enp0s8をHost Onlyの仮想NICデバイス(前述の例ではenp0s10)に変更
#   エディタはnanoでなくても、viでも何でもいいですよ。
$ sudo nano /etc/network/interfaces
# 編集後の内容を確認
$ cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
## allow-hotplug enp0s7
auto enp0s7
iface enp0s7 inet dhcp

auto enp0s10
iface enp0s10 inet static
address 192.168.56.101
network 192.168.56.0
netmask 255.255.255.0
broadcast 192.168.56.255

# 一旦シャットダウンする
$ sudo halt -p
```

```shell-session:ホスト側
% sudo nano /Library/Preferences/SystemConfiguration/com.apple.vmnet.plist

        <key>Host_Net_Address</key>
        <string>192.168.56.1</string>   <= Host_Net_Addressを192.168.56.1に変更
        <key>Host_Net_Mask</key>
        <string>255.255.255.0</string>

```

仮想マシン側、ホスト側両方の調整が終わりましたら、仮想マシンを再び起動させます。
起動が完了したところで、疎通確認とSSHログインをやってみましょう。

```shell-session:ホスト側
% ping 192.168.56.101
PING 192.168.56.101 (192.168.56.101): 56 data bytes
64 bytes from 192.168.56.101: icmp_seq=0 ttl=64 time=4.210 ms
64 bytes from 192.168.56.101: icmp_seq=1 ttl=64 time=1.609 ms
64 bytes from 192.168.56.101: icmp_seq=2 ttl=64 time=1.767 ms
64 bytes from 192.168.56.101: icmp_seq=3 ttl=64 time=1.927 ms
^C
--- 192.168.56.101 ping statistics ---
4 packets transmitted, 4 packets received, 0.0% packet loss
% ssh wasbook@192.168.56.101                                              
(中略)
wasbook@192.168.56.101's password: (パスワードを入力)
Linux wasbook 4.9.0-4-686 #1 SMP Debian 4.9.65-3+deb9u1 (2017-12-23) i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Sep 18 23:49:49 2021
wasbook@wasbook:~$ 
```

無事ログインできました！
ようやく実習のスタートラインに立てました。バンザーイ！