홈서버-따라하기 시리즈 3편. 터널로 공개한 서비스 중 나만 써야 하는 것(관리 화면, 개인 대시보드)을 로그인 뒤로 숨긴다. 앱에 로그인 기능을 만들지 않고 Cloudflare Access 를 앞에 세운다.
Access 가 하는 일
요청이 서버에 닿기 전에 Cloudflare 엣지에서 "이 사람이 들어와도 되는가"를 확인한다. 통과하지 못한 요청은 서버까지 오지 않는다. 앱은 로그인 화면도, 비밀번호 저장도 필요 없다.
설정 순서
- Zero Trust 대시보드에서 로그인 수단에 One-time PIN(이메일 일회용 코드)을 추가한다. 기본 수단만 있으면 이메일 입력란이 나오지 않는다.
- Access → Applications 에서 Self-hosted 애플리케이션을 만들고 보호할 주소(
admin.example.com)를 넣는다. - 로그인 수단은 One-time PIN 하나만 선택하고 Instant authentication 을 켠다.
- 정책을 만든다. Action 은 Allow, Include 는 Emails 에 내 메일 주소.
이제 그 주소로 들어가면 메일 주소를 묻고, 허용한 주소로만 코드가 간다.
같은 사이트의 일부만 잠그기
공개 사이트의 관리 화면만 잠그고 싶다면 호스트 이름을 나누는 편이 깔끔하다. 같은 컨테이너를 www.example.com 과 admin.example.com 두 이름으로 터널에 연결하고, Access 는 admin 쪽에만 건다. 앱은 Host 헤더를 보고 관리 경로를 admin 호스트에서만 응답한다.
오리진을 직접 못 두드리게
Access 는 엣지에서만 막는다. 서버 안에서는 Host 헤더만 맞추면 인증 없이 응답이 온다.
curl -H 'Host: admin.example.com' http://127.0.0.1:8081/
배포 직후 점검에는 편하지만, 이 포트가 LAN 이나 인터넷에 열려 있다면 누구나 같은 방법으로 우회할 수 있다는 뜻이다. 그래서 두 가지를 지킨다.
- 컨테이너 포트는
127.0.0.1에만 바인딩한다(2편). - 민감한 앱은 Access 가 요청에 붙여 주는 JWT(
Cf-Access-Jwt-Assertion헤더)를 서버에서 검증한다. 서명 키는 팀 도메인의 공개 인증서 주소에서 받고, 대상(aud) 값이 내 애플리케이션의 것인지 확인한다. 이렇게 하면 터널을 거치지 않은 요청은 앱이 스스로 거절한다.
서비스가 많아지면
사용자가 여럿이거나 앱마다 권한이 달라야 하면 자체 SSO(나는 Authentik)를 두는 방법도 있다. 프록시 방식으로 앱 앞에 세우면 앱을 고치지 않고 로그인을 붙일 수 있다. 다만 혼자 쓰는 서비스 몇 개라면 Access 의 이메일 코드로 충분했다.
설정 중에 막혔던 부분은 Cloudflare 라벨의 글에 따로 적었다. 다음 편은 백업과 정기 정비다. 시리즈 전체 목록은 여기.
댓글 없음:
댓글 쓰기