2026/06/16 ------ Canary用SG sg4cnrylambda1 Canary用SGは、インバウンドルールなし(全拒否)、アウトバウンドルールは全開放でOK ------ 監視対象のWebサーバのSGは、sg4cnrylambda1からのHTTP/HTTPSのインバウンドを開ける必要がある。 ------ VPCエンドポイントはs3,logs,monitoring s3はGateway型なのでセキュリティグループはない。 logs,monitoringはInterface型で、ともにセキュリティグループ sg4cloudwatch1 を開けていると com.amazonaws.ap-northeast-1.logs com.amazonaws.ap-northeast-1.monitoring はともにHTTPS APIなので、CanaryのLambda⇒VPCEへのインバウンドルールで443だけ開ければよい。 つまり、sg4cloudwatch1 のインバウンドルールに、sg4cnrylambda1 からのTCP=443を追加する。 ------ Canaryに付与するIAMロールは、マネージドポリシーCloudWatchSyntheticsFullAccess だけを持っていればよいですか。 ------ いいえ。Logs,Metrics,S3などのアクセス権限をも必要になる。 もし新規ロールを作るを選ぶと、デフォルトでCloudWatchSyntheticsRole-xxxx という物が作られるのでそれを参考にするといい。★★★CWSRoleみたいな名前の物があったはず ------ Route53はアウトバウンドエンドポイントで社内ドメインのURLを社内DNSサーバにフォワードして、名前解決ができています。 この状態で、WebサーバのURLが社内ドメインの場合、CanaryがDNS名前解決を行うためにはさらに何か追加の設定が必要ですか? ------ CanaryはLambdaとして動作し、VPCの標準DNS機能を利用します。そのため VPC ↓ AmazonProvidedDNS ↓ Route53 Resolver Rule ↓ Outbound Endpoint ↓ オンプレDNS の経路が正常なら、Canaryもそのまま名前解決できます。 ------ AWS社内環境で、ELBにTLS/SSLサーバ証明書と社内認証局のCA証明書をインポートして、 httpsのWebアプリケーションを運用中です。このWebアプリケーションに対してCanaryでURL監視したところ、 NET::ERR_CERT_AUTHORITY_INVALID エラーが発生しました。 サーバ証明書が有効期間内であることは確認済です。また自己証明書ではありません。 ランタイムがpuppeteer-16の場合の解決方法を教えてください。 ------ まず、下記のいずれかのコマンドで証明書チェーンが切れてないことをもう一度確認する。 ------ openssl s_client -connect web.example.co.jp:443 -showcerts curl -v https://web.example.co.jp ------ 現在のCloudWatch Syntheticsでは、 Puppeteerランタイムへ独自CA証明書をOSレベルで登録することはできません。 ------ 次の記述で回避できる。 ------ const synthetics = require('Synthetics'); const browser = await synthetics.launch({ args: ['--ignore-certificate-errors'] }); const page = await browser.newPage(); await page.goto( 'https://portal.company.local', { waitUntil: 'networkidle0' } ); await browser.close(); ------ または ------ // Syntheticsの設定でlaunchOptionsを上書き const syntheticsConfig = synthetics.getConfiguration(); syntheticsConfig.setConfig({ launchOptions: { args: [ '--ignore-certificate-errors', // 証明書エラーを無視 '--ignore-ssl-errors', '--disable-web-security', ] } }); ------ また暫定感はあるものの、こういう回避方法もあるらしい。 ------ const synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const apiCanaryBlueprint = async function () { const page = await synthetics.getPage(); // 証明書エラーを無視する設定(Puppeteer固有) await page._client().send('Security.setIgnoreCertificateErrors', { ignore: true }); await page.goto('https://your-internal-app.example.com', { waitUntil: 'networkidle0', timeout: 30000, }); const title = await page.title(); log.info('Title: ' + title); }; exports.handler = async () => { return await apiCanaryBlueprint(); }; ------ ちなみに、中間CA証明書をS3に配置し、スクリプトから参照させる技もあるらしい。 ------ const synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const AWS = require('aws-sdk'); const fs = require('fs'); const { execSync } = require('child_process'); const s3 = new AWS.S3(); const downloadCACert = async () => { const params = { Bucket: 'your-internal-bucket', Key: 'certs/internal-ca.crt', }; const data = await s3.getObject(params).promise(); fs.writeFileSync('/tmp/internal-ca.crt', data.Body); log.info('CA証明書をダウンロードしました'); }; const apiCanaryBlueprint = async function () { await downloadCACert(); // NODE_EXTRA_CA_CERTSでNode.js(HTTPリクエスト)に信頼させる process.env.NODE_EXTRA_CA_CERTS = '/tmp/internal-ca.crt'; const syntheticsConfig = synthetics.getConfiguration(); syntheticsConfig.setConfig({ launchOptions: { args: [ // ChromiumにCA証明書ディレクトリを指定 '--use-system-default-certificate-store', ], // CA証明書をChromiumに渡す環境変数 env: { ...process.env, SSL_CERT_FILE: '/tmp/internal-ca.crt', NODE_EXTRA_CA_CERTS: '/tmp/internal-ca.crt', } } }); const page = await synthetics.getPage(); await page.goto('https://your-internal-app.example.com', { waitUntil: 'networkidle0', timeout: 30000, }); log.info('ページ読み込み完了'); }; exports.handler = async () => { return await apiCanaryBlueprint(); }; ------ 現在AWSのCanaryのランタイムとして選択できるpuppeteerのバージョン9.1と16では、 文法やAPIはほぼ同じですか?それともかなり違いますか? ------ かなり違う。 ------ HTTPSエラーを無視するのではなく、証明書を認識させることでエラーを解消したいです。 httpsのWebサーバ自身のサーバ証明書と、社内CA証明書のPEM(CER)ファイルがそれぞれローカルPC上にあります。 この状態から、puppeteer-16のCanaryスクリプトのエラーを解消するための手順を教えてください。 ------ Canaryが使用するS3バケットがどこであるかは、どのように知ることができますか? ------ 方法�@:AWSマネジメントコンソールから確認(最も簡単) CloudWatch → Application Monitoring → Synthetics Canaries を開く 対象のCanary名をクリック 「Configuration」タブ を選択 「S3 bucket」 の項目にバケット名が表示される ------ Canaryが使用するS3バケット(cw-syn-results-...)に証明書ファイルを置くのは推奨しないとのことですが、 であるならば、証明書はどこに置けばよいのですか。 ↓ 専用バケットをどこでもいいので作ればよい。 # CA証明書をアップロード aws s3 cp ca-chain.pem s3://your-company-internal-certs/certs/ca-chain.pem ------ Chromiumが必要とするのは社内CA証明書のみです(サーバ証明書はELBが提示するため不要)。 ただし、中間CA証明書がある場合はチェーンを結合します。 # 中間CA証明書がある場合は結合する(順番は末端→ルートCA) cat intermediate-ca.pem root-ca.pem > ca-chain.pem # 中間CAがなくルートCAのみの場合はそのまま使用 cp internal-root-ca.pem ca-chain.pem Canary実行ロールに以下のS3権限が必要です。 { "Effect": "Allow", "Action": ["s3:GetObject"], "Resource": "arn:aws:s3:::YOUR-CANARY-BUCKET/certs/*" } ------- const synthetics = require('@aws/synthetics-puppeteer'); // puppeteer-16のnamespace const log = require('@aws/synthetics-logger'); const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'); // SDK v3 const fs = require('fs'); const path = require('path'); const CA_CERT_BUCKET = 'YOUR-CANARY-BUCKET'; const CA_CERT_KEY = 'certs/ca-chain.pem'; const CA_CERT_PATH = '/tmp/ca-chain.pem'; const TARGET_URL = 'https://your-internal-app.example.com'; // S3からCA証明書を取得して/tmpに保存 const downloadCACert = async () => { const client = new S3Client({}); const command = new GetObjectCommand({ Bucket: CA_CERT_BUCKET, Key: CA_CERT_KEY, }); const response = await client.send(command); // SDK v3のBodyはReadableStream const chunks = []; for await (const chunk of response.Body) { chunks.push(chunk); } fs.writeFileSync(CA_CERT_PATH, Buffer.concat(chunks)); log.info('CA証明書を取得しました: ' + CA_CERT_PATH); }; const canaryHandler = async () => { // 1. 証明書を取得 await downloadCACert(); // 2. Node.js(https モジュール)にCA証明書を信頼させる // ※ page.goto() 内部のNode.js HTTPSリクエストに効く process.env.NODE_EXTRA_CA_CERTS = CA_CERT_PATH; // 3. ChromiumにCA証明書を渡してブラウザを起動 const synConfig = synthetics.getConfiguration(); synConfig.setConfig({ launchOptions: { args: [ `--certificate-transparency-verification-disabled`, // Chromiumのトラストストアとして証明書ファイルを指定 // NSS形式のDBではなくPEMを直接渡す方法 `--use-client-certificate`, ], env: { ...process.env, // OpenSSLベースのChromiumビルドへのCA指定 SSL_CERT_FILE: CA_CERT_PATH, NODE_EXTRA_CA_CERTS: CA_CERT_PATH, }, }, }); // 4. ページ取得と監視 await synthetics.executeStep('checkPage', async () => { const page = await synthetics.getPage(); // ChromiumのCDPセッション経由でCA証明書を追加信頼させる const client = await page.createCDPSession(); // puppeteer-16はこちら await client.send('Security.setIgnoreCertificateErrors', { ignore: false }); // 無視はしない const response = await page.goto(TARGET_URL, { waitUntil: 'networkidle0', timeout: 30000, }); const status = response.status(); log.info('HTTPステータス: ' + status); if (status !== 200) { throw new Error(`期待しないステータスコード: ${status}`); } log.info('監視成功: ' + TARGET_URL); }); }; exports.handler = async () => { return await canaryHandler(); }; ------- 指定したバケットのcertsフォルダーの下にca-chain.pemを置いた場合 const CA_CERT_KEY = 'certs/ca-chain.pem'; となるのに、 const CA_CERT_PATH = '/tmp/ca-chain.pem'; となるのはなぜですか。/tmpは常に固定のパスですか。 ------- S3上の前者からファイルをDLして、Lambda上の後者にファイルを配置するから。 ------- 社内CA局に認証された社内httpsサイトでURL監視をしたいだけなのに、 Canaryを使うと様々なエラーが出て、なおかつランタイムのバージョンアップにも頻繁に追随しなければなりません。 対象のhttpsのURLが10個以内という中小規模環境で、もっと簡潔で頻繁なバージョンアップ対応改修を要求されない監視方法はありますか? ------- EC2 + curl + CloudWatch Alarm 監視専用EC2を1台作ります。 RHELでもAmazon Linuxでも可。 curl --fail \ --silent \ --show-error \ https://portal.company.local/health Nagios or Icinga2 ------- Nagios やIcinga2 を動かすのにもEC2を立てる必要がありますか。 ------- はい。 Nagios や Icinga 2 は監視サーバソフトウェアなので、どこかで動かすためのサーバが必要です。 ------- 24h監視し、NG時にはメール通知する運用状況で、 Canaryを使うのと、t2.microのEC2インスタンスでcurlやNagios,Ichinda2で監視するのでは、 費用はどちらが安いですか? ------- AWS料金も概ね同等か、監視頻度によってはEC2の方が安い ------- 監視用のEC2は、他のサーバーアプリケーションが不安定だとそのEC2自身がダウンしてしまい監視にならない危険がありますが、 安定しているEC2であれば、他用途のEC2をそのまま使ってURL監視を行う運用事例は多いですか。 ------- はい。運用管理ツールのみが稼働するEC2があればそれの転用も十分現実的。 WebサーバやDBサーバを使う事例は少ない。それがダウンすると監視にならないので、お勧めしない。 ------- Linux+curl自作プログラムやNagios,Icinga2等のOSSツールを、 podmanやdockerを使いLinuxコンテナで既存のEC2で運用実績を確認後、 規模が増えてきたら専用のEC2インスタンスで監視サーバ化する方針は企業事例としてありますか? ------- はい、そのような段階的な導入は実際によくあります。 特に 監視対象が最初は少数(10URL以下) 社内システム向け AWS上の中小規模環境 専任監視チームがない という環境では、 まず既存サーバ上で小さく始め、必要になったら監視基盤を独立させるという進め方は非常に現実的です。 ------- AWSのCanaryのランタイムにはPuppeteer,Playwright,素のNode.js、Python+Selenium,Java等がありますが、 最も安定し実績のあるランタイムとしてお勧めの物はありますか? ------- 実績があるという意味ならPuppeteer,Node.jsの順で、Playwrightは隆盛しつつ。 ただし、URL監視用途で応答200が返ればいいだけならブラウザベースのAPIは要らないので、 Node.js API Canaryが最もシンプルで安定する。 ------- const synthetics = require('Synthetics'); exports.handler = async () => { const requestOptions = { hostname: 'portal.company.local', protocol: 'https:', path: '/health', method: 'GET' }; await synthetics.executeHttpStep( 'HealthCheck', requestOptions ); }; ------- Node.js API Canaryのサンプルプログラムに、さらに社内CA証明書を使用した社内httpsサイトでのエラーを抑制する指定も可能ですか? ------- 抑制方法は基本的にPuppeteerの場合と同じ。 なお、 const browser = await synthetics.launch({ ignoreHTTPSErrors: true }); の代わりに最近は const browser = await puppeteer.launch({ acceptInsecureCerts: true }); ------- または ------- const synthetics = require('@aws/synthetics-puppeteer'); const browser = await synthetics.launch({ args: [ '--ignore-certificate-errors' ] }); const page = await browser.newPage(); await page.goto( 'https://portal.company.local', { waitUntil: 'networkidle0' } ); ------- Canaryスクリプト内に await synthetics.launch() を入れると、後の処理で以下のエラーが発生します。 「Error: Requesting main frame too early!」 AWSが自動生成するCanaryスクリプトを修正することで解決できますか。 ------- 原因は const page = await synthetics.getPage(); await page.goto(url); で取得するページと異なるブラウザを立ち上げているため。 解決法は synthetics.getPage() を使わずに自分でbrowserとpageを生成する方法。 ------ const synthetics = require('@aws/synthetics-puppeteer'); exports.handler = async () => { const browser = await synthetics.launch({ args: [ '--ignore-certificate-errors' ] }); const page = await browser.newPage(); await page.goto( 'https://portal.company.local', { waitUntil: 'networkidle0' } ); await browser.close(); }; ------ または、CDPセッション経由という方法もあるらしい。Claudeの生成例 ------ const synthetics = require('@aws/synthetics-puppeteer'); exports.handler = async () => { await synthetics.executeStep('checkPage', async () => { const page = await synthetics.getPage(); // CDPセッションで証明書エラーを無視 const client = await page.createCDPSession(); await client.send('Security.setIgnoreCertificateErrors', { ignore: true }); await page.goto('https://your-internal-app.example.com', { waitUntil: 'networkidle0', timeout: 30000, }); }); }; ------ 同じくGeminiの生成例。 ------ const synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const pageLoadBlueprint = async function () { let page = await synthetics.getPage(); // CDP セッションを初期化 const client = await page.createCDPSession(); // Security ドメインを有効化し、証明書エラーを無視 await client.send('Security.enable'); await client.send('Security.setIgnoreCertificateErrors', { ignore: true }); // Canary の実行したい URL を指定 const response = await page.goto('https://your-target-url.com', { waitUntil: 'domcontentloaded', timeout: 30000 }); }; exports.handler = async () => { return await pageLoadBlueprint(); }; ------ Canary実行時にAWS内部で既にbrowserが生成済の場合、そのbrowserに対して --ignore-certificate-errors を有効にする方法はありますか。 ------- できない。自動生成されたbrowserを使わずに自分で起動する方法に書き換えるか、 const browser = await synthetics.launch({ args: ['--ignore-certificate-errors'] }); const page = await browser.newPage(); またはNode.js API Canaryに書き換える。中間CAも埋め込める。 ------- Node.js API Canaryに書き換える案で、HTTPSエラーを回避する設定も行うサンプルプログラムを作ってください。 ------- const agent = new https.Agent({ rejectUnauthorized: false }); とする。 ------- まず中間CA証明書を作る案 ------- nodejs/ ├ index.js └ certs/ └ company-root-ca.pem ------- const synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const https = require('https'); const fs = require('fs'); const path = require('path'); exports.handler = async () => { const caCert = fs.readFileSync( path.join(__dirname, 'certs', 'company-root-ca.pem') ); const agent = new https.Agent({ ca: caCert }); const options = { hostname: 'portal.company.local', port: 443, path: '/', method: 'GET', agent: agent, timeout: 10000 }; await new Promise((resolve, reject) => { const req = https.request( options, (res) => { log.info( `StatusCode=${res.statusCode}` ); if (res.statusCode !== 200) { reject( new Error( `HTTP Error ${res.statusCode}` ) ); return; } resolve(); } ); req.on( 'error', reject ); req.end(); }); }; ------- エラーを回避する案 ------- const https = require('https'); exports.handler = async () => { const agent = new https.Agent({ rejectUnauthorized: false }); const options = { hostname: 'portal.company.local', port: 443, path: '/', method: 'GET', agent: agent }; await new Promise((resolve, reject) => { const req = https.request( options, (res) => { if (res.statusCode !== 200) { reject( new Error( `HTTP Error ${res.statusCode}` ) ); return; } resolve(); } ); req.on('error', reject); req.end(); }); }; ------- 「Canary ZIP」に社内CA証明書を追加する方法が分かりません。 Canaryを作成後、Lambda上のパスを知り、スクリプトの場所をダウンロードし、 Zipを展開して社内CA証明書を追加し、またZipに圧縮して、またアップロードするのですか? ------- 概ねそうだが、Syntheticsの標準UIではZipを上げ下げする操作は提供されていない。 おとなしくEC2+curlにしておけ ------- Canaryの利用によって発生している料金を、AWSコンソールのBilling and Cost Management等、 いずれかの画面で確認できますか? ------- はい。SyntheticsはCanaryの全額なので分かりやすいが、 LambdaやCloudWatch、S3はCanary利用有無で発生するしないの切り分けは結構難しい。 また、VPC EndpointはlogsやmonitoringはCloudWatch本体の利用に必須なので、Canary利用に伴う新規発生料金はない。 ------- | サービス | 主な課金要素 | | --------------------- | -------------------------- | | CloudWatch Synthetics | Canary実行回数・実行時間 | | AWS Lambda | Canary実行時のLambda利用 | | Amazon CloudWatch | メトリクス、アラーム | | CloudWatch Logs | ログ保存量 | | Amazon S3 | スクリーンショット、HARファイル等 | | VPC Endpoint | Interface Endpoint時間課金・通信量 | | SNS | 通知メール(通常はごく少額) | ------- ◆ここまでのまとめ URL監視の方法 ・Canary (pupeteer,playwrite,Node.js API,Python+selenium,Java+selenium) ・Nagios,Icinga2などのOSSツール ・EC2+curl手作り ・PHPが入っているWebサーバに相乗りしてget_headers() -------