Fastly で特定の IP アドレスからのリクエストを許可・拒否する

[Fastlyで特定の国からのアクセスをブロック](https://qiita.com/AtsushiFukuda/items/fbbbd3daf3aec96f568c)にて特定の地域からのアクセスを制御する方法を紹介していますが、ここでは不正なアクセスからサーバを守るための、特定アドレスからのリクエスト拒否の方法と、公開前のサイトをテストするために特定のアドレスからのみのリクエスト拒否の方法をご紹介します。
特定の IP アドレスからのリクエスト許可・拒否についてはオリジンサーバ側で実施することも可能です。ただ、DDoS などの大量アクセスがあった場合に、それをオリジンサーバ側で受けてしまうとオリジンが高負荷となり、正常なリクエストの処理さえできなくなってしまうため、CDN 側でブロックする必要が有ります。

Fastly でアクセスコントロールを実施するには以下の3つの方法があります。

* snippets を用いたアクセスコントロール
Fastly 設定言語である VCL により設定を行います。ACL をあまり変更しない場合に利用します。また、バージョン管理がされるため、設定を一時的に変更して再度戻すことがある場合に適しています。

* Edge ACL を用いたアクセスコントロール
API により設定を行います。API でコントロールできるため、他のシステムとの連携や頻繁に ACL を更新する場合に適しています。一旦設定をすれば、その後のエントリーの追加、変更、削除は Custom VCL の変更を必要としません。

* GUI での IP block list
Block のみですが、GUI で設定可能で即時反映されます。不適切な IP からのブロックを随時行う場合に便利です。

# snippets を用いたアクセスコントロール
ここでは `/admin` ページにアクセスできるアドレスを `192.168.1.1` および `192.168.2.0/24` のみとするように設定します。

## snippets の作成とコード追加
snippets の利用方法は [Fastly のドキュメント](https://docs.fastly.com/ja/vcl/vcl-snippets/using-regular-vcl-snippets/)もしくは [Fastly の snippets 機能を利用する](https://qiita.com/Satoshi-Ishii/items/d4345b3a2ddb954fbf14)を参照してください。
下記2つの snippets を作成して、下記のコードを追加します。

### snippets (init)

```
# アクセスを許可するアドレスを記載する
acl admusers {
  "192.168.1.1"; 
  "192.168.2.0"/24;
}
```

### snippets (recv)

  # リクエスト URL が /admin ではじまり、かつ IP が admusers リストにない場合、403 とする
  if (req.url ~ "^/admin" && client.ip !~ admusers) {
    error 403 "Forbidden";
  }
```
もし、Shielding を利用している場合には、この処理はエッジサーバのみで実施すればよいため、`if` 文に `!req.http.Fastly-FF` を追加し、

```
if (req.url ~ "^/admin" && client.ip !~ admusers && !req.http.Fastly-FF) {
```
とします。Fastly-FF ヘッダはエッジサーバでは存在しないヘッダなのでこの条件を追加します。

## アクティベーション
VCL に問題がなければ、ACTIVATE ボタンが有効になるので、クリックします。
<img width="1438" alt="Screen Shot 2020-03-30 at 12.13.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149542/0638bf9c-9881-d8ed-4078-71741cc825c8.png">
設定した snippets が適用され、ACLが有効になります。

# Edge ACL を用いたアクセスコントロール
## ACL の作成
ACL を設定するためにはじめに各項目を格納する箱を用意します。API で設定するにあたり下記が必要となるため、事前に確認してください。

- curl コマンド実行環境
- [Fastly API Key](https://docs.fastly.com/guides/account-management-and-security/finding-and-managing-your-account-info#finding-and-displaying-your-api-key) または [API トークン](https://docs.fastly.com/api/auth#tokens)
- サービスID
- サービスのバージョン番号（現在のアクティブバージョンをクローンして新しいバージョンを取得）

下記のコマンドを実行して、ACL の設定を行います。実行結果で得られる ACL ID (下記の `aabbccddee12345`)は以降の設定で利用します。

```
$ curl -H "Fastly-Key: FASTLY_KEY" -X POST https://api.fastly.com/service/<service_id>/version/<vcl_version_number>/acl -d name=admusers
{"name":"admusers","service_id":"123456ABCDEF","version":"10","created_at":"2016-11-25T03:07:17+00:00","deleted_at":null,"id":"aabbccddee12345","updated_at":"2016-11-25T03:07:17+00:00"}
```

VCL のコードを見ると

```
acl admusers {
}
```

という空のコードが確認できるはずです。

## ACL エントリーの作成
続いてアクセス制御を行うアドレスを ACL に追加します。

```
$ curl -H "Fastly-Key: FASTLY_KEY" -X POST https://api.fastly.com/service/<service_id>/acl/<acl_id>/entry -d 'ip=192.168.2.0&subnet=24&negated=0&comment=Allow'
{"service_id":"123456ABCDEF","acl_id":"aabbccddee12345","ip":"192.168.2.0","negated":0,"subnet":24,"comment":"Allow","deleted_at":null,"created_at":"2016-11-25T07:32:12+00:00","id":"987654ccbbaa","updated_at":"2016-11-25T07:32:12+00:00"}
```

<acl_id> には ACL 作成時に表示された ID を設定します。また、クエリで設定する各項目については

- ip: 許可する IPアドレス（ネットワークアドレス）を指定します
- subnet: subnet mask を設定します
- negated: 0 を指定します。0 を指定すると許可リストに、1 を指定すると除外リストになります
- comment: 任意のコメントを入力します

VCL のコードを見ると admusers にアドレスが追加されているのが確認できると思います。

```
acl admusers {
	"192.168.2.0"/24;   # Allow
}
```

ここでは、 192.168.2.0/24 から 192.168.2.5 のみを除外する設定を入れてみましょう。除外なので nogated は 1 に設定します。

```
$ curl -H "Fastly-Key: FASTLY_KEY" -X POST https://api.fastly.com/service/<service_id>/acl/<acl_id>/entry -d 'ip=192.168.2.5&subnet=32&negated=1&comment=Deny'
{"service_id":"123456ABCDEF","acl_id":"aabbccddee12345","ip":"192.168.2.5","negated":1,"subnet":32,"comment":"Deny","deleted_at":null,"created_at":"2016-11-25T07:59:15+00:00","id":"876543ccbbaa","updated_at":"2016-11-25T07:59:15+00:00"}
```

VCL のコードを見ると、以下のようになっているのが確認できます。

```
acl admusers {
	"192.168.2.0"/24;   # Allow
	! "192.168.2.5"/32;   # Deny
}
```

この状態で "Custom VCL を用いたアクセスコントロール"で設定した `vcl_recv` の設定を行い、"Custom VCL のアップロードとアクティベーション" を実施すれば、アクセスコントロールが適用されます。

Edge ACL による設定のメリットは先に述べたように、容易に設定変更が可能なところです。上記で設定した 192.168.2.5 の除外設定を解除して、192.168.2.10 の除外設定を追加してみましょう。

```
$ curl -H "Fastly-Key: FASTLY_KEY" -X PATCH https://api.fastly.com/service/<service_id>/acl/<acl_id>/entries -d '{"entries":[{"op": "create", "ip": "192.168.2.10","subnet": "32","negated":"1","commnet":"Deny"},{"op": "delete", "id": "876543ccbbaa"}]}' -H "Content-type: application/json"
```

VCL のコードでも変更が確認できるはずです。

## ACL の確認
ACL は VCL でも内容を見ることができますが、各 entry の ID などは API でしか確認できません。下記の API によって設定内容を確認することができます。

```
$ curl -H "Fastly-Key: FASTLY_KEY" https://api.fastly.com/service/<service_id>/acl/<acl_id>/entries
```

# GUI を用いた block list
## IP block list の有効化
Setting - IP block list を選択します。IP block list の ON/OFF トグルを ON にします。

<img width="1087" alt="Screen Shot 2020-03-30 at 12.20.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149542/78cb8c68-79b6-3173-43da-1301d7a61e88.png">

## IP block エントリーの追加および適用
ADDRESS にブロックしたい IP を追加します。

<img width="1087" alt="Screen Shot 2020-03-30 at 12.23.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149542/1e597bf0-17de-4c14-9934-10fbb9fc823d.png">

ADD ボタンをクリックすれば適用されます。

ここでは snippets によるアクセスコントロール、Edge ACL によるアクセスコントロール、および　GUI での IP block を紹介しました。それぞれの特徴を理解して、ご利用ケースにあった方法を選択してください。