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

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

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

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

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

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

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

## 構築構想

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

![no1.png](https://qiita-image-store.s3.amazonaws.com/0/52154/fdef37fe-41ee-83b8-1412-35035506c9fc.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を下記のソースにする。

```javascript
'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](https://qiita-image-store.s3.amazonaws.com/0/52154/674ec433-f6fc-c04e-ce9b-7307d8bd5c9c.png)

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

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

![スクリーンショット 2017-01-23 19.24.07.png](https://qiita-image-store.s3.amazonaws.com/0/52154/73e08b65-cb62-9013-aa82-50778753f0d4.png)

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

## まとめ

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