본문으로 건너뛰기

인증과 프로필

TRUSCA는 두 가지 대화형 로그인 방식 — 이메일 + 비밀번호와 OAuth(GitHub 또는 Google) — 그리고 셀프 서비스 비밀번호 복구 흐름을 제공합니다. 이 페이지는 각 경로를 따라가고 /profile 페이지에서의 신원 관리를 다룹니다.

대상 독자

로그인된 모든 사용자. 본인의 신원을 관리하는 데 특별한 역할은 필요 없습니다. OAuth 버튼은 운영자가 해당 *_CLIENT_ID / *_CLIENT_SECRET 환경 변수를 구성한 경우에만 표시됩니다.

이메일 + 비밀번호로 로그인​

  1. /login을 엽니다.
  2. 이메일과 비밀번호를 입력합니다.
  3. 제출합니다.

이메일·비밀번호 입력과 OAuth 공급자 버튼이 표시된 로그인 페이지 — KO locale

서버 측 동작

  • 비밀번호는 가입 시점에 bcrypt cost 12로 해시되며, 로그인 시 후보 값을 저장된 해시와 상수 시간 비교합니다.
  • 성공 시 JWT **access token(30분)**과 refresh token(7일, 매 사용 시 회전, 재사용 탐지로 전체 체인을 무효화)을 반환합니다.
  • Refresh token은 HttpOnly, Secure, SameSite=Lax 쿠키에 보관됩니다. JavaScript에서는 절대 접근할 수 없습니다.
  • 로그인 엔드포인트는 IP당 1분에 5회로 레이트 리밋이 걸려 있습니다. 초과 요청은 HTTP 429와 Retry-After 헤더로 응답합니다.
  • 실패는 이메일 주소 단위로도 셉니다. 그래서 여러 출처에 흩어진 추측도 함께 느려집니다. 몇 번 실패하면 그 주소가 잠시 거절되고, 거절이 이어질수록 기간이 길어집니다. 응답은 얼마나 기다려야 하는지 알려 주며, 그 주소에 계정이 있든 없든 내용이 같습니다.

"Invalid email or password" 메시지가 보이면 이메일이 정확한지 확인 후 한 번 더 시도하세요. 메시지는 의도적으로 일반화되어 있어 공격자가 계정을 열거할 수 없습니다.

기다리라는 안내를 받았다면​

비밀번호를 여러 번 틀리면 그 주소가 거절됩니다. 이 횟수는 본인의 시도만 세는 것이 아니어서, 이메일을 아는 사람이라면 누구나 실패를 만들어 넣을 수 있습니다. 돌아오는 방법은 셋입니다.

  • 기다리기. 거절은 반드시 스스로 끝납니다. 다시 거절되려면 시도 한 번이 아니라 처음부터 다시 실패가 쌓여야 하므로, 계속 막아 두려면 상대가 추측을 이어 가야 합니다.
  • 비밀번호 재설정. 횟수가 바로 지워집니다. 비밀번호가 아니라 받은 편지함이 필요하므로, 추측하는 쪽이 멈추지 않아도 쓸 수 있는 경로입니다. 가장 최근에 받은 재설정 메일을 쓰세요. 새로 요청하면 이전 링크가 무효가 되므로 편지함에 남아 있는 예전 메일은 동작하지 않을 수 있습니다.
  • 관리자에게 요청하기. 슈퍼관리자가 대신 횟수를 지울 수 있습니다. 받은 편지함까지 쓸 수 없게 된 경우의 답입니다.

비밀번호를 잊어버린 경우​

  1. /login에서 **Forgot password?**를 클릭하면 /forgot-password로 이동합니다.
  2. 계정과 연결된 이메일을 입력합니다.
  3. 제출합니다. 포털은 해당 이메일에 계정이 없더라도 항상 204 No Content를 반환합니다 — 사용자 열거를 막기 위한 설계입니다.
  4. 메일함을 확인합니다. 계정이 존재한다면 "Reset your TRUSCA password" 제목의 메시지가 약 30초 이내에 도착합니다.

리셋 링크는 24시간 동안 유효하며 1회만 사용 가능합니다. 만료되거나 사용된 후에는 토큰이 폐기됩니다.

이메일 입력 + 사용자 열거 방지 제출이 적용된 비밀번호 찾기 페이지 — KO locale

비밀번호 재설정​

이메일의 링크는 /reset-password?token=<opaque>로 연결됩니다.

  1. 새 비밀번호를 입력합니다(12자 이상, 침해된 사전 단어 금지).
  2. 두 번째 필드에서 한 번 더 확인 입력합니다.
  3. 제출합니다.

성공 시 /login으로 리다이렉트됩니다. 새 비밀번호는 bcrypt 해시되고 리셋 토큰은 소비됩니다. 다른 모든 세션은 즉시 끝납니다. refresh token이 폐기되고, 변경 이전에 발급된 access token도 남은 유효 기간을 채우지 못하고 거부되며, 리셋과 같은 시점에 진행되던 로그인이나 토큰 갱신도 뒤에 세션을 남기지 못합니다. 자격 증명이 유출됐다고 판단해 비밀번호를 바꾼 사람이 훔쳐간 세션이 만료되기를 기다릴 필요가 없습니다.

API 키는 영향을 받지 않습니다. 수명 주기가 따로 있는 별도 자격 증명이므로 API 키로 인증하는 빌드는 계속 동작합니다. 침해가 의심되어 비밀번호를 바꾸는 경우라면 Integrations 화면에서 키도 함께 점검하세요.

토큰이 만료되었거나 이미 사용된 경우, 페이지는 오류와 함께 /forgot-password로 돌아가는 링크를 표시합니다.

2단계 로그인​

비밀번호는 추측당하거나, 다른 곳에서 재사용되거나, 피싱으로 넘어갈 수 있습니다. 2단계 인증을 켜면 로그인에 휴대폰 앱이 보여 주는 여섯 자리 숫자가 함께 필요합니다. 이 숫자는 30초마다 바뀌고 이메일로 오가지 않습니다.

켜기 전에는 적용되지 않으며, 켜는 주체는 본인입니다.

켜기​

  1. /profile을 열어 2단계 로그인 항목을 찾습니다.
  2. 설정을 누른 뒤 현재 비밀번호를 입력합니다. 이미 로그인한 상태인데도 다시 묻는 이유는, 여기서 받는 것이 비밀번호를 바꾼 뒤에도 계속 쓰이기 때문입니다. 열려 있는 브라우저 탭만으로는 근거가 부족합니다.
  3. QR 코드와 그 아래에 같은 값을 글자로도 보여 줍니다.
  4. 인증 앱으로 QR 코드를 스캔합니다. 데스크톱 앱을 쓰거나, 카메라 초점이 맞지 않거나, 화면 낭독기를 쓰는 경우에는 글자로 된 값을 직접 입력합니다.
  5. 앱이 보여 주는 여섯 자리를 입력하고 제출합니다.

값을 보여 준 다음 코드를 한 번 더 묻는 것은 형식적인 절차가 아닙니다. 앱이 그 값을 실제로 받았다는 것을 코드로 확인하기 전에는 아무것도 켜지지 않으므로, 중간에 탭을 닫아도 이전과 똑같은 상태로 남습니다.

켜는 것은 이후의 로그인을 보호합니다. 이미 열려 있는 세션을 끊지는 않으므로, 다른 사람이 본인 계정으로 로그인해 있다고 생각된다면 이것 말고 비밀번호 재설정을 쓰세요. 재설정은 다른 세션을 즉시 모두 끊습니다.

성공하면 포털이 복구 코드 10개를 보여 줍니다. 읽을 수 있는 것은 이때뿐입니다. 해시로 저장하므로 관리자를 포함해 누구도 다시 보여 줄 수 없습니다. 인증 앱이 들어 있는 휴대폰이 아닌 다른 곳에 보관하세요.

이후 로그인​

  1. 이메일과 비밀번호를 이전처럼 입력합니다.
  2. 그다음 화면이 코드를 묻습니다. 여섯 자리를 입력합니다.

두 단계 사이에 주어지는 시간은 5분입니다. 더 걸렸다면 비밀번호부터 다시 시작하면 됩니다. 아직 로그인된 것이 없으므로 잃는 것도 없습니다.

코드는 한 번만 통합니다. 이미 쓴 코드는 화면에 아직 같은 숫자가 떠 있는 30초 안에도 거절됩니다. 옆에서 입력을 지켜본 사람이 뒤따라 들어오는 것을 막는 부분이 바로 이것입니다.

인증 앱을 잃어버렸다면​

여섯 자리를 묻는 자리에 복구 코드를 입력합니다. 하나는 한 번 쓰면 사라지므로 10개는 시도 10번이 아니라 로그인 10번입니다.

다시 들어온 뒤 /profile에서 새 묶음을 발급받습니다. 설정할 때와 같은 이유로 비밀번호나 인증 앱의 코드를 먼저 묻습니다. 발급하면 이전 묶음의 코드가 모두 무효가 되므로, 예전에 인쇄해 둔 목록은 누가 주워도 쓸모가 없습니다.

계정에 2단계 인증이 설정되거나 새 복구 코드가 발급되면 포털 알림으로 알려 드립니다. 본인이 하지 않은 알림이 오면 비밀번호를 바꾸고 관리자에게 알리세요. 다른 사람이 본인 계정으로 로그인해 있다는 뜻입니다.

앱도 복구 코드도 없다면 슈퍼관리자가 계정의 2단계 인증을 해제할 수 있고, 해제 사실은 본인에게 알림으로 전달됩니다.

적용되지 않는 곳​

  • API Key는 그대로 동작합니다. Key는 이미 아는 것이 아니라 가진 것이고, 휴대폰 코드를 기다리느라 멈추는 빌드는 끝나지 않는 빌드입니다. Key는 비밀번호와 같은 무게로 다루고, 비밀번호를 바꾸듯 폐기하세요.
  • OAuth도 코드를 묻습니다. GitHub나 Google로 로그인하면 공급자 계정은 증명되지만 2단계 인증은 증명되지 않습니다. 공급자가 포털로 돌려보낸 뒤에 코드를 묻습니다.

OAuth로 로그인​

GitHub 또는 Google이 구성되어 있다면 /login 페이지의 이메일 필드 아래에 해당 버튼이 표시됩니다.

  1. Continue with GitHub 또는 Continue with Google을 클릭합니다.
  2. 공급자 동의 화면에서 접근 요청을 승인합니다.
  3. 포털로 리다이렉트되어 로그인됩니다.

2단계 로그인을 켜 두었다면 공급자가 돌려보낸 뒤 코드를 묻고, 그전에는 아무것도 로그인되지 않습니다.

최초 OAuth 로그인 시 공급자가 검증한 이메일로 계정이 자동 생성됩니다. 개인 팀이 자동으로 프로비저닝됩니다(<your-handle>'s team 형식).

이후 로그인은 (provider, provider_user_id)로 기존 신원을 조회합니다. 공급자의 email 필드는 매칭에 사용되지 않습니다 — 공급자 측에서 재활용된 이메일 주소를 통한 계정 탈취를 방지합니다.

오류는 i18n으로 매핑된 메시지로 표면화됩니다. 일곱 가지 코드는 공급자 거부, 누락된 scope, 만료된 state, 반복된 state, 신원 충돌, 정지된 계정, 공급자 5xx를 다룹니다. 각 코드는 사용자에게 구체적인 복구 동작을 안내합니다.

/profile에서 연결된 계정 관리​

/profile 페이지의 Connected Accounts 섹션은 현재 본인 계정에 연결된 OAuth 신원을 나열합니다.

  • GitHub — GitHub로 한 번이라도 로그인한 적이 있으면 표시.
  • Google — Google로 한 번이라도 로그인한 적이 있으면 표시.

프로필 페이지 — 헤더, 신원 카드, Connected Accounts 패널

Connected Accounts 패널은 본인 포털 계정에 현재 연결된 모든 외부 신원을 한눈에 보여줍니다:

Connected Accounts — 연결된 GitHub 신원이 표시된 패널

현재 릴리스에서는 비밀번호 로그인이 Connected Accounts 목록에 별도 행으로 표시되지 않습니다 — 이메일+비밀번호로 가입했거나 비밀번호 재설정을 완료했다면 묵시적으로 활성 상태입니다. OAuth만 사용 중인 계정의 비밀번호 복구는 로드맵 항목입니다. 현재는 운영자 측 /admin/users/{id}/password-reset 엔드포인트가 유일한 경로입니다.

각 Connected Accounts 행에는 Unlink 버튼이 있습니다. 포털은 본인이 로그인 수단을 모두 잃는 상황을 방지합니다(마지막 인증 수단 보호).

  • 연결 해제로 인해 로그인 수단이 하나도 남지 않게 되면(예: OAuth 신원 하나만 있고 비밀번호도 설정되지 않은 경우) 요청은 HTTP 409로 거부되며 UI에 알림이 표시됩니다 — "Set a password before unlinking your last OAuth identity."
  • 대안 경로는 Forgot password입니다. 리셋 링크를 요청해 비밀번호를 설정한 다음 /profile로 돌아와 연결을 해제하세요.

새 공급자 연결은 대칭적입니다. 로그아웃 후 새 공급자로 로그인하면 검증된 이메일이 기존 계정과 일치하므로 새 신원이 자동으로 추가됩니다.

정상 동작 확인​

  • 비밀번호 로그인 후 글로벌 바에 이니셜과 지금 작업 중인 팀이 표시됩니다.

팀 전환​

두 개 이상의 팀에 속해 있으면 글로벌 바의 팀 이름이 메뉴가 됩니다. 다른 팀을 고르면 새 프로젝트가 생성될 팀이 바뀌고, 그 선택은 새로 고침 후에도 유지됩니다.

다만 어떤 화면도 걸러 내지 않습니다. 대시보드와 프로젝트 목록은 어떤 팀을 선택하든 소속으로 닿는 범위 전부를 보여 줍니다 — 조용히 페이지를 좁히는 컨트롤은 실수로 켜 둔 채 알아차리기 어렵기 때문입니다. 화면을 좁힐 때는 그 화면의 필터를 씁니다.

소속 팀이 하나면 이름이 평범한 라벨로만 표시되고, 소속이 없으면(예: 시드된 최고 관리자) 아무것도 표시되지 않습니다.

  • OAuth 로그인 후 /profile에 사용한 공급자가 나열됩니다.
  • 연결 해제 후 해당 행이 사라지며, 남은 행의 Unlink 버튼은 본인을 잠그게 될 경우 비활성화됩니다.

/about에서 보는 라이선스와 고지​

사이드바의 제품 정보는 이 설치본이 무엇이고 어떤 라이선스 고지를 함께 배포하는지 보여줍니다. 관리자 권한은 필요하지 않습니다. 라이선스 고지는 설치본을 쓰는 모든 사용자가 볼 수 있어야 하는 내용입니다.

이 화면은 제품 이름, 실행 중인 버전, SPDX 라이선스 식별자, 저작권자, 공개된 소스 코드 주소를 보여줍니다. 그 아래 세 개의 탭이 고지 파일 원문을 그대로 담습니다.

탭파일내용
라이선스LICENSETRUSCA 자체에 적용되는 라이선스(Apache-2.0).
고지NOTICEApache-2.0 라이선스 4(d)항이 요구하는 TRUSCA의 저작권 고지.
서드파티 고지THIRD_PARTY_NOTICES.md소스 트리에 포함한 서드파티 자료와 컨테이너 이미지에 번들한 도구의 귀속 정보.

같은 파일 세 개가 모든 컨테이너 이미지의 /licenses/ 경로와 Helm 차트에도 들어 있습니다. 셸에 접근할 수 있는 운영자는 UI 없이도 읽을 수 있습니다. 제품 안에도 둔 이유는 TRUSCA를 직접 설치해 운영하고 외부 망이 끊긴 환경도 지원하기 때문입니다. 그런 환경에서는 GitHub 링크를 따라가는 방법이 통하지 않습니다.

어떤 탭이 파일이 없다고 표시하면 이미지를 빌드할 때 파일이 빠진 것입니다. 포털이 아니라 릴리스 산출물을 확인하세요.

함께 보기​

  • 알림 — 프로젝트 이벤트가 어떻게 본인에게 도달하는지.
  • 통합 — 비대화형 클라이언트를 위한 API Key.
  • 사용자 및 팀 — 동일 신원의 admin 관점.
  • 컴포넌트와 라이선스 — TRUSCA 자체가 아니라 스캔 대상 코드의 라이선스.