IBM Cloudの仮想サーバをJuniper vSRXのIPSで保護する

# 目的

インターネットからのアクセスはWAFやIPSで防御する、とセキュリティルールが定められているエンタープライズな環境は多いと思います。IBM Cloudの場合、WAFはCloud Internet Servicesで対応するのが一般的と思いますが、IPSはSuricataなどのOSSを自力で構築するか、IaaSのゲートウェイアプライアンスで対応することになるでしょう。

現在IBM CloudでIPSに対応したアプライアンスはFortiGate Security Appliance 10Gbpsプランか、Juniper vSRXがあります。以前はFortiGate Security Appliance 1Gbpsプランが設定が簡単かつ10Gbpsプランに比べ安価で良かったのですが、残念ながら2021年5月末にEOSとなってしまいます。

そこで、今回はvSRXを使ってIPSが動くまでの手順を検証してみます。

# 構成

* httpdが動く仮想サーバ（パブリックインターフェース有）
* 仮想サーバのパブリックVLANを保護するvSRX

# 手順

## 仮想サーバの準備

パブリックインターフェースを有効にした仮想サーバをオーダーします。オーダー後、httpdを起動しておきます。

```
# dnf -y install httpd
# systemctl enable httpd
# systemctl start httpd
```

外部のマシンからインターネット経由でhttpdにアクセスできることを確認します。

```
$ curl 161.xx.xx.xx -s | head -5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE HTML>
<html lang="en">
  <head>
    <title>CentOS 提供的 Apache HTTP 服务器测试页</title>
```

## vSRXの設定

### オーダー

クラシックインフラストラクチャーのゲートウェイアプライアンスから追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/c614ab4f-c3b5-0bd6-b414-1b20251bd5ef.png)

ゲートウェイベンダーでJuniperを選択します。IPSを利用するため、ライセンスは``CSB License``を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ef75ca85-485f-5f8c-1138-c87403a1f21f.png)

オーダーしてからプロビジョンが完了するまで数時間かかります。気長に待ちましょう。

### 初期設定

IBM Cloudのガイドを見ていくつか初期設定をしておくとよいです。また、vSRXにログインするためのアドレスとadminのパスワードを確認しておきます。

> https://cloud.ibm.com/docs/vsrx?topic=vsrx-performing-ibm-cloud-juniper-vsrx-basics

### VLANの関連付け

vSRXはトランジットVLANと呼ばれる特殊なVLANに配置されます。仮想サーバを保護するため、仮想サーバのパブリックインターフェースが属するVLANをvSRXに関連付けします。

まず、仮想サーバのVLAN IDを確認します。例の場合、public(eth1)のVLAN tok02.fcr01a.896の896がVLAN IDです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/5dada7e3-e66c-30f5-e9f6-b61794094ac0.png)

次にこのパブリックインターフェースのサブネットアドレスとゲートウェイアドレスを確認します。public(eth1)のIPアドレスをクリックします。例の場合はぼかしていますが上部にサブネットのレンジが、表の2行目にゲートウェイアドレスが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/a712e68d-8fb6-319b-1aad-aa307f223151.png)

それではVLANをvSRXに関連付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/aa62ea08-705c-2a26-2a7b-85df32f7ba11.png)

先ほど確認したVLAN IDを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/db0a0c4a-d37c-48dd-67ec-cbc714f1a1e4.png)

関連付けが完了すると一覧に表示されます。状況が迂回経路となっていますが、このときはまだ仮想サーバへの通信はvSRXを通りません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/c3e2a647-7276-7a5f-f9d9-83f4d96cf324.png)

VLANを選択してルートスルーを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ba3c7d87-d4c2-ae63-8733-d1b75637d3fd.png)

変更には数分を要します。何度か画面をリロードして待っていると状況がルートスルーに変わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ada430df-77f4-9c40-f054-d3408d7a82bd.png)

これで仮想サーバのパブリックインターフェースはvSRXの保護下になりました。初期状態では全ての通信が拒否されています。httpdもアクセスできません。

```
$ curl 161.xx.xx.xx -s | head -5
(タイムアウト)
```

### インターフェースの設定

vSRXの設定に入っていきます。最初にやることはインターフェースの設定です。ここから先はsshで操作します。

インターフェースはreth0,1,2,3の4つがあります。

* reth0: Private 使用済
* reth1: Public 使用済
* reth2: Private ユーザー用
* reth3: Public ユーザー用

reth0とreth1はシステムで利用されているので、今回はreth3を使うことになります。以下は初期状態です。

```
> configure
# show interfaces
...
reth3 {
    vlan-tagging;
    redundant-ether-options {
        redundancy-group 1;
    }
}
...
```
先ほど控えた値を利用してインターフェースを設定します。

* VLAN ID: 896
* 仮想サーバのゲートウェイアドレス: 161.xx.xx.xx.65/28

```
# set interfaces reth3 unit 896 vlan-id 896
# set interfaces reth3 unit 896 family inet address 161.xx.xx.65/28
```

### ゾーンとアドレスブックの作成

CUSTOMER-PUBLICゾーンとVSI_PUB_NETアドレスブックを作成します。CUSTOMER-PUBLICゾーンは保護する仮想サーバが属するゾーン、VSI_PUB_NETアドレスブックは仮想サーバで使用しているサブネットのIPレンジです。

* 仮想サーバのサブネットレンジ: 161.xx.xx.xx.64/28

```
# set security zones security-zone CUSTOMER-PUBLIC interfaces reth3.896 host-inbound-traffic system-services all
# set security address-book global address VSI_PUB_NET 161.xx.xx.64/28
```

### ポリシーの作成

CUSTOMER-PUBLICゾーン内の通信はすべて許可するALLOW_INTERNALポリシーを作成します。

```
# set security policies from-zone CUSTOMER-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_INTERNAL description "Allow all traffic within CUSTOMER_PUBLIC zone" match source-address any destination-address any application any
# set security policies from-zone CUSTOMER-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_INTERNAL then permit
```

CUSTOMER-PUBLICゾーンから全てのパブリックへの通信を許可します。仮想サーバからvSRXが属するSL-PUBLICゾーンを経由して出ていくことになります。

```
# set security policies from-zone CUSTOMER-PUBLIC to-zone SL-PUBLIC policy ALLOW_OUTBOUND description "Allow all outbound traffic from CUSTOMER-PUBLIC to public network" match source-address any destination-address any application any
# set security policies from-zone CUSTOMER-PUBLIC to-zone SL-PUBLIC policy ALLOW_OUTBOUND then permit
```

パブリックからCUSTOMER-PUBLICゾーンへICMPとHTTPを許可します。ICMPは必ずしも必要ではありませんが、ネットワークで問題が起きたときに調査する際に必要になりますので、私は常に許可するようにしています。今度は先ほどとは逆にSL-PUBLICゾーンからCUSTOMER-PUBLICゾーンへの通信です。

```
# set security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_PING description "Allow ping from public network" match source-address any destination-address VSI_PUB_NET application junos-ping
# set security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_PING then permit
# set security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_HTTP description "Allow HTTP from public network" match source-address any destination-address VSI_PUB_NET application junos-http
# set security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_HTTP then permit
```

設定を反映します。

```
# show | compare
# commit
```

これでHTTPが再度通るようになりました。

```
$ curl 161.xx.xx.xx -s | head -5
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE HTML>
<html lang="en">
  <head>
    <title>CentOS 提供的 Apache HTTP 服务器测试页</title>
```

## IPSの設定

IPSのためのシグネチャ等をダウンロードするため、まずvSRXから外部のhttpsポートに接続できるようにします。PROTECT-INフィルターはvSRX本体への通信を許可するフィルターです。下記コマンドでは感覚的にINやfromの方向が逆な気がしますが、このフィルタはINとOUTが双方向で許可されますので問題はありません。

```
> configure
# set firewall filter PROTECT-IN term WEB from port https
# commit
```

それではIPSの設定をしていきます。ガイドは下記URLで参照することができます。

> https://public.dhe.ibm.com/cloud/bluemix/network/vsrx/idp.pdf

まずトレースを有効化します。

```
# set security idp traceoptions file idpd
# set security idp traceoptions file size 20m
# set security idp traceoptions flag all
# set security idp traceoptions level all
# commit
```

ライセンスを確認します。idp-sigがインストールされていますがまだ使用されていません。

```
# exit
> show system license
License usage:
                                 Licenses     Licenses    Licenses    Expiry
  Feature name                       used    installed      needed
  anti_spam_key_sbl                     0            1           0    2021-10-18 00:00:00 UTC
  idp-sig                               0            1           0    2021-10-18 00:00:00 UTC
  appid-sig                             0            1           0    2021-10-18 00:00:00 UTC
  av_key_sophos_engine                  0            1           0    2021-10-18 00:00:00 UTC
  logical-system                        1            3           0    permanent
  wf_key_websense_ewf                   0            1           0    2021-10-18 00:00:00 UTC
  Virtual Appliance                     1            1           0    2021-10-18 00:00:00 UTC
  remote-access-ipsec-vpn-client        0            2           0    permanent
```

セキュリティパッケージのダウンロードを行います。

```
> configure
# set security idp security-package url https://services.netscreen.com/cgi-bin/index.cgi
# commit
# exit
> request security idp security-package download full-update
node0:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI
```

ダウンロードは非同期で行われます。何度が状態を確認すると完了します。

```
> request security idp security-package download status
node0:
--------------------------------------------------------------------------
In progress: Downloading ...

> request security idp security-package download status
node0:
--------------------------------------------------------------------------
Done;Successfully downloaded from(https://services.netscreen.com/cgi-bin/index.cgi)
and synchronized to backup.
Version info:3340(Tue Dec 22 14:51:46 2020 UTC, Detector=12.6.130200828)
```

ポリシーテンプレートをダウンロードします。

```
> request security idp security-package download policy-templates
node0:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI

> request security idp security-package download status
node0:
--------------------------------------------------------------------------
Done;Successfully downloaded from(https://services.netscreen.com/cgi-bin/index.cgi)
and synchronized to backup.
Version info:3340
```

各ファイルがダウンロードされていることを確認します。

```
> start shell
% ls -l /var/db/idpd/sec-download/
total 151680
-rw-r--r--  1 root  wheel  55882769 Dec 23 10:49 SignatureUpdate.xml
-rw-r--r--  1 root  wheel    637792 Dec 23 10:49 application_groups2.xml
-rw-r--r--  1 root  wheel     11885 Dec 23 10:49 applications.xsd
-rw-r--r--  1 root  wheel   6294262 Dec 23 10:49 applications2.xml
-rw-r--r--  1 root  wheel    764170 Dec 25 02:47 detector-capabilities.xml
-rw-r--r--  1 root  wheel      4928 Dec 23 10:49 files.tgz
-rw-r--r--  1 root  wheel    577881 Dec 23 10:49 filters.xml
-rw-r--r--  1 root  wheel   5170710 Dec 23 10:49 groups.xml
-rw-r--r--  1 root  wheel   2568038 Sep 16 12:09 libidp-detector.so.tgz.v
-rw-r--r--  1 root  wheel   5329599 Nov  4 07:31 libqmprotocols.tgz
-rw-r--r--  1 root  wheel       495 Dec 23 10:49 platforms.xml
-rw-r--r--  1 root  wheel         1 Dec 26 00:26 secdb_result.txt
drwxr-xr-x  2 root  wheel       512 Dec 26 00:26 sub-download

% ls -l /var/db/idpd/sec-download/sub-download/
total 336
-rw-r--r--  1 root  wheel    2872 Dec 26 00:26 SignatureUpdate.xml
-rw-r--r--  1 root  wheel  165525 Dec 23 10:49 templates.xml

% exit
```

セキュリティパッケージをインストールします。

```
> request security idp security-package install
node0:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI

node1:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI

> request security idp security-package install status
node0:
--------------------------------------------------------------------------
In progress:performing DB update for an xml (SignatureUpdate.xml)

node1:
--------------------------------------------------------------------------
In progress:performing DB update for an xml (SignatureUpdate.xml)

> request security idp security-package install status
node0:
--------------------------------------------------------------------------
Done;Attack DB update : successful - [UpdateNumber=3340,ExportDate=Tue Dec 22 14:51:46 2020 UTC,Detector=12.6.130200828]
     Updating control-plane with new detector : successful
     Updating data-plane with new attack or detector : not performed
      due to no active policy configured.

node1:
--------------------------------------------------------------------------
Done;Attack DB update : successful - [UpdateNumber=3340,ExportDate=Tue Dec 22 14:51:46 2020 UTC,Detector=12.6.130200828]
     Updating control-plane with new detector : successful
     Updating data-plane with new attack or detector : not performed
      due to no active policy configured.
```

バージョンを確認します。

```
> show security idp security-package-version
node0:
--------------------------------------------------------------------------

  Attack database version:3340(Tue Dec 22 14:51:46 2020 UTC)
  Detector version :12.6.130200828
  Policy template version :N/A

node1:
--------------------------------------------------------------------------

  Attack database version:3340(Tue Dec 22 14:51:46 2020 UTC)
  Detector version :12.6.130200828
  Policy template version :N/A
```

ポリシーテンプレートをインストールします。

```
> request security idp security-package install policy-templates
node0:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI

node1:
--------------------------------------------------------------------------
Will be processed in async mode. Check the status using the status checking CLI

> request security idp security-package install status
node0:
--------------------------------------------------------------------------
Done;policy-templates has been successfully updated into internal repository
     (=>/var/run/scripts/commit/templates.xsl)!

node1:
--------------------------------------------------------------------------
Done;policy-templates has been successfully updated into internal repository
     (=>/var/run/scripts/commit/templates.xsl)!
```

テンプレートスクリプトをアクティベートします。

```
> configure
# set system scripts commit file templates.xsl
# commit
```

ポリシーの一覧を確認します。

```
# set security idp idp-policy ?
Possible completions:
  <policy-name>        IDP policy name
  Server-Protection    IDP policy name
  Server-Protection-1G  IDP policy name
  Client-Protection    IDP policy name
  Client-Protection-1G  IDP policy name
  Client-And-Server-Protection  IDP policy name
  Client-And-Server-Protection-1G  IDP policy name
  Web_Server           IDP policy name
  DMZ_Services         IDP policy name
  DNS_Service          IDP policy name
  File_Server          IDP policy name
  Getting_Started      IDP policy name
  IDP_Default          IDP policy name
  Recommended          IDP policy name
```

各テンプレートのポリシーは各サイトで解説されています。

> https://www.juniper.net/documentation/en_US/junos/topics/topic-map/security-idp-policy-templates.html

それぞれ特徴がありますが、まずは``Recommended``から始めるのがよいようです。

シグネチャですが、毎回手動では大変なので自動ダウンロードにします。毎日0時（日本時間）にセットします。なお、ダウンロード元のシグネチャは2週間に1度程度の頻度で更新しているようです。

```
# set security idp security-package automatic start-time "2020-01-01.00:00:00 +0900" interval 24 enable
# commit
```

テンプレートスクリプトファイルを非アクティブにします。こうすることで事前定義済のポリシーがコミット時に上書きされるリスクを回避できるそうです。

```
# deactivate system scripts commit file templates.xsl
# commit
```

ライセンスを確認します。先ほどはidp-sigのusedが0でしたが、1になっています。

```
# exit
> show system license
License usage:
                                 Licenses     Licenses    Licenses    Expiry
  Feature name                       used    installed      needed
  anti_spam_key_sbl                     0            1           0    2021-10-18 00:00:00 UTC
  idp-sig                               1            1           0    2021-10-18 00:00:00 UTC
  appid-sig                             0            1           0    2021-10-18 00:00:00 UTC
  av_key_sophos_engine                  0            1           0    2021-10-18 00:00:00 UTC
  logical-system                        1            3           0    permanent
  wf_key_websense_ewf                   0            1           0    2021-10-18 00:00:00 UTC
  Virtual Appliance                     1            1           0    2021-10-18 00:00:00 UTC
  remote-access-ipsec-vpn-client        0            2           0    permanent

Licenses installed:
  License identifier: E20190913001
  License version: 4
  Software Serial Number: SUB00024128768
  Customer ID: “IBM”
  Features:
    wf_key_websense_ewf - Web Filtering EWF
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
    Virtual Appliance - Virtual Appliance
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
    anti_spam_key_sbl - Anti-Spam
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
    idp-sig          - IDP Signature
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
    appid-sig        - APPID Signature
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
    av_key_sophos_engine - Anti Virus with Sophos Engine
      date-based, 2018-10-18 00:00:00 UTC - 2021-10-18 00:00:00 UTC
```

それでは、先ほど作成したALLOW_HTTPポリシーにIDPポリシーRecommendedを適用します。

```
# set security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC policy ALLOW_HTTP then permit application-services idp-policy Recommended

# show security policies from-zone SL-PUBLIC to-zone CUSTOMER-PUBLIC
policy ALLOW_PING {
    description "Allow ping from public network";
    match {
        source-address any;
        destination-address VSI_PUB_NET;
        application junos-ping;
    }
    then {
        permit;
    }
}
policy ALLOW_HTTP {
    description "Allow HTTP from public network";
    match {
        source-address any;
        destination-address VSI_PUB_NET;
        application junos-http;
    }
    then {
        permit {
            application-services {
                idp-policy Recommended;
            }
        }
    }
}
```

コミットします。

```
# commit
# exit
```

> 古いガイドだと、``set security idp active-policy ポリシー名``と``set security policy ～ then permit application-services idp``の組み合わせでIDPポリシーをセットする方法が書かれている場合がありますが、現在は非推奨のやり方だそうです。active-policyは使わず、上記のように``set security policy ～ then permit application-services idp-policy IDPポリシー名``とするのが推奨とのことです。

## IPSのテスト

IDPが機能していることを確認します。しかし、IDPが監視するレイヤーでのテストは非常に難しいです。今回は何かしらの攻撃を検知できればよしとすることにして、OWASP ZAPによる脆弱性スキャンを攻撃に見立ててみます。

```
$ docker run -t owasp/zap2docker-stable zap-full-scan.py -t http://161.xx.xx.xx/
```

ZAPを実行中、vSRX側で統計を確認します。

```
> show security idp attack table
node0:
--------------------------------------------------------------------------
IDP attack statistics:

  Attack name                                  #Hits
  HTTP:HTTP_PROXY-ATTACK                       26

node1:
--------------------------------------------------------------------------
```

具体的にはわかりませんが、HTTP_PROXY-ATTACKなる攻撃を検知した模様です。何度か打つとHitsが増えていくことがわかります。

基本的な設定は終わったので、次回以降に具体的なログの確認方法やイベントの通知方法等について検証していこうと思います。