社内開発環境を一時的に外部公開できるngrokの使い方

## はじめに

開発中のシステムや社内システムといった非公開のシステムを、一時的にインターネット経由でアクセスできるようにしたいといったことはありませんか？

例えば、ごく限られた顧客に対して開発中のシステムを触ってもらいたい場合や、リリース前のサービスに対してAeyeScanのようなクラウド型の脆弱性診断ツールを使って診断したい場合など。

そんな時に役立つのが、ngrokというサービスです。
ngrokを使うと、コマンド一つで社内システムを外部公開できます。

## ngrokとは？

ngrokを一言で表すとリバースプロキシサービスです。リバースプロキシとは外から来た通信を適切なサーバーに転送するシステムのことです。通常はサービスの負荷分散や、コンテンツのキャッシュ・暗号化などを目的に使われます。 ngrok for production というサービスもあるのでそのような目的でも使用できそうですが、今回は開発やテストのために一時的に外部アクセスを試したいというシナリオをもとに説明していきます。


通常、リバースプロキシは以下の図のようにサーバーとインターネットとの境界に配置し、サーバーへ到達するリクエストを中継します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/17eaca79-c079-20be-54ee-072547f66402.png" width=75%>

ngrokの場合はインターネット上にあるngrokがリクエストを受け付け、社内のPCやサーバーにリクエストを転送します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/4e9f8bd6-112d-979e-4dee-6d77c97105a7.png"/>


ngrok は無料で使うこともできますが、一ヶ月のリクエスト数に制限があります。業務で使う場合は pro以上のプランを選択するのがおすすめです。 インターネット経由でWebアプリケーションの脆弱性診断を行う場合も、一ヶ月のリクエスト数の制限を超える可能性が高いことから、pro版が必要になるでしょう。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/90c7e590-0096-80b2-c5e3-7ad314dbcd52.png)

https://ngrok.com/pricing

## 使い方

### 1.アカウント作成

最初にngrokのアカウントを作成します。
以下のリンクからngrokの画面を開き、右上の `Sign up` ボタンからアカウントを作成します。

https://ngrok.com/


### 2.インストール
アカウント登録後に表示される手順に従って、ngrokをインストールします。

インストール後、認証情報を登録するため、ブラウザに表示された赤枠部分のコマンドをコピーして実行します。

![インストール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/c217fdb8-3756-76fe-a240-836ea60f6938.png)

### 3.動作確認

インストール直後のXAMPPなど、適当なテストサイトを立ち上げた状態で以下のコマンドを実行します。コマンドの `8080` はWebアプリが使用するポート番号です。状況に応じて変更してください。

```sh
ngrok http http://localhost:8080 
```

:::note alert
重要！！
この時点ではアクセス制限がかかっていないため、社外秘のシステムはテストに使わないでください。
:::

ngrokが立ち上がると、以下のような情報が表示されます。

![動作確認2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/f3459724-2887-b5d7-eece-2f545d9a600e.png)


無料版では、ブラウザのアドレスバーに赤枠部分のアドレスを入力すると以下のような画面が表示されます。

![動作確認3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/acdc88ec-6242-3c3e-0181-1ce5d4896e40.png)


アドレスに誤りがないことを確認し、 `Visit Site` ボタンをクリックします。テストサイトにアクセスできれば動作確認完了です。pro版など有料版を使用している場合は、警告画面を省略できるようです。

なお、無料版で表示される ngrokの警告画面ですが、以下のように `ngrok-skip-browser-warning` ヘッダーを付与してリクエストを送信することで、スキップできます。

```
ngrok-skip-browser-warning:1
```

すでにお気づきかもしれませんが、手元で `http` で動作しているWebサービスであっても、ngrok経由でアクセスする時には自動的に暗号化され `https` でアクセスできるようになっています。一時的な外部アクセスのために証明書を準備しなくて済むのはありがたいですね。


### 4.設定ファイルの作成

実行のたびにコマンドオプションを指定するのはミスの元です。そこで設定ファイルを作りましょう。以下のコマンドを実行すると、デフォルトの設定ファイルの保存先が表示されます。


```powershell
ngrok config check
```

このファイルを編集すると、同じ設定を何度も再現できます。

```yml:ngrok.yml
# Version of the ngrok Agent Configuration file. Required.
version: 3

# Agent Configuration
agent:
  authtoken: *******************************************

# Endpoint Definitions
endpoints:
  - name: basic
    url: basic.ngrok.app
    upstream:
      url: http://localhost:8080
```

`endpoints` に名前をつけて設定を保存します。直前の `authtoken` は触らないでください。
`name` に書いた値は、設定を識別するための名前です。ファイルを保存したら、再度以下のコマンドを実行します。設定に誤りがあればエラーが表示されます。

```powershell
ngrok config check
```

設定に問題がなければ、以下のコマンドで設定を参照できます。
`basic` は設定の名前です。

```powershell
ngrok start basic
```

詳細なファイルの仕様はこちらを参考にしてください。

https://ngrok.com/docs/agent/config/v3/

:::note info
設定ファイルの `endpoints.url` の値( `basic.ngrok.app` )は外部からアクセスするためのドメインです。
ランダムな値にはなりますが、無料プランでも静的なドメインを1件取得できます。
:::

#### ngrok上で利用可能なドメインの取得方法

ドメインを取得するには、以下のURLにアクセスします。

[https://dashboard.ngrok.com/domains](https://dashboard.ngrok.com/domains)


アクセスしたら、 `Create Domain` ボタンを押すと、ランダムなドメインが割り当てられます。 

![create_domain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/2d7f5307-ae4f-d253-dd23-3ebbc7421c30.png)

割り当てられたドメインは以下のように表示されます。

![domain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2422105/44fb8a13-37f1-536b-4d8f-3029405033f2.png)


### 5.アクセス制限

ngrokはさまざまなアクセス制限を設定できます。
コマンドライン引数でも設定できますが、ここでは設定ファイルを使います。

#### Basic認証を行う場合

`endpoints` の対象エントリに、以下のような`traffic_policy` という項目を追加します。
`credentials` の`user:password1` は、Basic認証のダイアログに使用するユーザ名とパワードです。

```yml
traffic_policy:
  on_http_request:
    - actions:
      - type: basic-auth
        config:
          realm: sample-realm
          credentials:
            - user:password1 # ここは変更してください。
          enforce: true
```

全部の設定を記載した設定例はこちらです。

```yml:ngrok.yml
# Version of the ngrok Agent Configuration file. Required.
version: 3

# Agent Configuration
agent:
  authtoken: *******************************************

# Endpoint Definitions
endpoints:
  - name: basic
    url: basic.ngrok.app
    upstream:
      url: http://localhost:8080
    traffic_policy:
      on_http_request:
        - actions:
          - type: basic-auth
            config:
              realm: sample-realm
              credentials:
                - user:password1
              enforce: true
```

#### IP制限を行う場合

IP制限の場合もBasic認証と同じように、 `traffic_policy` を追加します。
IP制限はIPv4、IPv6 のどちらにも対応しています。IPv6対応のネットワークの場合、IPv6のアドレスも忘れずに設定しましょう。

アクセスを許可するIPアドレスを `allow` に、 アクセス拒否するIPアドレスを `deny` に指定します。`allow` は必須ですが、 `deny` は省略可能なようです。

```yml
traffic_policy:
  on_http_request:
    - actions:
        - type: restrict-ips
          config:
            enforce: true
            allow:
              - 1.1.1.1/32
            deny:
              - e680:5791:be4c:5739:d959:7b94:6d54:d4b4/128
```

もちろん、Basic認証と併用することができます。
複数設定する場合、記述順に評価されます。Basic認証よりIP制限を先に設定しておくと良いでしょう。

```yml:ngrok.yml
# Version of the ngrok Agent Configuration file. Required.
version: 3

# Agent Configuration
agent:
  authtoken: *******************************************

# Endpoint Definitions
endpoints:
  - name: basic
    url: basic.ngrok.app
    upstream:
      url: http://localhost:8080
    traffic_policy:
      on_http_request:
        - actions:
          - type: restrict-ips
            config:
              enforce: true
              allow:
                - 1.1.1.1/32
              deny:
                - e680:5791:be4c:5739:d959:7b94:6d54:d4b4/128
          - type: basic-auth
            config:
              realm: sample-realm
              credentials:
                - user:password1
              enforce: true
```

## 終わりに

このように、ngrokを使うと簡単に外部アクセスできるようになります。簡単に公開できる分、設定には十分注意してください。

株式会社エーアイセキュリティラボ では、AeyeScan というSaaS型のWebアプリケーション脆弱性診断プラットフォームを開発しています。かんたんに高精度なWeb診断を実施することができることから、Webアプリ診断の内製化ツールとして多くの企業様にご活用いただいております。

AeyeScanの詳細はこちら: https://www.aeyescan.jp