Asteriskセットアップのポイント

Asteriskはもっとも有名なオープンソースVoIPサーバーです。
SIPソフトフォンによる内線ネットワークをコアとして、電話網(PSTNゲートウェイ)との統合やCTIにも拡張可能な機能を持ちます。

理解しておいた方が良いポイント

Asteriskそのもののセットアップに入る前に、構築プロジェクトを次のようにフェーズ分けして段階的に構築することが有効です。

  1. ブルートフォース対策の完備。SIPポートを公開すると攻撃される
  2. 基礎的な内線通話接続の確保。NAT適応を完備して初めてつながる
  3. 拡張機能の追加

SIPクライアントはスマートフォンのアプリを利用できるため、インターネットに接続できる環境のどこでも利用できるSIPネットワークを構築することは可能です。
ただしその場合、AsteriskなどのSIPエンドポイントがインターネットからアクセスできる構成が前提となります。

SIPホストへの攻撃は活発であり、適切に防御するにはIPベースのファイアーウォールが必要になるでしょう。
これには例えば、fail2banを適切に導入できれば有効に対策できます。

ウェルノウンポート5060を避ける、パスワードを長大化するなどの緩和策もありますが、試行を制限しない限り攻撃は抑止できません。

または、利用する内部ネットワークをすべてVPN接続することでインターネットにSIPネットワークを公開しない構成もとれます。
ただし、VPNじたいの難点や使いにくさを伴う点がトレードオフです。

ビルドとコンテナ

Asteriskじたいは活発にメンテナンスが継続しているのですが、Debianのメンテナ不足によりbookworm(June 2023)からDebian系のパッケージが除去されました。
みずからビルドするか何らかの代替パッケージを利用する必要があります。

Dockerコンテナ向けのイメージについては、 andrius/asteriskのビルドスクリプトがよく考えられています。
ボイスメール管理機能などが音声ファイルを必要とするため、追加で asterisk-core-sounds-en-wavパッケージなどをインストールしておき、$astdatadir/sounds/enにリンクすると流用できます。

ただしコンテナ環境については、別の制約があります。
ひとつはiptablesが非互換である可能性が高いことです。fail2banなど既存のセキュリティ実装はiptablesを前提としているため、ファイアーウォール構築に別の手段が必要になります。
たとえばkubernetesクラスタの場合、 NetworkPolicyが有望です。

また、デバイスファイルへのアクセスに制限があることにより、音声制御に制約が出るケースがあります。
各SIPクライアントがサポートする codecが多様であるため、Asteriskにはcodecを変換する機能があるのですが、そのデーモンが起動しない挙動になります。
起動ログにエラー出力する一方、機能が欠けたまま動作を継続します。

codecのトランスコーダーが欠けている構成では、両端のクライアントがサポートしているcodecを選択した場合のみ適切に動作します。
サポートしていないcodecの音声データが流れてくると、接続が切れるか無音になります。「接続はするが音が流れない」という挙動は他の原因によっても起きるため、切り分けの難易度が上がります。
この事象は、サポートするcodecを狭く限定することで回避できる場合があります。

Asteriskのconfig

SIPネットワークの構築は、基本的にはAsteriskのconfigに集約しており、適切に設定すれば動作します。
ただし適切さを確保することは単純ではありません。次のようなアプローチで情報収集することが有効です。

  • 公式ドキュメントを理解する
    • これはある意味当然ではあるのですが、おそらくオーソドックスな静的サイトではないため検索エンジンの結果にほぼリストされておらず全く注目されていません
    • また、ページ間リンクが非表示の左ナビ内に集約されており、関連情報が豊富に存在していることに気づけません。各ページで左ナビを開いて確認することが重要です
  • configのsampleを参考にする
    • Asteriskのconfigは、モジュールごとの設定ファイルの集合で構成されており複雑です。おそらくこのsampleがもっとも完備したリファレンスです
    • 文法は簡素なTOMLです。再利用のための Templateは理解しておいた方が良いでしょう
  • SIPネットワークの理解を深める
    • Asteriskの複雑さは、SIPネットワークそのものの複雑さに由来しています。けっきょくのところ、SIP技術を理解せずにAsteriskを運用することは現実的ではないでしょう
    • 基礎的なSIP構築に必要なコア要素は、SIP, RTP, ICEです

古い情報に頼らないことも重要です。
Asteriskの長い歴史のなかで、コアのSIP機能をchan_sip -> chan_pjsipへ移行した経緯があり、2023年リリースのv21.0でchan_sipは削除されました。

現在は pjsip.confが主要なconfigの1つになっています。
今となってはsip.confは使われていないため、似て非なる古い情報を設定に活かすことは難しいでしょう。

なお、 ダイヤルプランの設定は別記事で解説しています。

デバッグログ

ネットワークエンジニアリングの難点は因果関係を直接把握しにくいことです。
Asteriskも通話セッションが開始し、音声データが流れるまで、原因不明に見えるトラブルが続きます。

ログ類も因果関係を示すものは乏しいのですが、それでもログがなければ推測することもより難しくなります。
最初のSIP通話確立までにもっとも役立つのはSDPを含むSIPログです。

asterisk -rでTUIの対話ツールが起動し、pjsip set logger onを実行するとログ出力モードが切り替わります。 logger onの状態でSIP接続を実行すると、SIPメッセージがコンソールに流れます。ツールはquitコマンドで終了します。

ログから直接読みとれるケースはほぼないのですが、よくある原因には次のようなものがあります。

  • Asteriskサーバー側のルーティング不備により、リクエストが全く到達していない。TCP/UDPの取り違えなど
  • プライベートネットワークを優先する挙動をとり、メッセージが適切に到達しない
  • クライアント側のルーターがパケットを破棄している
  • codecの選択が不調でセッション継続をあきらめる
  • 特定のセキュリティ通信方式を強制するリクエストを満たす設定になっておらず、セッション継続をあきらめる
  • 起動時に必要なモジュールがロードされていない。または、そもそもビルドから除外されている

このように、メッセージが到達していないことも大きなヒントになるため、構築時にはAsteriskだけでなくクライアントもすべてのSIPログを出力できるツールを利用した方が相対的にスムーズです。

また、次のようにエラーに見えるもののエラーの原因ではないログも含まれ、混乱に拍車をかけます。

  • プライベートIPはパケット不達と関係あるが、SDPにはプライベートIPが表示されていても動作することもある。ICEで解決される
  • 401 Unauthorizedは正常動作のプロセスであることも多い

SIPの体系を網羅的に理解するまで、挙動を理解することは難しいと言えます。

その他のCLIコマンド

ログ以外にも、asteriskコマンドからインタラクティブに状況分析できるサブコマンドがあります。
たとえばSIPクライアントの接続状況はshow endpoints、SIPメッセージの履歴はshow historyで表示できます。

asterisk*CLI> pjsip show endpoints
asterisk*CLI> pjsip set history on
asterisk*CLI> pjsip show history
asterisk*CLI> pjsip show history entry 1

history分析で一番分かりづらく、かつよく遭遇するケースが無応答のケースです。リクエストメッセージだけ記録されていていてエラーレスポンスがない点に注意する必要があります。
無応答は、NATによるIP変換の影響、ファイアーウォールによるフィルタのほか、接続先サービスが認証エラーの際リクエストをドロップするケースもあります。

この場合、まずはレスポンスを得られる状況になるまでネットワーク構成や接続設定を修正する必要があるでしょう。

pjsip.confのポイント

pjsip.confは、AsteriskのSIPサービスを定義するtransportとSIPクライアントなどの接続情報を定義するendpoint系のブロックを主に設定します。
公式ガイドに 各セクションの役割の解説があります。

transportブロックの例

transportは、より複雑なsipsのケースで次のような記述になるでしょう。

[transport-tls]
type = transport
protocol = tls
bind = 0.0.0.0:5061
; 外部からアクセス可能なアドレス設定が不可欠
external_media_address=203.0.113.1
external_signaling_address=203.0.113.1
local_net = 192.168.0.0/255.255.255.0
; cert_fileとpriv_key_fileはセットで指定する
cert_file = /etc/asterisk/cert.pem
priv_key_file = /etc/asterisk/privkey.pem
; ほかに tlsv1 | sslv23 を指定できる。enumリストは不明
method = tlsv1_2

TLS証明書が、自己署名方式で作成したファイルを用いて動作するか否かは接続クライアントの設定によります。
接続先の検証を度外視するならとくに問題なく動作するでしょう。通信の暗号化は機能するため、それで足りるとする運用はあり得ます。

transport設定のうち、分かりづらいポイントとしてlocal_netは挙動に大きな影響があります。
これは内部IPを除外するための設定で、Asteriskホストのローカルネットワークを適切に指定します。

local_netを指定しなくてもクライアント間の接続はエラーなく完了するのですが、音声パケットが届かず音が出ない挙動になることがあります。
これはINVITEされた側に届くSDPにAsteriskサーバーの内部IPを案内する挙動から生じるため、着信クライアントのSDPログを念入りに確認すると切り分けられます。

UDPベースのRTPはパケット不達が起きても異常と見なさず、単に無音になります。
エラーが出ない分、原因特定の難易度は上がります。

endpointブロックの例

クライアント側のendpointは、aor, authとセットで指定するという構造がまず理解しづらい点でしょう。 authは認証情報、aor(Address of Record)は着信ルーティングの検索に用いるアドレスです。
endpointにはブロックの参照関係とSIPのオプションを指定します。

[101]
type = endpoint
context = default
auth = 101
outbound_auth = 101
aors = 101
; codecの指定は必要
allow = g729,ulaw,alaw,ilbc
; NATを意識する構成は事実上不可欠
direct_media = no
ice_support = yes
rewrite_contact = yes
rtp_symmetric = yes
force_rport = yes

NATのオプション群は構成に応じて適切に指定する必要があります。
LAN内に限定したSIPネットワークでない限り、NATのための追加設定は不可欠と言えます。
多くの場合、ICEのうちSTUNはおそらく必須、よりセキュアなルーター(Symmetric NAT)を導入している場合にはTURNを併用する必要がある、という概況でしょう。

また、分かりづらいポイントとして、codecリストを的確に指定することが必要です。
codecを何も指定していない場合、SIP呼び出し時に488 Not Acceptable Hereエラーが返ります。より一般的には、SIPクライアントがINVITEリクエストで提案したcodecリストと適合しなければ488エラーです。
このエラーは関連情報をログ出力しないため、適合するcodec候補がなかった状況を示している可能性を示唆していることに気づくのは困難でしょう。
なお、呼び出し先にルーティングできなかった場合のエラーコードは404 Not Foundです。

既述のとおり、ピア間のcodecが一致しない場合、Asteriskはトランスコードしようとしますが、コンテナ環境では動作していない場合があります。この場合は無音です。

SIPトランキングの設定

SIPトランキングとの接続は、各サービス事業者の仕様に合わせる必要があります。
REGISTERが必要なサービスではtype = registrationの設定を追加する必要があります。INVITEでコール時に接続するサービスの場合、endpoint.outbound_proxyに接続先ホストを指定します。

ユーザー認証が必要な場合、構成に合わせてregistraion.outbound_authまたはendpoint.outbound_authauth設定を指定します。

Asteriskへの着信時のユーザー認証設定はendpoint.authに指定できます。また着信IP制限は、identity.matchに実装できます。ドキュメントには記載がないものの、IPはカンマ区切りでリスト指定できます。

接続設定と別に、outbound_proxyaor.contactは発信時SIPメッセージのRequest-URIToヘッダーを書きかえる作用があります。
サービスによってはSIPメッセージの各フィールドに期待するURIが定まっている場合があり、ローカルネットワークが記載された素朴なリクエストを送ると拒否します。

リクエスト送信IPが適切であるにも関わらず無応答であったり403FORBIDDENを受け取る場合には、SIPリクエストの妥当性を確認し、妥当なメッセージを生成するような設定に変更することが有効でしょう。

TLSとSRTPの設定

TLSやSRTPによる暗号化については、対応を強制する設定の方が当然セキュアです。非TLSや非SRTPにフォールバックする設定を排除すると、機能を持たないクライアントは接続できなくなります。

SIPのTLS保護については、先ほどのconfigのとおりTLS設定のtransportを作成し、それを利用します。
SRTPはendpointにmedia_encryptionの設定を追加します。

[101]
type = endpoint

media_encryption = sdes

;media_encryption_optimistic=no ; Use encryption if possible but don't fail the call
                                ; if not possible.

オプションが直感的ではないのですが、SRTPの指定はsdesです。デフォルトがnoであることから考えてyesを指定するとParse Errorになるでしょう。
SRTPは設定項目が少なく想定外の影響を受ける余地があまりありません。動作しない場合、モジュールをロードできていない可能性が考えられます。

モジュールのロード状況を知る手段はないため、コンソールからmodule load res_srtp.soコマンドを実行すると改めてロードし、問題があれば再現するでしょう。
モジュールを適切にロードできていた状況ならalready loaded and runningというWARNINGが出ます。

公式ガイドにも 暗号化の解説があります。

rtp.confのポイント

rtp.confの設定じたいは比較的簡素なのですが、RTPは適切に動作しないことが多く、また多くの場合エラーログも出ません。
RTPの構成に不備がある場合、音が出ません。

[general]
;
; RTP start and RTP end configure start and end addresses
;
; Defaults are rtpstart=5000 and rtpend=31000
;
rtpstart=10000
rtpend=20000

; Hostname or address for the STUN server used when determining the external
; IP address and port an RTP session can be reached at. The port number is
; optional. If omitted the default value of 3478 will be used. This option is
; disabled by default. Name resolution will occur at load time, and if DNS is
; used, name resolution will occur repeatedly after the TTL expires.

stunaddr=stun.l.google.com:19302

; Hostname or address for the TURN server to be used as a relay. The port
; number is optional. If omitted the default value of 3478 will be used.
; This option is disabled by default.
;
; e.g. turnaddr=myturn.server.com:34780
;
; turnaddr=
;
; Username used to authenticate with TURN relay server.
; turnusername=
;
; Password used to authenticate with TURN relay server.
; turnpassword=

構成上のポイントは、rtpstartrtpendの範囲のポートに適切にUDPアクセスできるようルーティングを完備しておくことです。
サーバーのIPにパケットを送信しない挙動が起きやすく、そのうえポートが閉じていたとすると切り分けできなくなるでしょう。

STUNについては、多くの場合必須であると考えられます。
TURNはまず、設置しているルーターの種類から必要か否かを決めます。TURNがなくても動作するネットワーク構成も多くあるでしょう。そして、必要なのであれば別途構築します。STUN/TURNサーバーはいずれもAsteriskは機能を提供していません。

音が出ない事象は、クライアントの不備やcodec選択の不備も含まれるため確認すべき範囲は広いのですが、サーバー側の問題はSTUN/TURNを含むICEの設定不良が主要因でしょう。
ICEについては、rtp.confよりもpjsip.confの項目の方が意図せず誤設定になる可能性が高いように思えます。

⁋ 2023/12/06↻ 2024/11/07
中馬崇尋
Chuma Takahiro