DOTSプロトコルを使ってDDoS対策を自動化してみたい！


[NTTコミュニケーションズアドベントカレンダー](https://qiita.com/advent-calendar/2017/nttcom) 12日目。
今日は、荒ぶるDDoS攻撃[^1]からサービスを防御するための新しいプロトコル **DOTS** (**D**DoS **O**pen **T**hreat **S**ignaling)を紹介します。
DOTSプロトコルについての詳しい日本語の記事は初めてなのではないかと思います。


[^1]: DDoS攻撃:脆弱性を利用して踏み台にしたインターネット上の多数のデバイスからターゲットに大量のパケットを送信し、サービスを不能にさせる攻撃。Miraiボットネットの事例(2016年9月)をきっかけとして、2017年には「DDoS攻撃」という言葉が一般向けの説明にも使われるようになりました。ビジネスにおいてDDoS攻撃の脅威は無視できないものになっています。


# DOTSとは？
 * DOTSとはIETFで策定中のDDoS対策のためのプロトコル
 * DDoS対策の自動化と標準化を実現するよ
 * OSSによる実装がでているよ

この記事では、OSS実装である [go-dots](https://github.com/nttdots/go-dots) を使って、DOTSプロトコルの利用方法を紹介します。


# これからのDDoS対策の話をしよう

DDoS攻撃は2つの方向で脅威が進化しています。

 * **大規模化:** [Arbor社によると](http://jp.arbornetworks.com/%E3%83%AA%E3%82%AA%E3%83%87%E3%82%B8%E3%83%A3%E3%83%8D%E3%82%A4%E3%83%AD%E3%82%AA%E3%83%AA%E3%83%B3%E3%83%94%E3%83%83%E3%82%AF%E3%81%A7%E3%80%81%E6%AF%8E%E7%A7%92540gb%E3%81%AEddos%E6%94%BB%E6%92%83/)、2016年のリオオリンピックでは、500Gbpsを超えるDDoS攻撃があったとのことです。IoTなどインターネットに接続される機器が増えると、その中の一定の割合は脆弱性を持っていると考えられますので、今後も攻撃が大規模化していくことが予想されます。

 * **洗練化:** [incapsula社のブログ](https://www.incapsula.com/blog/pulse-wave-ddos-pins-down-multiple-targets.html)では、300Gbps程度の攻撃を5分単位で開始・停止を繰り返すようなパルス状のDDoS攻撃が報告されています。長時間継続する攻撃には、人力でも辛うじて対策が立てられるかもしれませんが、このような短時間で繰り返される攻撃には人力での対策はやめてください、死んでしまいます。

これらの傾向を考えると、これからのDDoS対策がどのようであるべきかが、自ずと見えてきいます。

#### 今後のDDoS対策のキーポイント
 * **パケットフィルタアウトソーシング:** 攻撃パケットの廃棄などの防波堤は、自組織の外部に作る
 * **セキュリティオートメーション:** 攻撃の検知・防御のアクションに人手を介させず、対策までの時間を短くする

DOTSプロトコルがこれらの2点を実現します。


# DOTSプロトコル 1分解説

DOTSは、DDoS Open Threat Signalingの略で、DDoS防御を依頼するフォーマットを標準化するプロトコルです。IETF[^2]にて策定中で、2017年末あるいは2018年初めには、基本仕様がRFCとなる見込みです。

一言でざっくりまとめると、**「このIPアドレスを攻撃から守って！」**というメッセージを送るためのプロトコルです。

DOTSプロトコル以前の世界での防御依頼はこうです。

[^2]: IETF(Internet Engineering Task Force): RFC文書によりインターネット技術のプロトコルを策定する組織。


#### Before

 * 攻撃を受けている組織は、メールや電話などのレガシーな方法でしか、他の組織に防御を依頼できない
 * APIがあったとしても、DDoS対策プロバイダや対策機器が持っているAPIがそれぞれ異なる

これが、DOTSプロトコルによってこうなります。

#### After

 * DDoS対策プロバイダ側がDOTSサーバを用意し、利用者側がDOTSクライアントを用意する
 * DOTSクライアントから遠隔のDOTSサーバに対して、DOTSプロトコルを用いてIPアドレス等の情報を通知し、防御を依頼する
 * DOTSサーバ側は、情報を元に防御を実施する

#### How it works(どのように動作するか)

 * DOTSプロトコルは、防御を依頼するシグナルチャンネルと、防御内容をセットアップするデータチャンネルの2つのチャンネルからなります
 * プロトコルの詳細はここでは割愛しますが、シグナルチャンネルは、CoAP over DTLS で動作し、証明書を使って相互認証します
 * PUT, GET, DELETE メソッドを使って、DOTSクライアント側から防御のステータスを制御します



# OSSによるDOTSプロトコルの利用方法


では、実際にDOTSプロトコルを使って、攻撃を防御してみましょう。
DOTSプロトコルのOSS実装である [go-dots](https://github.com/nttdots/go-dots) を使っていきます。go-dots は Go言語で書かれています。go-dots では、防御手法の一つとして、[gobgp](https://github.com/osrg/gobgp)[^3]の制御ができるようになっています。
今回構築する構成は以下です。IETFらしく、アスキーアートで書いてみました。

[^3]: gobgp: Go言語で実装されたBGP(Border Gateway Protocol)デーモン。使い勝手が良くて素晴らしい。

```
攻撃を受けている側(DOTS client)                 攻撃を防御する側(DOTS server)
Mac                                          AWS
+------------+                               +---------------------------+
| +--------+ |    ------>DOTS messages       | +--------+                |
| |DOTS    | |            4646/udp           | |DOTS    |      +------+  |
| |Client  | +--------(The Internet)---------+ |Server  |----->|gobgp |  |
| |        | |                               | |        |      +------+  |
| +--------+ |                               | +--------+                |
+------------+                               |     ^                     |
                                             |     |                     |
                                             |     v                     |
                                             |  +------+                 |
                                             |  |mysql |(設定の格納)      |
                                             |  +------+                 |
                                             +---------------------------+
```

攻撃を受けている側のサービスのIPアドレスを仮に`10.100.0.1`としましょう。
MacにインストールしたDOTSクライアントを利用して、`10.100.0.1`への攻撃について対策して欲しいという依頼を、DDoS対策プロバイダに通知します。
今回は、DDoS対策プロバイダではなく、AWS上にDOTSサーバを構築し、gobgpを使ってブラックホール経路(RTBH)を生成して、パケットを破棄するというストーリーにします。


## DOTSサーバのセットアップ(AWSでの例)

DOTSサーバをAWS上にセットアップします。
AWS上で、EC2インスタンスを作成します。ここでは、以下とします。

* Ubuntu Server 16.04 LTS (HVM), SSD Volume Type
* t2.small (vCPU:1, Mem:2GiB)

後に 4646/udp を待ち受ける[^4]ことになるので、セキュリティグループの設定にて、``カスタムUDPルール > port range: 4646``を追加しておくのを忘れないようにしましょう。

[^4]: go-dots のデフォルトのポートが、4646/udp (シグナルチャンネル)です。IANAによるアサイン待ちです。なぜ"4646"かというと、"."(ドット)のASCIIコードが、46なので、4646で、".."。ドットが2つでdots(おあとがよろしいようで)


### 1. Go言語のインストール

Go言語のインストール手順は[公式のドキュメント](https://golang.org/doc/install)を見ることを推奨しますが、ここでは簡単に手元の手順を共有します。

golangのインストール(apt-get)

```shell
$ sudo apt-get install golang
```

バージョンの確認

```shell
$ go version
go version go1.6.2 linux/amd64
```

GOPATHの設定

```shell
$ cd ~/
$ mkdir go
$ vim .bashrc
    export GOPATH=$HOME/go
    export PATH=$PATH:$HOME/go/bin:/usr/local/go/bin
$ source .bashrc
```


### 2. go-dots のインストール

go-dots は、`go get -u github.com/nttdots/go-dots/...` のたった一行でインストールできます。
ただし、DTLSを利用するので、依存している gnutls-devel を先にインストールします。
DTLSは、WebRTCでも用いられている、UDP上のTLSです(雑な説明)。


gnutls-develのインストール

```shell
$ sudo apt-get install libgnutls-dev
```

go-dotsのインストール

```shell
$ go get -u github.com/nttdots/go-dots/...
```

ビルドが無事されていることの確認

```shell
$ ll $GOPATH/bin
  -rwxrwxr-x 1 ubuntu ubuntu 17491488 Oct 30 03:15 dots_client*
  -rwxrwxr-x 1 ubuntu ubuntu  9724752 Oct 30 03:11 dots_client_controller*
  -rwxrwxr-x 1 ubuntu ubuntu 31952616 Oct 30 03:31 dots_server*
```

### 3. mysqlサーバのインストール

go-dots のDOTSサーバは、ユーザ情報の管理に mysql サーバを利用しています。
mysqlサーバをサクッとインストールして、初期設定をダンプから投入しましょう。
DB(mysql)にパスワードを設定した場合は、後でDOTSサーバの設定(dots_server.yaml)に記入します。

```shell
$ sudo apt-get install mysql-server mysql-client
```

go-dots用のデータベースを作成します

```shell
$ mysql -u root -p
mysql> create database dots;
```

作成したデータベースに、試験用のデータをロードします。

```shell
$ cd $GOPATH/src/github.com/nttdots/go-dots
$ mysql -u root -p dots < dots_server/db_models/test_dump.sql
```

DOTSサーバの設定(dots_server.yaml)にDBの情報を記入します。

```shell
$ cp $GOPATH/src/github.com/nttdots/go-dots/dots_server/dots_server.yaml <your_dots_server_setting>.yml
$ vim <your_dots_server_setting>.yml
        database:
          username: root
          password: <-- your password.
          protocol: tcp
          host: localhost
          port: 3306
          databaseName: dots
```

最後に、DOTSクライアントの証明書情報[^5]を所定のフォルダに格納しておきます

[^5]: 今回の例では、オレオレ証明書を使っています

```shell
$ mkdir -p ~/dots/certs
$ cd ~/dots/certs
$ cp  $GOPATH/src/github.com/nttdots/go-dots/certs/* .
```

### 4. gobgpサーバの起動

gobgpサーバも動かしておきましょう[^6]。
今回は DOTSサーバと同一のインスタンスに gobgpサーバを立てます。(go get にちょっと時間がかかるよ)

```shell
go get github.com/osrg/gobgp/...
sudo $GOPATH/bin/gobgpd -f gobgpd.conf
```

[^6]: もちろん、localhost以外のgobgpサーバも利用できます。利用するgobgpサーバは、先ほどロードした mysql のテーブルに記載してあります。デフォルトで、127.0.0.1 の gobgpサーバを利用するようになっています。


### 5. DOTSサーバの起動

さぁ、あと一息です。以下のコマンドでDOTSサーバが立ち上がります。

```shell
$GOPATH/bin/dots_server --config <your_dots_server_setting>.yml -vv
```

## DOTSクライアントのセットアップ(Macでの例)

手元のMacにも go-dots をインストールして、こちらではDOTSクライアントを動かしてみましょう。MacへのGo言語のインストールは[公式のドキュメント](https://golang.org/doc/install)をご覧ください。

### 1. go-dotsのインストール
[gnutls](https://gnutls.org/) のインストール

```shell
$ brew install gnutls
```

go-dots のインストール

```shell
$ go get -u github.com/nttdots/go-dots/...
```

### 2. DOTSクライアントの起動

DOTSサーバのIPアドレス(IPv4,IPv6両方可能)を設定して、クライアントを起動しましょう。クライアント側は簡単ですね。

```shell
$GOPATH/bin/dots_client --server <your_dots_server_IPaddress> -vv 
```

## 防御依頼の実施

では、実際にDDoS防御の依頼をしてみましょう。
`10.100.0.1` に対してDDoS攻撃が発生しています。それは、あなたにとって非常に重要なWebサーバかもしれません。
以下の JSON ファイルに書かれた内容で、防御依頼を実施します。
防御依頼が許可されるアドレス帯は、クライアント側の証明書に基づいて、すでにサーバ側に設定されています。

```MitigationRequestTest.json
{
  "mitigation-scope": {
    "client-identifier": [
      "E9CZ9INDbd+2eRQo"
    ],
    "scope": [
      {
        "mitigation-id": 10011,
        "target-ip": [
         "10.100.0.1"
        ],
        "target-port-range": [
          {
            "lower-port": 80
          }
       ],
        "target-protocol": [
         6
       ]
      }
    ]
  }
}
```

Mac上で、上記JSONファイルを作成し、クライアントコントローラを用いて、DOTSクライアントにメッセージを送ってもらいます。

```shell
$GOPATH/bin/dots_client_controller -request mitigation_request -method Put -json MitigationRequestTest.json
```

`-vv` オプションをつけているので、手元で試した場合は、デバッグメッセージを見ることができると思います。

大まかな通信の流れは以下です。

**DOTSクライアント/サーバ**
DTLSのハンドシェイクを行う
**DOTSクライアント**
防御依頼内容を、CBOR にエンコードする
CoAP のメソッド(防御依頼は PUT)にて、DOTSサーバにメッセージを送付する
**DOTSサーバ**
クライアント証明書との関連付けに基づいて、防御依頼されているアドレスが正しいかバリデーションする
正しければ、利用可能な防御手法(今回はgobgp)を用いて、防御を実施する

## 防御成功

おめでとうございます。gobgpに経路が投入されました。

```shell
$ gobgp global rib 
   Network              Next Hop             AS_PATH              Age        Attrs
*> 10.100.0.1/32        0.0.0.1                                   00:00:27   [{Origin: i}]
```

gobgpと、実際のネットワークのルータとの間でピアを張っておけば、DOTSでバリデーションされた経路を任意のネクストホップで注入することができます。ネクストホップ先をNull0にしておけば、ブラックホールルーティングになりますし、ArborやRadwareなどのDDoS緩和装置にしておけば、攻撃の緩和をすることができます。

### Dockerfileも利用可能

[go-dots](https://github.com/nttdots/go-dots) のリポジトリには、Dockerfileも用意してありますので、Docker環境があれば、上記の各種セットアップを省略していきなり試すこともできます。


## 最後に

今日はDOTSプロトコルの機能のごく一部を紹介しました。go-dots は我々が開発しており、現時点(2017/12)で世界唯一のDOTSプロトコルのOSS実装です。

筆者は 2017年11月に開催された IETF100のハッカソンで、go-dots とNCCグループ(イギリスのセキュリティコンサル会社)の実装との間で、相互接続試験を実施しました。活動が認められハッカソンでは、Best Open Source賞を受賞しました。

IETFでの提案活動やOSSを公開する活動については、2018年1月24日(水)〜26日(金)に広島で開催される [JANOG41](https://www.janog.gr.jp/meeting/janog41/) にて、「[日本でのオープンループ](https://www.janog.gr.jp/meeting/janog41/program/openloop)」というタイトルで発表する予定になっています。

近いうちに、より多くのDDoS対策プロバイダが、DOTSプロトコル対応を謳ってくるのではないかと思います。ありとあらゆるサービスにDOTSクライアントを入れるだけで、DDoS防御依頼ができるようになる世界観になることを目指しています。