LoginSignup
15
18

More than 5 years have passed since last update.

AWS LambdaでSSL証明書を毎日自動チェックし、期限が迫ってきたら通知(ChatworkやSlack)する仕組み

Posted at

AWS LambdaでSSL証明書を毎日自動チェックし、期限が迫ってきたら通知(ChatworkやSlack)する仕組み

SSL証明書で失敗した経験はありますか?
自分は何度かあります。。

SSL証明書の終了期限を忘れており、気づいたら証明書の警告画面がでていたり、気づいたらギリギリで証明書申請に間に合わないかったり等色々ありました。

証明書終了期限ギリギリになると、ベンダーさんからメール来ますが、メールだと埋もれて気づけない・・

そこで、毎日自動チェックして、毎日使うChatツールに通知する方法を導入しました。

また、最近だとLet's Encryptを使用しているサイトもあるので、証明書の期限が来るのが早いです。(90日しかないです)

構築構想

AWS LambdaにCloudWatch Events - Schedule というものがあるので、CronみたいにLambdaを指定して自動実行ができます。
これをベースに、Lambdaに各指定したドメインの証明書の期限を調べさせて期限が迫っているものに関してはChatツールに流す仕組みを考えました。

no1.png

キーワード一覧

  • AWS Lambda
    • Node.js4.3
    • CloudWatch Events - Schedule
  • ChatツールAPI
    • ChatworkかSlack(今回はChatwork)
  • openSSLコマンド

実装

Lambdaは直接ソースコードを書けますが、今回はライブラリを使用するので、Zip圧縮してアップロードする形でやっていこうと思います。
なので、ローカル環境に一旦Node.jsを書ける環境を作りましょう。

Node.jsを書ける環境構築は割愛

$ mkdir project
$ cd project
$ npm init
$ npm install request
$ npm install underscore

必要なライブラリをnpmでインストールしていきます。

index.jsを作成してindex.jsを下記のソースにする。

'use strict';

console.log('Loading function');

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

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

    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   = process.env.ROOM_ID;
                var apiToken = process.env.API_TOKEN;
                var options = {
                    url: 'https://api.chatwork.com/v1/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上でしていきます。
※ 今回はChatworkAPIを利用しているので、Chawork用に書いてます

ROOM_ID 1111111
apiToken hogehogehoge

実際にテストを叩いてみます。

START RequestId: 76c2b6f9-e134-11e6-a3e1-fbf07a26df51 Version: $LATEST
2017-01-23T06:23:32.940Z    76c2b6f9-e134-11e6-a3e1-fbf07a26df51    exec cmd
2017-01-23T06:23:32.948Z    76c2b6f9-e134-11e6-a3e1-fbf07a26df51    exec cmd
END RequestId: 76c2b6f9-e134-11e6-a3e1-fbf07a26df51
REPORT RequestId: 76c2b6f9-e134-11e6-a3e1-fbf07a26df51  Duration: 2110.19 ms    Billed Duration: 2200 ms Memory Size: 512 MB    Max Memory Used: 71 MB

上記ログが確認でき、きちんと動いていることが確認できました。

ちなみに、Chatworkではこんな感じで通知が来ます。

スクリーンショット 2017-01-23 19.19.08.png

では次にScheduleの設定をしてきます。

Scheduleは1日毎に通知するようにしていきます。

スクリーンショット 2017-01-23 19.24.07.png

こうすることで、毎日通知が自動で来るようになります。

まとめ

これをLambdaでいれておけば、SSL証明書をきちんと普段使うChatツールに通知することができます。
メールよりも気づく確率が高くなり、全員が意識してSSL証明書の更新期限を気にすることができます。

15
18
2

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
15
18