🛡

Cloudflare Tunnel, Access で GitHub Actions から SSH で接続

2024/04/25に公開

はじめに

Cloudflare Tunnel, Access を使用してポートを開放せずに SSH 接続できることを知りました。
VPS で試しにポートを開放せず Tunnel で SSH 接続、Access でメール認証などのセキュリティ機能を挟むこともでき、より安全にサーバーを公開できて便利だと感じました。
ただ、GitHub Actions で SSH を利用した自動化を行う場合、人間が操作する前提のものとは異なる設定が必要だったので、その内容を記載します。

結論

  • Cloudflare Tunnel でポートを開放せずに SSH 接続が可能
  • Cloudflare Access でメール認証などのセキュリティ機能を挟むことが可能
  • GitHub Actions のように自動で Cloudflare Access の認証を通るようにするには、Service Token を使用する

Cloudflare Tunnel とは

https://www.cloudflare.com/ja-jp/products/tunnel/

直接攻撃から Web サーバーを保護

開発者や IT 部門は、アプリケーションが展開された瞬間から、ACL の設定、IP アドレスのローテーション、GRE トンネルのような使いにくいソリューションを使用しながら、アプリケーションのロックダウンに時間を費やします。

そこで、よりシンプルで安全に、お客様のアプリケーションや Web サーバーを直接攻撃から保護する手段があります。それが Cloudflare Tunnel です。

パブリッククラウド、プライベートクラウド、Kubernetes クラスター、または TV 経由の Mac ミニなど、どこで実行していようともサーバーの安全を確保します。

Cloudflare Access とは

https://www.cloudflare.com/ja-jp/zero-trust/products/access/

インターネットネイティブな Zero Trust ネットワークアクセス(ZTNA)

すべての自己ホスト環境、SaaS、または非 Web アプリケーションに対する安全なアクセスのためのアグリゲーションレイヤーを作成する

Cloudflare Tunnel の作成, サーバーへ cloudflared をインストール

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/create-remote-tunnel/

Tunnel を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。

  1. Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Networks」 > 「Tunnels」 を開く
  2. 「Create a tunnel」を押す
  3. 「Select your connector」で「Cloudflared」を選択して、「Next」を押す
  4. 「Tunnel name」を入力し、「Save tunnel」を押す
  5. 次の画面で表示された手順に従って、SSH 接続したいサーバーへ cloudflared をインストール
    install_cloudflared
  6. cloudflared をサーバーへインストール後、「Next」を押す
  7. 「Public Hostname」で SSH 接続で使用したいドメインを入力し、「Type: SSH」「URL: localhost:22」を入力して「Save tunnel」を押す
    public_hostnames

Cloudflare Access (Self-hosted application) の作成

https://developers.cloudflare.com/cloudflare-one/applications/configure-apps/self-hosted-apps/

Access (Self-hosted application) を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。

  1. Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Access」 > 「Applications」 を開く

  2. 「Add an application」を押す

  3. 「Self-hosted」を選択する

  4. 「Application name」「Application domain」を入力し、「Next」を押す

    • 「Application domain」は Tunnel で入力したドメインと合わせる

    add_application

  5. Policy 設定を入力し、「Next」を押す

    • 「Policy name」を入力
    • 「Action: Allow」
    • 「Configure rules」で「Selector:Emails」「Value」に自分のメールアドレスを入力

    policy_emails

  6. 「Add application」を押す

ローカルから SSH 接続

Cloudflare Tunnel, Access で SSH 接続するには、cloudflared のインストールと、.ssh/config の設定を行います。

cloudflared のインストール

cloudflared のインストール方法は OS によって異なるので、以下のリンクを参照してください。

https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/

.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」を押すと、そのメールアドレス宛てにコードが送信されます。

access_auth1

コードを入力し、「Sign in」を押すと、SSH 接続できます。

access_auth2

ローカルからの SSH 接続までのまとめ

上記の手順で、サーバーでポートを開放せずにローカルから SSH 接続することができました。
Cloudflare Access のメール認証が、SSH の認証より前に追加されるので、より安全な状態になっていると思います。
ただ GitHub Actions などの自動処理では、メールを受け取ってコード入力するということはできないため、Service Token を使用した方法を記載します。

GitHub Actions から SSH 接続

Cloudflare Access の Policy を追加し、メールアドレス認証 または Service Token 認証で SSH 接続できるようにします。

Service Token の作成

https://developers.cloudflare.com/cloudflare-one/identity/service-tokens/

Service Token を作成します。
UI など変更される可能性もあるので、正しい手順は上記リンクから参照してください。

  1. Cloudflare Dashboard のメニューから 「Zero Trust」 > 「Access」 > 「Service Auth」 を開く
  2. 「Create Service Token」を押す
  3. 「Servcie token name」を入力し、「Service Token Duration」を選択して「Generate token」を押す
    service_token1
  4. Service Token が作成され、「Client ID」「Client Secret」が表示されるので、コピーしておく
    service_token2

Cloudflare Access の Policy を追加

  1. Cloudflare Access に作成した Application を開く

  2. 「Policies」 > 「Add a policy」を押す

  3. Policy 設定を入力し、「Add policy」を押す

    • 「Policy name」を入力
    • 「Action: Service Auth」
    • 「Configure rules」で「Selector: Service Token」「Value」で作成した Service Token を選択

    policy_service_token

ローカルからの SSH 接続で、Service Token を指定

ローカルからの SSH 接続で、Service Token を指定することも可能です。
.ssh/configProxyCommand を以下のように変更すれば、メールアドレス認証ではなく、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