🚨

閉域環境のWebアプリケーションを CloudWatch Synthetics + Selenium で外形監視してみた

に公開

この記事は、ナウキャスト Advent Calendar 2025 の19日目の記事です。

1. はじめに

こんにちは。株式会社ナウキャストでデータエンジニアをしている加藤です。

今年1年を振り返ると昨年末から実装・構築していた金融系クライアント向けのWebアプリケーションが無事にローンチし、初期構築フェーズから運用フェーズに移行しました。
日々の運用を実行していく中で、Webアプリケーションが安定稼働する為の取り組みや監視・モニタリングもこなしてきました。
実際のユーザーがアクセスするのと同じ方法で監視する 外形監視 の仕組み作りもその一つでした。

そこで本記事では、閉域(イントラネット)環境にある Webアプリケーションに対して、
AWS CloudWatch Synthetics の Canary と Python + Selenium を使って「外形監視」を実装した事例を紹介します。

2. 前提となるシステム構成と制約

本記事で扱うのは、いわゆる「社内イントラ環境からしかアクセスできない閉域 Webアプリケーション」を対象とした外形監視です。
まずは、前提となるシステム構成と、運用上の制約について整理していきます。

2-1. 社内イントラ環境と AWS 環境の接続

対象となる Webアプリケーションは、クライアント企業の社内イントラ環境とは別の AWS アカウント上に構築されています。
AWS 側の環境はインターネットから直接はアクセスできない閉域構成になっており、イントラ環境からの通信のみが許可されています。
通信フローを詳細化すると以下の3段階のフローとなります。

  • クライアント企業の社内イントラ環境
  • 社内イントラから AWS Direct Connect を経由して自社 AWS 環境へ接続
  • Direct Connect の先にある Transit Gateway を経由し、対象 VPC へルーティング

このため、社内イントラと AWS 間の通信は、基本的にクライアントネットワーク経由の専用線ルートに限定されています。
また、AWS 上の Webアプリケーションは、典型的なロードバランサ+コンテナ構成になっており、以下の通信フローとなっています。

  • VPC 内に配置された Network Load Balancer (NLB)
  • NLB から Application Load Balancer (ALB) へ振り分け
  • ALB の背後に、アプリケーションサーバーとしての ECS コンテナ

最後に、社内ユーザーがブラウザからアクセスする際の経路も整理しておきます。

  1. ユーザーのブラウザは、クライアント社内イントラ環境にある PC 上で動作
  2. 社内イントラの Private DNS を使って、アプリケーションの FQDN を名前解決
  3. 解決結果として得られたNLBのプライベート IP 宛てに、Direct Connect → Transit Gateway → VPC 内の NLB へアクセス
  4. NLB → ALB → ECS を経由し、最終的に Webアプリケーション画面が表示される

以上が、インターネットからのアクセスは想定していない 社内イントラからの閉域アクセスのみ を前提とした構成です。

2-2. 認証基盤:Amazon Cognito + Azure Entra ID による SSO

Webアプリケーションへのログインには、Amazon Cognito を認証基盤として採用し、クライアント企業が管理している Azure Entra ID(旧 Azure AD) を外部 IdP(Identity Provider)として SAML 連携 しています。

認証フローの概要

[ユーザー] → [Webアプリケーション] → [Amazon Cognito] ←SAML連携→ [Azure Entra ID]

構成のポイント

  • 認証基盤(Amazon Cognito): AWS 基盤側で Cognito ユーザープールを構築・管理
  • 外部 IdP(Azure Entra ID): クライアント側が管理し、SAML 認証で Cognito と連携
  • 対象アプリケーションは Entra ID 上にエンタープライズアプリケーションとして登録され、SSO 設定済み
  • 利用者は社内イントラ環境からブラウザでアクセスし、Entra ID のサインイン画面を経由してアプリケーションにログイン

今回の外形監視でも、ユーザーの認証経路と同じ Cognito + Entra ID ログインフローを通す ことを前提にしています。

2-3. 弊社側の運用・作業上の制約

この章の最後に本アプリケーションの開発・運用保守は弊社で担当していますが、実際のアクセスにはいくつか制約があることにも触れておきたいと思います。

  • サイト閲覧用 PC はクライアント貸与 PC
    • 弊社メンバーは、クライアント企業から貸与された PC にログインし、リモートデスクトップ上からサイトを確認する
  • クライアント貸与 PC ログインには事前申請と承認が必要
    • 利用前にクライアント側への申請と承認が必要
  • ログインパスワードは毎回ランダムに変更
    • 事前申請が承認されると、毎回ランダムな貸与 PC のログインパスワードが送付されてきて、そのパスワードでログイン

このため従来は、

事前申請・承認 → 貸与 PC にログイン → ブラウザでサイトにアクセス → Entra ID でログイン → 画面表示を目視確認

という手順を人手で行う必要があり、継続的にチェックを続けるには負荷と制約が大きい状況 になっていました。


3. 解決したかった課題

上記のような前提と制約のもとで、弊社には運用保守として次の役割が求められていました。

  • Webアプリケーションが正常に表示できることを確認する
  • Azure Entra ID を利用したログインが正常に完了することを確認する

しかし、これを毎日「貸与 PC にログインして、人がブラウザ操作する」前提で続けるのは現実的ではありませんでした。
そこで今回の取り組みでは、次のような課題の解決を目標にしました。

3-1. 人力・手動のログイン確認を自動化したい

まず一番の目的は、

  • 貸与 PC を利用して人力かつ手動で行っていた「Entra ID ログイン → サイト表示確認」を、できるだけ同じ粒度で自動化したい

という点です。

単なる URL の死活監視(HTTP ステータスが 200 かどうか)ではなく、
実際のユーザーと同じようにログインフローを通した上で画面が表示されるか を確認したい、という要求になります。

3-2. 監視で保証したい4つの動作

今回の外形監視では、特に次の 4 点を保証対象としました。

  1. Entra ID でのログインが成功すること

    • ログイン画面でユーザー名・パスワードを入力し、SSO フローを通ってアプリケーションに遷移できること
  2. ログイン後の TOP ページが表示されること

    • 単に HTML が返ってくるだけでなく、
      ログイン成功時にのみ表示される要素(メニューやタイトルなど)が表示されていること
  3. TOP ページから特定の詳細ページへ遷移できること

    • TOP ページに表示されるリンクから詳細ページに遷移し、
      想定した要素が表示されていること
  4. 特定 Backend エンドポイントに対して、HTTP ステータスコードが 200 番台で返ってきていること

    • 画面の見た目だけでなく バックエンド側の処理の正常性 も担保できていること

3-3. 異常時にはアラート通知を受け取りたい

もうひとつ重要な要件として、異常が発生したときに早期に気づけること があります。

  • ログインが失敗する
  • TOP ページが表示されない
  • 詳細ページ遷移に失敗する
  • Backend エンドポイントが 5xx,4xx やタイムアウトになる

といった状況が発生した場合には、CloudWatch アラームなどを通じて通知を飛ばし、
運用メンバーがすぐに調査・復旧に動けるようにしたい、というのが今回の要件です。

この「人力ログイン確認をやめたいが、確認している内容の粒度は落としたくない」というギャップを、
CloudWatch Synthetics と Python + Selenium の組み合わせでどう埋めたか、というのが以降の章のテーマになります。

4. 今回採用した解決方針の概要

ここまでで挙げた課題に対して、本記事で採用した解決方針はざっくり言うと

  • CloudWatch Synthetics の Canary を VPC 内で動かし、その中で Python + Selenium を使って、Entra ID ログイン〜画面表示〜一部 Backend のステータス確認までを一括でやる

というものです。

詳細なアーキテクチャやコードは 後ほど掘り下げるとして、ここでは全体像だけを整理しておきます。


4-1. 監視全体の構成イメージ

実現したかったのは、次のような「ユーザー視点に近い外形監視」です。

  1. 監視用の Canary が定期的に起動する
  2. 閉域 VPC 内から、対象 Webアプリケーションの URL へアクセスする
  3. Entra ID のログイン画面でユーザー名・パスワードを入力し、ログインする
  4. ログイン後の TOP ページが正常に表示されていることを確認する
  5. TOP ページから特定の詳細ページへ遷移できることを確認する
  6. Backendで呼ばれる特定のエンドポイントのステータスコードが 200 番台であることを確認する
  7. どこかで失敗したら Canary を失敗として扱い、CloudWatch アラーム経由で通知する

この 1〜7 の流れを ひとつの Canary スクリプトでまとめて実行する 方針にしました。


4-2. 外形監視の実行基盤:CloudWatch Synthetics Canary

外形監視の実行基盤としては、AWS のマネージドサービスである CloudWatch Synthetics を採用しました。

  • 定期実行のスケジューリングが可能
  • 成功 / 失敗のメトリクスがそのまま CloudWatch に載る
  • 失敗時のスクリーンショットやコンソールログが残る
  • Canary を VPC 内で実行 できる(閉域 Webアプリケーションにアクセスさせやすい)

といった点から、今回の「閉域 × Webアプリケーション × ログイン監視」と相性が良かったためです。

Canary 自体は Lambda ベースの実行環境なので、
あとの章で出てくる Python スクリプトをそのまま実行させることができます。


4-3. 画面操作の実装方式:Python + Selenium

画面操作の自動化には、CloudWatch Synthetics が用意している GUI ワークフローではなく、
Python + Selenium を使う方式を取っています。

  • JavaScript の DOM 操作に近い感覚で、以下のような処理が書きやすい
    • 入力欄に値を入れる
    • ボタンをクリックする
    • 特定の要素が表示されるまで待つ
  • Entra ID のログイン画面やアプリケーションの画面構造に合わせて、CSS セレクタを細かく調整しやすい
  • チームとして Python の方が読み書きしやすく、今後の保守も見据えて Python を選択

具体的には、事前に以下を調査してスクリプトに落とし込んでいます。

  • ログイン画面の入力欄やボタンの CSS セレクタ
    • ユーザー名入力欄
    • 次へボタン
    • パスワード入力欄
    • サインインボタン
  • ログイン成功後の TOP ページにだけ現れる要素(タイトルやメニュー)
  • TOP ページから詳細ページへのリンク要素

これらをもとに、「値を入力 → ボタンをクリック → 遷移先で要素の有無を確認」 という流れを Selenium で組んでいます。

5. Canary 実装前に準備した AWS リソース(事前設定)

CloudWatch Synthetics の Canary 自体はAWSコンソール上からすぐ作れますが、
事前にネットワークまわりを整えておかないと、Canary 作成後に通信が繋がらずエラーになってしまう ためです。

この章では、Canary の設定画面を触る前に準備した AWS リソース・設定をまとめます。


5-1. VPC / サブネット

今回の Canary は「インターネット側からではなく、閉域 VPC 内から」Webアプリケーションにアクセスさせる必要があります。
そのため、既存の Webアプリケーションと同じ VPC / サブネットをそのまま使う方針にしました。

  • 既存の Webアプリケーション用 VPC / プライベートサブネット を利用
  • Canary もこの VPC 内のプライベートサブネットで実行
  • インターネット(Entra ID)への出口は既存の NAT Gateway を利用

ポイントは、

  • Webアプリケーションに到達できるルート(VPC 内)
  • Entra ID 側に出ていけるルート(NAT)

の両方がそのサブネットに対して有効になっていることを確認しておくことです。


5-2. Security Group

Security Group は「Canary からどこに出ていけるか」「Webアプリケーション側で誰からのアクセスを受けるか」を決める部分なので、
Canary 作成前に形を決めておきました。

5-2-1. Synthetics Canary 用 Security Group(新規)

Canaryのために、新しく SG を 1 つ作成しました。

  • アウトバウンド
    • Webアプリケーション用 NLB 宛て を許可
      • タイプ:HTTPS
      • プロトコル:TCP
      • ポート範囲:443
      • 送信先:NLBのSecurity Groupを指定
    • Entra ID など外部エンドポイントへの 接続 を許可
      • タイプ:HTTPS
      • プロトコル:TCP
      • ポート範囲:443
      • 送信先:0.0.0.0/0を指定
  • インバウンド
    • Canary は「自分から出ていく」だけなので、特に開放せずデフォルトのまま

5-2-2. NLB 側 Security Group

Webアプリケーション入口の NLB にアタッチされている Security Group 側にも、Canary からのアクセスを許可するルールを足しました。

  • インバウンド
    • タイプ:HTTPS
    • プロトコル:TCP
    • ポート範囲:443
    • ソース:Synthetics Canary 用 Security Group を指定

これで、

  • 社内イントラ環境からアクセスユーザー
  • Canary(監視)

の両方が、同じ NLB を通ってアプリケーションに到達できるようになります。

5-2-3. 番外編 外形監視用のEntra IDアカウント

今回、外形監視の自動化にあたり、特別にログインID・パスワードが動的に変わらない外形監視専用のアカウントをクライアント側に準備いただきました。

6. ログイン監視スクリプトの実装(Python + Selenium)

この章では、実装しているシナリオを次の 5 つに分けて説明します。

  1. WebDriver のセットアップ
  2. Entra ID ログイン
  3. 画面表示確認(TOPページ → 詳細ページ)
  4. 複数 Backend API エンドポイントのステータス確認
  5. 最後にスクリーンショットと DOM を必ず取得

6-1. WebDriver のセットアップ

CloudWatch Synthetics 付属の synthetics_webdriver を使って、ヘッドレス Chrome を起動しています。
あわせて、明示的な待機用に WebDriverWait を用意しています。

例:

logger.info("Step 2: Setting up WebDriver...")
options = ChromeOptions()
options.set_capability('goog:loggingPrefs', {'performance': 'ALL'})

driver = syn_webdriver.Chrome(chrome_options=options)
wait = WebDriverWait(driver, 30)  # 最大30秒待機

この driver / wait を、以降のログイン・画面確認・API 呼び出しで共通利用しています。


6-2. Entra ID ログイン

アプリケーションの URL にアクセスすると Entra ID のログインページにリダイレクトされる前提で、

  • ユーザー名入力
  • パスワード入力
  • フォーカス外し(サインインボタン有効化)
  • 「サインイン状態を維持しますか?」ダイアログ対応
  • ログイン後 TOP(録音一覧)までの遷移

を自動化しています。

処理の流れは次の通りです。

  1. 対象 URL にアクセス
  2. ユーザー名入力欄 に ユーザー名 を入力 → 「次へ」ボタン をクリック
  3. パスワード入力欄 にパスワードを入力
  4. サインインボタンを活性化させる為、タイトルや <body> をクリックしてフォーカスを外し、JS 側の検証を完了させる
  5. 「サインイン」ボタン を JavaScript 経由でクリック
  6. 「サインイン状態を維持しますか?」ダイアログが出た場合のみ「はい」ボタンをクリック(最大 10 秒待機)
  7. ログイン後の画面で、<h1> に「XXX一覧」というテキストを含む要素が現れるまで待機

サンプル(イメージ):

logger.info("Step 3: Starting Azure Entra ID login...")
# 対象 URL にアクセスします
driver.get(URL)
time.sleep(5)

# ユーザー名を入力します
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "{ユーザー名入力欄のID属性}"))).send_keys(USERNAME)
# 「次へ」ボタンをクリックします
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "{「次へ」ボタンのID属性}"))).click()
time.sleep(5)

# パスワードを入力します
password_field = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "{パスワード入力欄のID属性}")))
password_field.send_keys(PASSWORD)

try:
    # サインインボタンを活性化させる為、タイトル や `<body>` をクリックしてフォーカスを外します
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "{タイトルのID属性}"))).click()
except Exception:
    driver.find_element(By.TAG_NAME, "body").click()

time.sleep(5)

# サインインボタンをクリックします
sign_in_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "{「サインイン」ボタンのID属性}")))
driver.execute_script("arguments[0].click();", sign_in_button)

try:
    # 「サインイン状態を維持しますか?」ダイアログが出た場合のみ「はい」ボタンをクリックします
    yes_button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, "{「はい」ボタンのID属性}"))
    )
    yes_button.click()
except Exception:
    pass

# ログイン後の画面で、`<h1>` に「XXX一覧」というテキストを含む要素が現れるまで待機します
wait.until(EC.presence_of_element_located(
    (By.XPATH, "//h1[contains(text(), 'XXX一覧')]")
))
time.sleep(10)

この時点で、「Entra ID ログイン → アプリケーションの一覧画面が表示される」ことまでを 1 セットで確認できています。


6-3. 画面表示確認(録音一覧 → 録音詳細)

ログイン成功後は、TOPページから 1 件選び、詳細ページまで遷移できることを確認します。

やっていることはシンプルで、

  1. TOPページで、href/{詳細ページURL}/ を含む <a> 要素を 1 件クリック
  2. 遷移先のページで <h1> 要素が表示されることを確認
  3. 証跡としてスクリーンショットを保存

サンプル(イメージ):

logger.info("Step 4: Navigating to recording detail page...")

first_recording_link = wait.until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "a[href*='/{詳細ページURL}/']"))
)
first_recording_link.click()
time.sleep(10)

logger.info("Step 7.1: Verifying recording detail page loaded...")
title_element = wait.until(EC.presence_of_element_located((By.TAG_NAME, "h1")))
title_text = title_element.text.strip()
logger.info(f"Recording detail page loaded successfully. Title: '{title_text}'")

driver.save_screenshot("canary_recording_detail_page_success.png")

これで、

  • TOPページが正常に表示されていること
  • TOPページ → 詳細ページへの画面遷移が成功すること

の 2 点を確認しています。


6-4. 複数 Backend API エンドポイントのステータス確認

画面だけでなく、代表的な Backend API もチェックしています。
ポイントは「ブラウザコンテキスト内で fetch を実行し、ログイン済みセッションをそのまま利用している」ことです。

チェック対象(例):

  • /{エンドポイントURL1}
  • /{エンドポイントURL2}
  • /{エンドポイントURL3}

これらを API_BASE_URL と組み合わせてフル URL にし、fetch でステータスコードを取得しています。

サンプル(イメージ):

logger.info("Step 5: Starting API endpoint verification...")

api_endpoints_to_check = [
    "/{エンドポイントURL1}",
    "/{エンドポイントURL2}",
    "/{エンドポイントURL3}",
]

if not API_BASE_URL:
    raise Exception("Environment variable API_URL is not set.")

api_errors = []

for endpoint in api_endpoints_to_check:
    full_api_url = API_BASE_URL + endpoint
    logger.info(f"Checking API: {full_api_url}")

    script = f"""
        const response = await fetch('{full_api_url}');
        return response.status;
    """

    try:
        status_code = driver.execute_script(
            f"return await (async () => {{ {script} }})();"
        )

        if status_code >= 400:
            error_message = f"API Error! URL: {full_api_url}, Status: {status_code}"
            logger.error(error_message)
            api_errors.append(error_message)
        else:
            logger.info(f"API {full_api_url} - Status: {status_code} ✓")

    except Exception as e:
        error_message = f"Failed to execute fetch for {full_api_url}. Error: {e}"
        logger.error(error_message)
        api_errors.append(error_message)

time.sleep(10)

if api_errors:
    raise Exception("API Errors Found:\n" + "\n".join(api_errors))

logger.info("Step 6: All verifications completed successfully!")
driver.save_screenshot("canary_all_apis_verification_complete.png")

  • 2xx → OK
  • 4xx / 5xx / 実行エラー → api_errors に積み、最後にまとめて例外化

というシンプルな判定にしています。


6-5. 最後にスクリーンショットと DOM を必ず取得

成功・失敗に関わらず、最後に DOM とスクリーンショットを必ず残すため、try ... finallyfinally 側で処理しています。

サンプル(イメージ):

logger.info("--- Page Source (DOM) ---")
logger.info(driver.page_source)
logger.info("--- End Page Source ---")

driver.save_screenshot("canary_final_page_state.png")
driver.quit()

これにより、

  • 成功時: 最終状態の DOM / 画面の証跡
  • 失敗時: エラー発生時点の DOM / 画面の証跡

が必ず残るため、CloudWatch Logs / S3 上の情報だけで「どの画面で失敗したのか」を追いやすくなります。

ここまでで「Canary の中身(何をどうチェックするのか)」が作成できました。
ここまで整えておけば、あとは Canary 作成画面で実際に設定をしていくだけとなります。

7. CloudWatch Synthetics Canary の設定

それでは実際にCanaryを作成していきたいと思います。

  • CloudWatch > Synthetics Canaries > Canaryを作成

と進みCanary作成画面を開きます。

7-1. Canary の基本設定

ここでは、Canaryの基本設定および実行ランタイムやPython + Seleniumスクリプトを指定します。


① 作成方法:インラインエディターを選択
② 名前・説明:対象システムがわかる名前を入力(例: intra-app-login-canary
③ ランタイム:Python / Selenium 対応のランタイムを選択
④ Lambdaハンドラー:スクリプトが実行されるエントリーポイントを入力
⑤ スクリプト:S3 参照 or 直接貼り付け

7-2. 実行スケジュール

Canaryの実行スケジュールを指定します。外形監視の場合は一定頻度で実行したい為、継続実行で一定間隔の時間指定をするかcron式で指定するのが良いかと思います。


⑥ スケジュール:継続実行(Every X minutes) や Cron式 を指定

7-3. アクセス許可

ここではCanaryを実行するIAMロールを指定します。


⑦ アクセス許可:新しいロールを作成 or 既存で作成したロールがあればそれを選択

7-4. CloudWatch アラームと SNS 通知

今回はCanaryが実行結果が失敗となった時にアラームが記録されるように設定と通知設定をしていきたいと思います。


⑧ 新しいアラームを追加Clickし以下の設定を入力する

  • メトリクス名:失敗 を選択
  • アラームの状態:より大きい/等しい を選択
  • しきい値:1 を入力
  • 期間:任意の時間を設定

⑨ 通知設定:新規SNSトピックの作成 or 既存SNSトピックを選択

7-5. VPC / サブネット / Security Group

最後にVPC関連の設定をしていきます。
Canaryから閉域 Webアプリケーションへアクセスする為の重要な設定がこの部分になります。

  • VPC:対象 Webアプリケーションと同じ VPC を選択
  • サブネット:Webアプリケーションと通信可能な プライベートサブネット を選択
  • Security Group:事前準備 Canary 用 Security Group を選択

以上で、Canaryの設定は終了になります。
それでは、実行結果を確認してみましょう。

8. 実行結果確認と判明した躓きポイント

実行結果を確認していくと、エラーで失敗していました。
エラー内容や状況を確認し、以下の躓きポイントが判明しましたので、解説していきます。

8-1. 躓きポイント|DNS設定関連(Private DNS と Route 53)

今回のエラー内容としては、Canary実行環境のAWSのVPC内からでは参照できないイントラ環境内のPrivate DNSに名前解決しようとして、Entra ID ログイン画面まで到達しないという状態でした。
イメージとしては以下になります。

  • ブラウザでのアクセス
    クライアント社内ブラウザ → イントラ環境内の Private DNS で 名前解決 → DirectConnect 経由で NLB へ
  • Canary のアクセスパス
    VPC 内で実行 → イントラ環境内の DNS には届かない

このようにエラーの原因は DNS にあることがわかりました。
そこで対応策として、AWS 側に以下の内容で設定した 同じドメイン名の Route 53 プライベートホストゾーン を作るという形にしました。

  • 同じドメインの プライベートホストゾーン を作成
  • ドメイン を NLB 向きのレコード として登録
  • このホストゾーンを Canaryを実行するVPC に関連付け

これで、VPC 内からも 名前解決できるようになり、Canary も問題なくアプリケーションに到達するようになりました。
ここで学んだポイントとしては、

  • 閉域構成+Private DNS な環境では、
    「Canary が参照する DNS はどこか?」を最初に確認する

でした。

8-2. 実行結果の確認

再度、Canaryを実行したら処理が成功しました!!
実行結果としてスクリーンショットとログを確認してみましょう。

▼スクリーンショットの確認
(※画面は開発環境のものです)

WebアプリケーションのTOPページがスクリーンショットとして残っています。
無事にCanaryがログインしTOPページを表示できたということです。

▼ログの確認
(※画面は開発環境のものです)

Canaryのスクリプトに仕込んでいたログも確認できます。
無事に正常終了したログを確認できました。

以上で、実行結果としては正常終了したことが分かりました。

9. まとめ

本記事では、閉域環境の Webアプリケーションに対して、
CloudWatch Synthetics + Python + Selenium を用いて外形監視を実装した事例を紹介しました。

あらためて、やったことを簡単に振り返ると:

  • クライアント社内イントラ環境からしかアクセスできない Webアプリケーションに対し、
    • CloudWatch Synthetics の Canary を VPC 内で実行 するように変更
    • Canary 用 Security Group と NLB 側 Security Group を整理して通信経路を確保
    • イントラ環境内の Private DNS に依存せず、Route 53 プライベートホストゾーンで同じ FQDN を解決できるようにした
  • Python + Selenium を使って、
    • Azure Entra ID を利用したログインフローを自動化
    • TOP ページ表示・詳細ページ遷移・特定 Backend エンドポイントの 200 系確認までを一連のシナリオとして実装
  • 異常時には CloudWatch アラーム + SNS による通知で、
    人がログイン確認をしなくても早期に気づける体制 を整えた

特に、今回のような構成では、

  • 「Canary を VPC 内で実行する」こと
  • 「イントラ環境内の Private DNS には頼らず、Route 53 で同じドメインを定義すること」

の 2 点が、閉域 × SSO × 外形監視 を成立させるうえでのキーポイントでした。

同じように、

  • 社内イントラからだけアクセスできる業務システムがある
  • でも監視は AWS 側からやりたい
  • しかも SSO ログインまで含めてユーザー視点で確認したい

という要件をお持ちの方は、今回の構成や考え方をベースにカスタマイズしてみると、
「人力チェックを減らしつつ、監視の粒度は落とさない」構成が作りやすくなると思います。

以上で本記事はおしまいです。どこか一部でも設計の参考になれば幸いです。

Finatext Tech Blog

Discussion