この記事はCloudflare Advent Calendar 2024 4日目の記事です🎅
ABEMAの黒崎(@kuro_m88)です。今回はCloudflare Zero Trustの新しいSSHについて紹介します。

Cloudflare Zero Trustは2年ほど前に当時の所属部署で導入し、非常に便利だったため個人でも自宅サーバの管理等に利用しています。
ABEMAでも導入の可能性を検証しており、ちょうどその時に新しいSSHの発表を知ったため触ってみました。

Cloudflare Zero Trustを利用して開発環境への安全なアクセス方法を構築する

CloudflareでSSHをするメリットとは

SSHはSecure SHellの略であるようにセキュアであることは名前からして自明です。なぜCloudflareを使うのでしょうか?
業務上利用するSSHサーバをインターネットに公開して問題があるかで言えばただちに問題があるわけではないとは思いますが、インターネットにサーバを公開すると絶えず不審なログインの試行や脆弱性のスキャンに晒されるリスクが発生します。DoS攻撃を受けてしまうとアクセスできなくなったりそのサーバが提供している機能が停止する可能性があります。業務で利用するサーバは複数人で利用することが多いため、アカウント管理や棚卸しも行う必要が出てきます。
SSHサーバとはいえ許可された人以外の通信が到達しないに越したことがないし、シングルサインオンやAPI経由の操作でアクセス制御の管理ができると便利です。Cloudflare Zero TrustのSSHはこのあたりの需要をカバーしてくれます。

Cloudflare Zero Trustの新しいSSH

10月に新しい機能が発表されました。
Fearless SSH: short-lived certificates bring Zero Trust to infrastructure
また、さらに前の5月にBastionZeroの買収も発表されており、今回はBastionZeroの統合の第一弾のリリースのようです。
Cloudflare acquires BastionZero to extend Zero Trust access to IT infrastructure

仕組みを簡単に説明していきます。

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/private-net/cloudflared/ より

接続するユーザはCloudflare WARPアプリでCloudflareのネットワークと繋がります(VPNのようなもの)。SSHサーバもcloudflaredやWARP connectorを稼働させてCloudflareのネットワークと繋がります。これによりCloudflareがユーザとSSHサーバの中継ができるようになります。さらにSSHの場合はCloudflareが中間でSSHのセッションに介入します。

https://blog.cloudflare.com/intro-access-for-infrastructure-ssh/ より

SSHは「none」という認証方法をサポートしており、これはOpenSSHの設定でいうところの PermitEmptyPasswords yes に相当します。
多くの人はパスワードなしでSSH Serverを構成したことはないと思いますが、CloudflareはSSHの認証を行いません!もちろん、別の方法で認証を行っています。

ユーザはCloudflare WARP(クライアントアプリ)を利用してCloudflareのネットワークに接続するため、Cloudflareはコネクション単位でユーザの識別(認証)がすでにできています。同様にコネクション単位で認可が可能なため、Cloudflare上でポリシを評価した結果許可された人だけがSSH接続できるようになります。

Cloudflareで接続を一度終端しているため、SSHで暗号化されているトラフィックはCloudflare内で一度復号されます。そのためCloudflareは平文通信を取り扱うことになりますが、セキュリティ製品としてCloudflare Zero Trustを使う以上は許容してもよいポイントだと思います。Cloudflareから実態のSSHサーバへの接続は、Cloudflare内から新たにSSHのセッションを確立します。SSHサーバは特にCloudflareと統合するための実装を持っていないため、SSHの認証なしにCloudflareからの許可された通信かどうかを識別することはできません。また、接続元IPアドレスのみにたよって識別することはZero Trustの思想に反するため、少し手の込んだ公開鍵認証を使います。

CloudflareとSSHサーバの間の認証にX.509証明書を用い、SSHサーバにはCloudflareが発行したルート証明書の公開鍵を登録します。Cloudflareは接続元のユーザがSSH接続の認可を持っている場合に、ルート証明書から短命な証明書を発行します。この証明書を使ってSSH接続し、SSHサーバはこの証明書の署名を検証することでCloudflareからの接続であることを確認します。
この証明書はセッションの初めの認証時にのみ利用されるため、一度セッションを確立してしまえばこの証明書は有効期限が切れたことでSSHが切断されることはありません。短命な証明書を使うことで、鍵管理に伴うセキュリティリスクを軽減することができます。

古い方法との違い

「新しい」と書いたのは古い方法があるからです。
Short-lived certificates (legacy)
今までは短命な証明書をCloudflareのCILで発行してその鍵を使ってSSH接続を行う必要があったため、以下のようなsshの設定を記述する必要がありました。

Match host vm.example.com exec "/usr/local/bin/cloudflared access ssh-gen --hostname %h"
    HostName vm.example.com
    ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
    IdentityFile ~/.cloudflared/vm.example.com-cf_key
    CertificateFile ~/.cloudflared/vm.example.com-cf_key-cert.pub

一度設定してしまえばあとは特段意識せずにsshコマンドが使えたものの、多くの開発者に使ってもらおうと思うとこの手順が面倒だったり、ssh configに対応していないSSHクライアントがあると使えない問題がありました。Cloudflare側で透過的に処理してもらえるようになったので、ユーザ視点では非常にシンプルになりました。
また、今まではデフォルトではCloudflare Zero Trustのログイン時のメールアドレスのユーザ名部分とSSHのユーザ名が一致している必要があり、これもユーザにとっては不便な制約でした。新しい方法ではCloudflareのユーザ名とSSHのユーザ名を別々に設定できるため非常に使いやすくなりました。具体的には後述します。

実際に使ってみた

設定の手順はこちらです。特にハマりどころはありませんでした。
SSH with Access for Infrastructure (recommended)

SSH用の鍵を生成するのに直接APIを叩かないといけないのはちょっと不便なので、Web UIやterraform対応するといいなと思いました。
前述の仕組みより、SSHの終端をするのはCloudflare内であることからWARP connectorでもcloudflaredでもどちらでも動作可能なのは納得ですね。

sshのポリシ設定の例です。ログイン時のメールアドレスが @cyberagent.co.jp で終わっていてかつ、日本国内からのアクセスと判定される場合にSSHを許可します。
SSHする時のユーザ名は許可するものとリストすることもできますし、古い方式同様Cloudflare Zero Trustにログインしているユーザのメーアルアドレスのユーザ名部分をマッピングすることもできます。ここではec2-userとしました。

今後の期待

新しい機能ということもあってか、惜しいポイントもいくつかあったので紹介します。

認可制御に使えるパラメータが少ない

認可制御に使えるパラメータが少なめで物足りないように感じました。
Infrastructure policy selectors
ぱっと見ですぐ使えそうなのはメールアドレスやメールアドレスのドメイン一致、接続元の地域判定くらいでした。 SAML GroupやGitHub organizationの選択肢はなかったですが、OIDCしかIdPを設定していなかったせいかもしれません。

Network policiesの場合は認可に使えるパラメータが色々あり、特にSSHのアクセス制御で使えると便利そうなのはEmail Listによる制御です。認可したいユーザをリストでグルーピングしておき、リスト単位でSSHのポリシに書くことができれば認可対象のユーザの増減に対応しやすくなります。
Network policies

SSH対象のホスト自体にアクセスできないようにNetwork Firewall Ruleで上記設定で細かく認可制御をした上でSSHのポリシで緩めの認可を書けば制御としては可能ですが、運用が煩雑になりそうなのでEmail Listに対応してくれると嬉しいなと思います。

ブラウザSSHとも統合されてほしい

ここまで全く触れてきませんでしたが、Cloudflare Zero TrustにはブラウザでSSHができる便利機能があります。
Connect to SSH in the browser

ブラウザSSHの様子

ブラウザでアクセスするだけでSSHのターミナルがレンダリングされるため、URLだけでアクセス先を共有できたりスマホやタブレット等からもアクセスしようと思えばできて非常に便利です。
こちらもCloudflareが発行する短命な証明書に対応しており、Cloudflare Zero Trust上でログイン(シングルサインオン)して認可されればサーバのパスワード入力等なしにSSHが可能なのですが、こちらは古い(legacy)方法のSSHのセットアップにしか対応しておらず、新しいSSHと両方対応させようと思うと設定が複雑になります。また、SSHログインのユーザがメールアドレスとマッピングされてしまって使いづらい問題も起きてしまいます。
ブラウザSSHも新しいSSHの方式に統合されると嬉しいですね。

さいごに

Cloudflare Zero Trustの新しいSSHの機能について紹介しました。
CloudflareがBastionZeroを買収したニュースは個人的にとても気になっており、SSH以外にもリモートデスクトップやkubernetes、データベースへのアクセスにも対応する予定があるようなので今後の機能追加にも期待ですね!