無料で JUNOS を体感しよう(Vagrant + vSRX)

Juniper Networks の製品は Junos OS で動作しています。なんとそれが「無料」、「簡単」、「早く？」環境を用意できると知ったのでまとめようと思います。(何番煎じかわかりません)

# 環境について

簡単に言いますと、mac の上で VirtulaBox の仮想化 SW を利用し、Vagrant で構成管理を行います。
(Windows でもインストールするパッケージが変わるだけかと思います。)

- mac(Mojave v10.14.6, CPU 2.3GHz intel Core i5, RAM 8GB)
- VirtualBox 6.0.24
- Vagrant 2.2.14
- vSRX(12.1X47-D15.4-packetmode)

# 環境構築

## VirtualBox のインストール

Oracle 社の無料の仮想化基盤です。[公式サイト](https://www.virtualbox.org/wiki/Download_Old_Builds_6_0)からダウンロードします。x86 向けなので、話題の M1 では使えません・・・悲しい。。
ちなみに最新 version では 6.1 があるのですが、version up すると動作が不安定になったので、私は 6.0 を利用しています。

## Vagrant のインストール

HashiCorp 社の提供する構成管理ツールで、VitualBox を利用して仮想環境を立ち上げることが可能です。Ruby に慣れていない方でも最低限の理解で十分価値があります。
[公式サイト](https://www.vagrantup.com/downloads.html)からダウンロードします。

その後、plugin をインストールします。

```sh
$ vagrant plugin install vagrant-junos
$ vagrant plugin install vagrant-host-shell
```

インストールできたら確認しましょう。

```sh
$ vagrant plugin list
vagrant-host-shell (0.0.4, global)
vagrant-junos (0.2.1, global)
```

## vSRX のダウンロード

[Vagrant Cloud](https://app.vagrantup.com/boxes/search?utf8=%E2%9C%93&sort=downloads&provider=&q=juniper) からダウンロード可能です。ただ、設定ファイルから自動でダウンロードするため、事前にダウンロードする必要はありません。ちなみに、version がどう見ても古いです・・・が、基礎的な理解には十分です。

- juniper/ffp-12.1X47-D15.4-packetmode
- juniper/ffp-12.1X47-D15.4

SRX には flow base と package base の 2 種類あり、次のモードから要望に合わせて選択します。

- flow: firewall として session 管理を行うモード
- packet: L2/L3 ルータとしてパケット転送を行うモード

# Vagrantfile の作成

構成ファイルにあたる、「Vagrantfile」を作成します。
以下は、`vsrx1 ge-0/0/[1-2] --- ge-0/0/[1-2] vsrx2` のイメージで書いたサンプルです。一つずつ分解していきましょう。

[Gist](https://gist.github.com/sourjp/99df9a894d9e0a69e304a6acb6759b53)にも転記しました。

```rb
Vagrant.configure(2) do |config|
  config.vm.box = "juniper/ffp-12.1X47-D15.4-packetmode"
  config.vm.boot_timeout = 1000

  config.vm.provider "virtualbox" do |vb|
    vb.memory = 512
    vb.cpus = 2
    vb.gui = false
  end

  # vsrx1
  config.vm.define "vsrx1" do |vsrx|
    vsrx.vm.hostname = "vsrx1"
    vsrx.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2201
    # ge-0/0/1
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-1"
    # ge-0/0/2
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-2"

    config.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--nicpromisc2", "deny"]
    end
  end

  # vsrx2
  config.vm.define "vsrx2" do |vsrx|
    vsrx.vm.hostname = "vsrx2"
    vsrx.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2202
    # ge-0/0/1
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-1"
    # ge-0/0/2
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-2"
    config.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--nicpromisc2", "deny"]
    end
  end

end
```

利用するイメージ(Box)を指定します。端末上に該当イメージがない場合は、先ほどの Hashicorp Cloud から自動でダウンロードします。

```rb
  config.vm.box = "juniper/ffp-12.1X47-D15.4-packetmode"
```

vSRX の起動はひじょーーーーーに遅いです。そのため起動中にタイムアウトして失敗するため、追加します。

```rb
  config.vm.boot_timeout = 1000
```

利用するイメージのスペックを指定しています。

- vSRX の RAM 要件は 4GB ですが、試す程度では 512MB でも十分快適(commit が早い)です。
- vp.gui は VirtualBox で GUI 接続するか？ですが、CUI なので不要です。vSRX の GUI 画面とは別の話です。

```rb
  config.vm.provider "virtualbox" do |vb|
    vb.memory = 512
    vb.cpus = 2
    vb.gui = false
```

最後に vSRX 自体の設定を適用します。

- .vm.hostname で hostname が設定されます。
- .vm.netowrk.forward_port は localhost で転送する port を指定します。下記は `ssh localhost -p 2201` で port 22 に転送して接続できます。GUI を試す場合は `id: "http", guest: 80, host: 8080` のように追加します。
- .vm.network.private_network は IF を増やします。 `virtualbox__intent`は VirtualBox の `Internal Link` 機能を利用して、指定グループ(e.g. 1-2-1)だけ接続する LAN を構築します。ちなみに、 `ge-0/0/0` はシステム側で利用するため、`ge-0/0/1`からスタートします。

```rb
  # vsrx1
  config.vm.define "vsrx1" do |vsrx|
    vsrx.vm.hostname = "vsrx1"
    vsrx.vm.network :forwarded_port, id: "ssh", guest: 22, host: 2201
    # ge-0/0/1
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-1"
    # ge-0/0/2
    vsrx.vm.network "private_network",
                     virtualbox__intnet: "1-2-2"

    config.vm.provider "virtualbox" do |vb|
      vb.customize ["modifyvm", :id, "--nicpromisc2", "deny"]
    end
  end
```

# vSRX の起動

作成した Vagrantfile があるディレクトリで起動しましょう。先ほども書きましたが非常にながーーーーい時間がかかるので気長に待ちましょう。

```sh
$ ls | grep V
Vagrantfile

$ vagrant up
Bringing machine 'vsrx1' up with 'virtualbox' provider...
Bringing machine 'vsrx2' up with 'virtualbox' provider...
==> vsrx1: Importing base box 'juniper/ffp-12.1X47-D15.4-packetmode'...
...
==> vsrx2: Configuring and enabling network interfaces...
```

作成できたら、いずれかで接続します。

- vagrant ssh hostname(e.g. vagrant ssh vsrx1)
- ssh root@localhost -p port (e.g. ssh root@localhost -p 2201)

vagrant はデフォルトで、 `user: vagrant passowrd:vagrant + SSH鍵` を作成します。vagrant ssh はそれを利用して接続します。また Junos は root user が必要です。これにはデフォルトで、`user: root password: Juniper`が設定されています。そのため、後者はそれらを指定して接続する方法です。netmiko など自動化ツールを試したい場合は SSH 接続方法の把握が必須なので後者の理解が必要です。

```sh
$ ssh root@localhost -p 2201
Password: # Juniper
--- JUNOS 12.1X47-D15.4 built 2014-11-12 02:13:59 UTC
root@vsrx1% cli
root@vsrx1> show version
Hostname: vsrx1
Model: firefly-perimeter
JUNOS Software Release [12.1X47-D15.4]
```

# vSRX の初期設定ファイルを眺める

こちらが初期設定ファイルです。興味深かったのは次です。system 周りはすでに設定されているので即座に利用できますね。

- root-authentication が設定(`Juniper`)済み。
- user vagrant が作成済み。`vagrant ssh`を利用して接続する時に使っています。
- `ge-0/0/0.0 family inet dhcp`が設定ずみ。これは VirtualBox が外部(要は端末)と SSH するために利用します。そのため、設定を削除するとアクセスできなくなります。

```sh
root@vsrx1> show configuration | display set
set version 12.1X47-D15.4
set system host-name vsrx1
set system root-authentication encrypted-password "$1$nq.N1UsY$JxA/ESAj3KuXseXE597gg0"
set system root-authentication ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCpxmAkPNX/qhiHjtWkj7PYP+NAGW16XUOo7lF7aSPvqoLRtlpN91CKLiiSnuA131b2x2am02/XjG5TdZbLWqfx8Vxvkm9Psfjy66o3+oF6d5yMgAV3AH5c7NYLn0w7Kt6hXzMEPHuc+69rgHQvCiUtxCB91LbbYyQh5w6N0Z/aLyOgDWxwOhtoS99r5nARroecIEDkZTz9NXYPw11mXzpGSko1poG8RuMkzIUUk0aI9sJO3M2730L/BiyFsdivhrvAfqvpeEdbb3oDWhn7QnSUVa0ESyRyNG5hfCd0ff+z0QHrnCigGP7Rr/R0nWq+u0+kPbFgvyVhLMsjZe7CDa+f vagrant"
set system login user vagrant uid 2000
set system login user vagrant class super-user
set system login user vagrant authentication ssh-rsa "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key"
set system services ssh root-login allow
set system services netconf ssh
set system services web-management http interface ge-0/0/0.0
set system syslog user * any emergency
set system syslog file messages any any
set system syslog file messages authorization info
set system syslog file interactive-commands interactive-commands any
set system license autoupdate url https://ae1.juniper.net/junos/key_retrieval
set interfaces ge-0/0/0 unit 0 family inet dhcp
set interfaces ge-0/0/1 unit 0 family inet
set interfaces ge-0/0/2 unit 0 family inet
set interfaces ge-0/0/3 unit 0 family inet
set security forwarding-options family inet6 mode packet-based
set security forwarding-options family mpls mode packet-based
```

最後に interface をみてみると、設定ファイルで作成した inteface が up で用意されています。

```sh
root@vsrx1> show interfaces terse | grep ge
ge-0/0/0                up    up
ge-0/0/0.0              up    up   inet     10.0.2.15/24
ge-0/0/1                up    up
ge-0/0/1.0              up    up   inet
ge-0/0/2                up    up
ge-0/0/2.0              up    up   inet
```

# まとめ

いかがでしょうか？一概に Junos OS と言っても、シリーズによって設定の書き方は若干(特に L2 設定周り)違います。しかしながら、そのエッセンスは十分学ぶことができるので興味がある方はぜひ試してください。

vMX や vQFX なども使えたらいいのですが、、情報お持ちの方は共有いただけると嬉しいです。
Let's Junos Life!

# 最低限知っておきたい vagrant コマンド

色々コマンドはありますが、これだけ知ってれば不便はしないコマンドたちです。

## vagrant up

先ほども試しましたが、Vagrantfile を読み取って環境を構築します。

## vagrant halt

現在の環境を shutdown してくれます。リソースを確保されてしまうので、不要な時は落としておきましょう。

## vagrant destroy

現在の環境を shutdown して跡形もなく削除してくれます。リセットしたい場合はやっちゃいましょう。

## vagrant status

Vagrant で管理しているイメージのステータスを確認できます。なんかおかしい・・・と思ったら `running` か確認しましょう。

```sh
$ vagrant status
Current machine states:

vsrx1                     running (virtualbox)
vsrx2                     running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.
```

## vagrant ssh

Vagrant で管理しているイメージに ssh が可能です。

```
$ vagrant ssh vsrx1
--- JUNOS 12.1X47-D15.4 built 2014-11-12 02:13:59 UTC
```

## vagrant ssh-config

Vagrant で管理しているイメージの ssh の設定ファイルです。鍵の場所は記載の通りです。

```
$ vagrant ssh-config
Host vsrx1
  HostName 127.0.0.1
  User root
  Port 2201
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/sourjp/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL

Host vsrx2
  HostName 127.0.0.1
  User root
  Port 2202
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /Users/sourjp/.vagrant.d/insecure_private_key
  IdentitiesOnly yes
  LogLevel FATAL
```

# うまくいかない時

## 設定ファイル変更したら起動しない

おそらくネットワーク周りをいじっているかと思います。大した量ではないので公式ドキュメントを読んでみたら解決するかもしれません。

https://www.vagrantup.com/docs/networking/basic_usage

## Timed out while waiting for the machine to boot

以下のエラーが出て失敗した雰囲気を醸していますが、単純に起動が遅いので、タイムアウトしているだけです。ほっといたらそのうち起動しています。気になる場合はタイムアウト時間を伸ばすようにしましょう。
ちなみに、vsrx2 の起動処理が入る前にタイムアウトすると作成されていないため、気にせずもう一回トライ(`vagrant up`)しましょう。そうすると vsrx2 の起動を開始するはずです。

```sh
(lab-network) bash-3.2$ vagrant up
Bringing machine 'vsrx1' up with 'virtualbox' provider...
Bringing machine 'vsrx2' up with 'virtualbox' provider...
==> vsrx1: Importing base box 'juniper/ffp-12.1X47-D15.4-packetmode'...
...
    vsrx1: SSH address: 127.0.0.1:2201
    vsrx1: SSH username: root
    vsrx1: SSH auth method: private key
Timed out while waiting for the machine to boot. This means that
Vagrant was unable to communicate with the guest machine within
the configured ("config.vm.boot_timeout" value) time period.

If you look above, you should be able to see the error(s) that
Vagrant had when attempting to connect to the machine. These errors
are usually good hints as to what may be wrong.

If you're using a custom box, make sure that networking is properly
working and you're able to connect to the machine. It is a common
problem that networking isn't setup properly in these boxes.
Verify that authentication configurations are also setup properly,
as well.

If the box appears to be booting properly, you may want to increase
the timeout ("config.vm.boot_timeout") value.
```

## 最終手段？

こんなんもめんどくさいからさっさと触りたいんだ！！という方は、AWS marketplace にて vSRX, vMX が配信されています。どちらも最新 version なので、それを利用するのが一番手っ取り早いかと思いますが、、お金がマッハなので注意ください。。

# 参考

[仮想 Junos4 台と Ansible ホストを Vagrant で構築する Vagrantfile](https://tekunabe.hatenablog.jp/entry/2017/08/26/junos-ansible-vagrant)