API Gatewayからバックエンドまで、自己署名証明書で構成されててもエンドツーエンドなSSL構成を取る方法

2021.11.22

いわさです。

前回はパブリックなREST API GatewayからプライベートネットワークのEC2ウェブサーバーに対してエンドツーエンドなHTTPS通信をしてみました。

その際、ウェブサーバーが自己署名証明書を利用していたためにAPI Gatewayのバックエンドに指定することが出来ませんでした。
前回はパブリックな証明書に変更して通信させることが出来ましたが、自己署名証明書を回避できない場合、どういう対応をAWS側で取ることが出来るか検証してみました。

先にまとめ

以下のどちらかの方法で実現が出来ます。

  • ACM+LBをプライベートネットワークの前段において多段SSLにする
  • API GatewayのSwagger+API Gateway拡張をつかって、エンドポイントの証明書の検証をスキップするように設定

順に紹介していきます。

多段SSL

API Gatewayから自己照明証明書で通信は出来ませんが、ALBのターゲットに自己署名証明書なウェブサーバーを紐付けることが出来ます。
ALBで一度ターミネートしたあとに、再度暗号してまたバックエンドに対して通信する方法です。
なお、ダメ元で自己署名証明書をACMへインポートし、それを使った検証も行っておきたいとおもいます。

ちなみに、NLBもTLS終端出来るのですが、せっかくなので今回試してみればよかったです。
NLBにACMあてて、ターゲット通信をTLSにすればエンドツーエンド構成取れるみたいです。

ちなみに、ターゲットグループで別ネットワークを指定する場合、ターゲットはプライベートIPアドレスでのみ指定可能です。
今回EC2のCNにはプライベートIPアドレスを指定してみました。

sh-4.2$ sudo openssl genrsa -out ca.key 2048
Generating RSA private key, 2048 bit long modulus
............................................+++
............................+++
e is 65537 (0x10001)
sh-4.2$ sudo openssl req -new -key ca.key -out ca.csr -subj "/C=JP/ST=Hokkaido/L=Sapporo/O=Hoge/OU=Piyo/CN=10.103.10.95"
sh-4.2$ sudo openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
Signature ok
subject=/C=JP/ST=Hokkaido/L=Sapporo/O=Hoge/OU=Piyo/CN=10.103.10.95
Getting Private key
sh-4.2$

443でヘルスチェックが通ってればOKです。

ACMに自己署名証明書をインポート

以下の記事が本当に凄くて。
今後度々お世話になりそうです。

スクリプト一発でACMに自己照明証明書をインポートしてくれます。

sh-4.2$ sudo sh create_ca.sh
ドメイン名を入力してください:myca.test.com
myca.test.com
mkdir: cannot create directory ‘/home/ec2-user/certdir/’: File exists
Generating RSA private key, 2048 bit long modulus
..........................................+++
.................................+++
e is 65537 (0x10001)
Generating RSA private key, 2048 bit long modulus
.+++
..+++
e is 65537 (0x10001)
Signature ok
subject=/C=JP/ST=Osaka/O=mycorp./CN=testCN
Getting CA Private Key
Generating RSA private key, 2048 bit long modulus
..............................................................+++
........+++
e is 65537 (0x10001)
Signature ok
subject=/C=JP/ST=Osaka/O=mycorp./CN=myca.test.com
Getting CA Private Key
{
    "CertificateArn": "arn:aws:acm:ap-northeast-1:123456789012:certificate/79774090-8c36-47b0-aa72-4968b8fc9752"
}
sh-4.2$

これだけ!本当にすごい。

プライベートホストゾーンを作成し、NLBのエイリアスレコードを登録してAPI GatewayのHTTPSエンドポイントとして指定してみましょう。

Sun Nov 21 22:24:53 UTC 2021 : Sending request to https://myca.test.com/
Sun Nov 21 22:24:58 UTC 2021 : Execution failed due to configuration error: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Sun Nov 21 22:24:58 UTC 2021 : Method completed with status: 500

ダメでした。
ACMにインポートしようと、API Gatewayさんは自己署名証明書は許しちゃくれない。

ACMでパブリック証明書を発行

前回の記事で確認しているように、パブリック証明書であればもちろん通信が出来ます。

証明書の検証をスキップ

前回の記事で、

信頼、あるいは無視する設定が必要なのですが、API Gatewayでは用意されていませんので別の方法を考える必要があります。

なんて言ったのですが、パラメータがありました、スミマセン。

x-amazon-apigateway-integration.tlsConfigを使うことでエンドポイントに対するAPI Gatewayによる証明書をスキップ出来ます。

REST API でのみサポートされます。サポートされている認証機関から統合エンドポイントの証明書が発行されているかどうかの検証を API Gateway がスキップするかどうかを指定します。これはお勧めしませんが、プライベート認証機関によって署名された証明書、または自己署名された証明書を使用できます。有効にした場合でも、API Gateway は証明書の基本的な検証を実行します。これには、証明書の有効期限、ホスト名、ルート認証機関の存在の確認が含まれます。HTTP および HTTP_PROXY 統合でのみサポートされます。

推奨はされていませんが、プライベートCAや自己署名証明書のときに使うことが出来るパラメータです。
REST API Gatewayでのみ利用可能です。

設定にはSwaggerからのAPI Gateway拡張をインポートする必要があります。
ステージのエクスポートタブからSwagger+API Gateway拡張をダウンロードしておきます。

拡張パラメータを追加します。

{
  "swagger": "2.0",
  "info": {
    "version": "2021-11-22T00:48:02Z",
    "title": "hogeapi"
  },
  "host": "k43h2sfu7i.execute-api.ap-northeast-1.amazonaws.com",
  "basePath": "/iwasa1",
  "schemes": [
    "https"
  ],
  "paths": {
    "/": {
      "get": {
        "produces": [
          "application/json"
        ],
        "responses": {
          "200": {
            "description": "200 response",
            "schema": {
              "$ref": "#/definitions/Empty"
            }
          }
        },
        "x-amazon-apigateway-integration": {
          "type": "http_proxy",
          "connectionId": "g1ke1w",
          "httpMethod": "GET",
          "uri": "https://myca.test.com/",
          "responses": {
            "default": {
              "statusCode": "200"
            }
          },
          "passthroughBehavior": "when_no_match",
          "tlsConfig": {
            "insecureSkipVerification": true
          },
          "connectionType": "VPC_LINK"
        }
      }
    }
  },
  "definitions": {
    "Empty": {
      "type": "object",
      "title": "Empty Schema"
    }
  }
}

修正したドキュメントをリソースのAPIインポート機能を使ってインポートします。

バックエンドをTCP443なNLB->(HTTPS)->オレオレEC2 でテスト実行してみます。

信頼できない証明書に起因するExceptionが発生しなくなり、SSL通信が出来るようになりました!

さいごに

本日は、自己署名証明書なプライベートWebサーバーをAPI GatewayのバックエンドにしてエンドツーエンドHTTPSを実現するための方法を2つご紹介しました。
何らかの理由でパブリックな証明書が発行出来ない場合は、後者の方法を取ると良いですね。

SSL検証のスキップ設定についてはマネジメントコンソール上に設定項目はなく、APIドキュメントのアップロードでのみ反映出来る設定値のようです。
今回Swagger+API Gateway拡張を使ったのですが、すごい数のパラメータが存在していました。
マネジメントコンソール上で設定出来無さそうな場合でも一旦目を通してみると解決策が見つかるかもしれません。