InfoGrab DocsInfoGrab Docs

인증 개발 가이드라인

요약

Authentication 팀은 System Access와 User Profile 두 가지 기능 카테고리를 담당합니다. GitLab의 인증 및 인가에 관한 심층적인 보안 지식은 아래 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

Authentication 팀은 System Access와 User Profile 두 가지 기능 카테고리를 담당합니다. 이 가이드는 두 카테고리의 주요 주제를 참조 위치와 주의할 점과 함께 다룹니다.

GitLab의 인증 및 인가에 관한 심층적인 보안 지식은 아래 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

요청 흐름 개요#

모든 인증 흐름은 current_user로 수렴됩니다.

HTTP Request
    │
    ▼
Rack Middleware (Labkit → Rack::Attack → Warden → CSRF)
    │
    ├── Web Request ──► SessionsController / OmniauthCallbacks ──► Warden Strategies
    │
    └── API Request ──► API::APIGuard ──► AuthFinders (token lookup)
                                              │
                                              ▼
                                         current_user

API 요청에서 AuthFinders(lib/gitlab/auth/auth_finders.rb)는 다음 순서로 인증 소스를 확인합니다.

  1. 배포 토큰
  2. Bearer 토큰(job 토큰, PAT 또는 OAuth)
  3. Job 토큰(헤더 또는 파라미터)
  4. 세션 폴백(웹에서 시작된 API 호출)

가드레일:

  • AuthFinders의 토큰 확인 순서를 변경하지 않습니다. 배포 토큰, bearer 토큰, job 토큰, 세션은 정해진 우선순위에 따라 확인됩니다. 순서를 바꾸면 한 토큰 유형이 다른 토큰 유형을 가릴 수 있습니다.

토큰 접두사#

토큰 접두사를 사용하여 디버깅과 코드 리뷰 중에 토큰 유형을 식별합니다.

접두사 토큰 유형 저장 방식
glpat- 개인, 프로젝트 또는 그룹 액세스 토큰 SHA-256 digest
gldt- 배포 토큰 AES-256-GCM 암호화
glcbt- CI job 토큰 AES-256-GCM 암호화
gloas- OAuth 애플리케이션 시크릿 SHA-512 digest

토큰 유형과 저장 전략의 전체 목록은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

로그인 및 세션#

웹 로그인은 Devise와 Warden을 사용합니다. 설정은 config/initializers/8_devise.rb에 있습니다(8_ 접두사가 로드 순서를 제어합니다).

참조 위치 목적
app/controllers/sessions_controller.rb 웹 로그인 및 로그아웃.
config/initializers/warden.rb Warden 콜백, 세션 설정.
app/models/active_session.rb Redis 에서의 세션 추적.
app/controllers/admin/sessions_controller.rb Admin 모드 인증.

가드레일:

  • 병렬 세션 저장소를 따로 만들지 않습니다. Devise와 ActiveSession을 함께 사용합니다.
  • 로그인 제한에는 Rack::Attack(config/initializers/rack_attack.rb)을 사용합니다.
  • 기능 수준의 속도 제한(예: 토큰 생성, 비밀번호 재설정)에는 Gitlab::ApplicationRateLimiter를 사용합니다. 자세한 내용은 application rate limiter를 참고합니다.
  • 자격 증명(비밀번호, 토큰, 2FA 코드, 복구 코드)을 검증하는 모든 엔드포인트에는 속도 제한을 적용해야 합니다. 속도 제한 키에는 가능한 경우 소스 IP 만이 아니라 자격 증명 주체(로그인 또는 사용자)를 포함해야 합니다. 성공 시 초기화되는 IP 단위 전용 스로틀은 자격 증명 스터핑으로 우회할 수 있습니다.
  • 권한이 변경되는 모든 시점(로그인, 2FA 통과, 비밀번호 변경, admin 모드 진입)에 세션 ID를 다시 생성합니다. 세션 고정 공격을 방어합니다.

세션 기반 인증에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

액세스 토큰#

개인 액세스 토큰(PAT), 그룹 액세스 토큰, 프로젝트 액세스 토큰, 서비스 계정 PAT는 모두 personal_access_tokens 테이블에 저장되며 동일한 인증 흐름을 공유합니다. 다만 생성 방식, 토큰을 소유하는 사용자 유형, 인증을 마친 뒤에 적용되는 인가 검사는 서로 다릅니다.

개인 액세스 토큰#

참조 위치 목적
app/models/personal_access_token.rb PAT 모델, 스코프, 만료 유효성 검사.
lib/api/personal_access_tokens.rb PAT REST API(목록 조회, 취소, 교체).
app/controllers/user_settings/personal_access_tokens_controller.rb PAT UI.
app/services/personal_access_tokens/ 생성, 취소, 교체 서비스.

그룹 및 프로젝트 액세스 토큰#

참조 위치 목적
lib/api/resource_access_tokens.rb 그룹 및 프로젝트 토큰용 REST API.
app/services/resource_access_tokens/create_service.rb bot 사용자 프로비저닝을 포함한 토큰 생성.
app/controllers/groups/settings/access_tokens_controller.rb 그룹 토큰 UI.
app/controllers/projects/settings/access_tokens_controller.rb 프로젝트 토큰 UI.

서비스 계정#

서비스 계정(user_type: :service_account)은 외부 통합과 자동화를 위한 전용 사용자입니다. 인스턴스, 그룹 또는 프로젝트 수준에서 프로비저닝할 수 있습니다.

  • 인스턴스 관리자만 인스턴스 수준 서비스 계정을 만들 수 있습니다 (app/services/users/service_accounts/create_service.rb).
  • 그룹 Owner만 그룹 수준 서비스 계정을 만들 수 있습니다 (app/services/namespaces/service_accounts/group_create_service.rb).
  • Maintainer 이상 권한을 가진 사용자는 프로젝트 수준 서비스 계정을 만들 수 있습니다 (app/services/namespaces/service_accounts/project_create_service.rb).
  • composite_identity_enforced: true 인 서비스 계정은 시트 계산에서 제외됩니다.
참조 위치 목적
lib/api/service_accounts.rb 인스턴스 SA REST API.
lib/api/group_service_accounts.rb 그룹 SA REST API.
lib/api/project_service_accounts.rb 프로젝트 SA REST API.

액세스 토큰 가드레일#

  • 임시 토큰 칼럼이나 수동 해싱을 만들지 않습니다. add_authentication_token_field와 함께 TokenAuthenticatable concern을 사용합니다. 자세한 내용은 TokenAuthenticatable concern 사용을 참고합니다.
  • insecure: true 저장 전략으로 새 토큰 유형을 추가하지 않습니다. SHA-256 digest로 저장할 때는 digest: true를, 저장 데이터를 AES-256-GCM으로 암호화할 때는 encrypted: :required를 사용합니다. 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.
  • MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS(365)는 날짜를 지정하지 않았을 때 적용되는 기본 만료 값입니다. require_personal_access_token_expiry가 비활성화된 경우에는 상한으로 강제되지 않습니다.
  • 교체 중에 토큰 만료 로직을 변경하지 않습니다. 토큰 교체는 원래의 만료 정책을 유지해야 합니다. 과거 사례로 PAT를 교체하면서 서비스 계정의 만료 날짜와 그룹 멤버십 만료가 함께 변경된 일이 있습니다.
  • 사용자를 차단할 때는 모든 서브시스템에서 활성 토큰 전체가 무효화되는지 확인합니다. 과거 사례로 차단된 사용자의 PAT가 유효한 컨테이너 레지스트리 JWT를 계속 발급한 일이 있습니다.
  • 새 토큰 유형에는 만료를 기본값으로 둡니다. 명시적으로 필요한 경우가 아니라면 만료 없는 토큰 생성을 허용하지 않습니다.
  • 새 엔드포인트에서 URL 쿼리 파라미터로 토큰을 받지 않습니다. PAT에는 PRIVATE-TOKEN 헤더를, OAuth에는 Authorization: Bearer를 사용합니다.

액세스 토큰 인증에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

CI job 토큰#

CI job 토큰은 파이프라인 job을 GitLab API에 인증합니다.

참조 위치 목적
lib/ci/job_token/jwt.rb JWT 생성 및 서명.
lib/gitlab/auth/auth_finders.rb Job 토큰 추출 및 조회.
app/models/ci/build.rb Build 모델, 토큰 저장(암호화).
ee/app/models/concerns/ee/ci/job_token/jwt.rb EE 확장(composite identity).

가드레일:

  • CI job 토큰은 RSA로 서명한 JWT 입니다. 평문으로 저장하거나 문자열 동등 비교로 비교하지 않습니다.
  • Job 토큰은 특정 파이프라인 job으로 스코프가 한정되며 job과 함께 만료됩니다. job 실행 기간을 넘겨 수명을 연장하지 않습니다.

자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

OAuth 및 OpenID Connect#

GitLab은 OAuth 공급자와 클라이언트 역할을 모두 수행합니다. 또한 doorkeeper-openid_connect를 통해 OpenID Connect(OIDC) 공급자로도 동작합니다.

OAuth 및 OIDC 공급자로서의 GitLab#

외부 애플리케이션은 Doorkeeper를 사용하여 GitLab을 통해 사용자를 인증합니다. OIDC는 OAuth 위에 ID 계층을 추가하여 액세스 토큰과 함께 ID 토큰을 발급합니다.

참조 위치 목적
app/controllers/oauth/authorizations_controller.rb 인가 프롬프트 및 코드 생성.
app/controllers/oauth/tokens_controller.rb 토큰 교환 엔드포인트.
app/models/authn/oauth_application.rb OAuth 애플리케이션 등록.
app/models/oauth_access_token.rb 액세스 토큰 저장(Sha512Hash).
config/initializers/doorkeeper.rb Doorkeeper 설정, 스코프, 그랜트 흐름.
config/initializers/doorkeeper_openid_connect.rb OIDC 공급자 설정, 클레임, 서명 키.
app/controllers/oauth/discovery_controller.rb OIDC 디스커버리 엔드포인트(/.well-known/openid-configuration).

OIDC 클레임은 doorkeeper_openid_connect.rb에 정의합니다. 표준 클레임에는 sub, name, email, groups와 권한 기반 그룹 클레임 (https://gitlab.org/claims/groups/owner 등)이 포함됩니다.

GitLab의 OAuth에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

가드레일:

  • 데이터 노출을 검토하지 않은 채 새 OIDC 클레임을 추가하지 않습니다. 각 클레임은 요청한 애플리케이션이 볼 수 있는 ID 토큰에 포함됩니다.
  • OIDC 서명 키(openid_connect_signing_key)는 Rails 자격 증명에 저장됩니다. 인프라 팀과 협의하지 않고 로깅하거나 노출하거나 교체하지 않습니다.
  • 토큰은 항상 만료를 지정해 생성합니다. 만료 기간은 가능한 한 짧게 유지합니다.

OAuth 클라이언트로서의 GitLab#

사용자는 OmniAuth 전략을 통해 외부 공급자(Google, GitHub, Azure)로 GitLab에 로그인합니다.

참조 위치 목적
app/controllers/omniauth_callbacks_controller.rb 모든 공급자의 콜백 핸들러.
lib/gitlab/auth/o_auth/user.rb 사용자 조회, 생성, ID 연결.
lib/gitlab/auth/o_auth/auth_hash.rb 공급자로부터 받은 인증 데이터 파싱.
config/initializers/omniauth.rb OmniAuth 초기화.

가드레일:

  • 커스텀 OAuth 흐름을 구현하지 않습니다. 외부 공급자에는 OmniAuth 전략을, 공급자 측에는 Doorkeeper를 사용합니다.
  • GitLab 이 OAuth 클라이언트로 동작할 때는 PKCE를 사용합니다.

SAML#

SAML은 ID 공급자(Okta, Azure AD)를 통해 SSO를 제공합니다. GitLab은 두 가지 SAML 모드를 지원합니다.

측면 인스턴스 SAML Group SAML (EE)
범위 전체 GitLab 인스턴스 최상위 그룹별
설정 gitlab.rb 또는 omniauth_providers Group Settings UI
라우트 /users/auth/saml /groups/:path/-/saml
전략 omniauth-saml gem 커스텀 GroupSaml 전략
적용 인스턴스 전체 그룹별 SSO 적용
참조 위치 목적
lib/gitlab/auth/saml/ 인스턴스 수준 SAML 전략 및 ID 연결자.
ee/lib/gitlab/auth/group_saml/ Group SAML: 사용자 확인, ID 연결, 멤버십 업데이트.
ee/app/controllers/groups/omniauth_callbacks_controller.rb Group SAML 콜백 핸들러.
ee/app/controllers/groups/sso_controller.rb Group SSO 페이지.
ee/app/controllers/groups/saml_providers_controller.rb SAML 공급자 설정 UI.
ee/lib/api/provider_identity.rb SAML/SCIM ID 및 extern_uid 관리 API.

가드레일:

  • SAML RelayState 파라미터를 리다이렉트 타깃으로 사용하기 전에 검증합니다. 과거 사례로 SAML Single Logout에서 검증되지 않은 RelayState를 통한 오픈 리다이렉트가 있었습니다.
  • 모든 SAML 응답에서 XML 서명을 검증하고, 서명된 요소가 신뢰하려는 어설션인지 확인합니다. XML 서명 래핑 공격을 방어합니다. 과거 사례는 다음과 같습니다. #486565 - 인증되지 않은 SAML 로그인 우회.

SCIM#

SCIM은 사용자 수명 주기 관리(프로비저닝 및 디프로비저닝)를 자동화합니다. SCIM은 프로비저닝 전용이며 인증은 처리하지 않습니다.

참조 위치 목적
ee/app/models/scim_identity.rb SCIM ID 레코드.
ee/lib/api/scim/group_scim.rb Group SCIM API(RFC 7644).
ee/app/controllers/groups/settings/domain_verification_controller.rb SCIM 용 도메인 검증.

자세한 내용은 SCIM 설정을 참고합니다.

LDAP#

LDAP은 디렉터리 서비스(Active Directory, OpenLDAP)를 통해 사용자를 인증합니다.

참조 위치 목적
lib/gitlab/auth/ldap/ LDAP 인증 및 어댑터.
ee/lib/gitlab/auth/ldap/ EE LDAP 동기화, 그룹 링크.
ee/app/controllers/groups/ldaps_controller.rb LDAP 그룹 동기화 UI.
ee/lib/api/ldap.rb LDAP REST API.

자세한 내용은 GitLab과 LDAP 통합을 참고합니다.

2단계 인증#

2단계 인증(2FA)은 로그인에 두 번째 검증 단계를 추가합니다.

참조 위치 목적
app/controllers/profiles/two_factor_auths_controller.rb 2FA 설정 UI(TOTP, WebAuthn).
app/controllers/profiles/passkeys_controller.rb 패스키 관리.
app/controllers/concerns/authenticates_with_two_factor.rb 로그인 흐름에서의 2FA 적용.
app/controllers/concerns/enforces_two_factor_authentication.rb 2FA 요구 사항 확인.

가드레일:

  • 인증 전에 로그인 파라미터(사용자 이름, 이메일)를 정제합니다. 과거 사례로 로그인 파라미터에 포함된 공백 문자가 WebAuthn 2FA를 우회한 일이 있습니다(#585333).
  • 패스키나 2FA 장치를 삭제하면 해당 자격 증명으로 인증된 모든 세션을 무효화합니다.
  • read_api 등 스코프가 제한된 토큰이 sudo 모드나 상승된 인증 요구 사항을 우회하도록 허용하지 않습니다.

SSH 키#

SSH 키는 SSH를 통한 Git 작업을 인증합니다.

참조 위치 목적
app/controllers/user_settings/ssh_keys_controller.rb SSH 키 관리 UI.
lib/api/keys.rb SSH 키 REST API.
app/models/key.rb SSH 키 모델 및 유효성 검사.

ID 연결 및 extern_uid#

사용자가 외부 공급자를 통해 인증하면 GitLab은 GitLab 사용자와 공급자 계정을 연결하는 Identity 레코드를 생성합니다.

Identity 모델(app/models/identity.rb)은 다음을 저장합니다.

  • user_id: GitLab 사용자입니다.
  • provider: 공급자 이름입니다(예: google_oauth2, group_saml, ldapmain).
  • extern_uid: 공급자가 부여한 사용자의 고유 식별자입니다.
  • saml_provider_id: Group SAML에서 그룹의 SAML 설정에 연결됩니다.

로그인 과정에서 GitLab은 ID를 통해 사용자를 확인합니다.

  1. 외부 공급자가 UID를 포함한 인증 응답을 반환합니다.
  2. GitLab은 공급자와 UID가 일치하는 Identity 레코드를 조회합니다.
  3. 레코드를 찾고 신뢰할 수 있으면 GitLab은 연결된 사용자로 로그인합니다.
  4. 찾지 못하면 GitLab은 새 사용자를 만들거나 계정 연결을 요청합니다.

가드레일:

  • 공급자가 해당 UID가 그 계정에 속한다는 점을 보장하지 않는 경우 extern_uid 만으로 사용자를 확인하지 않습니다.

비밀번호 관리#

참조 위치 목적
app/controllers/passwords_controller.rb 비밀번호 재설정 흐름.
app/controllers/user_settings/passwords_controller.rb 비밀번호 변경.
app/models/concerns/recoverable_by_any_email.rb 기본 또는 보조 이메일을 통한 재설정.

가드레일:

  • 비밀번호 재설정 흐름에서 사용자가 제공한 모든 리다이렉트 타깃은 InternalRedirect#sanitize_redirect 또는 safe_redirect_path로 검증합니다. 원시 파라미터를 redirect_to에 전달하지 않습니다. 항상 폴백을 지정합니다.
redirect_to sanitize_redirect(params[:redirect]) || root_path
  • 비밀번호 재설정 토큰은 한 번만 사용할 수 있고 수명이 짧아야 하며 사용에 성공하면 무효화되어야 합니다. 재설정에 성공하면 해당 사용자의 다른 모든 활성 세션을 무효화해야 합니다.
  • 비밀번호 재설정 엔드포인트는 이메일 파라미터가 단일 문자열 값인지 검증하고, 배열이나 그 밖의 비문자열 유형으로 전달된 요청은 모두 거부해야 합니다. 과거 사례는 다음과 같습니다. #436084 - 비밀번호 재설정을 통한 계정 탈취.
  • 로그인 실패 응답과 비밀번호 재설정 응답은 "사용자는 있으나 자격 증명이 틀림" 과 "사용자가 없음" 사이에 차이가 없어야 합니다. 동일한 응답 본문과 동일한 타이밍을 사용합니다. 계정 열거 공격을 방어합니다.

사용자 프로필#

참조 위치 목적
app/controllers/profiles_controller.rb 프로필 표시.
app/controllers/user_settings/profiles_controller.rb 프로필 편집.
app/controllers/profiles/emails_controller.rb 이메일 관리.
app/controllers/profiles/avatars_controller.rb 아바타 업로드.
app/controllers/profiles/preferences_controller.rb 사용자 환경 설정.

API 인증#

API 요청은 API::APIGuard(lib/api/api_guard.rb)를 통해 인증합니다. API::APIGuard는 OAuth2 bearer 토큰, 스코프 적용, DPoP 검사, 오류 처리를 담당합니다.

참조 위치 목적
lib/api/api_guard.rb API 인증 모듈.
lib/gitlab/auth/auth_finders.rb API 요청의 토큰 조회.
lib/gitlab/auth/request_authenticator.rb Rack::Attack과 로깅 전용 요청 ID 확인. 액세스 제어에는 사용하지 않습니다.
app/services/auth/dpop_authentication_service.rb DPoP proof-of-possession 검증.

가드레일:

  • 커스텀 API 인증을 구현하지 않습니다. API::APIGuard를 사용합니다.
  • JWT 나 토큰 파싱을 직접 구현하지 않습니다. Authn::IamService::JwtValidationService를 사용합니다.
  • 토큰 생성 엔드포인트와 검증 엔드포인트의 속도 제한에는 check_rate_limit!를 사용합니다.

공유 인프라#

인증 코드는 웹, API, OAuth, SAML 진입점 전체에서 공유합니다. 공유 인프라를 변경하면 모든 흐름이 중단될 수 있습니다.

참조 위치 목적
app/models/authn/, app/services/authn/, lib/authn/ 인증 모델, 서비스, 토큰 프레임워크.
lib/gitlab/auth/ 핵심 인증 인프라.
app/controllers/concerns/internal_redirect.rb 안전한 리다이렉트 검증.

가드레일:

  • 모든 호출부를 확인하지 않은 채 인증 메서드의 반환 유형이나 nil-vs-value 시맨틱을 변경하지 않습니다.
  • 인증 코드는 모든 진입점에서 공유합니다. 공유 인프라를 수정할 때는 모든 흐름이 여전히 동작하는지 확인합니다.
  • 토큰 값, 비밀번호 값, 세션 ID는 절대 로깅하지 않습니다. 오류 메시지, 감사 이벤트, 구조화된 로그, 백트레이스 모두 해당됩니다.
  • 토큰 동등 비교에는 일정 시간 함수 (ActiveSupport::SecurityUtils.secure_compare)를 사용해야 합니다. 토큰 검증에 대한 타이밍 공격을 방어합니다.
  • 사용자 차단, 금지, 비활성화를 수정할 때는 차단 상태를 로그인 시점만이 아니라 사용 시점에도 확인하는지 검증합니다. 토큰, 세션, API 액세스는 모두 차단 상태를 따라야 합니다.
  • 새 인증 경로나 토큰 유형을 추가할 때는 user.blocked? 검사를 따르는지 확인합니다.
  • 사용자가 제공한 원시 파라미터를 redirect_to에 전달하지 않습니다. InternalRedirect#sanitize_redirect 또는 safe_redirect_path를 사용합니다. 리다이렉트 헬퍼는 유효하지 않은 타깃에 nil을 반환합니다. 항상 폴백을 지정합니다.

기능 플래그#

인증 관련 기능 플래그에는 group: group::authentication을 사용합니다.

관련 주제#

인증 개발 가이드라인

GitLab v19.4
원문 보기

요약

Authentication 팀은 System Access와 User Profile 두 가지 기능 카테고리를 담당합니다. GitLab의 인증 및 인가에 관한 심층적인 보안 지식은 아래 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

Authentication 팀은 System Access와 User Profile 두 가지 기능 카테고리를 담당합니다. 이 가이드는 두 카테고리의 주요 주제를 참조 위치와 주의할 점과 함께 다룹니다.

GitLab의 인증 및 인가에 관한 심층적인 보안 지식은 아래 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

요청 흐름 개요#

모든 인증 흐름은 current_user로 수렴됩니다.

HTTP Request
    │
    ▼
Rack Middleware (Labkit → Rack::Attack → Warden → CSRF)
    │
    ├── Web Request ──► SessionsController / OmniauthCallbacks ──► Warden Strategies
    │
    └── API Request ──► API::APIGuard ──► AuthFinders (token lookup)
                                              │
                                              ▼
                                         current_user

API 요청에서 AuthFinders(lib/gitlab/auth/auth_finders.rb)는 다음 순서로 인증 소스를 확인합니다.

  1. 배포 토큰
  2. Bearer 토큰(job 토큰, PAT 또는 OAuth)
  3. Job 토큰(헤더 또는 파라미터)
  4. 세션 폴백(웹에서 시작된 API 호출)

가드레일:

  • AuthFinders의 토큰 확인 순서를 변경하지 않습니다. 배포 토큰, bearer 토큰, job 토큰, 세션은 정해진 우선순위에 따라 확인됩니다. 순서를 바꾸면 한 토큰 유형이 다른 토큰 유형을 가릴 수 있습니다.

토큰 접두사#

토큰 접두사를 사용하여 디버깅과 코드 리뷰 중에 토큰 유형을 식별합니다.

접두사 토큰 유형 저장 방식
glpat- 개인, 프로젝트 또는 그룹 액세스 토큰 SHA-256 digest
gldt- 배포 토큰 AES-256-GCM 암호화
glcbt- CI job 토큰 AES-256-GCM 암호화
gloas- OAuth 애플리케이션 시크릿 SHA-512 digest

토큰 유형과 저장 전략의 전체 목록은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

로그인 및 세션#

웹 로그인은 Devise와 Warden을 사용합니다. 설정은 config/initializers/8_devise.rb에 있습니다(8_ 접두사가 로드 순서를 제어합니다).

참조 위치 목적
app/controllers/sessions_controller.rb 웹 로그인 및 로그아웃.
config/initializers/warden.rb Warden 콜백, 세션 설정.
app/models/active_session.rb Redis 에서의 세션 추적.
app/controllers/admin/sessions_controller.rb Admin 모드 인증.

가드레일:

  • 병렬 세션 저장소를 따로 만들지 않습니다. Devise와 ActiveSession을 함께 사용합니다.
  • 로그인 제한에는 Rack::Attack(config/initializers/rack_attack.rb)을 사용합니다.
  • 기능 수준의 속도 제한(예: 토큰 생성, 비밀번호 재설정)에는 Gitlab::ApplicationRateLimiter를 사용합니다. 자세한 내용은 application rate limiter를 참고합니다.
  • 자격 증명(비밀번호, 토큰, 2FA 코드, 복구 코드)을 검증하는 모든 엔드포인트에는 속도 제한을 적용해야 합니다. 속도 제한 키에는 가능한 경우 소스 IP 만이 아니라 자격 증명 주체(로그인 또는 사용자)를 포함해야 합니다. 성공 시 초기화되는 IP 단위 전용 스로틀은 자격 증명 스터핑으로 우회할 수 있습니다.
  • 권한이 변경되는 모든 시점(로그인, 2FA 통과, 비밀번호 변경, admin 모드 진입)에 세션 ID를 다시 생성합니다. 세션 고정 공격을 방어합니다.

세션 기반 인증에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

액세스 토큰#

개인 액세스 토큰(PAT), 그룹 액세스 토큰, 프로젝트 액세스 토큰, 서비스 계정 PAT는 모두 personal_access_tokens 테이블에 저장되며 동일한 인증 흐름을 공유합니다. 다만 생성 방식, 토큰을 소유하는 사용자 유형, 인증을 마친 뒤에 적용되는 인가 검사는 서로 다릅니다.

개인 액세스 토큰#

참조 위치 목적
app/models/personal_access_token.rb PAT 모델, 스코프, 만료 유효성 검사.
lib/api/personal_access_tokens.rb PAT REST API(목록 조회, 취소, 교체).
app/controllers/user_settings/personal_access_tokens_controller.rb PAT UI.
app/services/personal_access_tokens/ 생성, 취소, 교체 서비스.

그룹 및 프로젝트 액세스 토큰#

참조 위치 목적
lib/api/resource_access_tokens.rb 그룹 및 프로젝트 토큰용 REST API.
app/services/resource_access_tokens/create_service.rb bot 사용자 프로비저닝을 포함한 토큰 생성.
app/controllers/groups/settings/access_tokens_controller.rb 그룹 토큰 UI.
app/controllers/projects/settings/access_tokens_controller.rb 프로젝트 토큰 UI.

서비스 계정#

서비스 계정(user_type: :service_account)은 외부 통합과 자동화를 위한 전용 사용자입니다. 인스턴스, 그룹 또는 프로젝트 수준에서 프로비저닝할 수 있습니다.

  • 인스턴스 관리자만 인스턴스 수준 서비스 계정을 만들 수 있습니다 (app/services/users/service_accounts/create_service.rb).
  • 그룹 Owner만 그룹 수준 서비스 계정을 만들 수 있습니다 (app/services/namespaces/service_accounts/group_create_service.rb).
  • Maintainer 이상 권한을 가진 사용자는 프로젝트 수준 서비스 계정을 만들 수 있습니다 (app/services/namespaces/service_accounts/project_create_service.rb).
  • composite_identity_enforced: true 인 서비스 계정은 시트 계산에서 제외됩니다.
참조 위치 목적
lib/api/service_accounts.rb 인스턴스 SA REST API.
lib/api/group_service_accounts.rb 그룹 SA REST API.
lib/api/project_service_accounts.rb 프로젝트 SA REST API.

액세스 토큰 가드레일#

  • 임시 토큰 칼럼이나 수동 해싱을 만들지 않습니다. add_authentication_token_field와 함께 TokenAuthenticatable concern을 사용합니다. 자세한 내용은 TokenAuthenticatable concern 사용을 참고합니다.
  • insecure: true 저장 전략으로 새 토큰 유형을 추가하지 않습니다. SHA-256 digest로 저장할 때는 digest: true를, 저장 데이터를 AES-256-GCM으로 암호화할 때는 encrypted: :required를 사용합니다. 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.
  • MAX_PERSONAL_ACCESS_TOKEN_LIFETIME_IN_DAYS(365)는 날짜를 지정하지 않았을 때 적용되는 기본 만료 값입니다. require_personal_access_token_expiry가 비활성화된 경우에는 상한으로 강제되지 않습니다.
  • 교체 중에 토큰 만료 로직을 변경하지 않습니다. 토큰 교체는 원래의 만료 정책을 유지해야 합니다. 과거 사례로 PAT를 교체하면서 서비스 계정의 만료 날짜와 그룹 멤버십 만료가 함께 변경된 일이 있습니다.
  • 사용자를 차단할 때는 모든 서브시스템에서 활성 토큰 전체가 무효화되는지 확인합니다. 과거 사례로 차단된 사용자의 PAT가 유효한 컨테이너 레지스트리 JWT를 계속 발급한 일이 있습니다.
  • 새 토큰 유형에는 만료를 기본값으로 둡니다. 명시적으로 필요한 경우가 아니라면 만료 없는 토큰 생성을 허용하지 않습니다.
  • 새 엔드포인트에서 URL 쿼리 파라미터로 토큰을 받지 않습니다. PAT에는 PRIVATE-TOKEN 헤더를, OAuth에는 Authorization: Bearer를 사용합니다.

액세스 토큰 인증에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

CI job 토큰#

CI job 토큰은 파이프라인 job을 GitLab API에 인증합니다.

참조 위치 목적
lib/ci/job_token/jwt.rb JWT 생성 및 서명.
lib/gitlab/auth/auth_finders.rb Job 토큰 추출 및 조회.
app/models/ci/build.rb Build 모델, 토큰 저장(암호화).
ee/app/models/concerns/ee/ci/job_token/jwt.rb EE 확장(composite identity).

가드레일:

  • CI job 토큰은 RSA로 서명한 JWT 입니다. 평문으로 저장하거나 문자열 동등 비교로 비교하지 않습니다.
  • Job 토큰은 특정 파이프라인 job으로 스코프가 한정되며 job과 함께 만료됩니다. job 실행 기간을 넘겨 수명을 연장하지 않습니다.

자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

OAuth 및 OpenID Connect#

GitLab은 OAuth 공급자와 클라이언트 역할을 모두 수행합니다. 또한 doorkeeper-openid_connect를 통해 OpenID Connect(OIDC) 공급자로도 동작합니다.

OAuth 및 OIDC 공급자로서의 GitLab#

외부 애플리케이션은 Doorkeeper를 사용하여 GitLab을 통해 사용자를 인증합니다. OIDC는 OAuth 위에 ID 계층을 추가하여 액세스 토큰과 함께 ID 토큰을 발급합니다.

참조 위치 목적
app/controllers/oauth/authorizations_controller.rb 인가 프롬프트 및 코드 생성.
app/controllers/oauth/tokens_controller.rb 토큰 교환 엔드포인트.
app/models/authn/oauth_application.rb OAuth 애플리케이션 등록.
app/models/oauth_access_token.rb 액세스 토큰 저장(Sha512Hash).
config/initializers/doorkeeper.rb Doorkeeper 설정, 스코프, 그랜트 흐름.
config/initializers/doorkeeper_openid_connect.rb OIDC 공급자 설정, 클레임, 서명 키.
app/controllers/oauth/discovery_controller.rb OIDC 디스커버리 엔드포인트(/.well-known/openid-configuration).

OIDC 클레임은 doorkeeper_openid_connect.rb에 정의합니다. 표준 클레임에는 sub, name, email, groups와 권한 기반 그룹 클레임 (https://gitlab.org/claims/groups/owner 등)이 포함됩니다.

GitLab의 OAuth에 대한 자세한 내용은 Authentication & Authorization Security Knowledge Base (내부 문서)를 참고합니다.

가드레일:

  • 데이터 노출을 검토하지 않은 채 새 OIDC 클레임을 추가하지 않습니다. 각 클레임은 요청한 애플리케이션이 볼 수 있는 ID 토큰에 포함됩니다.
  • OIDC 서명 키(openid_connect_signing_key)는 Rails 자격 증명에 저장됩니다. 인프라 팀과 협의하지 않고 로깅하거나 노출하거나 교체하지 않습니다.
  • 토큰은 항상 만료를 지정해 생성합니다. 만료 기간은 가능한 한 짧게 유지합니다.

OAuth 클라이언트로서의 GitLab#

사용자는 OmniAuth 전략을 통해 외부 공급자(Google, GitHub, Azure)로 GitLab에 로그인합니다.

참조 위치 목적
app/controllers/omniauth_callbacks_controller.rb 모든 공급자의 콜백 핸들러.
lib/gitlab/auth/o_auth/user.rb 사용자 조회, 생성, ID 연결.
lib/gitlab/auth/o_auth/auth_hash.rb 공급자로부터 받은 인증 데이터 파싱.
config/initializers/omniauth.rb OmniAuth 초기화.

가드레일:

  • 커스텀 OAuth 흐름을 구현하지 않습니다. 외부 공급자에는 OmniAuth 전략을, 공급자 측에는 Doorkeeper를 사용합니다.
  • GitLab 이 OAuth 클라이언트로 동작할 때는 PKCE를 사용합니다.

SAML#

SAML은 ID 공급자(Okta, Azure AD)를 통해 SSO를 제공합니다. GitLab은 두 가지 SAML 모드를 지원합니다.

측면 인스턴스 SAML Group SAML (EE)
범위 전체 GitLab 인스턴스 최상위 그룹별
설정 gitlab.rb 또는 omniauth_providers Group Settings UI
라우트 /users/auth/saml /groups/:path/-/saml
전략 omniauth-saml gem 커스텀 GroupSaml 전략
적용 인스턴스 전체 그룹별 SSO 적용
참조 위치 목적
lib/gitlab/auth/saml/ 인스턴스 수준 SAML 전략 및 ID 연결자.
ee/lib/gitlab/auth/group_saml/ Group SAML: 사용자 확인, ID 연결, 멤버십 업데이트.
ee/app/controllers/groups/omniauth_callbacks_controller.rb Group SAML 콜백 핸들러.
ee/app/controllers/groups/sso_controller.rb Group SSO 페이지.
ee/app/controllers/groups/saml_providers_controller.rb SAML 공급자 설정 UI.
ee/lib/api/provider_identity.rb SAML/SCIM ID 및 extern_uid 관리 API.

가드레일:

  • SAML RelayState 파라미터를 리다이렉트 타깃으로 사용하기 전에 검증합니다. 과거 사례로 SAML Single Logout에서 검증되지 않은 RelayState를 통한 오픈 리다이렉트가 있었습니다.
  • 모든 SAML 응답에서 XML 서명을 검증하고, 서명된 요소가 신뢰하려는 어설션인지 확인합니다. XML 서명 래핑 공격을 방어합니다. 과거 사례는 다음과 같습니다. #486565 - 인증되지 않은 SAML 로그인 우회.

SCIM#

SCIM은 사용자 수명 주기 관리(프로비저닝 및 디프로비저닝)를 자동화합니다. SCIM은 프로비저닝 전용이며 인증은 처리하지 않습니다.

참조 위치 목적
ee/app/models/scim_identity.rb SCIM ID 레코드.
ee/lib/api/scim/group_scim.rb Group SCIM API(RFC 7644).
ee/app/controllers/groups/settings/domain_verification_controller.rb SCIM 용 도메인 검증.

자세한 내용은 SCIM 설정을 참고합니다.

LDAP#

LDAP은 디렉터리 서비스(Active Directory, OpenLDAP)를 통해 사용자를 인증합니다.

참조 위치 목적
lib/gitlab/auth/ldap/ LDAP 인증 및 어댑터.
ee/lib/gitlab/auth/ldap/ EE LDAP 동기화, 그룹 링크.
ee/app/controllers/groups/ldaps_controller.rb LDAP 그룹 동기화 UI.
ee/lib/api/ldap.rb LDAP REST API.

자세한 내용은 GitLab과 LDAP 통합을 참고합니다.

2단계 인증#

2단계 인증(2FA)은 로그인에 두 번째 검증 단계를 추가합니다.

참조 위치 목적
app/controllers/profiles/two_factor_auths_controller.rb 2FA 설정 UI(TOTP, WebAuthn).
app/controllers/profiles/passkeys_controller.rb 패스키 관리.
app/controllers/concerns/authenticates_with_two_factor.rb 로그인 흐름에서의 2FA 적용.
app/controllers/concerns/enforces_two_factor_authentication.rb 2FA 요구 사항 확인.

가드레일:

  • 인증 전에 로그인 파라미터(사용자 이름, 이메일)를 정제합니다. 과거 사례로 로그인 파라미터에 포함된 공백 문자가 WebAuthn 2FA를 우회한 일이 있습니다(#585333).
  • 패스키나 2FA 장치를 삭제하면 해당 자격 증명으로 인증된 모든 세션을 무효화합니다.
  • read_api 등 스코프가 제한된 토큰이 sudo 모드나 상승된 인증 요구 사항을 우회하도록 허용하지 않습니다.

SSH 키#

SSH 키는 SSH를 통한 Git 작업을 인증합니다.

참조 위치 목적
app/controllers/user_settings/ssh_keys_controller.rb SSH 키 관리 UI.
lib/api/keys.rb SSH 키 REST API.
app/models/key.rb SSH 키 모델 및 유효성 검사.

ID 연결 및 extern_uid#

사용자가 외부 공급자를 통해 인증하면 GitLab은 GitLab 사용자와 공급자 계정을 연결하는 Identity 레코드를 생성합니다.

Identity 모델(app/models/identity.rb)은 다음을 저장합니다.

  • user_id: GitLab 사용자입니다.
  • provider: 공급자 이름입니다(예: google_oauth2, group_saml, ldapmain).
  • extern_uid: 공급자가 부여한 사용자의 고유 식별자입니다.
  • saml_provider_id: Group SAML에서 그룹의 SAML 설정에 연결됩니다.

로그인 과정에서 GitLab은 ID를 통해 사용자를 확인합니다.

  1. 외부 공급자가 UID를 포함한 인증 응답을 반환합니다.
  2. GitLab은 공급자와 UID가 일치하는 Identity 레코드를 조회합니다.
  3. 레코드를 찾고 신뢰할 수 있으면 GitLab은 연결된 사용자로 로그인합니다.
  4. 찾지 못하면 GitLab은 새 사용자를 만들거나 계정 연결을 요청합니다.

가드레일:

  • 공급자가 해당 UID가 그 계정에 속한다는 점을 보장하지 않는 경우 extern_uid 만으로 사용자를 확인하지 않습니다.

비밀번호 관리#

참조 위치 목적
app/controllers/passwords_controller.rb 비밀번호 재설정 흐름.
app/controllers/user_settings/passwords_controller.rb 비밀번호 변경.
app/models/concerns/recoverable_by_any_email.rb 기본 또는 보조 이메일을 통한 재설정.

가드레일:

  • 비밀번호 재설정 흐름에서 사용자가 제공한 모든 리다이렉트 타깃은 InternalRedirect#sanitize_redirect 또는 safe_redirect_path로 검증합니다. 원시 파라미터를 redirect_to에 전달하지 않습니다. 항상 폴백을 지정합니다.
redirect_to sanitize_redirect(params[:redirect]) || root_path
  • 비밀번호 재설정 토큰은 한 번만 사용할 수 있고 수명이 짧아야 하며 사용에 성공하면 무효화되어야 합니다. 재설정에 성공하면 해당 사용자의 다른 모든 활성 세션을 무효화해야 합니다.
  • 비밀번호 재설정 엔드포인트는 이메일 파라미터가 단일 문자열 값인지 검증하고, 배열이나 그 밖의 비문자열 유형으로 전달된 요청은 모두 거부해야 합니다. 과거 사례는 다음과 같습니다. #436084 - 비밀번호 재설정을 통한 계정 탈취.
  • 로그인 실패 응답과 비밀번호 재설정 응답은 "사용자는 있으나 자격 증명이 틀림" 과 "사용자가 없음" 사이에 차이가 없어야 합니다. 동일한 응답 본문과 동일한 타이밍을 사용합니다. 계정 열거 공격을 방어합니다.

사용자 프로필#

참조 위치 목적
app/controllers/profiles_controller.rb 프로필 표시.
app/controllers/user_settings/profiles_controller.rb 프로필 편집.
app/controllers/profiles/emails_controller.rb 이메일 관리.
app/controllers/profiles/avatars_controller.rb 아바타 업로드.
app/controllers/profiles/preferences_controller.rb 사용자 환경 설정.

API 인증#

API 요청은 API::APIGuard(lib/api/api_guard.rb)를 통해 인증합니다. API::APIGuard는 OAuth2 bearer 토큰, 스코프 적용, DPoP 검사, 오류 처리를 담당합니다.

참조 위치 목적
lib/api/api_guard.rb API 인증 모듈.
lib/gitlab/auth/auth_finders.rb API 요청의 토큰 조회.
lib/gitlab/auth/request_authenticator.rb Rack::Attack과 로깅 전용 요청 ID 확인. 액세스 제어에는 사용하지 않습니다.
app/services/auth/dpop_authentication_service.rb DPoP proof-of-possession 검증.

가드레일:

  • 커스텀 API 인증을 구현하지 않습니다. API::APIGuard를 사용합니다.
  • JWT 나 토큰 파싱을 직접 구현하지 않습니다. Authn::IamService::JwtValidationService를 사용합니다.
  • 토큰 생성 엔드포인트와 검증 엔드포인트의 속도 제한에는 check_rate_limit!를 사용합니다.

공유 인프라#

인증 코드는 웹, API, OAuth, SAML 진입점 전체에서 공유합니다. 공유 인프라를 변경하면 모든 흐름이 중단될 수 있습니다.

참조 위치 목적
app/models/authn/, app/services/authn/, lib/authn/ 인증 모델, 서비스, 토큰 프레임워크.
lib/gitlab/auth/ 핵심 인증 인프라.
app/controllers/concerns/internal_redirect.rb 안전한 리다이렉트 검증.

가드레일:

  • 모든 호출부를 확인하지 않은 채 인증 메서드의 반환 유형이나 nil-vs-value 시맨틱을 변경하지 않습니다.
  • 인증 코드는 모든 진입점에서 공유합니다. 공유 인프라를 수정할 때는 모든 흐름이 여전히 동작하는지 확인합니다.
  • 토큰 값, 비밀번호 값, 세션 ID는 절대 로깅하지 않습니다. 오류 메시지, 감사 이벤트, 구조화된 로그, 백트레이스 모두 해당됩니다.
  • 토큰 동등 비교에는 일정 시간 함수 (ActiveSupport::SecurityUtils.secure_compare)를 사용해야 합니다. 토큰 검증에 대한 타이밍 공격을 방어합니다.
  • 사용자 차단, 금지, 비활성화를 수정할 때는 차단 상태를 로그인 시점만이 아니라 사용 시점에도 확인하는지 검증합니다. 토큰, 세션, API 액세스는 모두 차단 상태를 따라야 합니다.
  • 새 인증 경로나 토큰 유형을 추가할 때는 user.blocked? 검사를 따르는지 확인합니다.
  • 사용자가 제공한 원시 파라미터를 redirect_to에 전달하지 않습니다. InternalRedirect#sanitize_redirect 또는 safe_redirect_path를 사용합니다. 리다이렉트 헬퍼는 유효하지 않은 타깃에 nil을 반환합니다. 항상 폴백을 지정합니다.

기능 플래그#

인증 관련 기능 플래그에는 group: group::authentication을 사용합니다.

관련 주제#