프로덕션 배포 하드닝
대상 독자
프로덕션 트래픽을 앞두고 배포를 준비하거나 기존 배포를 점검하는 super_admin 운영자. .env / Helm 값, 그리고 이 페이지가 반복하지 않는 환경 변수 참조에 익숙해야 합니다.
하드닝된 TRUSCA 배포에 필요한 것 대부분은 이미 기본값으로 갖춰져 있습니다. 비밀번호 정책, 리프레시 토큰 회전, CORS 검증, 레이트 리밋 모두 설정 파일을 건드리기 전부터 켜져 있습니다. 이 페이지는 실제로 운영자가 손대야 하는 설정만 영역별로 짚고, 각 항목을 깊이 다루는 문서로 연결합니다. 새 배포를 세울 때나 기존 배포를 점검할 때 훑어보는 순서로 쓰고, 참조 페이지를 대신하는 문서로는 쓰지 마십시오.
네트워크와 TLS
- **
CORS_ALLOWED_ORIGINS**는 관대한 기본값 이 없는 필수 키입니다.*가 들어 있으면(자격 증명을 포함한 요청과 함께 쓸 수 없음) 백엔드가 부팅을 거부하고,APP_ENV=prod일 때 origin 중 하나라도http://를 쓰면 역시 부팅을 거부합니다. SPA가 실제로 서비스되는 scheme과 host를 정확히 적으십시오. 그보다 넓게 잡지 마십시오. - 엣지에서 TLS를 종료하십시오. 프로덕션
docker-compose.yml은DOMAIN과TLS_EMAIL로 구성되는 Let's Encrypt HTTP-01 챌린지와 함께 Traefik을 포함합니다 - Docker Compose로 설치를 참고하십시오. Helm 차트는 대신 Ingress + cert-managerClusterIssuer를 기대합니다 - Kubernetes에 Helm으로 설치를 참고하십시오. - 네트워크가 사내 인증 기관이나 TLS를 가로채는 프록시 뒤에 있다면 인증서 검증을 끄지 마십시오. 대신 스캔 파이프라인과 포털 자체의 외부 호출이 여러분의 CA 번들을 보게 하십시오 - 사설 인증 기관을 참고하십시오.
인증과 세션
- 비밀번호 정책은 설정 항목이 아닙니다. 모든 비밀번호는 등록과 재설정 경로마다 스키마 계층에서 8자리 NIST 800-63B 하한과 흔한 비밀번호 차단 목록 검사를 통과해야 합니다. 여기서 더 강화할 것도 없고, 약화시킬 방법도 없습니다.
- **
SECRET_KEY**는 모든 JWT에 서명합니다. 필수 키이 며,dev외 환경에서 32자 미만이면 부팅을 거부합니다.openssl rand -hex 32로 생성하고 배포마다 다른 값을 쓰십시오 - 교체하면 발급된 모든 리프레시 토큰이 무효화되므로, 교체는 일상적인 작업이 아니라 미리 알리는 의도적인 이벤트로 다루십시오. ACCESS_TOKEN_EXPIRE_MINUTES(기본 30)와REFRESH_TOKEN_EXPIRE_DAYS(기본 7)는 탈취된 토큰이 쓸모 있는 기간을 정합니다. 리프레시 토큰은 사용할 때마다 회전하고 재사용 탐지가 이미 내장돼 있습니다. 기본값을 줄이면 편의를 노출 구간과 맞바꾸는 것일 뿐, 없던 취약점을 메우는 것이 아닙니다.- MFA(TOTP + 복구 코드)는 모든 사용자가 본인 계정에서 직접 켤 수 있습니다. 이번 릴리스에는 조직 전체에 강제하는 토글이 없습니다.
super_admin을 비롯한 권한이 높은 계정이 스스로 등록하도록 권장하십시오. - **
AUTH_SELF_REGISTRATION**은 기본값이true입니다(공개 가입 폼이 열려 있습니다). 내부 배포라면 이를 끄고 대신 ID 공급자나 일괄 등록으로 계정을 발급하십시오 - 자체 가입과 SSO를 동시에 열어 두면 누군가 회사 주소로 가입한 뒤 나중에 SSO로 그 계정을 연결할 수 있습니다.OIDC_GROUP_ROLE_MAP이super_admin부여를 거부하는 이유와 issuer가 반드시https여야 하는 이유를 포함한 전체 그림은 환경 변수 참조의 SSO 절을 참고하십시오. LOGIN_THROTTLE_ENABLED(기본 켜짐)는 IP당 레이트 리밋 위에 주소별로 점점 길어지는 잠금을 추가로 겁니다. 여러 출발지에 걸쳐 흩어진 추측 시도도 한 계정을 노리면 걸립니다. 돌아오는 길은 비밀번호 재설정이나 관리자의 잠금 해제 엔드포인트뿐입니다 - 환경 변수 참조의LOGIN_THROTTLE_WINDOWS를 참고하십시오.- **
PERMISSION_CACHE_TTL_SECONDS**는 기본값이0(꺼짐)입니다. 모든 요청이 호출자의 역할과 멤버십을 매번 다시 읽습니다. 값을 올리면 그 보장을 DB 부하 감소와 맞바꾸는 것이며, 설정한 값만큼이 강등이나 비활성화가 반영되지 않을 수 있는 최대 시간이 됩니다. Postgres 크기 산정과 커넥션 튜닝의 커넥션 예산이 실제로 여유가 필요할 때만 올리십시오.
레이트 리밋과 남용 방지
CPU를 쓰거나 세션을 여는 공개 엔드포인트에는 처음부터 slowapi 레이트 리밋이 걸려 있습니다 - 등록, 로그인, 리프레시, 비밀번호 재설정, 티켓 상태 새로 고침, 그룹 검색, 스캔 트리거, 두 웹훅 수신 엔드포인트까지 전부입니다. 기본값을 포함한 전체 목록은 환경 변수 참조에 있습니다. 다시 살펴볼 가치가 있는 것은 트래픽 패턴이 브라우저 앞의 사용자 한 명과 다른 경우입니다.
- CI 러너나 NAT 뒤의 사무실 네트워크가 여러 사용자를 대신해 한 주소에서 스캔을 트리거하거나 토큰을 새로 고치면, 남용을 겨냥한 IP당 제한에 걸릴 수 있습니다. 이럴 때는 제한을 끄는 대신 해당 항목의 값을 올리십시오.
- **
RATELIMIT_DISABLED**는 테스트 전용 비상 스위치입니다(공유 IP를 쓰는 CI 러너가 e2e 스위트를 돌리다 로그인 제한에 걸리지 않게 하려고 존재합니다). API나 관리 화면에는 이 값을 바꿀 방법이 없으므로, 프로덕션 프로세스에 이 값이 들어가는 경로는 우연히 섞여 들어간 환경 변수뿐입니다 - 만약 그렇게 설정되면 백엔드의 모든slowapi제한이 한 번에 꺼집니다. 실제 트래픽을 받는 배포에는 이 값이 비어 있는지 확인하십시오. - **
WEBHOOK_MAX_BODY_BYTES**와 **WEBHOOK_RATE_LIMIT**은 서명 검증 전에 인증되지 않은 호출자가 부담시킬 수 있는 비용을 제한합니다. 두 수신 엔드포인트 모두 서명을 검증하기 전에 본문을 읽어 버퍼링하기 때문입니다. 웹훅을 참고하십시오. WEBSOCKET_MAX_CONNECTIONS_PER_USER/ **WEBSOCKET_MAX_CONNECTIONS_GLOBAL**은 WebSocket 게이트웨이를 같은 방식으로 제한합니다. 공유 레지스트리를 기준으로 강제하므로 백엔드 프로세스 수와 무관하게 상한이 유지됩니다.- 팀별 스캔 동시 실행 상한은 사용자별 트리거 제한과 별개로 한 팀의 버스트가 공유 Celery 워커 풀을 독점하지 못하게 막습니다 - 공식과 산정 방법은 Docker Compose - 스캔 용량을, 사용자별 절반은 환경 변수 참조의
SCAN_TRIGGER_RATE_LIMIT을 참고하십시오.