オンプレ環境で甘くなりがちなリバプロと開発サーバー間の通信も保護してみる

# オンプレ環境で甘くなりがちなリバプロと開発サーバー間の通信も保護してみる

## 挨拶

今年も AdventCalendar の季節がやってきました ㊗

今年も日立グループ からも元気に参加します！
OSSソリューションセンタ 神山 が先陣を切らせて頂きたく。

私はとある社内システムの設計、構築、運用、etc …ゆりかごから墓場まで面倒を見ています。最近はコンテナが大好物です。

社内システムの開発環境を検討している時に、セキュリティで悩んだことがあったので、その時の話から1つ書いてみます（今更オンプレ＆プライベート認証局かよ感ありますが・・・）

～事例やネットワーク構成等は例であり、実在の規則基準・インフラとは一切関係ありません～

## リバースプロキシを安全に

クラウドが当たり前なご時世ではありますが、諸般の事情でクラウドが使えず、昔ながらの物理・VMで社内に開発環境を構築するケースもあります。

VMを使って、シンプルに次のような構成を取ることがあります。

![玄関が厳重なのに、後ろががら空き](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316550/057c8d9d-a366-cd15-b2b3-f0a8682c70da.png)

この構成、リバースプロキシから後ろををしっかり保護してあげないと、開発サーバーが社内ネットワークのウィークポイントになってしまいます。例えば、リバースプロキシ側でしっかりアクセスできる人を認証してたのに、裏側の開発サーバーには認証なしでアクセスできたりといった事が発生しがちです。
随分と前ならファイアウォールで守られた境界内(社内ネットワーク)だから安全…と甘く見られがちでしたが、今時のセキュリティ基準では対策が必要になります。


ファイアウォール(iptables)の設定を頑張ったり、開発環境用のローカルネットワークを組んだりと保護する方法はいくつかありますが…これらは、取り回しが悪いので、今回はリバプロと開発サーバーの間を暗号化し相互に認証する形を考えてみます。

## 対策後のイメージ

![リバプロと開発サーバー間を暗号化・認証](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316550/64a241de-ab24-830a-b944-b0e62f6ef539.png)

認証局を立てて、サーバ証明書とクライアント証明書を発行、この証明書を使い、ロードバランサと開発サーバーを相互に認証させてみます。

開発物にクライアント認証を組み込むのは大変なので、開発サーバーの入口にさらにリバースプロキシのNginxを置く構成としています（ローカルな通信だけHTTP通信を許容）。

## 構築

今回は、`nginx 1.21.4`, `linux 5.14.16` にて検証しています。
しっかり設計すると考えることは多いですが、今回は最低限必要な設定をしていきます。

### プライベート認証局

プライベート認証局で、サーバ証明書やクライアント証明書を発行する方法については今回は割愛します。（ご参考に、コマンドでプライベート認証局を作るのが大変な場合は [XCA](https://hohnstaedt.de/xca/) が便利です。）

この後、次のファイルを使っていきます。
サーバ証明書やクライアント証明書は、プライベート認証局により署名しています。

|  対象  |  ファイル名  |
| ---- | ---- |
|  プライベート認証局-ルート証明書  |  ca.crt  |
|  サーバ証明書-証明書  |  server.pem |
|  サーバ証明書-秘密キー  |  server-key.pem |
|  クライアント証明書-証明書  |  client.pem |
|  クライアント証明書-秘密キー  |  client-key.pem |

今回はサーバ証明書とクライアント証明書をおなじ認証局で認証していきます。

### 開発サーバ側 nginx

開発サーバー側の ngixn を構築します。
証明書関連のファイルは `/etc/nginx/pki/`以下に配置したとして、`/etc/nginx/nginx.conf` もしくは `/etc/nginx/conf.d/something.conf` に次のように設定します。

```plain
...
http {
    ...
    server {
        ...
        listen       443 ssl;
        ssl_certificate /etc/nginx/pki/server.pem;
        ssl_certificate_key /etc/nginx/pki/server-key.pem;

        ssl_client_certificate "/etc/nginx/pki/ca.crt";
        ssl_verify_client on;
        ...
    }
    ...
}
```
`ssl_certificate`及び `ssl_certificate_key` はサーバ認証の設定となります。

`ssl_client_certificate` 及び `ssl_verify_client`がクライアント認証の設定になります。この設定をすることで、認証局が認証していないクライアントは接続できなくなります。

### ロードバランサー側 nginx

ロードバランサー側の nginx を構築します。
証明書関連のファイルは `/etc/nginx/pki/`以下に配置したとして、`/etc/nginx/nginx.conf` もしくは `/etc/nginx/conf.d/something.conf` に次のように設定します（この例では開発サーバーのIPを `192.168.10.100`としてます）

```plain
...
http {
    ...
    server {
        ...
        location / {
          ...
          proxy_pass https://192.168.10.100;
          proxy_ssl_certificate     /etc/nginx/pki/client.pem;
          proxy_ssl_certificate_key /etc/nginx/pki/client-key.pem;

          proxy_ssl_trusted_certificate /etc/nginx/pki/ca.crt;
          proxy_ssl_verify on;
          proxy_ssl_verify_depth 2;
          ...
        }
        ...
    }
    ...
}
```
`proxy_ssl_certificate`及び `proxy_ssl_certificate` はリバースプロキシ時に利用する認証書の設定となります。

nginx(少なくとも`1.21.4`時点)において、デフォルト設定はサーバ証明書の妥当性を確認しないようです。今回はサーバ証明書もしっかり検証するように設定(`proxy_ssl_verify`)しておきます。

サーバ証明書の妥当性を確認するためにプライベート認証局のルート証明書を参照する必要があります。nginxを動かしている環境にインストールしても良いのですが、nginxではproxy設定で用いる証明書を指定できるのでこちらで実施しています(`proxy_ssl_trusted_certificate`)。



## さいごに

今回は、VM間の通信を暗号化し、部外者が通信できないように証明書で通信相手を限るようにしました。セキュリティは大変ですが、転ばぬ先の杖ということで、意識していきたい所です。

※ 本当は実験なども行っているのでそこまで書きたかったのですが…社内ネットワークの色々な事情が垣間見えてしまうので、本稿では割愛しました。
気になる点などあれば、コメントください！