Tech

SSL証明書の有効期限監視をLambdaで実装してChatworkに送信

Let's Encryptを使用したサービスを運用していて、


↑の記事のように自動更新の仕組みを入れていましたが、
証明書自体は更新されて新しいのができていたけど、Apacheのエラーでhttpdの再起動に失敗して、結果的に証明書の期限が切れるという悲劇が起きたので、
なんとかSSL/TLS証明書の期限を手っ取り早く監視する方法がないかと探して実装した際のログです。

Table of Contents

概要

以下2つの記事を参考にしました。これらをまとめたような内容です。

Cloudwatch Eventで1日1回イベントを発生
 ↓
Lambda関数を実行
 ↓
証明書の期限が15日を切っていたらChatworkに送信
という流れです。

手順

Lambda関数の作成

'use strict';

console.log('Loading function');

var request = require('request');
var _ = require('underscore');

exports.handler = (event, context, callback) => {
    var domains = [
        // ここに管理したいドメイン一覧を記入
        'example1.com',
        'example2.com',
        'example3.com'
    ];

    var checkSSLDate = function(domain) {
        console.log('exec cmd');
        return new Promise(function(resolve, reject) {
            var exec = require('child_process').exec;
            // execするコマンド
            var cmd = "openssl s_client -connect " + domain + ":443 < /dev/null 2> /dev/null | openssl x509 -text | grep Not | sed -e 's/^  *//g' | sed -e 's/Not.*:\ //g'";
            // 日付の差分を取得するために実行するときの日付が必要
            var today = new Date();

            exec(cmd, function(error, stdout, stderr) {
                if (!error) {
                    var results = stdout.split("\n");
                    // 期限期限のデータを取得
                    var date = new Date(results[1]);
                    // 日付の差分がミリ秒で取得できるので差分にする
                    var diffDays = Math.floor((date - today) / 1000 / 3600 / 24);
                    // chatworkに送るメッセージ
                    var message = '';
                    if (diffDays < 1) {
                        message = domain + 'の証明書期限が残り' + diffDays + '日です・・。';
                    } else if (diffDays < 3) {
                        message = domain + 'の証明書期限が残り' + diffDays + '日です!!デッドラインだよ!';
                    } else if (diffDays < 7) {
                        message = domain + 'の証明書期限が残り' + diffDays + '日です!早く対処してください。';
                    } else if (diffDays < 15) {
                        message = domain + 'の証明書期限が残り' + diffDays + '日です。更新を確認してください。';
                    } else if (diffDays == 30) {
                        message = domain + 'の証明書期限が残り30日です。';
                    }
                    return resolve(message);
                } else {
                    return reject('reject');
                }
            });
        });
    };

    _.each(domains, function(val, key) {
        checkSSLDate(val).then(function(message) {
            // chatwork用
            if (message !== '') {
                // chatwork側に飛ばす処理
                var roomId   = 'ここにChatworkのRoomID';
                var apiToken = 'ここにAPIToken';
                var options = {
                    url: 'https://api.chatwork.com/v2/rooms/' + roomId +'/messages',
                    headers: {
                        'X-ChatWorkToken': apiToken
                    },
                    form : {body : message},
                    useQuerystring: true
                };

                console.log('Sending message');

                request.post(options, function (err, res, body) {
                    if (!err && res.statusCode == 200) {
                        console.log('done');
                        context.done(null, body);
                    } else {
                        console.log('error');
                        context.done('error', err);
                    } 
                });
            }
        });
    });
};

Lambdaに登録するコードはこれだけです。
監視ドメイン一覧、ChatworkのRoomIDとAPITokenを変更してください。送信するメッセージも好きなように変えてください。

このコードだと、requestとunderscoreのmoduleを一緒に上げないといけないので、
https://ggeennooxx.com/wp-content/uploads/2019/06/node_modules.zip
楽をしたい人はこのzipをAWSにアップすれば、moduleと上記の内容のindex.jsがセットでアップされます。
※zipに変なものは入れてませんが、自己責任でお願いします。
ランタイムはNode.js 6.10で動作します。

Cloudwatch Event作成

頻繁にUI変わるし、キャプチャとかは載せません。

  1. Cloudwatchを開く
  2. イベント > ルール > ルールの作成
  3. イベントソースにスケジュールを選択
    1日1回(日本時間午前10時)の実行を想定
    cron式で以下を入力

    0 1 * * ? *
  4. ターゲットにLambda関数 > 先ほど登録した関数を選択
  5. 名前、説明を入力し、完了

おわりに

AWS STS(Security Token Service)にChatworkのトークン入れて、適切にアクセス権限つけて使いまわせるようにして・・
などということはこの記事では考えていません。
一番手っ取り早い構成にしています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

x  Powerful Protection for WordPress, from Shield Security
このサイトは
Shield Security によって保護されています →