
[!] この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
クラウドと事業所のネットワークを VPN で接続してイントラネットを拡張する場合、VPN の状態をモニタリングして障害時に通知する仕組みも求められます。通知先がメールアドレスや Slack 等のチャットサービスであれば、クラウドサービスの標準的な機能で実現できそうです。しかし、VPN 障害の通知先をオンプレミスのチャットサーバーにしたい場合、当該 VPN を通知経路として使えないので、他の経路で迂回して通知させる必要があります。
ここでは、Oracle Cloud Infrastructure(OCI)とオンプレミス間の VPN 障害を Oracle Functions と Amazon API Gateway を使用して、別にオンプレミスと VPN 接続している AWS 経由でオンプレミスのチャットサーバーへ通知する仕組みを紹介します。
全体の構成
以下のような構成で、OCI とオンプレミスの間に構築している VPN 接続を監視し、問題が発生した際に通知を行う仕組みを整備しました。
VPN の監視には、OCI のサービスである Monitoring を使用し、Alarming、Notifications と連携することで通知を行うように設定しました。
- Monitoring
- メトリック・ネームスペースで「oci_vpn」を選択することで VPN の状態を監視できる。
- メトリック・ネームスペースを選択すると複数のメトリックの状態がグラフ化される。
- Alarming
- 選択したメトリックに閾値と条件を設定し、条件を満たした場合にアラームが起動する。
- アラーム起動時に「宛先」で設定した Notifications のトピックを呼び出す。
- Notifications
- トピックが呼び出されたとき、サブスクリプションに設定されているアクションを実行する。
前述の通り、通知経路として障害の発生した VPN を使用することはできません。そのため、Oracle Functions から AWS の Amazon API Gateway でデプロイした API へ POST リクエストを送り、AWS とオンプレミス間に構築している VPN 接続を経由してオンプレミスのチャットサーバーへ通知する構成にしました。
Amazon API Gateway の仕様上、API をデプロイしたら誰でも利用可能となってしまうため、Lambda 関数で認証情報を判別する Lambda オーソライザーによって API の利用を制限しています。Notifications のサブスクリプションから直接 Amazon API Gateway の API を呼び出すこともできますが、設定できる項目が少なく Lambda オーソライザーで使用する認証情報を付け加えることができなかったため、サブスクリプションに Oracle Functions の関数を設定しました。
通知の流れ
- OCI Monitoring で VPN の状態を監視
- メトリックの数値に異常があった場合 OCI Alarming のアラームが起動
- アラームから OCI Notifcations のトピックが呼び出され、サブスクリプションに設定された Oracle Functions 関数アプリを実行
- 関数が Amazon API Gateway の API に POST リクエストを送信
- API が呼び出されたときに AWS Lambda のオーソライザー用の関数が起動し認証処理を実行
- 認証が通った場合、オンプレミスのチャットサーバーに通知を行う関数を起動し、通知を送信
Oracle Functions で VPN 障害情報を渡す
Oracle Functions は、OCI で使える FaaS(Function as a Service)プラットフォームです。AWS Lambda などと違い、コンテナ環境を準備する必要があります。環境構築の詳しい手順については、OCI のチュートリアル ⧉があります。
環境構築が終了した後、関数を動かすまでの手順は、以下の通りです。
- アプリケーションの作成
- ログの設定
- 関数の作成・デプロイ
アプリケーションの作成とログの設定
「OCI コンソール画面のハンバーガーメニュー > 開発者サービス > ファンクション > アプリケーションの作成」からアプリケーションを作成します。作成した関数はこのアプリケーション上でデプロイすることになります。
Oracle Functions のメトリック画面は、「ファンクションが呼ばれたか」「どれくらいの処理時間だったか」「エラーだったか」のみ記載されており、それ以上の情報を得られません。エラーの詳細などを得るためには、Logging サービスで Functions のサービス・ログを有効化する必要があります。
関数の作成・デプロイ
環境構築で作成した、Fn Project を稼働させているインスタンスへ接続し、ランタイム言語と関数名を指定して fn init
コマンドを実行すると関数が作成されます。今回は Python を使用しました。
$ fn init --runtime python {作成する関数名}
コマンドを実行すると、指定した関数名のディレクトリが作成され、その配下にある func.py
へコードを書き込むことで関数を編集できます。
関数呼び出し時に受け取った情報(アラームの情報)は data.getvalue()
で JSON 形式で取得できます。そのため、以下のようにすることで、アラームの情報を body
とした POST リクエストを行うことができます。Amazon API Gateway や、ヘッダーで設定している Lambda オーソライザーの認証情報については次項で説明します。
import ioimport jsonfrom fdk import responseimport urllib.request
def handler(ctx, data: io.BytesIO = None):
url = 'Amazon API Gateway で作成した API の POST メソッドを呼び出す url'
# ヘッダーで Lambda オーソライザーの認証情報を追加 header={ 'Content-Type': 'application/json', '{Amazon API Gateway で設定した認証トークン}': '{Amazon API Gateway で設定した正しい値}' }
# 受け取ったイベントを body にして POST リクエスト request = urllib.request.Request(url, json.dumps(json.loads(data.getvalue())).encode(), headers=header) urllib.request.urlopen(request)
関数の作成後、作成された関数名のディレクトリへ移動し fn deploy --app {作成したアプリケーション名}
を実行することでデプロイできます。デプロイ後は OCI のコンソール画面から「アプリケーションの詳細」を確認することで関数のメトリック等が確認できます。
Amazon API Gatewayで認証をかける
Amazon API Gateway とは、API の作成、公開、管理、モニタリング、保護を実現するマネージドサービスです。仕様上、API をデプロイするとインターネット側に公開されるため、そのままでは誰でもアクセスできてしまいます。AWS Black Belt Online Seminar 2019 Amazon API Gateway ⧉ では、認証を行う方法として以下の3つが紹介されており、今回は Lambda オーソライザーを採用しました。
- IAM アクセス権限
- API クライアントが認証対象の IAM ユーザーのアクセスキー等から⽣成した AWS 署名 v4 を送信することを要求する⽅式
- Lambda オーソライザー
- 所定の⼊出⼒仕様を満たすよう実装された Lamda 関数を⽤いる⽅式(リクエストデータを元に認証し、認証結果として IAM ポリシー JSON を返す)
- Cognito オーソライザー
- Amazon Cognito ユーザープールで認証し、取得したトークンを HTTP ヘッダーに指定して API に渡すことを要求する⽅式
Lambda オーソライザー
認証処理を委譲する Lambda 関数を指定して API へのアクセスを制御します。認証成功時にプリンシパル ID とバックエンドの実行を許可するポリシーを返す仕様となっており、独⾃の認証⽅式や OAuth などの認証⽅式を組み込む⽅法として利⽤されます。
Lambda オーソライザーを設定することにより API に対するリクエストのヘッダーを読み取り、設定した認証トークンと正しい値があるときのみバックエンド(今回はオンプレミスのチャットサーバーへ通知を行う関数)を実行するようになります。認証処理を行う Lambda 関数の詳細は、公式ドキュメント ⧉に記載されています。
まとめ
「OCI とオンプレミス間の VPN 障害時に、オンプレミスのチャットサーバーへ通知する仕組み」について紹介しました。オンプレミスのチャットサーバーで通知を受け取りたい要件のために、いささか複雑な構成となりました。ちなみに、通知手段がメールで構わなければ、Notifications にメールアドレスを設定するだけです。Slack 等のチャットサービスへ通知する場合は、Oracle Functions から API を叩けばいけそうです。
OCI に限らず、クラウドとのネットワーク接続を監視して、障害時に他の経路でオンプレミスに通知したいケースはあるかもしれません。今回紹介した仕組みを洗練し、汎用的なパターンが確立できると面白そうです。