LoginSignup
8
3

More than 1 year has passed since last update.

AWS lambda(Node.js)でオレオレ証明書(self-signed)を一時的に信頼してSSL通信を行う方法

Last updated at Posted at 2020-04-16

はじめに

AWS lambdaのNode.js(https標準モジュール)で実装した、WEBサイトへhttpsのリクエストを投げる処理で、以下の2つのエラーが発生した際の対応についての記事です。
※急いでいる方、ソースコードだけ見たい方はここから見ればOKです

スクリーンショット 2020-04-16 22.24.09.png
スクリーンショット 2020-04-16 18.31.17.png

これ何

調べたところ、リクエスト先のWEBサーバから送出されているサーバ証明書に対してのnodejs内部での検証失敗のため生じたエラーでした。
2つのエラーの違いは、
* 自分自身が署名(オレオレ証明書(self-signed))
* サーバ証明書の発行元が信頼されていないか
👉2つのエラーは共に、Node.jsとして信頼1していないCA証明書にチェーンしていたため生じていました。

環境

  • AWS lambda
  • Node.js ランタイム12.x
  • 接続イメージ [AWS lambda]-->(WAN HTTP over SSL)-->[WEBサーバ]

対処案

3つ考えましたが、妥協点で私の環境では3つ目で実装しましたので以下にまとめます。

1.WEBサーバ側にちゃんとしたサーバ証明書2に変更してもらう

この対応ができたらこんな記事はいらない気もする。
自局署名の問題については、ネット上でも従前から議論されおり3、本記事をご覧になっている方でも既知のことと思います。WEBサーバ管理者に対しては、セキュリティの観点で懸念点を伝えてさしあげる程度にしました。

2.TLSハンドシェイクエラーを無視・無効にする

NODE_TLS_REJECT_UNAUTHORIZEDを環境変数に定義し、値を0とすれば検証自体がdisableになる模様。これは、curlでいうところの--insecureオプションと類似していますが、検証を全て無視するため有効期限やトラストアンカーとのチェーン等々を丸っとすっ飛ばす模様。(詳細は未検証のため割愛)
https://nodejs.org/api/cli.html#cli_node_tls_reject_unauthorized_value

3.オレオレ証明書(self-signed)を一時的に信頼する

公式ドキュメントに書いてありました。
https://nodejs.org/api/tls.html#tls_tls_connect_options_callback
具体的には、通信先のWEBサーバのオレオレ証明書(サーバ証明書自体)ないしは、サーバ証明書のissuerとなっている現状信頼されていない自局CA証明書(pem形式)を取得し、https.requestのoptionにcaを追加するというものです。以下にサンプルを用いて実装例を示しています。

※今回の実装ではpemファイルの読み込みを、諸般の事情によりlambdaのみで完結したかったため、環境変数に事前に設定して、そこから読み込ませるという方法を使っています。(S3に入れて読み込むという方法もありかと思います。)

3-1.pemファイルを1行化する

環境変数にpemを入れるため、改行を¥nに置換します。

[work@localhost]$ awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' cacert.pem
-----BEGIN CERTIFICATE-----\nAIIDQjCCAiHCEQCQzvg6BX4eF(中略)v2wk3xtME7i8Jb2aUQH9vFVYuXUN2\nUO+j8l1OA4p1ew0kCsit2HOn\n-----END CERTIFICATE-----\n [work@localhost]$

余談ですが、当初は、pem形式って改行まで含んで形式であるということを理解しておらず、改行を単純に削除して環境変数に入れていたためエラーが発生して、ここで地味に悩みました。ちなみに、pemの改行は、Windows形式(CR+LF)、Unix形式(LF)どちらで良い模様なのでCRを削除後に置換している。4

3-2.AWS lamda環境変数の設定

上コマンドで表示された内容を環境変数にCA_PEMとして保存します。
スクリーンショット 2020-04-16 14.43.23.png

3-3. 実際のスクリプト(sample)

const https = require('https');

//ここで環境変数からcacertにPEMを読み込んでいる
var cacert = process.env['CA_PEM'].replace(/\\n/g, '\n');

exports.handler = (event, context) => {
    //caを追加してcacertを設定
    const options = {
      protocol: 'https:',
      host: 'example.com',
      path: '/index.html',
      port: 443,
      method: 'GET',
      timeout: 8000,
      ca: cacert,
      headers: {
        'User-Agent': 'AWS-lambda',
      }
    };

    let req =  https.request(options, (res) => {
      res.setEncoding('utf8');
      let body = '';
      res.on('data', (chunk) => {
        body += chunk;
      });
      res.on('end', () => {
        console.log(body);
      });
    });
    req.end();
}

3-4. エラー解消。取れました

Response:
null

Request ID:
"XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

Function Logs:
START RequestId: XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX Version: $LATEST
2020-04-16T14:26:29.930Z    XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX INFO
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Hello</title>
</head>
<body>
    This is test page ;>
</body>
</html>

END RequestId: XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
REPORT RequestId: XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
Duration: 210.24 ms Billed Duration: 300 ms Memory Size: 128 MB Max Memory Used: 68 MB  

  1. Node.jsのSSL通信時のトラストアンカーってなんだろ?と思い調べた。https://github.com/nodejs/node/blob/bf7409e9740ce602b09e088aac70b7c817f5d27c/doc/guides/maintaining-root-certs.md 読んでみると、このソースに書いてあるよとのこと。Mozilla NSSのトラストアンカーと合わせているみたいですね、定期的にメンテはされている模様。ここに自己署名をここに入れるのは影響が大きそうです。 

  2. Node.jsのトラストアンカー1に含まれるCAに直接または間接的に署名されているサーバ証明書のこと。 

  3. Qiitaですと、こちらの記事がとても参考になりました。オレオレ証明書を使いたがる人を例を用いて説得する 

  4. 出典:https://stackoverflow.com/questions/57870914/how-to-create-a-single-line-x509-certificate-that-can-be-parsed-by-openssl-comma 

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3