相互 TLS 認証

Dialogflow が Webhook リクエストに対して開始するネットワーク トラフィックは、パブリック ネットワークで送信されます。両方向のトラフィックの安全性と信頼性を確保するため、Dialogflow は相互 TLS 認証(mTLS)をオプションでサポートします。mTLS では、クライアント(Dialogflow)とサーバー(Webhook サーバー)の両方が TLS handshake の間に証明書を提示し、相互に ID を証明します。

mTLS のリクエスト

mTLS をリクエストするには:

  1. Webhook HTTPS サーバーが TLS handshake 中にクライアント証明書をリクエストするように、準備をします。
  2. Webhook サーバーは、クライアント証明書の受信時に、この証明書を検証する必要があります。
  3. クライアントとサーバーの両方で相互に信頼できる Webhook サーバーの証明書チェーンをインストールします。Google Trust Services CA 1O1(GTS CA 1O1)を使用する必要があります。GTS CA 1O1 は、Google Trust Services が所有および管理する GlobalSign R2 ルート(GS Root R2)を使用します。これは、https://pki.goog/ からダウンロードできます。

デモ用 Node.js サーバー

Node.js デモサーバーの例を示します。

  1. 自己署名証明書と pem ファイルを準備します。
  2. 証明書チェーン ファイルを準備します。
    curl https://pki.goog/gsr2/GTS1O1.crt | openssl x509 -inform der >> ca-crt.pem
    curl https://pki.goog/gsr2/GSR2.crt | openssl x509 -inform der >> ca-crt.pem
        
  3. 次のサンプルを server.js として保存します。
    var https = require('https');
    const express = require('express')
    var fs = require('fs');
    var options = {
      // Specify the key file for the server
      key: fs.readFileSync('./server-key.pem'),
      // Specify the certificate file
      cert: fs.readFileSync('./server-crt.pem'),
      // Specify the Certificate Authority certificate
      ca: fs.readFileSync('./ca-crt.pem'),
      // Requesting the client to provide a certificate, to authenticate the user.
      requestCert: true,
      // As specified as "true", so no unauthenticated traffic
      // will make it to the specified route specified
      rejectUnauthorized: false
    };
    
    var app = express();
    app.use(function (req, res, next) {
      if (!req.client.authorized) {
        //return res.status(401).send('Client cert failed. User is not authorized\n');
      }
      // Examine the cert itself, and even validate based on that!
      var cert = req.socket.getPeerCertificate();
      if (cert.subject) {
        console.log('Client Certificate: ',cert);
        console.log('Client Certificate Common Name: '+cert.subject.CN);
        console.log('Client Certificate Location: '+cert.subject.L);
        console.log('Client Certificate Organization Name: '+cert.subject.O);
        console.log('Client Certificate Email Address: '+cert.subject.emailAddress);
      }
    
      res.writeHead(200, {'Content-Type': 'text/plain'});
      res.end("hello world from client cert\n");
      next();
    });
    var listener = https.createServer(options, app).listen(4433, function () {
      console.log('Express HTTPS server listening on port ' + listener.address().port);
    });
         
  4. server.js を実行します。
  5. requestCert を true に設定します。
    curl https://127.0.0.1:4433 -k
        
  6. クライアント証明書を送信します。SSL handshake が完了しました。
    curl -v -s -k --key client-key.pem --cert client-crt.pem https://localhost:4433
    openssl s_client -key client-key.pem -cert client-crt.pem -connect localhost:4433 -CAfile ca-crt.pem
        

エラー

クライアント証明書が失敗した場合(たとえば、クライアント証明書がクライアントから送信されなかった場合や、クライアント証明書が正しく署名されていない場合など)、TLS handshake は失敗し、セッションは終了します。

一般的なエラー メッセージ:

エラー メッセージ 説明
Failed to verify client's certificate: x509: certificate signed by unknown authority(クライアントの証明書を検証できませんでした: x509: 不明な権限で署名された証明書) Dialogflow はクライアント証明書を外部 Webhook に送信しましたが、外部 Webhook で検証できませんでした。外部 Webhook で CA チェーンが正しくインストールされなかったことが原因として考えられます。Dialogflow の現在の CA は Google Trust Services CA 1O1 です。GTS CA 1O1 は、Google Trust Services が所有および管理する GlobalSign R2 ルートを使用します。