Cloudflare Tunnel, Access で GitHub Actions から SSH で接続
はじめに
Cloudflare Tunnel, Access を使用してポートを開放せずに SSH 接続できることを知りました。
VPS で試しにポートを開放せず Tunnel で SSH 接続、Access でメール認証などのセキュリティ機能を挟むこともでき、より安全にサーバーを公開できて便利だと感じました。
ただ、GitHub Actions で SSH を利用した自動化を行う場合、人間が操作する前提のものとは異なる設定が必要だったので、その内容を記載します。
結論
- Cloudflare Tunnel でポートを開放せずに SSH 接続が可能
- Cloudflare Access でメール認証などのセキュリティ機能を挟むことが可能
- GitHub Actions のように自動で Cloudflare Access の認証を通るようにするには、Service Token を使用する
Cloudflare Tunnel とは
直接攻撃から Web サーバーを保護
開発者や IT 部門は、アプリケーションが展開された瞬間から、ACL の設定、IP アドレスのローテーション、GRE トンネルのような使いにくいソリューションを使用しながら、アプリケーションのロックダウンに時間を費やします。
そこで、よりシンプルで安全に、お客様のアプリケーションや Web サーバーを直接攻撃から保護する手段があります。それが Cloudflare Tunnel です。
パブリッククラウド、プライベートクラウド、Kubernetes クラスター、または TV 経由の Mac ミニなど、どこで実行していようともサーバーの安全を確保します。
Cloudflare Access とは
インターネットネイティブな Zero Trust ネットワークアクセス(ZTNA)
すべての自己ホスト環境、SaaS、または非 Web アプリケーションに対する安全なアクセスのためのアグリゲーションレイヤーを作成する
Cloudflare Tunnel の作成, サーバーへ cloudflared をインストール
Tunnel を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。
- Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Networks」 > 「Tunnels」 を開く
- 「Create a tunnel」を押す
- 「Select your connector」で「Cloudflared」を選択して、「Next」を押す
- 「Tunnel name」を入力し、「Save tunnel」を押す
- 次の画面で表示された手順に従って、SSH 接続したいサーバーへ cloudflared をインストール
- cloudflared をサーバーへインストール後、「Next」を押す
- 「Public Hostname」で SSH 接続で使用したいドメインを入力し、「Type: SSH」「URL: localhost:22」を入力して「Save tunnel」を押す
Cloudflare Access (Self-hosted application) の作成
Access (Self-hosted application) を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。
-
Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Access」 > 「Applications」 を開く
-
「Add an application」を押す
-
「Self-hosted」を選択する
-
「Application name」「Application domain」を入力し、「Next」を押す
- 「Application domain」は Tunnel で入力したドメインと合わせる
-
Policy 設定を入力し、「Next」を押す
- 「Policy name」を入力
- 「Action: Allow」
- 「Configure rules」で「Selector:Emails」「Value」に自分のメールアドレスを入力
-
「Add application」を押す
ローカルから SSH 接続
Cloudflare Tunnel, Access で SSH 接続するには、cloudflared のインストールと、.ssh/config の設定を行います。
cloudflared のインストール
cloudflared のインストール方法は OS によって異なるので、以下のリンクを参照してください。
.ssh/config の設定
Host testvps.example.com
HostName testvps.example.com
Port 22
User ubuntu
IdentityFile ~/.ssh/testvps.example.com.key
ProxyCommand /path/to/cloudflared access ssh --hostname %h
SSH 接続するには、ProxyCommand
の設定が必要です。
cloudflared
のパスは、インストール先のパスを指定してください。
また、User
Port
IdentityFile
などは接続するサーバーの SSH の内容に合わせて設定してください。
SSH 接続
ssh testvps.example.com
を実行すると、ブラウザで Cloudflare Access の認証画面が開きます。
そこで、Access の設定で入力したメールアドレスを入力し、「Send me a code」を押すと、そのメールアドレス宛てにコードが送信されます。
コードを入力し、「Sign in」を押すと、SSH 接続できます。
ローカルからの SSH 接続までのまとめ
上記の手順で、サーバーでポートを開放せずにローカルから SSH 接続することができました。
Cloudflare Access のメール認証が、SSH の認証より前に追加されるので、より安全な状態になっていると思います。
ただ GitHub Actions などの自動処理では、メールを受け取ってコード入力するということはできないため、Service Token を使用した方法を記載します。
GitHub Actions から SSH 接続
Cloudflare Access の Policy を追加し、メールアドレス認証 または Service Token 認証で SSH 接続できるようにします。
Service Token の作成
Service Token を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。
- Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Access」 > 「Service Auth」 を開く
- 「Create Service Token」を押す
- 「Servcie token name」を入力し、「Service Token Duration」を選択して「Generate token」を押す
- Service Token が作成され、「Client ID」「Client Secret」が表示されるので、コピーしておく
Cloudflare Access の Policy を追加
-
Cloudflare Access に作成した Application を開く
-
「Policies」 > 「Add a policy」を押す
-
Policy 設定を入力し、「Add policy」を押す
- 「Policy name」を入力
- 「Action: Service Auth」
- 「Configure rules」で「Selector: Service Token」「Value」で作成した Service Token を選択
ローカルからの SSH 接続で、Service Token を指定
ローカルからの SSH 接続で、Service Token を指定することも可能です。
.ssh/config
の ProxyCommand
を以下のように変更すれば、メールアドレス認証ではなく、Service Token 認証となります。
ProxyCommand /opt/homebrew/bin/cloudflared access ssh --id __CLIENT_ID__ --secret __CLIENT_SECRET__ --hostname %h
__CLIENT_ID__
__CLIENT_SECRET__
は作成した Service Token の値で置換してください。
GitHub Actions の設定例
GitHub Actions ではローカルと同じく.ssh/config
を作成してもこの内容は反映されませんでした。
そのため、ssh
のオプションで、ProxyCommand
を指定する必要があります。
jobs:
sample:
name: SSH Sample
runs-on: ubuntu-latest
env:
SSH_PROXY_COMMAND: /tmp/cloudflared/cloudflared access ssh --id ${{ secrets.SSH_CLOUDFLARED_ID }} --secret ${{ secrets.SSH_CLOUDFLARED_SECRET }} --hostname %h
steps:
- name: Install cloudflared
run: |
lastest_version=$(curl -s $GITHUB_API_URL/repos/cloudflare/cloudflared/releases/latest | jq -r '.tag_name')
mkdir -p /tmp/cloudflared
curl -sL -o /tmp/cloudflared/cloudflared $GITHUB_SERVER_URL/cloudflare/cloudflared/releases/download/$lastest_version/cloudflared-linux-amd64
chmod +x /tmp/cloudflared/cloudflared
/tmp/cloudflared/cloudflared --version
- name: run ssh
run: |
ssh -o StrictHostKeyChecking=no -o ProxyCommand="$SSH_PROXY_COMMAND" ssh://testvps.example.com -- date
- name: run git push
run: |
git -c core.sshCommand='ssh -o StrictHostKeyChecking=no -o ProxyCommand="`echo "$SSH_PROXY_COMMAND"`"' push ssh://testvps.example.com/example
まとめ
Cloudflare Tunnel を使用してポートを開放せずに SSH 接続できることができました。
Cloudflare Access でメール認証などのセキュリティ機能を挟むこともでき、より安全にサーバーを公開できて便利です。
GitHub Actions で SSH を利用した自動化を行う場合も、Service Token を使用することで可能になります。
Discussion