Geometric pattern carved into white paper

現場のHome Assistantにセキュアにリモートアクセスする設計と手順

はじめに

IoTの施設管理をやっていると、「現場設置のHome Assistantに外からアクセスしたい」という場面が出てきます。

保守でアクセスしたい。お客さんにもダッシュボードを見せたい。でも、スマートロックなどにつながっているHome Assistantをインターネットに公開するのは怖い。

今回は、Cloudflare TunnelとZero Trustを使って、ポートを一切開けずに、認証付きでHome Assistantに外部アクセスできる構成を作ったので、その設計と手順をまとめます。

そもそも何が問題なのか

Home Assistantを外部からアクセスする方法はいくつかあります。

一番シンプルなのはルーターのポートフォワーディング。
8123番ポートを開けて、DuckDNSあたりでドメインを設定します。

これが定番で手軽ですが、ポートを開けた瞬間にボットのスキャン対象になります。
ログを見ると、数時間で不正アクセスの試行が記録されることも珍しくないです。

VPN(WireGuardやTailscale)を使う方法は安全性が高いのですが、アクセスする全員にVPNアプリのインストールと設定が必要になります。保守要員であれば問題ないですが、お客さまに「まずこのアプリを入れてください」とお願いするのは、正直ハードルが高い。

設計方針:経路を2つに分ける

考えた結果、こういう構成にしました。

保守用(自分達が使う)→ Cloudflare Tunnel + Zero Trust

こちらは保守時に自分達だけがアクセスする経路。ポート開放なし、IPアドレス非公開。アクセス時にCloudflare Zero Trustの認証(メールにワンタイムコードが届く方式)を通過しないとHome Assistantの画面にすら到達しない。

この2経路を完全に分離することで、お客さんには「URLだけ」のシンプルさを、保守側には「多層認証」のセキュリティを、それぞれ提供できます。

お客さま向け → Nabu Casa ※これは別記事予定

月額$6.5かかりますが、それを許容いただければお客様向けはNabu Casaで設定。
URLを共有するだけでアプリのインストールもVPN設定も不要。
Companion Appとの連携もネイティブで安定します。
(Nabu CasaはHome Assistantの開発をしているので、支援にもなります)

全体のアーキテクチャ

構成を図にするとこんな感じです。

【施設内】
  Home Assistant OS (Raspberry Pi)
    ├── Nabu Casa アドオン ─→ Nabu Casa Cloud ─→ お客さま
    └── Cloudflared アドオン ─→ Cloudflare Tunnel
                                    ↓
                              Zero Trust 認証(メールOTP)
                                    ↓
                              HA ログイン画面 ─→ 保守担当者

ポイントは、どちらの経路もルーターのポートを開けていないこと。Nabu CasaもCloudflare Tunnelも、デバイス側からクラウドに向けてアウトバウンド接続を張るので、インバウンドのポート開放が不要です。外部からスキャンしても何も見えない。

認証の仕組み

Cloudflare Tunnel単体だと「ポートを開けない安全なトンネル」ですが、URLを知っていれば誰でもHome Assistantのログイン画面にたどり着けてしまいます。

ここにCloudflare Zero Trustの認証レイヤーを被せます。

認証フロー

  1. ブラウザで https://ha-xxxxx.example.net にアクセス
  2. Cloudflare Accessの認証画面が表示される(HAの画面ではない)
  3. メールアドレスを入力
  4. 許可されたメールアドレスであれば、ワンタイムPINがメールに届く
  5. PINを入力して認証通過
  6. ここでやっとHome Assistantのログイン画面に到達
  7. HAのユーザー名・パスワードでログイン

つまり、認証が2層になっています。
Cloudflare側で「誰がアクセスできるか」を制御し、HA側でログインを制御する。
URLが漏洩しても、登録されていないメールアドレスではワンタイムPINすら届きません。

さらに強化するなら

Zero Trustの認証方式はメールOTPだけではなく、以下のような段階的な強化が可能です。

Google / GitHub などのIdP連携: メールOTPの代わりに、Googleアカウントでログインさせる。Googleアカウント側で二要素認証(Google Authenticator等)を設定しておけば、実質的にTOTP認証になる。

mTLS(クライアント証明書): 特定の証明書がインストールされた端末でしか接続できなくする。証明書を持っていない端末からは、認証画面にすら到達しない。保守用端末が限られている場合に有効。

国別制限: Zero Trustのポリシーで「日本からのアクセスのみ許可」といったジオブロッキングも設定可能。

最初はメールOTPで始めて、人数が増えたら運用しながら段階的に強化していくのがよさそうです。

ドメイン設計のポイント

保守用のサブドメインは推測されにくくする工夫が必要です。

# 悪い例(施設名が推測できる)
ryokan-kusatsu.example.net
hotel-tokyo.example.net

# 良い例(ランダム文字列 + 内部台帳で管理)
ha-c4f2e8.example.net
ha-9a3b7d.example.net

ただし、サブドメインの秘匿はあくまで補助的な防御で本質的なセキュリティではありません。
ログインURLがバレてもZero Trustの認証壁があるので問題ない、という設計が正しい。

さらに、ワイルドカードDNSレコード(*.example.net)を設定しないことで、サブドメインの総当たりスキャンに対してもDNS応答を返さない構成にできます。

セットアップ手順

詳細な手順は環境によって異なりますが、大まかな流れは以下の通りです。

1. ドメインのネームサーバーをCloudflareに向ける(初回のみ)

使用するドメインのNSレコードを、ドメインレジストラの管理画面でCloudflare指定のネームサーバーに変更します。反映には数時間〜24時間程度かかります。

Cloudflareダッシュボード( https://dash.cloudflare.com )にログイン

  • 左上の「+ 追加」> 「ドメインを接続する」をクリック
  • ドメイン名に管理画面用に使用予定のドメインを入力
  • プランは「Free」を選択
  • Cloudflareが既存のDNSレコードをスキャンしますが、未使用であれば何もないはず
    そのまま「アクティベーションに進む
  • レコードを後で追加する、とポップアップが出たら「確認」を選択
  • ネームサーバーが2つ表示される(例:xxx.ns.cloudflare.comyyy.ns.cloudflare.com
  • ドメインレジストラの管理画面で、ネームサーバーを上記2つに変更する
    (私の場合はXServerなのでこんな画面でした)

2. HAOSにCloudflaredアプリをインストール

Home Assistantのアドオンストアにサードパーティリポジトリ(https://github.com/brenner-tobias/ha-addons)を追加し、Cloudflaredアドオンをインストールします。

  • 左メニュー「設定」→「アプリ」→ 右下の「アプリをインストール
  • 右上の「⋮」→「リポジトリ」をクリック
  • 右下の「+add」→以下のURLを追加:
    https://github.com/brenner-tobias/ha-addons
  • 左上の「←」でアプリの画面へ戻る
  • 「Cloudflared」 を見つけてクリック → 「インストール」
    ※「開始」 はまだ押さない
インストール後の画面

3. Cloudflare Zero Trustでトンネルを作成

Cloudflare Zero Trust ダッシュボード(https://one.dash.cloudflare.com/)でトンネルを作成し、発行されたトークンをHAOSのCloudflaredアドオンの「Cloudflare Tunnel Token」欄に貼り付けます。

  1. Cloudflare Zero Trust ダッシュボード( https://dash.cloudflare.com/one/ )にアクセス
  2. チーム名を選択してください と聞かれたら任意のチーム名を入力して「次へ」
  3. 左メニュー「ネットワーク」→「コネクタ」をクリック
  4. トンネルを作成」をクリック
  5. トンネルタイプは「Cloudflared」を選択
  6. トンネル名を入力:hatest など、(検証用なので仮の名前でOK)
  7. 次の画面で トンネルトークン(長い文字列)が表示されます
    (オペレーティングシステムを選択する はどれでも良いので
     下に表示されるトンネルトークンをコピーしておく)

このトークンをコピーしてください。下の画面だとeyJ... で始まる、見切れている長い文字列です。

コネクタをインストールして実行する の画面
  1. ウィザードを「次へ」を押して「トンネルのルーティング」設定画面まで進めておく

4. HAOSのCloudflaredアドオンにトークンを設定

  1. HAOSのCloudflaredアドオンの画面に戻る
  2. 上部の「構成」タブをクリック
  3. 「未使用の設定オプションを表示する」をON
  4. 設定項目の中に「Tunnel Token」(またはそれに類する入力欄)がある
  5. コピーしたトークンを貼り付け
    ※他の欄はすべて空欄のまま・デフォルトのままでOKです
  6. 保存

5. Public Hostnameを設定

Cloudflare側のトンネルの設定画面に戻り、以下を入力してください

ホスト名

Subdomain:ha-test01 など

ドメイン:ドロップダウンから登録済みのドメインを選択

※Path は空欄のまま(サンプルの薄字は無視してOK)

サービス

タイプ:HTTP

URL:homeassistant:8123

入力したら「ホスト名を保存」をクリック

6. HAOSの configuration.yaml を編集

Cloudflare経由のリクエストを受け付けるために、http セクションを追加します。

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 172.30.33.0/24

※もし既に http: セクションがある場合は、その中に use_x_forwarded_fortrusted_proxies を追加してください。重複して http: を書かないように注意。

保存したら、HAを再起動してください(「設定」→「システム」→ 右上「」→「再起動」)。

再起動後に

https://[手順5で設定したSubdomain].[手順5で設定したドメイン]

にアクセスしてみてください。HAのログイン画面が出るはずです!

続いて、セキュリティの設定です

7. Zero Trustのアクセスポリシーを設定

  • Cloudflare Zero Trustダッシュボード( https://one.dash.cloudflare.com/ )を開く
  • 左メニュー「Access コントロール」→「アプリケーション
  • アプリケーションを追加する」をクリック
  • セルフホスト」を選択

次の画面で以下を入力(例)

Application name:HA Maintenance

Session Duration:24 hours

「+パブリックホスト名を追加」を押して

入力方法:デフォルト
サブドメイン:手順5と同じもの

ドメイン:手順5と同じもの

パス:(空欄のまま)

「ポリシーを追加する」を押すとポリシー設定画面に進みます。そこで:

Policy name:任意(〇〇onlyなど)

Action:Allow

Include → セレクタ:Emails

Value:自身の認証用メールアドレス

ポリシーを作ったら、

Access ポリシー>既存のポリシーを選択 から、先ほど作ったPolicy nameを選択

エクスペリエンス設定、詳細設定(オプション)は何もいじらず「次へ」で
アプリケーション追加を完了


8. 動作確認

シークレットウィンドウ(プライベートブラウズ)で設定したURLにアクセス。
Cloudflare Accessの認証画面が表示されて、メールアドレス入力 → ワンタイムPIN → HAログイン画面、という流れが確認できれば完了です。

施設を増やすとき

この構成の良いところは、施設が増えてもスケールしやすいことです。

新しい施設を追加する場合は、その施設のHAOSにCloudflaredアドオンをインストールし、トンネルの設定でPublic Hostnameを追加するだけ。Zero TrustのAccessポリシーはワイルドカード(*.example.net)で設定しておけば、1つのポリシーで全施設をカバーできます。

Accessポリシーのワイルドカード設定手順(1回だけ)

2施設目以降のサブドメインにもZero Trust認証を自動適用するには、Accessアプリケーションのホスト名をワイルドカードに変更しておきます。

  1. Zero Trustダッシュボード →「Access コントロール」→「アプリケーション」
  2. 1施設目で作ったアプリケーション(例:HA Maintenance)を編集
  3. パブリックホスト名のサブドメインを *(アスタリスク)に変更
  4. 保存

これで *.example.net のすべてのサブドメインに対して、同じ認証ポリシーが適用されます。施設ごとにAccessアプリケーションを作る必要はありません。

施設追加のまとめ

1施設追加するのにやることは、実質的に以下の5つだけです。

  1. サブドメイン名を決めて台帳に記録
  2. 施設のHAOSにCloudflaredアドオンをインストール
  3. Cloudflareでトンネル作成 → トークン取得
  4. Public Hostname設定(サブドメイン + ドメイン + URL)
  5. HAOSにトークンを貼って起動

まとめ

今回の構成のポイントをまとめると:

  • ポート開放ゼロ: Nabu CasaもCloudflare Tunnelもアウトバウンド接続なので、ルーターの設定は一切不要
  • 経路の分離: お客さまには簡単なNabu Casa、保守には堅いCloudflare Tunnel + Zero Trust
  • 認証の多層化: URLの秘匿 + Zero Trust認証 + HAログインの3層構造
  • スケーラビリティ: ドメイン1つで施設を横展開可能
  • 段階的な強化: メールOTP → IdP連携 → mTLS と、必要に応じてセキュリティレベルを上げられる

どなたかの参考になれば嬉しいです☺️

No comments yet