クラスターセキュリティ
EMQX は、データの機密性、完全性、および可用性を確保するために、ノードレベルでの認証および認可機構、クラスター内のノード間通信の安全性を保証するシークレットクッキー、およびノード間トラフィックのエンドツーエンド暗号化を提供するTLS/SSL暗号化など、複数のセキュリティ機構を備えています。
また、ファイアウォールルールのプロビジョニングを支援するために、EMQXのブローカー間通信ポートマッピングルールについても説明します。
ノードクッキーの設定
セキュリティ上の理由から、クラスターに参加するすべてのノードの emqx.conf でデフォルトのクッキー設定をシークレットクッキーに変更する必要があります。
注意:クラスターに参加するすべてのノードは同じシークレットクッキーを使用する必要があります。使用されるマジッククッキーの詳細については、Distributed Erlang - Security を参照してください。
node {
cookie = "<シークレットクッキー>"
}ヒント
クラスターに参加するすべてのノードは同じセキュリティクッキーを使用する必要があります。使用されるマジッククッキーの詳細については、Distributed Erlang - Security を参照してください。
クラスター接続を保護するための TLS/SSL の設定
EMQX は、ノード間の通信チャネルをTLSで保護し、交換されるデータの機密性、完全性、および真正性を守ることもサポートしています。TLSはCPU負荷やメモリ使用量の増加を伴うため、ビジネスニーズに応じて設定してください。
本節では、EMQXクラスターでTLSを設定する方法を紹介します。SSL/TLS証明書の取得方法については、SSL/TLS証明書をご参照ください。
クラスターRPC接続にTLS/SSLを使用する
クラスターRPCにTLS/SSLを設定するには、以下の設定項目を emqx.conf に設定します。
rpc {
driver = ssl
# リスナーがクラスターのピアの真正性を検証するために使用する信頼されたCA(認証局)証明書を含むPEM形式ファイル
cacertfile = "/path/to/cert/ca.pem"
# リスナーのSSL/TLS証明書チェーンを含むPEM形式ファイル。証明書がルートCAから直接発行されていない場合、中間CA証明書をリスナー証明書の後に連結してチェーンを形成する必要があります。
certfile = "/path/to/cert/domain.pem"
# SSL/TLS証明書に対応する秘密鍵を含むPEM形式ファイル
keyfile = "/path/to/cert/domain.key"
# クライアント証明書の真正性を検証する場合は 'verify_peer'、そうでなければ 'verify_none' に設定
verify = verify_peer
# trueに設定すると、ピアが証明書を送信しない(空の証明書を送信する)場合にハンドシェイクが失敗します。falseの場合は、無効な証明書を送信した場合のみ失敗します(空の証明書は有効とみなされます)。
fail_if_no_peer_cert = true
}Erlang Distribution にTLS/SSLを使用する
EMQXコアノードは、データベースの更新同期やノード管理(コンポーネントの起動/停止、ランタイムメトリクスの収集など)にErlang Distributionを使用しています。
etc/ssl_dist.confファイルに正しい鍵と証明書のパスが設定されていることを確認してください。- 設定
cluster.proto_distがinet_tlsに設定されていることを確認してください。
ポートマッピング
クラスター間のポートを内部に限定し、ファイアウォールルール(例: AWSセキュリティグループ や iptables)で制御することは良いプラクティスです。クラスターノード間にファイアウォールがある場合、他のノードが到達できるように従来のリスニングポートを許可する必要があります。本節では、ファイアウォールルールが正しく設定され、EMQXノードが相互に接続できる一方で外部からの不正アクセスを防止するためのポートマッピングルールを紹介します。
EMQXは、クラスター通信の信頼性と効率性を確保するためにポートマッピングルールを使用しています。EMQXノードは、Erlang DistributionポートとクラスターRPCポートという2つの異なるチャネルで通信します。
| チャネル | 説明 | デフォルトポート |
|---|---|---|
| Erlang Distribution ポート | ノード間通信に使用 | 4370 |
| クラスターRPCポート | ノードの管理タスク(ノードの参加や離脱など)に使用 | 5370 またはDocker展開時は 5369 |
EMQXはErlang DistributionポートとクラスターRPCポートに同じポートマッピングルールを適用します。
ListeningPort = BasePort + Offsetオフセットはノード名の数値サフィックスに基づいて計算されます。ノード名に数値サフィックスがない場合はオフセットは0に設定されます。例:
- ノード
emqx@192.168.0.12は数値サフィックスがないため、Erlang Distributionポートは4370(クラスターRPCポートは5370)になります。 - ノード
emqx1@192.168.0.12は数値サフィックスが1のため、ポートは4371(クラスターRPCポートは5371)になります。
ルールエンジンポリシーとファイアウォールルールによるSSRFの軽減
EMQXのコネクター、ブリッジ、およびアクションは外部サービスへのアウトバウンドネットワーク接続を開きます。制御がなければ、誤設定や悪意のあるターゲットにより、EMQXが内部や機密性の高い宛先に意図しないリクエストを送信する可能性があり、これはServer-Side Request Forgery(SSRF)と呼ばれる脆弱性の一種です。EMQXは、構成時にターゲットを検証する組み込みのルールエンジンSSRFポリシーと、実行時にネットワーク境界を強制するホストレベルのイグレスフィルタリングという2つの補完的な防御策を提供します。
最初の防御ラインとしての rule_engine.ssrf の利用
EMQX 6.0.3、6.1.2、6.2.1以降、EMQXはコネクター、ブリッジ、アクションなどのアウトバウンドルールエンジンターゲットに対してクラスター単位のSSRFポリシーを提供しています。
rule_engine {
ssrf {
enable = true
allow_cidrs = []
deny_cidrs = [
"127.0.0.0/8",
"::1/128",
"169.254.0.0/16",
"fe80::/10",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"fc00::/7",
"0.0.0.0/32",
"224.0.0.0/4",
"ff00::/8",
"100.100.100.200/32",
"169.254.169.253/32"
]
deny_hosts = [
"metadata.tencentyun.com",
"metadata.google.internal",
"metadata.azure.internal"
]
}
}有効にすると、EMQXは構成更新時にアウトバウンドターゲットを検証します。deny_hosts に完全一致する場合は即座に拒否されます。解決されたIPはまず allow_cidrs と照合され、一致しなければ deny_cidrs と照合されます。
このポリシーは互換性のためデフォルトで無効です。コネクターやアクションが内部サービスにアクセスする必要がない限り、すべてのデプロイメントで有効化してください。その場合は、有効化前に allow_cidrs と deny_cidrs を見直し、調整してください。
rule_engine.ssrf のみで十分な場合
以下の条件すべてが満たされる場合、rule_engine.ssrf のみで通常は十分です。
- 信頼できる管理者のみがコネクター、ブリッジ、アクションを作成または更新できる。
- アウトバウンドターゲットは固定されたSaaSエンドポイントや明示的に承認された公開サービスなど、安定して予測可能である。
- 主に設定更新時の誤設定や明らかなSSRFターゲットを防止したい。
- 後で異なるアドレスに再バインドされる可能性のあるDNS名に依存していない。
ファイアウォールルールも追加すべき場合
以下のいずれかに該当する場合は、iptables、nftables、クラウドセキュリティグループ、Kubernetesネットワークポリシーなどによるホストレベルのイグレスフィルタリングを追加してください。
- 委任された管理者がネームスペーススコープのリソースを設定できる。
- EMQXが設定時の検証を通過したターゲットであっても、内部サービス、メタデータエンドポイント、管理ネットワークに到達できてはならない。
- DNS再バインディングや検証後のアドレス変更が脅威モデルに含まれる。
- マルチテナント、高リスク、または実行時に厳格なアウトバウンドネットワーク境界を強制する必要がある。
イグレス制限を計画する際は:
- IDプロバイダー、Webhook、コネクターバックエンドなど、デプロイメントに必要な宛先のみを許可する。
- ループバック、リンクローカル、インスタンスメタデータエンドポイントなど、SSRF攻撃で一般的に悪用される機密性の高いアドレスへのアクセスは、デプロイメントで明示的に必要としない限り拒否する。特に以下のメタデータエンドポイントのブロックを検討してください:
- Alibaba Cloudメタデータサービス用の
100.100.100.200 - AWS外部メタデータサービス用の
169.254.169.253 - AWSおよびAzureメタデータサービス用の
169.254.169.254 - AWS IPv6メタデータサービス用の
fd00:ec2::254
- Alibaba Cloudメタデータサービス用の
- EC2上のAWSベースのコネクターやアクションで、アクセスキーIDやシークレットアクセスキーを省略してインスタンスメタデータサービスから認証情報を取得する場合、
169.254.169.254をブロックしないでください。これはAmazon MSK IAMだけでなく、S3、S3 Tables、DynamoDB、Kinesisなどの統合にも該当します。同様の例外をiptablesやnftablesのルールにも反映させてください。 - 本番環境に適用する前にステージング環境でルールを慎重に検証してください。
- EMQXがコンテナやKubernetesで動作している場合は、コンテナホストのファイアウォール、クラウドセキュリティグループ、Kubernetesネットワークポリシーなどで同等のイグレス制御を適用してください。
rule_engine.ssrf はこれらのネットワーク層の制御に代わるものではありません。SSRFポリシーは構成作成または更新時にのみターゲットを検証します。DNS再バインディングや検証後に解決されたアドレスが変更される場合などの保護には、実行時のネットワーク制御が引き続き必要です。
以下の iptables の例は一般的なアプローチを示しています。インターフェース名、ポート、宛先アドレスは環境に合わせて調整してください。ホストに iptables がない場合は、同等のルールを nftables で適用してください。
# 確立済みのアウトバウンド接続を許可
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# ホストが必要とする場合はDNSとNTPを許可
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
# 承認された外部サービスへのアクセスのみ許可
iptables -A OUTPUT -p tcp -d 198.51.100.10 --dport 443 -j ACCEPT
iptables -A OUTPUT -p tcp -d 203.0.113.20 --dport 443 -j ACCEPT
# 一般的なメタデータおよびローカル専用宛先をブロック
iptables -A OUTPUT -d 127.0.0.0/8 -j REJECT
# EC2上のAWSベースのコネクターやアクションがインスタンスメタデータサービスから認証情報を取得する場合は、
# 169.254.169.254 への一括拒否を適用しないでください。代わりにより具体的な許可ルールを追加してください。
iptables -A OUTPUT -d 169.254.0.0/16 -j REJECT
iptables -A OUTPUT -d 100.100.100.200 -j REJECT
ip6tables -A OUTPUT -d fd00:ec2::254 -j REJECT
# その他の新規アウトバウンド接続はデフォルトで拒否
iptables -A OUTPUT -m conntrack --ctstate NEW -j REJECTホストが iptables ではなく nftables を使用している場合は、同様のポリシーを実装してください。100.100.100.200、169.254.169.253、169.254.169.254、fd00:ec2::254 などの既知のメタデータエンドポイントに対する明示的な拒否も含めてください。EC2上のAWSベースのコネクターやアクションがインスタンスメタデータサービスから認証情報を取得する場合は、169.254.169.254 へのアクセスが可能な状態にしてください。