本文へ移動
runlot

アクセス制御

デプロイにアクセスできる人を決めます。アプリのユーザーのログインとは別の機能です。

公開前のデプロイを保護したり、特定の人にだけ見せたりするときに使ってください。アクセス方式は次の 4 つです。

runlot access set public      # 誰でもアクセスできる(デフォルト)
runlot access set org         # この組織のメンバーだけがアクセスできる
runlot access set password    # 共有パスワードを知っている人だけがアクセスできる
runlot access set app         # このアプリにサインインした人だけがアクセスできる
runlot access            # 現在の設定を確認する
runlot access --json

これらのコマンドの実行には admin ロールが必要です。

password モード

runlot access set password --password 'my-secret'

--password を省略すると、ターミナルでパスワードの入力を求められます。保護されたデプロイにアクセスすると、アプリより先にパスワード入力画面が表示されます。

org モード

組織のメンバーは、ダッシュボードのログインでそのままアクセスできます。組織のメンバーでないユーザーには 403 が返ります。

app モード

runlot access set app         # このアプリにサインインした人だけがアクセス可能

このプロジェクトの有効なログインセッションを持つリクエストだけがコードに届きます。それ以外にはプラットフォームが応答します。

リクエスト応答
HTML を求めるブラウザの GET・HEAD/__runlot/auth/sign-in?next=<path> への 302
その他のリクエスト401、{"error":{"code":"sign_in_required"}}
/__runlot/auth/*サインインできるよう常に通過
バイパスキー付きのリクエストorg・password と同じく通過
  • 静的ファイルも例外ではありません。保護されたアプリの JavaScript バンドルも保護対象です。
  • パスルールは通過したリクエストにそのまま適用され、範囲を狭めるだけです。
  • app にはプロジェクトのログイン機能がオンである必要があります。オフの場合は 409 login_required を返します。モードが app の間はログイン機能をオフにできず (409 access_mode_app)、先に別のモードに変更する必要があります。
  • セッション Cookie のないリクエストは、プロジェクトを起動せずにフロントで拒否します。Cookie のあるリクエストは、データベースでセッションを確認するためプロジェクトを起動します。

ワーカーでアクセス情報を読む

フロント側で確認したアクセス情報は、リクエストヘッダーとしてワーカーに渡されます。

ヘッダー値
Runlot-Access-Modepublic · org · password · app · bypass
Runlot-Access-Subjectユーザー ID(モードによって異なります)
Runlot-Access-Emailログインに使ったメールアドレス(org モード)
Runlot-Access-Org-Roleadmin · member · viewer(org モード)

提供しているヘルパーで読み取れます。

import { identity, isSignedIn } from "@runlot/access";

const who = identity(request);
// { mode: "org", subject: "…", email: "[email protected]", orgRole: "admin" }

if (who.orgRole !== "admin") return new Response(null, { status: 403 });

クライアントが送った runlot-* ヘッダーはフロント側ですべて削除され、確認済みの値だけがあらためて追加されます。そのため、クライアントがこれらの値を偽装することはできません。

フロントを介さずに実行するローカル環境では、mode は public になり、残りの値は null です。

CI から迂回する

自動化された処理が保護されたデプロイを確認する必要があるときに使えます。

runlot access bypass --new

シークレットは一度だけ表示されます。表示されたあとに再確認する方法はありません。

curl -H "Runlot-Access-Bypass: <secret>" https://my-app.me.runlot.app/health
runlot access bypass --revoke

権限のないリクエストはプロジェクトを起動しません

アクセス権限はプロジェクトを起動する前に確認します。権限のないリクエストが来ても、自動停止したプロジェクト は起動されず、そのリクエストは使用量にも含まれません。

パスごとのルール

runlot.json でパスごとにモードをさらに絞り込めます。ルールはデプロイと一緒に動くので、以前のデプロイに戻すとルールも戻ります。

{
  "access": [
    { "path": "/admin/*", "require": { "orgRole": "admin" } },
    { "path": "/internal/*", "require": { "emailDomain": ["acme.com", "acme.co.kr"] } }
  ]
}
  • path は完全一致のパス、または /* で終わるプレフィックスです。プレフィックスはそれ自体も含みます(/admin/* は /admin も含む)。* はほかの位置には使えません。
  • require.orgRole は最低限の組織ロールです: viewer、member、admin。require.emailDomain はドメイン 1 つまたはリストです。指定した条件はすべて満たす必要があり、パスが一致するルールもすべて満たす必要があります。{} はモードがすでに許可した人をすべて許可します。
  • ルールが拒否したリクエストには 403 を返します。ルールは最大 64 個です。
  • ルールは絞り込むだけです。 モードが閉じているパスを開くことはできません。
  • モードが public のときルールは無視されます。 その場合 runlot deploy が警告します。ルールを適用するには org、password、app のいずれかに切り替えてください。
  • app モードでは、ルールに orgRole や emailDomain を要求できません。 アプリにログインした人は組織ロールも Runlot のメールも持たないため、そのようなルールは決して満たされません。app のプロジェクトにそのルールを含めてデプロイすること、またライブのデプロイにそのルールがあるまま app に切り替えることは、どちらも 409 access_mode_app_rules で拒否されます。require が空のルールは問題ありません。
  • 共有パスワードで入った訪問者やバイパスシークレットを使ったリクエストは、組織ロールとメールを持たないため、require が空のルールだけを満たします。

現在の制限

password モードは繰り返しの誤入力を制限します。連続して何度も失敗すると、しばらくの間それ以降の試行に 429 Too Many Requests を返します。推測を遅らせるだけなので、短いパスワードや推測しやすいパスワードは使わないでください。

このページの目次