[Amazon Connect] CloudWatch Alarm の電話通知で最小限の運用コストを検討してみました

[Amazon Connect] CloudWatch Alarm の電話通知で最小限の運用コストを検討してみました

Amazon Connectを使ったCloudWatch Alarmの電話通知を構築し、実測データから最小コストの運用を検証してみました。
2026.11.04

1 はじめに

製造ビジネステクノロジー部の平内(SIN)です。

CloudWatch Alarm の通知先は、メールやSlackなどが可能ですが、深夜や移動中など画面を見ていない時間帯でも気づける手段としては、電話をコールするというのも1つの方法として有力なようです。

Amazon Connect には、API から電話をかける StartOutboundVoiceContact があり、SNS と Lambda を組み合わせると 簡単に、Alarm から電話をかけることができます。Amazon Connect を使った電話通知の記事は、既に数多く公開されています。本記事は、その中で以下の仕様に特化したものとして書かせていただきました。特定のニーズになっていることをご了承ください。

  • CloudWatch Alarm を携帯に発信することで、担当者に知らせる
  • 担当者には、あらかじめ発信番号を伝えておく。着信があればアラームが発生したと認識するだけで、電話には出ない
  • 発信用の国内番号は申請しない。国内番号は取得の手続きに時間が必要になるので、いったん海外(米国)の番号を使用する
  • 着信先は、国内の携帯電話とする
  • アラートの発生が比較的多いので、可能な限り運用費用を抑える

最後の要件が、この記事の主題です。電話に出なければ通話料はかからないはず、という想定で始めましたが、実測すると違いました。そこで今回は、この仕様を Amazon Connect のインスタンス・電話番号・フローまで含めて CDK 一式で構築し、通話料が最小になる運用を実験で確かめてみました。

先に結論を述べると、以下のとおりです。

  • 電話に出なくても、発信から約 20 秒で携帯の留守番電話サービスが応答し、接続が成立します。出なければ $0、は成り立ちません
  • 課金は 2 本立てでした。Connect の音声利用料(1 分あたり $0.038)は秒単位で呼び出し中の時間も含み、日本の携帯向けの通話料(1 分あたり $0.078)は接続後の時間を 1 分単位で切り上げます。これは Cost and Usage Report(CUR)の明細を 1 通話ずつ突き合わせて確認してみました
  • 出ない運用の実測は 1 通話 $0.093、留守電にアラート内容を残す運用は $0.112 でした。費用の主役は接続後 0 秒でも 1 分分かかる通話料で、接続後 60 秒以内なら読み上げを足しても差は $0.02 ほどです
  • 通話料と電話番号の日額は、Cost Explorer の「Connect」フィルタでは確認できませんでした。別のサービス「Contact Center Telecommunications (service sold by AMCS, LLC)」として計上されます
  • 同じ切断だけのフローでも、2020 年に作った既存インスタンスからの発信は 1 分あたり $0.018、今回作ったインスタンスは $0.038 で、単価はインスタンスで決まっているようでした
  • 米国の電話番号は ID 書類なしで CDK の deploy の中で取得でき、東京リージョンのインスタンスから国内の携帯へ、クォータの申請なしで着信しました

携帯に着信したときの画面です。米国の番号から、国と地域名付きで着信します。

なお、本稿はあくまで特定の要件と、私の携帯の回線(LINEモバイルのソフトバンク回線)での一例として捉えてください。留守番電話の動きはキャリアと契約内容で変わると思います。金額は 2026 年 11 月の請求明細(CUR)の実測です。

2 構成と設計

(1) 構成

構成要素 役割
CloudWatch Alarm 検証用。カスタムメトリクスが 1 以上で ALARM
SNS トピック Alarm のアクション
Lambda(Node.js 22) ALARM のときだけ、着信先ごとに StartOutboundVoiceContact を呼ぶ
Amazon Connect インスタンス 東京リージョン。着信は無効、発信だけ有効
電話番号 米国の DID。発信者番号として使う
フロー 切断(Disconnect)だけ。実験用に読み上げ付きへ切り替えられる

リソースは 1 つの CDK スタックで作りました。cdk destroy で電話番号とインスタンスも消えるので、番号の日額課金も残りません。

(2) 出ない運用

電話に出ない運用を土台にしました。着信した番号を見て「アラームが発生した」と分かればよい、という割り切りです。読み上げのプロンプト、キー入力の受け付け、不在時の再架電が丸ごと不要になり、フローは切断だけの最小構成になります。複数の Alarm を区別したい場合は、発信番号を複数持つか SMS を併用する方が素直だと思いますが、本稿のスコープ外としました。

(3) 米国番号と東京リージョン

発信者番号には、取得時の条件が軽い米国の番号を使いました。

観点 日本の番号 米国の番号(採用)
取得時の ID 書類 必要。登記簿・代表者の身分証・所在地証明の 3 点 不要
取得できるリージョン 東京(03 / 06)、全リージョン(050) 全リージョン
携帯側の見え方 国内番号 +1 から始まる国際着信

参考: Region requirements for ordering and porting phone numbers

インスタンスは東京リージョンに作る必要があります。既定で発信できる国はインスタンスのリージョンで決まり、米国リージョンのインスタンスは既定では日本へ発信できません。東京リージョンのインスタンスは、日本・ベトナム・米国へ既定で発信できます。

参考: Countries that call centers using Amazon Connect can call by default

なお、国内のキャリアは国際電話の着信拒否を無料で提供しており、有効にしていると +1 からの着信は届きません。運用に入れる前に、担当者の携帯で確認が必要です。

(4) CDK の範囲

Connect のインスタンス・電話番号・フローまで CDK で作りました。cdk destroy 一発で番号ごと消える方が「残さない」保証として強いためです。フローも CDK に含めたことで、実験のたびにフローの中身を context で切り替えて deploy し直せました。

注意点が 2 つあります。AWS::Connect::Instance は 30 日間に作成・削除できる数に上限があるので、destroy を乱発しない方が安全です。AWS::Connect::PhoneNumber の CountryCode / Type / Prefix は、変更すると番号が置き換わるので、deploy 後は触らないようにします。

3 作業手順

コードは GitHub に置いています。手順の詳細は README.ja.md を参照してください。

GitHub: cloudwatch-alarm-amazon-connect-call

項目 バージョン
aws-cdk-lib 2.273.0
aws-cdk(CLI) 2.1147.0
TypeScript 7.0.2
Node.js 22.23.4
pnpm 10.24.0
Lambda ランタイム nodejs22.x
リージョン ap-northeast-1

(1) デプロイ

着信先の携帯番号を E.164 形式(090-xxxx-xxxx なら +8190xxxxxxxx)で、deploy 時に -c で渡します。複数の着信先はカンマで区切ります。

$ git clone https://github.com/furuya02/cloudwatch-alarm-amazon-connect-call.git
$ cd cloudwatch-alarm-amazon-connect-call/cdk
$ pnpm install
$ pnpm cdk deploy -c destinations=+8190xxxxxxxx,+8180yyyyyyyy
# => CloudWatchAlarmAmazonConnectCall.SourcePhoneNumber = +1208460xxxx

私の環境では、デプロイは 134.72 秒 でした。この中で Connect インスタンスの作成と米国番号の取得が終わっています。Outputs の SourcePhoneNumber が発信番号で、担当者に伝えておきます。取得した番号は +1 208 で始まる、アイダホ州の番号でした。

フローの中身は context の flow で切り替えます。省略すると切断だけのフローです。

$ pnpm cdk deploy -c destinations=+8190xxxxxxxx -c flow=message
flow の値 フローの内容 用途
disconnect(既定) 切断だけ 出ない運用
probe 約 45 秒の読み上げの後に切断 誰が応答しているかの切り分け
message アラート名と状態を 3 回読み上げて切断 留守番電話にアラート内容を残す

(2) 動作確認

検証用の Alarm は、カスタムメトリクスが 1 以上になると ALARM になります。alarm.sh でメトリクスを 1 件送ると、1 分ほどで ALARM になって Lambda が発信します。status.sh で Alarm の状態と Lambda のログを確認でき、contactId が出ていれば Connect が発信を受け付けています。

$ ../scripts/alarm.sh
# => 2026-11-01 17:51:43 put value=1
$ ../scripts/status.sh
# => ALARM   2026-11-01T17:52:39.539000+09:00
# => ... INFO {"destination":"+8190xxxxxxxx","contactId":"a5646ac4-xxxx-xxxx-xxxx-xxxxxxxxxxxx"}

ALARM への遷移から Connect が発信を受け付けるまでは、3 回とも 2 秒以内 でした。携帯が鳴り始めるまでは約 10 秒です。メトリクスを送ってから ALARM に変わるまでの 56〜96 秒は、Alarm の評価周期(1 分)の仕様で、本構成の遅延ではありません。

(3) 後片付け

$ pnpm cdk destroy -c destinations=+8190xxxxxxxx

Amazon Connectでは、電話番号は保持している間、日額が発生します(東京リージョンの米国番号で 1 日 $0.06)。必要がなくなったら、必ず destroy してください。

4 CDK とコード

Github cdk/lib/stack.ts

// cdk/lib/stack.ts(要点抜粋)
const instance = new connect.CfnInstance(this, 'Instance', {
  instanceAlias: `cw-alarm-connect-call-${suffix}`,
  identityManagementType: 'CONNECT_MANAGED',
  attributes: { inboundCalls: false, outboundCalls: true }, // 発信だけ有効
})
const phoneNumber = new connect.CfnPhoneNumber(this, 'PhoneNumber', {
  targetArn: instance.attrArn,
  countryCode: 'US',
  type: 'DID',
})
const flow = new connect.CfnContactFlow(this, 'ContactFlow', {
  instanceArn: instance.attrArn,
  name: `${PROJECT}-disconnect`,
  type: 'CONTACT_FLOW',
  content: JSON.stringify({
    Version: '2019-10-30',
    StartAction: flowMode === 'disconnect' ? disconnectId : messageId,
    Actions: flowMode === 'disconnect' ? [disconnect] : [message, disconnect],
  }),
})

要点は以下です。

  • 電話番号は TargetArn にインスタンスの ARN を渡すだけです。CountryCode を US、Type を DID にすると、米国のローカル番号が割り当てられます
  • フローは Flow language の JSON です。既定は切断のアクション 1 つだけで、context の flow に応じて読み上げ(MessageParticipant)を前に足します。読み上げの文には、Lambda が渡す Contact attributes(Alarm 名と状態)を $.Attributes.AlarmName の形で埋め込みます
  • インスタンスのエイリアスは 45 文字が上限です。最初は 49 文字にしていて、変更セットの作成時に止まりました
  • flow の値は 3 つに限定し、それ以外は synth でエラーにしています

Lambda は、SNS のメッセージが ALARM のときだけ、着信先ごとに StartOutboundVoiceContact を呼びます。SourcePhoneNumber を指定するのでキューは不要です。着信先が複数のときは同時に発信し、1 件が失敗しても他を止めないよう Promise.allSettled にしています。検証用の Alarm は okAction を付けていないので、実運用では既存の Alarm のアクションにこの SNS トピックを追加するだけで使えます。

5 実験 1、出ない運用

出ない運用で 3 回発信し、携帯側の操作を変えて、Connect 側の記録を比べました。

(1) 着信

2026 年 11 月 1 日に東京リージョンへ新規作成したインスタンスから、090 の携帯へ、申請なしで着信しました。公式ドキュメントには「+8170、8180、8190 の携帯番号は、デフォルトでは許可されていない場合があります」とあり、過去には申請が必要だったという報告もありますが、今回はこの「場合」には当たりませんでした。発信可能な国は Service Quotas ではなくサポートケース(Country Allowlisting for Outbound Calls)で扱われます。

iPhone の着信画面には「アメリカ合衆国 アイダホ ボイシ +1 (208) 460-xxxx」と表示され、出ずに放置すると十数秒で鳴り止み、不在着信になりました。留守番電話にメッセージは残っていません。ここまでは、当初の想定どおりに見えました。

(2) Connect 側の記録

Connect 側の記録では、電話に出ていないのに誰かが応答したことになっていました。発信の記録は、AWS コンソールの Connect インスタンス画面にある「Log in for emergency access」から管理 Web サイトに入り、Contact search で確認できます。

回 携帯側の操作 Duration Disconnect reason
1 着信後、拒否ボタンを押した 24 秒 Contact flow disconnect
2 何も操作せず放置 22 秒 Contact flow disconnect
3 着信から約 3 秒で拒否ボタンを押した 22 秒 Contact flow disconnect

Contact flow disconnect は、フローの Disconnect ブロックが実行されたことを意味します。アウトバウンドでフローが動くのは相手が応答した後なので、誰かが応答したことになります。Connected at は通話の終了時刻と同じで、応答した瞬間に切断しています。携帯側の操作は Connect 側の通話に影響していません。

応答したのが留守番電話センターなのか、キャリアの不応答アナウンスなのか、米国番号からの国際経路の途中で応答扱いになっているのかは、この記録からは決められません。通話料に直結するので、切り分けました。

(3) 切り分け

フローの読み上げと発信元を変えて 3 回発信しました。

切り分け 発信元とフロー 発信から応答まで 結果
1 米国番号、5 秒の読み上げ 21 秒 留守電に何も残らない。留守電の応答メッセージの最中に切れるため、切り分けとして不十分
2 別インスタンスの日本の 050 番号、切断だけ 20.2 秒 同じ約 20 秒で応答。経路ではなく着信側の網が応答している
3 米国番号、45 秒の読み上げ 21 秒 留守電に 34 秒の録音が残り、3 番目の文から始まる

これで確定です。発信から約 20 秒で携帯のキャリアの留守番電話センターが応答し、Connect はその瞬間に切っていました。携帯には不在着信だけが残り、留守電には何も残らないので、気づきにくい動きです。約 20 秒はキャリアの留守番電話の呼び出し時間の設定で決まり、携帯側で拒否しても変わりません。

なお、私の回線の留守番電話は、LINEモバイルのソフトバンク回線に標準で付いている無料のものです。留守電を解約すれば接続は成立しなくなるはずですが、請求の明細では呼び出し中の時間も音声利用料の対象だったので、$0 になるかは分かりません。留守電の無い携帯を用意できなかったので、本稿では確認できていません。

6 実験 2、留守電へのメッセージ

出なくても接続が成立して通話料がかかるなら、少し読み上げを足して、アラートの内容を留守電に残せないか、というのが実験 2 です。実験の時点では「通話料は 1 分単位」と考え、同じ 1 分の中に収める狙いで設計しました。後で請求の明細を見ると、費用の大半を占める通話料についてはこの狙いが当たっていました。

(1) 設計

実験 1 の 45 秒読み上げから、接続後の内訳が分かっています。

区間 時間 根拠
留守電の応答メッセージと発信音 約 11 秒 読み上げ 45 秒のうち録音されたのが 34 秒
録音される時間 60 秒からの残り 通話料を 1 分分に収めるなら、接続後の読み上げ全体を 60 秒未満にする

Connect の通常の発信では、留守電の検知(Answering Machine Detection)はアウトバウンドキャンペーン専用で使えません。そこで、同じ文を 3 回繰り返す読み上げにしました。1 回目は応答メッセージに重なって消え、2 回目以降が録音される想定です。人が出た場合は 1 回目から聞こえます。1 回が約 10 秒で、3 回で約 30 秒です。

This is an automated call from Amazon CloudWatch. Alarm cloudwatch-alarm-amazon-connect-call-test is now in state ALARM. Please check the console.

(2) 結果

message のフローで deploy し直して 1 回発信したところ、発信から 21 秒で留守電が応答し、接続後 31 秒で切断しました。留守電には 18 秒の録音が残り、1 回目が応答メッセージに消えて 2 回目と 3 回目が録音された、という設計どおりの結果です。

接続後 31 秒なら通話料は 1 分分のままです。応答メッセージの長さはキャリアや個人の設定で変わるので、繰り返しの回数と 1 回の長さは、接続後 60 秒以内に収まる範囲で余裕を持たせます。

7 請求額

(1) Cost Explorer

Connect の費用は、Cost Explorer の「Connect」フィルタだけでは半分しか見えません。音声利用料は「Connect」に、通話料と電話番号の日額は「Contact Center Telecommunications (service sold by AMCS, LLC)」という別のサービスに計上されます。2 つを選んで使用タイプ別に表示した画面です。

サービス 使用タイプ 内容
Connect APN1-ai-end-customer-mins 音声利用料($0.038/分)
Contact Center Telecommunications APN1-JP-outbound-mins 日本の携帯向け通話料($0.078/分)
同上 APN1-US-did-numbers 米国番号の日額($0.06/日)

なお、APN1-JP-did-numbers は切り分けで使った別インスタンスの 050 番号の日額で、本稿の構成には含まれません。Cost Explorer は日ごとの合計までなので、1 通話ずつの確認には S3 に配信される CUR を使いました。CUR の行は ResourceId に Contact の ARN が入り、DescribeContact の時刻と突き合わせられます。反映は発信からおよそ 2 日でした。

(2) 8 通話の明細

本稿で発信した全 8 通話です。TOTAL は発信から切断まで、TALK は接続から切断までの秒数です。

発信(JST) 内容 TOTAL TALK 音声利用料($0.038/分) 通話料($0.078/分) 合計
11/01 17:52 切断のみ、拒否ボタン 24 秒 0 秒 25 秒、$0.0158 1 分、$0.078 $0.094
11/01 18:09 切断のみ、放置 22 秒 0 秒 23 秒、$0.0146 1 分、$0.078 $0.093
11/01 18:18 切断のみ、3 秒で拒否 22 秒 0 秒 23 秒、$0.0146 1 分、$0.078 $0.093
11/02 02:05 5 秒の読み上げ 26 秒 5 秒 27 秒、$0.0171 1 分、$0.078 $0.095
11/02 02:48 切断のみ、別インスタンスの日本番号から 21 秒 0 秒 21 秒、$0.0063($0.018/分) 1 分、$0.078 $0.084
11/02 02:58 切断のみ 22 秒 0 秒 23 秒、$0.0146 1 分、$0.078 $0.093
11/02 03:25 45 秒の読み上げ 68 秒 47 秒 69 秒、$0.0437 1 分、$0.078 $0.122
11/02 03:58 留守電にメッセージ(3 回読み上げ) 53 秒 31 秒 54 秒、$0.0342 1 分、$0.078 $0.112

明細で分かったことは 3 つです。

  1. 音声利用料は秒単位で、呼び出し中も対象です。課金秒は TOTAL に 0〜1 秒を足した値で、留守電が応答するまでの約 20 秒も含まれています
  2. 通話料は接続後の時間を 1 分単位で切り上げです。8 通話すべてが 1 分で、TOTAL が 68 秒の通話も 1 分なので、基準は接続後(TALK 47 秒)の時間です。接続後 0 秒で切っても 1 分分かかります
  3. 音声利用料の単価はインスタンスで決まっているようでした。$0.038 の行は「Amazon Connect AI Voice Minutes」で料金ページの Connect Customer の単価、2020 年作成の既存インスタンスからの $0.018 は「End customer minutes used」で Customer Basic の単価にあたります。読み上げの有無は関係ありませんでした

米国番号の日額は 1 日 $0.06 で、1 時間ごとに 1/24 日が計上されます。料金ページで最初に見た $0.03 は米国リージョンの値で、東京リージョンで持つ米国番号は 2 倍でした。月に約 $1.8 で、通話が無くてもかかります。

(3) 試算

実測値で、運用ごとの費用を試算します。1 アラートを 1 人に通知する場合です。

運用 1 アラートあたりの通話 音声利用料 通話料 1 アラートの合計 月 100 件
出ない運用(切断だけ) 1 回。約 23 秒、接続後 0 秒 $0.015 $0.078(1 分) $0.093 約 $9.3
留守電にメッセージを残す(3 回読み上げ) 1 回。約 54 秒、接続後 31 秒 $0.034 $0.078(1 分) $0.112 約 $11.2
出て読み上げを聞く 1 回。接続後 60〜90 秒 $0.04〜0.06 $0.078〜0.156(1〜2 分) $0.12〜0.22 約 $12〜22
出てキー応答、無ければ再架電(上限 3 回) 最大 3 回。不在なら留守電が応答して毎回 1 分分 最大 $0.045 最大 $0.234(3 分) 最大 $0.28 約 $28

これに番号の日額が月約 $1.8、通話回数によらず加わります。着信先が複数なら通話の費用はその人数倍です。Lambda や SNS の費用は、電話に比べて無視できます。

出ない運用と留守電にメッセージを残す運用の差は、音声利用料の約 $0.02 だけです。費用で効くのは通話の回数と、接続後 60 秒を超えないことです。

8 結論

安全策は、切断だけのフローで電話に出ない運用です。フローの設定がほとんど無く、留守電を汚さず、費用は 1 通話 約 $0.093 です。その大半は、接続後 0 秒で切っても 1 分分かかる通話料です。

留守電に短いメッセージを残す運用は、1 通話あたり約 $0.02 の上乗せで成立します。着信の履歴だけでは分からないアラート名が留守電で分かるので、複数の Alarm を 1 つの番号で運用する場合には有効だと思います。ただし、接続後 60 秒を超えると通話料が 2 分分になるので、読み上げの長さには余裕が必要です。

課金される秒数は、scripts/contacts.sh で確認できます。直近の発信について、発信から接続までの秒数(RING)、接続から切断までの秒数(TALK)、その合計(TOTAL)を一覧にし、TALK が 60 秒を超えたものに目印を付けます。

$ ../scripts/contacts.sh
INITIATED            CONNECTED    DISCONNECTED   RING   TALK  TOTAL  REASON
2026-11-01 17:52:41 17:53:05     17:53:05         24      0     24  CONTACT_FLOW_DISCONNECT
2026-11-02 03:25:41 03:26:02     03:26:49         21     47     68  CONTACT_FLOW_DISCONNECT
2026-11-02 03:58:41 03:59:03     03:59:34         23     31     54  CONTACT_FLOW_DISCONNECT

運用に入れた後も、このスクリプトを定期的に実行して TALK を見ておけば、通話料が 2 分分になった発信があればすぐに分かります。

9 最後に

今回は、CloudWatch Alarm を Amazon Connect で携帯に電話通知する構成を CDK 一式で構築し、通話料が最小になる運用を実験で確かめてみました。

実務で意識しておきたい点を 3 つ挙げます。

  • 費用は通話の回数で決まります。出なくても接続は成立し、通話料は 1 分分かかるので、単価を下げる余地はほとんどありません。多発する前提では「1 回だけ鳴らす」を土台にして、確実さが必要な一部の Alarm だけ再架電の仕組みに乗せる二段構えが現実的だと思います
  • 読み上げを入れるなら、接続後 60 秒を超えないことを監視します。応答メッセージの長さが変われば、同じ読み上げでも 2 分分になり得ます
  • Connect の費用は、Cost Explorer の Connect フィルタだけでは足りません。通話料と番号の日額は別のサービスとして計上されるので、合わせて見る必要があります

当初は「出なければ無料」のつもりで始めましたが、留守電が応答する動きは、Connect 側の記録を読み上げ付きで切り分けるまで分かりませんでした。課金の内訳も、請求の明細を見るまで思い込みのままでした。想定で試算する前に、まず数回発信して請求の明細を見る、という順序の方が早かったと感じています。出ない運用か留守電にメッセージを残す運用を土台にした電話通知のたたき台になれば嬉しいです。

この記事で使用したコードは、以下に置きました。

GitHub: cloudwatch-alarm-amazon-connect-call

10 参考リンク

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事