본문으로 건너뛰기
runlot

접근 제어

배포에 접근할 수 있는 사람을 정합니다. 앱 사용자 로그인과는 별개의 기능입니다.

공개 전 배포를 보호하거나 특정 사람에게만 보여 줄 때 사용하세요. 접근 방식은 다음 네 가지입니다.

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 와 마찬가지로 통과
  • 정적 파일도 예외가 아닙니다. 보호된 앱의 자바스크립트 번들도 보호 대상입니다.
  • 경로 규칙은 통과한 요청에 그대로 적용되며, 범위를 좁히기만 합니다.
  • app 은 프로젝트의 로그인 기능이 켜져 있어야 합니다. 꺼져 있으면 409 login_required 로 답합니다. 모드가 app 인 동안에는 로그인 기능을 끌 수 없으며(409 access_mode_app), 먼저 다른 모드로 바꿔야 합니다.
  • 세션 쿠키가 없는 요청은 프로젝트를 시작하지 않고 프런트에서 거절합니다. 쿠키가 있는 요청은 데이터베이스에서 세션을 확인해야 하므로 프로젝트를 시작합니다.

워커에서 접근 정보 읽기

앞단에서 확인한 접근 정보는 요청 헤더로 워커에 전달됩니다.

헤더값
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 은 도메인 하나 또는 목록입니다. 지정한 조건은 모두 충족해야 하고, 경로가 일치하는 규칙도 모두 충족해야 합니다. {} 는 모드가 이미 허용한 사람을 모두 허용합니다.
  • 규칙이 거부한 요청은 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 로 응답합니다. 추측을 늦출 뿐이므로 짧거나 추측하기 쉬운 비밀번호는 사용하지 마세요.

이 페이지의 목차