SSL証明書有効期限を定期的に確認して有効期限が短い場合は通知を行う

# 概要
サーバー等に設定したSSL証明書の有効期限を定期的にチェックして有効期限が15日を下回った場合は通知します。

有効期限が近づくと証明書発行元から通知されたり、自動的に証明書更新する仕組みを実装することで期限切れを防ぎますが、それらで対応漏れがあった場合の補完的な機能です。

# 方法1:Shell定期実行
## 構成
証明書をチェックするShellをVMで定期実行します
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/3fb34a39-b636-861d-0f6c-3938f7b4918e.png">

## 準備
Oracle Cloud Infrastructure (OCI)内に以下を準備します
- Linux VM
- [Notifications](https://oracle-japan.github.io/ocitutorials/intermediates/monitoring-resources/#4-%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%A0%E3%81%AE%E9%80%9A%E7%9F%A5%E5%85%88%E3%81%AE%E4%BD%9C%E6%88%90)を利用して通知先設定
- VMからNotificationsを実行できるための[ポリシー](https://docs.oracle.com/ja-jp/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm)設定
  *Allow dynamic-group 【インスタンスを含む動的グループ】 to use ons-topics in compartment 【コンパートメント名】*

## Shell

```ssl-expire-alert.sh
#!/bin/bash

expire_date=`curl -v $1 3> /dev/null 2>&1  1>&3 | grep 'expire date:' | awk '{print $4, $5, $6, $7, $8}'`
expire_date_sec=`date +%s -d "$expire_date"`

today_sec=`date +%s`

expire_remain=$(((expire_date_sec-today_sec)/86400))

if [ "$expire_remain" -le 15 ]; then
    oci ons message publish \
    --auth instance_principal \
    --topic-id 【TOPIC OCID】 \
    --title "Certificate will expire in $expire_remain days" \
    --body " $1 certificate will expire in $expire_remain days. Please take action to renew the certificate."
fi
```

以下のように実行します
```
$ /bin/bash ssl-expire-alert.sh https://【HOST NAME】
```

有効期限が15日未満になると通知が行われます
*題名:Certificate will expire in 13 days
本文:【URL】certificate will expire in 13 days. Please take action to renew the certificate.*

実行が確認できたらcronはジョブ管理ルールに登録して定期実行します

# 方法2:OCI Functions定期実行
## 構成
証明書をチェックするShellをOCI Functionsで定期実行します
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/89004ad8-8b97-8351-7a4f-69db582ee9fd.png">

## 準備
Oracle Cloud Infrastructure (OCI)内に以下を準備します
- [OCI Functions](https://oracle-japan.github.io/ocitutorials/cloud-native/functions-for-beginners/#2-2-oracle-functions%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90) アプリケーション作成
- [Notifications](https://oracle-japan.github.io/ocitutorials/intermediates/monitoring-resources/#4-%E3%82%A2%E3%83%A9%E3%83%BC%E3%83%A0%E3%81%AE%E9%80%9A%E7%9F%A5%E5%85%88%E3%81%AE%E4%BD%9C%E6%88%90)を利用して通知先設定
- FunctionsからNotificationsを実行できるための[ポリシー](https://docs.oracle.com/ja-jp/iaas/Content/Identity/Tasks/callingservicesfrominstances.htm)設定
  *Allow dynamic-group 【インスタンスを含む動的グループ】 to use ons-topics in compartment 【コンパートメント名】*



## OCI Functions
```func.py
import io
import json
import logging
import oci
import ssl
import OpenSSL
import datetime

def handler(ctx, data: io.BytesIO = None):
    try:
        site = '【HOST NAME】'
        cert = ssl.get_server_certificate((site, 443))
        x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
        not_after  = datetime.datetime.strptime(str(x509.get_notAfter())[2:16],'%Y%m%d%H%M%S')  + datetime.timedelta(hours=9)
        print(not_after)
        expire_remain=not_after-datetime.datetime.now()
        expire_remain_days=expire_remain.days
        print(expire_remain_days)
        

        if expire_remain_days < 15:
            signer = oci.auth.signers.get_resource_principals_signer()
            ons_client = oci.ons.NotificationDataPlaneClient(config={},signer=signer,service_endpoint="https://notification.ap-tokyo-1.oci.oraclecloud.com")
    
            publish_message_response = ons_client.publish_message(
                topic_id="【TOPIC OCID】",
                message_details=oci.ons.models.MessageDetails(
                    title="Certificate will expire in" + str(expire_remain_days) +" days",
                    body =site +" certificate will expire in" + str(expire_remain_days) +" days. Please take action to renew the certificate.")
                )

    except Exception as e:
        print('ERROR: bad Event!', flush=True)
        raise
```

```func.yaml
schema_version: 20180708
name: ssl_expire_alert
version: 0.0.1
runtime: python
build_image: fnproject/python:3.11-dev
run_image: fnproject/python:3.11
entrypoint: /python/bin/fdk /function/func.py handler
memory: 256
```

```requirements.txt
fdk>=0.1.83
oci
```
デプロイして実行します
```
$ fn -v deploy --app fnapp
$ fn invoke fnapp ssl_expire_alert
```

有効期限が15日未満になると通知が行われます
*題名:Certificate will expire in 13 days
本文:【URL】certificate will expire in 13 days. Please take action to renew the certificate.*

実行が確認できたら[Resource scheduler](https://docs.oracle.com/ja-jp/iaas/Content/resource-scheduler/tasks/create-manage.htm#create-manage)でOCI Functionsを1日毎に実行できるよう設定します。
<img width="600" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730992/c902484f-4e07-e930-1c30-18c26bbfa2d7.png">