LDAP 문제 해결

Tier: Free, Premium, Ultimate Offering: Self-managed

관리자라면 LDAP 문제 해결을 위해 다음 정보를 사용하세요.

일반적인 문제 및 워크플로우

연결

연결 거부

LDAP 서버에 연결하려고 할 때 Connection Refused 오류 메시지가 표시되면, GitLab에서 사용하는 LDAP 포트암호화 설정을 검토하세요. 일반적으로 사용되는 조합은 encryption: 'plain'port: 389, 또는 encryption: 'simple_tls'port: 636입니다.

연결 시간 초과

GitLab이 LDAP 엔드포인트에 도달할 수 없는 경우, 다음과 같은 메시지가 표시됩니다:

Could not authenticate you from Ldapmain because "Connection timed out - user specified timeout".

구성된 LDAP 공급자 및/또는 엔드포인트가 오프라인이거나 GitLab이 접근할 수 없는 경우, 어떤 LDAP 사용자도 인증하거나 로그인할 수 없습니다. GitLab은 LDAP 중단 동안 인증을 제공하기 위해 LDAP 사용자에 대한 자격 증명을 캐시하거나 저장하지 않습니다.

이 오류가 표시되면 LDAP 공급자나 관리자에게 문의하세요.

참조 오류

로그에서 LDAP search error: Referral이 표시되거나 LDAP 그룹 동기화 중 문제를 해결할 때, 이 오류는 구성 문제를 나타낼 수 있습니다. LDAP 구성 파일 /etc/gitlab/gitlab.rb(Omnibus) 또는 config/gitlab.yml(소스)은 YAML 형식이며 들여쓰기에 민감합니다. group_baseadmin_group 구성 키가 서버 식별자 2칸 들여쓰기로 되어 있는지 확인하세요. 기본 식별자는 main이며 예시 스니펫은 다음과 같습니다:

main: # 'main'은 이 LDAP 서버의 GitLab 'provider ID'입니다
  label: 'LDAP'
  host: 'ldap.example.com'
  ...
  group_base: 'cn=my_group,ou=groups,dc=example,dc=com'
  admin_group: 'my_admin_group'

LDAP 쿼리

Tier: Premium, Ultimate Offering: Self-managed

다음 코드를 사용하여 Rails 콘솔에서 LDAP 검색을 수행할 수 있습니다. 수행하려는 작업에 따라 사용자 쿼리 또는 그룹 쿼리를 직접 하거나, ldapsearch 사용하는 것이 더 의미가 있을 수 있습니다.

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
    # :base는 필수
    # .base와 .group_base 중 하나를 사용
    base: adapter.config.group_base,

    # :filter는 선택 사항
    # 'cn'은 :base 아래의 모든 "cn"을 검색합니다
    # '*'는 검색 문자열 - 여기서는 와일드카드입니다
    filter: Net::LDAP::Filter.eq('cn', '*'),

    # :attributes는 선택 사항
    # 반환할 속성
    attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)

필터에서 OID를 사용할 때는 Net::LDAP::Filter.eqNet::LDAP::Filter.construct로 교체하세요:

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
    # :base는 필수
    # .base와 .group_base 중 하나를 사용
    base: adapter.config.base,

    # :filter는 선택 사항
    # 이 필터는 OID 1.2.840.113556.1.4.1941을 포함합니다
    # LDAP 디렉토리에서 그룹 gitlab_grp의 모든 직접 및 중첩 멤버를 검색합니다
    filter: Net::LDAP::Filter.construct("(memberOf:1.2.840.113556.1.4.1941:=CN=gitlab_grp,DC=example,DC=com)"),

    # :attributes는 선택 사항
    # 반환할 속성
    attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)

이 코드가 어떻게 실행되는지에 대한 예시는
Adapter 모듈을 검토하세요.

사용자 로그인

사용자를 찾을 수 없습니다

LDAP 연결이 확인되었다면 GitLab이 출력에서 LDAP 사용자를 표시하지 않는 경우, 다음 중 하나가 가장 가능성이 높습니다:

  • bind_dn 사용자가 사용자 트리를 탐색할 수 있는 권한이 충분하지 않습니다.
  • 사용자가 구성된 base 아래에 포함되지 않습니다.
  • 구성된 user_filter가 사용자 접근을 차단합니다.

이 경우 위의 사항 중 어떤 것이 사실인지 확인하려면 기존 LDAP 구성으로 /etc/gitlab/gitlab.rb에서 ldapsearch를 사용하여 확인할 수 있습니다.

사용자가 로그인할 수 없습니다

사용자가 로그인하는 데 문제를 겪는 이유는 여러 가지가 있을 수 있습니다. 시작하기 위해 스스로에게 물어볼 몇 가지 질문은 다음과 같습니다:

  • 사용자가 LDAP의 구성된 base 아래에 포함됩니까? 사용자는 로그인하기 위해 이 base 아래에 있어야 합니다.
  • 사용자가 구성된 user_filter를 통과합니까? 설정되지 않은 경우 이 질문은 무시할 수 있습니다. 만약 설정되어 있다면, 사용자는 로그인할 수 있도록 이 필터를 통과해야 합니다.

위의 사항이 모두 괜찮다면, 문제를 찾기 위해 다음 단계는 로그 자체를 살펴보는 것입니다.

  • 사용자에게 로그인하라고 요청하고 실패하게 하십시오.
  • 출력을 살펴보세요 로그인에 대한 오류나 다른 메시지를 찾으세요. 이 페이지의 다른 오류 메시지 중 하나를 볼 수 있으며, 이 경우 해당 섹션이 문제를 해결하는 데 도움이 될 수 있습니다.

로그가 문제의 근본 원인으로 이어지지 않으면, rails console를 사용하여 LDAP에서 이 사용자 쿼리하기 를 통해 GitLab이 LDAP 서버에서 이 사용자를 읽을 수 있는지 확인하십시오.

또한 사용자 동기화 디버깅이 도움이 될 수 있습니다.

사용자가 “잘못된 로그인 또는 비밀번호” 오류를 봅니다.

사용자가 이 오류를 보이면 LDAP 로그인 양식 대신 Standard 로그인 양식을 사용하여 로그인하려고 하기 때문일 수 있습니다.

해결하려면 사용자에게 LDAP 로그인 양식에 LDAP 사용자 이름과 비밀번호를 입력하도록 요청하세요.

로그인 시 잘못된 자격 증명

사용자가 사용하는 로그인 자격 증명이 LDAP에서 정확한 경우, 해당 사용자에 대해 다음 사항이 사실인지 확인하십시오:

  • 바인딩하는 사용자가 사용자의 트리를 읽고 탐색할 수 있는 충분한 권한이 있는지 확인하십시오.
  • user_filter가 유효한 사용자를 차단하지 않는지 확인하십시오.
  • LDAP 점검 명령을 실행하여 LDAP 설정이 올바른지 확인하고 GitLab이 사용자를 볼 수 있는지 확인하십시오.

LDAP 계정에 대한 접근 거부

오류가 있습니다 감사자 수준 액세스가 있는 사용자가 영향을 받을 수 있습니다. Premium/Ultimate에서 다운그레이드할 때 로그인하려는 감사자 사용자는 다음 메시지를 볼 수 있습니다: Access denied for your LDAP account.

영향을 받는 사용자의 접근 수준을 전환하여 해결 방법이 있습니다:

  1. 왼쪽 사이드바에서 하단의 관리자를 선택합니다.
  2. 개요 > 사용자를 선택합니다.
  3. 영향을 받은 사용자의 이름을 선택합니다.
  4. 오른쪽 상단에서 편집을 선택합니다.
  5. 사용자의 접근 수준을 Regular에서 Administrator(또는 그 반대)로 변경합니다.
  6. 페이지 하단에서 변경 사항 저장을 선택합니다.
  7. 오른쪽 상단에서 편집을 다시 선택합니다.
  8. 사용자의 원래 접근 수준(Regular 또는 Administrator)으로 복원하고 변경 사항 저장을 다시 선택합니다.

이제 사용자가 로그인할 수 있어야 합니다.

이메일이 이미 사용 중입니다

사용자가 올바른 LDAP 자격 증명으로 로그인하려고 하면 액세스가 거부되며,

production.log에는 다음과 비슷한 오류가 표시됩니다:

(LDAP) Error saving user <USER DN> (email@example.com): ["Email has already been taken"]

이 오류는 LDAP의 이메일 주소 email@example.com을 나타냅니다.

이메일 주소는 GitLab과 LDAP에서 고유해야 하며, LDAP은 사용자의 기본 이메일에 연결됩니다 (여러 개의 보조 이메일 중 하나가 아닙니다). 다른 사용자(또는 동일한 사용자)에게 email@example.com이 보조 이메일로 설정되어 있어 이 오류가 발생합니다.

이 충돌하는 이메일 주소가 어디서 오는지 확인하려면 rails console을 사용할 수 있습니다.

콘솔에서 다음을 실행하세요:

# 기본 및 보조 이메일에서 이메일을 검색합니다
user = User.find_by_any_email('email@example.com')
user.username

이것은 이 이메일 주소를 가진 사용자를 보여줍니다. 여기서 두 가지 단계 중 하나를 수행해야 합니다:

  • LDAP로 로그인할 때 이 사용자에 대한 새로운 GitLab 사용자/사용자 이름을 만들려면 충돌을 제거하기 위해 보조 이메일을 삭제합니다.
  • 이 사용자와 함께 LDAP에서 사용할 기존 GitLab 사용자/사용자 이름을 사용하려면 이 이메일을 보조 이메일에서 삭제하고 기본 이메일로 설정하여 GitLab이 이 프로필을 LDAP ID와 연결하도록 합니다.

사용자는 프로필에서 이 단계 중 하나를 수행할 수 있거나 관리자가 수행할 수 있습니다.

프로젝트 제한 오류

다음 오류는 제한 또는 제한이 활성화되어 있지만 관련 데이터 필드에 데이터가 없음을 나타냅니다:

  • Projects limit can't be blank.
  • Projects limit is not a number.

해결 방법은 다음과 같습니다:

  1. 왼쪽 사이드바에서 하단의 Admin을 선택합니다.
  2. Settings > General을 선택합니다.
  3. 다음 두 가지를 확장합니다:
    • Account and limit.
    • Sign-up restrictions.
  4. 예를 들어 Default projects limit 또는 Allowed domains for sign-ups 필드를 확인하고 관련 값이 구성되어 있는지 확인합니다.

LDAP 사용자 필터 디버그

ldapsearch를 사용하면 구성된

user filter를 테스트하여

예상한 대로 사용자를 반환하는지 확인할 수 있습니다.

ldapsearch -H ldaps://$host:$port -D "$bind_dn" -y bind_dn_password.txt -b "$base" "$user_filter" sAMAccountName
  • $로 시작하는 변수는 구성 파일의 LDAP 섹션에서 가져온 변수를 나타냅니다.
  • 일반 인증 방법을 사용하는 경우 ldaps://ldap://로 교체합니다. 포트 389는 기본 ldap:// 포트이고 636은 기본 ldaps:// 포트입니다.
  • bind_dn 사용자의 비밀번호는 bind_dn_password.txt에 있다고 가정합니다.

모든 사용자 동기화

Tier: Premium, Ultimate Offering: Self-managed

수동 사용자 동기화의 출력은

GitLab이 LDAP에 대해 사용자를 동기화하려고 할 때 발생하는 상황을 보여줍니다.

rails console에 입력한 후 다음을 실행하세요:

Rails.logger.level = Logger::DEBUG

LdapSyncWorker.new.perform

다음으로, 출력을 읽는 방법을 알아보세요.

사용자 동기화 후 예시 콘솔 출력
Tier: Premium, Ultimate Offering: Self-managed

수동 사용자 동기화의 출력은 매우 자세하며,

단일 사용자의 성공적인 동기화는 다음과 같이 보일 수 있습니다:

Syncing user John, email@example.com
  Identity Load (0.9ms)  SELECT  "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1
Instantiating Gitlab::Auth::Ldap::Person with LDIF:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: email@example.com
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John
  
  UserSyncedAttributesMetadata Load (0.9ms)  SELECT  "user_synced_attributes_metadata".* FROM "user_synced_attributes_metadata" WHERE "user_synced_attributes_metadata"."user_id" = 20 LIMIT 1
   (0.3ms)  BEGIN
  Namespace Load (1.0ms)  SELECT  "namespaces".* FROM "namespaces" WHERE "namespaces"."owner_id" = 20 AND "namespaces"."type" IS NULL LIMIT 1
  Route Load (0.8ms)  SELECT  "routes".* FROM "routes" WHERE "routes"."source_id" = 27 AND "routes"."source_type" = 'Namespace' LIMIT 1
  Ci::Runner Load (1.1ms)  SELECT "ci_runners".* FROM "ci_runners" INNER JOIN "ci_runner_namespaces" ON "ci_runners"."id" = "ci_runner_namespaces"."runner_id" WHERE "ci_runner_namespaces"."namespace_id" = 27
   (0.7ms)  COMMIT
   (0.4ms)  BEGIN
  Route Load (0.8ms)  SELECT "routes".* FROM "routes" WHERE (LOWER("routes"."path") = LOWER('John'))
  Namespace Load (1.0ms)  SELECT  "namespaces".* FROM "namespaces" WHERE "namespaces"."id" = 27 LIMIT 1
  Route Exists (0.9ms)  SELECT  1 AS one FROM "routes" WHERE LOWER("routes"."path") = LOWER('John') AND "routes"."id" != 50 LIMIT 1
  User Update (1.1ms)  UPDATE "users" SET "updated_at" = '2019-10-17 14:40:59.751685', "last_credential_check_at" = '2019-10-17 14:40:59.738714' WHERE "users"."id" = 20

여기에는 많은 정보가 있으므로, 디버깅 시 도움이 될 수 있는 사항을 살펴보겠습니다.

첫째, GitLab은 이전에 LDAP로 로그인한 모든 사용자를 찾아 반복합니다. 각 사용자의 동기는 다음 줄로 시작되며,

이는 현재 GitLab에 존재하는 사용자의 사용자 이름과 이메일을 포함합니다:

Syncing user John, email@example.com

특정 사용자의 GitLab 이메일이 출력에 없으면 해당 사용자는 아직 LDAP로 로그인하지 않은 것입니다.

다음으로 GitLab은 identities 테이블에서 이 사용자와 구성된 LDAP 제공자 간의 기존 링크를 검색합니다:

  Identity Load (0.9ms)  SELECT  "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1

identity 객체에는 GitLab이 LDAP에서 사용자를 찾는 데 사용하는 DN이 있습니다. DN이 발견되지 않으면 이메일이 대신 사용됩니다. 이 사용자가 LDAP에서 발견되었음을 알 수 있습니다:

Instantiating Gitlab::Auth::Ldap::Person with LDIF:
dn: cn=John Smith,ou=people,dc=example,dc=com
cn: John Smith
mail: email@example.com
memberof: cn=admin_staff,ou=people,dc=example,dc=com
uid: John

사용자가 DN이나 이메일로 LDAP에서 발견되지 않으면 다음과 같은 메시지를 대신 볼 수 있습니다:

LDAP search error: No Such Object

… 이 경우 사용자는 차단됩니다:

  User Update (0.4ms)  UPDATE "users" SET "state" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [["state", "ldap_blocked"], ["updated_at", "2019-10-18 15:46:22.902177"], ["id", 20]]

사용자가 LDAP에서 발견된 후 나머지 출력은 GitLab 데이터베이스를 업데이트하여 변경 사항을 반영합니다.

LDAP에서 사용자 쿼리

이 테스트는 GitLab이 LDAP에 연결하여 특정 사용자를 읽을 수 있는지를 확인합니다.

GitLab UI에서 조용히 실패할 수 있는 LDAP 연결 및/또는 쿼리 시의 잠재적인 오류를 노출할 수 있습니다.

Rails.logger.level = Logger::DEBUG

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # 'main'이 LDAP 공급자일 경우
Gitlab::Auth::Ldap::Person.find_by_uid('<uid>', adapter)

그룹 멤버십

Tier: Premium, Ultimate

Offering: Self-managed

멤버십이 부여되지 않음

때때로 특정 사용자가 LDAP 그룹 동기화를 통해 GitLab 그룹에 추가되어야 한다고 생각할 수 있지만, 어떤 이유로 인해 그렇지 않을 수 있습니다. 상황을 디버깅하기 위해 몇 가지 사항을 확인할 수 있습니다.

  • LDAP 구성에 group_base가 지정되어 있는지 확인합니다. 이 구성은 그룹 동기화가 제대로 작동하기 위해 필요합니다.

  • 올바른 LDAP 그룹 링크가 GitLab 그룹에 추가되었는지 확인합니다.

  • 사용자가 LDAP 신원을 가지고 있는지 확인합니다:
    1. 관리자로 GitLab에 로그인합니다.
    2. 왼쪽 사이드바에서 아래쪽의 관리자를 선택합니다.
    3. 왼쪽 사이드바에서 개요 > 사용자를 선택합니다.
    4. 사용자를 검색합니다.
    5. 사용자의 이름을 선택하여 사용자를 엽니다. 편집을 선택하지 마십시오.
    6. 신원 탭을 선택합니다. LDAP DN이 Identifier로 있는 LDAP 신원이 있어야 합니다. 그렇지 않다면, 이 사용자는 아직 LDAP로 로그인하지 않았으며 먼저 로그인해야 합니다.
  • 그룹이 동기화되기 위해 한 시간 또는 구성된 간격을 기다렸습니다.

    프로세스를 가속화하려면, GitLab 그룹 관리 > 구성원으로 이동하여 지금 동기화를 클릭하십시오(하나의 그룹 동기화) 또는 그룹 동기화 Rake 작업을 실행하세요 (모든 그룹 동기화).

위의 모든 사항이 괜찮다면, Rails 콘솔에서 좀 더 고급 디버깅을 시도해 보세요.

  1. Rails 콘솔에 들어갑니다.
  2. 테스트할 GitLab 그룹을 선택합니다. 이 그룹은 이미 LDAP 그룹 링크가 구성되어 있어야 합니다.
  3. 디버그 로깅을 활성화하고, 위의 GitLab 그룹을 찾아 LDAP와 동기화합니다.
  4. 동기화의 출력을 확인합니다. 출력을 읽는 방법은 예시 로그 출력을 참조하십시오.
  5. 여전히 사용자가 추가되지 않는 이유를 확인할 수 없다면, LDAP 그룹을 직접 쿼리하여 나열된 멤버를 확인합니다.
  6. 사용자의 DN 또는 UID가 위의 출력 목록 중 하나에 포함되어 있습니까? 여기의 DNs 또는 UIDs 중 하나는 이전에 확인한 LDAP 신원에서 ‘Identifier’와 일치해야 합니다. 그렇지 않다면, 사용자가 LDAP 그룹에 없는 것입니다.

LDAP 동기화가 활성화된 그룹에 서비스 계정 사용자를 추가할 수 없음

그룹에 LDAP 동기화가 활성화되어 있는 경우, 새 그룹 구성원을 초대하기 위해 “초대” 대화 상자를 사용할 수 없습니다.

GitLab 16.8 이상에서 이 문제를 해결하려면, 그룹 구성원 API 엔드포인트를 사용하여 서비스 계정을 그룹에 초대하고 제거할 수 있습니다.

관리 권한이 부여되지 않음

관리자 동기화가 구성되어 있지만

구성된 사용자에게 올바른 관리자 권한이 부여되지 않은 경우, 다음 사항이 사실인지 확인하세요:

  • group_base가 또한 구성되어 있음.
  • gitlab.rb에 구성된 admin_group이 DN이나 배열이 아니라 CN입니다.
  • 이 CN이 구성된 group_base 범위에 포함됩니다.
  • admin_group의 구성원은 이미 LDAP 자격 증명으로 GitLab에 로그인했습니다. GitLab은 이미 LDAP에 연결된 계정을 가진 사용자에게만 관리자 액세스를 부여합니다.

위의 모든 사항이 사실이고 사용자에게 여전히 액세스 권한이 부여되지 않는 경우,

수동 그룹 동기화를 Rails 콘솔에서 실행하고

출력을 확인하세요

GitLab이 admin_group을 동기화할 때 어떤 일이 발생하는지 알아보세요.

UI에서 지금 동기화 버튼이 멈춤

그룹의 그룹 > 구성원 페이지에서 지금 동기화 버튼이 멈출 수 있습니다. 이 버튼은 눌린 후 페이지가 새로 고쳐지면 멈춥니다. 버튼은 다시 선택할 수 없습니다.

지금 동기화 버튼이 멈출 수 있는 여러 가지 이유가 있으며, 특정 사례에 대한 디버깅이 필요합니다. 다음은 문제의 두 가지 가능한 원인과 해결책입니다.

유효하지 않은 구성원

그룹의 구성원 또는 요청된 구성원이 유효하지 않은 경우 지금 동기화 버튼이 멈춥니다. 이 문제의 가시성을 개선하는 진행 상황은 관련 이슈에서 확인할 수 있습니다. 지금 동기화 버튼이 멈춘 원인을 확인하기 위해 Rails 콘솔을 사용할 수 있습니다:

# 문제의 그룹을 찾습니다
group = Group.find_by(name: 'my_gitlab_group')

# 그룹 자체의 오류를 확인합니다
group.valid?
group.errors.map(&:full_messages)

# 그룹의 구성원 및 요청자 중 오류를 확인합니다
group.requesters.map(&:valid?)
group.requesters.map(&:errors).map(&:full_messages)
group.members.map(&:valid?)
group.members.map(&:errors).map(&:full_messages)

표시된 오류는 문제를 식별하고 해결책을 제시할 수 있습니다. 예를 들어, 지원 팀은 다음과 같은 오류를 보았습니다:

irb(main):018:0> group.members.map(&:errors).map(&:full_messages)
=> [["구성원의 이메일 주소가 이 그룹에 허용되지 않습니다. 그룹의 &#39;설정 &gt; 일반&#39; 페이지로 이동하여 &#39;이메일 도메인으로 구성원 제한&#39;을 확인하세요."]]

이 오류는 관리자가 이메일 도메인으로 그룹 구성원 제한 설정을 선택했지만 도메인에 오타가 있음을 나타냈습니다. 도메인 설정이 수정된 후, 지금 동기화 버튼이 다시 작동했습니다.

Sidekiq 노드에서 누락된 LDAP 구성

GitLab이 여러 노드에 걸쳐 확장되었을 때, 지금 동기화 버튼이 멈춥니다. 이 경우, Sidekiq를 실행 중인 노드의 /etc/gitlab/gitlab.rb에서 LDAP 구성이 누락되었습니다. 이 경우, Sidekiq 작업이 사라진 것처럼 보입니다.

LDAP는 Sidekiq 노드에서 필요하며, LDAP는 비동기적으로 실행되는 여러 작업이 있으며, 로컬 LDAP 구성이 필요합니다:

누락된 LDAP 구성이 문제인지 확인하기 위해, Sidekiq를 실행 중인 각 노드에서 LDAP 확인을 위한 Rake 작업을 실행할 수 있습니다. 이 노드에 LDAP가 올바르게 설정되어 있으면 LDAP 서버에 연결되고 사용자를 반환합니다.

이 문제를 해결하려면, Sidekiq 노드에서 LDAP을 구성하세요. 구성한 후, LDAP 확인을 위한 Rake 작업을 실행하여 GitLab 노드가 LDAP에 연결할 수 있는지 확인하세요.

모든 그룹 동기화

note
디버깅 시 수동으로 모든 그룹을 동기화하는 것은 불필요하므로,
레일크 작업을 사용하세요 대신.

수동 그룹 동기화에서 출력되는 내용은
GitLab이 LDAP에 대해 LDAP 그룹 멤버십을 동기화할 때 어떤 일이 발생하는지를 보여줍니다.
레일스 콘솔에 들어가서 다음을 실행하세요:

Rails.logger.level = Logger::DEBUG

LdapAllGroupsSyncWorker.new.perform

다음으로, 출력 읽는 방법을 알아보세요.

그룹 동기화 후 예제 콘솔 출력

사용자 동기화의 출력과 마찬가지로
수동 그룹 동기화에서 출력된 내용도 매우 자세합니다.
하지만 유용한 정보를 많이 포함하고 있습니다.

실제로 동기화가 시작되는 지점을 나타냅니다:

'ldapmain' 공급자를 위해 'my_group' 그룹 동기화 시작

다음 항목은 GitLab이 LDAP 서버에서 보고 있는 모든 사용자 DN의 배열을 보여줍니다.
이 DNs는 단일 LDAP 그룹의 사용자로, GitLab 그룹이 아닙니다.
이 GitLab 그룹에 연결된 여러 LDAP 그룹이 있는 경우,
각 LDAP 그룹에 대해 이러한 로그 항목이 여러 개 표시됩니다.
로그 항목에서 LDAP 사용자 DN을 보지 못한다면,
LDAP에서 사용자를 찾지 못하고 있다는 것입니다.
사용자가 실제로 LDAP 그룹에 있는지 확인하세요.

'ldap_group_1' LDAP 그룹의 멤버: ["uid=john0,ou=people,dc=example,dc=com",  
"uid=mary0,ou=people,dc=example,dc=com", "uid=john1,ou=people,dc=example,dc=com",  
"uid=mary1,ou=people,dc=example,dc=com", "uid=john2,ou=people,dc=example,dc=com",  
"uid=mary2,ou=people,dc=example,dc=com", "uid=john3,ou=people,dc=example,dc=com",  
"uid=mary3,ou=people,dc=example,dc=com", "uid=john4,ou=people,dc=example,dc=com",  
"uid=mary4,ou=people,dc=example,dc=com"]

위의 각 항목 직후에는 해결된 멤버 액세스 수준의 해시를 볼 수 있습니다.
이 해시는 GitLab이 이 그룹에 액세스해야 한다고 생각하는 모든 사용자 DN과
그 액세스 수준(역할)을 나타냅니다.
이 해시는 추가적이며, 추가 LDAP 그룹 조회에 따라 더 많은 DN이 추가되거나
기존 항목이 수정될 수 있습니다.
이 항목의 마지막 발생은 GitLab이 그룹에 추가해야 한다고 생각하는
정확한 사용자를 나타내야 합니다.

note
10은 Guest, 20은 Reporter, 30은 Developer, 40은 Maintainer
그리고 50은 Owner입니다.
'my_group' 그룹 멤버 액세스 해결됨: {"uid=john0,ou=people,dc=example,dc=com"=>30,  
"uid=mary0,ou=people,dc=example,dc=com"=>30, "uid=john1,ou=people,dc=example,dc=com"=>30,  
"uid=mary1,ou=people,dc=example,dc=com"=>30, "uid=john2,ou=people,dc=example,dc=com"=>30,  
"uid=mary2,ou=people,dc=example,dc=com"=>30, "uid=john3,ou=people,dc=example,dc=com"=>30,  
"uid=mary3,ou=people,dc=example,dc=com"=>30, "uid=john4,ou=people,dc=example,dc=com"=>30,  
"uid=mary4,ou=people,dc=example,dc=com"=>30}

다음과 같은 경고가 표시되는 것은 드문 일이 아닙니다.
이들은 GitLab이 사용자를 그룹에 추가했어야 했지만,
해당 사용자를 GitLab에서 찾을 수 없음을 나타냅니다.
보통 이는 우려할 만한 이유는 아닙니다.

특정 사용자가 이미 GitLab에 존재해야 한다고 생각하지만
이 항목이 표시되는 경우, GitLab에 저장된 DN이 불일치할 수 있습니다.
사용자의 LDAP 신원을 업데이트하려면 사용자 DN 및 이메일 변경을 참조하세요.

DN `uid=john0,ou=people,dc=example,dc=com`을 가진 사용자는  
'my_group' 그룹에 접근할 수 있어야 하지만, 해당 신원을 가진 사용자가 GitLab에 없습니다.  
사용자가 처음 로그인할 때 멤버십이 업데이트됩니다.

마지막으로, 다음 항목은 이 그룹의 동기화가 끝났음을 나타냅니다:

'my_group' 그룹에 대한 모든 공급자의 동기화 완료

모든 구성된 그룹 링크가 동기화되면, GitLab은
동기화할 Administrators 또는 External 사용자를 찾습니다:

'ldapmain' 공급자를 위한 관리자 사용자 동기화 중

출력은 단일 그룹에서 발생하는 것과 유사하게 보이며,
이 행은 동기화가 완료되었음을 나타냅니다:

'ldapmain' 공급자를 위한 관리자 사용자 동기화 완료

관리자 동기화가 구성되지 않은 경우,
다음과 같은 메시지를 보게 됩니다:

'ldapmain' 공급자에 대해 구성된 `admin_group`이 없습니다. 건너뜁니다.

그룹 동기화

모든 그룹 동기화는 출력에 많은 소음을 생성할 수 있으며, 이는 단일 GitLab 그룹의 멤버십 문제를 해결하는 데만 관심이 있을 때 산만할 수 있습니다. 그런 경우, 이 그룹만 동기화하고 디버그 출력을 확인하는 방법은 다음과 같습니다:

Rails.logger.level = Logger::DEBUG

# GitLab 그룹 찾기.
# 출력이 `nil`인 경우, 그룹을 찾을 수 없습니다.
# 출력에 많은 그룹 속성이 포함되어 있으면, 그룹이 성공적으로 발견된 것입니다.
group = Group.find_by(name: 'my_gitlab_group')

# LDAP에 대해 이 그룹 동기화
EE::Gitlab::Auth::Ldap::Sync::Group.execute_all_providers(group)

출력은 모든 그룹을 동기화할 때 얻는 것과 비슷합니다.

LDAP에서 그룹 쿼리하기

GitLab이 LDAP 그룹을 읽을 수 있고 모든 구성원을 볼 수 있는지 확인하고 싶다면, 다음을 실행할 수 있습니다:

# 어댑터와 그룹 자체 찾기
adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain') # `main`이 LDAP 제공자인 경우
ldap_group = EE::Gitlab::Auth::Ldap::Group.find_by_cn('group_cn_here', adapter)

# LDAP 그룹의 구성원 찾기
ldap_group.member_dns
ldap_group.member_uids

LDAP 동기화는 그룹 생성자를 그룹에서 제거하지 않습니다

LDAP 동기화는 해당 사용자가 그룹에 존재하지 않는 경우 LDAP 그룹의 생성자를 해당 그룹에서 제거해야 합니다. LDAP 동기화가 이를 수행하지 않으면:

  1. 사용자를 LDAP 그룹에 추가합니다.
  2. LDAP 그룹 동기화가 완료될 때까지 기다립니다.
  3. LDAP 그룹에서 사용자를 제거합니다.

사용자 DN 및 이메일이 변경되었습니다

기본 이메일 DN이 LDAP에서 변경된 경우, GitLab은 사용자의 올바른 LDAP 레코드를 식별할 수 없습니다. 그 결과, GitLab은 해당 사용자를 차단합니다. GitLab이 LDAP 레코드를 찾을 수 있도록, 사용자의 기존 GitLab 프로필을 최소한 다음 중 하나로 업데이트하세요:

  • 새로운 기본 이메일.
  • DN 값.

다음 스크립트는 제공된 모든 사용자의 이메일을 업데이트하여 차단되거나 계정에 접근할 수 없게 되는 것을 방지합니다.

참고: 다음 스크립트는 새로운 이메일 주소를 가진 새로운 계정이 먼저 제거되어야 합니다. GitLab에서 이메일 주소는 고유해야 합니다.

레일즈 콘솔로 가서 다음을 실행합니다:

# 각 항목은 이전 사용자 이름과 새 이메일을 포함해야 합니다
emails = {
  'ORIGINAL_USERNAME' => 'NEW_EMAIL_ADDRESS',
  ...
}

emails.each do |username, email|
  user = User.find_by_username(username)
  user.email = email
  user.skip_reconfirmation!
  user.save!
end

그런 다음 사용자 동기화를 실행하여 이러한 각 사용자에 대해 최신 DN을 동기화할 수 있습니다.

“Invalid grant”로 인해 AzureActivedirectoryV2에서 인증하지 못했습니다

LDAP에서 SAML로 변환할 때 Azure에서 다음과 같은 오류가 발생할 수 있습니다:

Authentication failure! invalid_credentials: OAuth2::Error, invalid_grant.

이 문제는 다음 두 가지가 모두 참일 때 발생합니다:

  • SAML이 구성된 후에도 사용자의 LDAP ID가 여전히 존재합니다.
  • 해당 사용자에 대해 LDAP가 비활성화되었습니다.

로그에는 LDAP 및 Azure 메타데이터가 모두 기록되어 있으며, 이로 인해 Azure에서 오류가 발생합니다.

단일 사용자에 대한 우회 방법은 관리 > 아이덴티티에서 사용자에게서 LDAP ID를 제거하는 것입니다.

여러 LDAP ID를 제거하려면 Could not authenticate you from Ldapmain because "Unknown provider" 오류에 대한 두 가지 우회 방법 중 하나를 사용하세요.

인증할 수 없습니다. Ldapmain에서 "알 수 없는 제공자" 때문입니다.

LDAP 서버에서 인증할 때 다음과 같은 오류가 발생할 수 있습니다:

Ldapmain에서 "알 수 없는 제공자(ldapsecondary)" 때문에 인증할 수 없습니다. 사용 가능한 제공자: ["ldapmain"].

이 오류는 이전에 LDAP 서버에서 인증된 계정을 사용하고자 할 때 발생하며, 해당 LDAP 서버가 GitLab 구성에서 이름이 변경되거나 제거된 경우입니다. 예를 들어:

  • 처음에 mainsecondary가 GitLab 구성에서 ldap_servers에 설정되어 있습니다.
  • secondary 설정이 제거되거나 main으로 이름이 변경됩니다.
  • 로그인하려는 사용자가 secondary에 대한 identify 레코드를 가지고 있지만, 그 설정은 더 이상 구성되어 있지 않습니다.

Rails 콘솔을 사용하여 영향을 받는 사용자를 나열하고 그들이 가지고 있는 LDAP 서버의 아이덴티티를 확인하세요:

ldap_identities = Identity.where(provider: "ldapsecondary")
ldap_identities.each do |identity|
  u=User.find_by_id(identity.user_id)
  ui=Identity.where(user_id: identity.user_id)
  puts "user: #{u.username}\n   #{u.email}\n   last activity: #{u.last_activity_on}\n   #{identity.provider} ID: #{identity.id} external: #{identity.extern_uid}"
  puts "   all identities:"
  ui.each do |alli|
    puts "    - #{alli.provider} ID: #{alli.id} external: #{alli.extern_uid}"
  end
end;nil

이 오류를 두 가지 방법으로 해결할 수 있습니다.

LDAP 서버에 대한 참조 이름 변경

이 솔루션은 LDAP 서버가 서로 복제된 경우에 적합하며, 영향받은 사용자가 구성된 LDAP 서버를 사용하여 로그인할 수 있어야 합니다.
예를 들어, 이제 로드 밸런서를 사용하여 LDAP 고가용성을 관리하고 있어 별도의 보조 로그인 옵션이 더 이상 필요하지 않은 경우입니다.

참고:
LDAP 서버가 서로 복제되지 않는 경우, 이 솔루션은 영향받은 사용자가 로그인할 수 없도록 합니다.

구성되지 않은 LDAP 서버에 대한 참조 이름을 변경하려면 다음을 실행하세요:

sudo gitlab-rake gitlab:ldap:rename_provider[ldapsecondary,ldapmain]

제거된 LDAP 서버와 관련된 identity 레코드 삭제

전제 조건:

  • auto_link_ldap_user가 활성화되어 있는지 확인합니다.

이 솔루션을 사용하면, 아이덴티티가 삭제된 후 영향을 받는 사용자가 구성된 LDAP 서버로 로그인을 할 수 있으며, GitLab에 의해 새 identity 레코드가 생성됩니다.

제거된 LDAP 서버가 ldapsecondary였기 때문에, Rails 콘솔에서 모든 ldapsecondary 아이덴티티를 삭제하세요:

ldap_identities = Identity.where(provider: "ldapsecondary")
ldap_identities.each do |identity|
  puts "Destroying identity: #{identity.id} #{identity.provider}: #{identity.extern_uid}"
  identity.destroy!
rescue => e
  puts 'Error generated when destroying identity:\n ' + e.to_s
end; nil

만료된 라이센스가 여러 LDAP 서버에서 오류를 발생시킵니다

multiple LDAP servers를 사용하려면 유효한 라이센스가 필요합니다. 만료된 라이센스는 다음을 유발할 수 있습니다:

  • 웹 인터페이스에서 502 오류.
  • 로그에서 다음 오류(실제 전략 이름은 /etc/gitlab/gitlab.rb에 구성된 이름에 따라 다름):

    Could not find a strategy with name `Ldapsecondary'. Please ensure it is required or explicitly set it using the :strategy_class option. (Devise::OmniAuth::StrategyNotFound)
    

이 오류를 해결하려면, 웹 인터페이스 없이 GitLab 인스턴스에 새 라이센스를 적용해야 합니다:

  1. 모든 비기본 LDAP 서버에 대한 GitLab 구성 라인을 제거하거나 주석 처리합니다.

  2. GitLab을 재구성하여 임시로 한 개의 LDAP 서버만 사용하게 합니다.

  3. Rails 콘솔에 들어가서 라이센스 키를 추가합니다.

  4. GitLab 구성에서 추가 LDAP 서버를 다시 활성화하고 GitLab을 다시 재구성합니다.

그룹에서 사용자를 제거한 후 다시 추가하기

사용자가 그룹 동기화 중에 그룹에 추가되었다가 다음 동기화에서 제거되고 이 과정이 반복적으로 발생하는 경우, 사용자가 중복되거나 불필요한 LDAP 식별자를 가지고 있지 않은지 확인하십시오.

이 식별자 중 하나가 더 이상 사용하지 않는 이전 LDAP 공급자를 위해 추가되었다면, 제거된 LDAP 서버와 관련된 identity 기록을 제거하십시오.

디버깅 도구

LDAP 확인

LDAP을 확인하기 위한 Rake 작업은 GitLab이 LDAP에 성공적으로 연결할 수 있는지 확인하고 사용자를 읽을 수 있는지 판단하는 데 유용한 도구입니다.

연결을 설정할 수 없는 경우, 이는 구성 문제 또는 방화벽이 연결을 차단하고 있기 때문일 수 있습니다.

  • 방화벽이 연결을 차단하고 있지 않은지 확인하고, LDAP 서버가 GitLab 호스트에 접근 가능하도록 합니다.
  • Rake 체크 출력에서 오류 메시지를 찾아보세요. 이 메시지는 LDAP 구성에 대한 문제를 확인하며 ‘host’, ‘port’, ‘bind_dn’, ‘password’와 같은 구성 값이 올바른지 확인하는 데 도움이 될 수 있습니다.
  • 로그에서 오류를 찾아 추가로 연결 실패를 디버그합니다.

GitLab이 LDAP에 성공적으로 연결되지만 사용자가 반환되지 않는 경우, 사용자가 발견되지 않을 때 할 일을 참조하십시오.

GitLab 로그

사용자 계정이 LDAP 구성으로 인해 차단되거나 차단 해제된 경우, 메시지가 application_json.log에 기록됩니다.

LDAP 조회 중 예기치 않은 오류(구성 오류, 타임아웃)가 있으면, 로그인 요청이 거부되며 메시지가 production.log에 기록됩니다.

ldapsearch

ldapsearch는 LDAP 서버를 쿼리할 수 있게 해주는 유틸리티입니다. 이 유틸리티를 사용하여 LDAP 설정을 테스트하고, 사용하고 있는 설정이 예상한 결과를 가져오는지 확인할 수 있습니다.

ldapsearch를 사용할 때는 gitlab.rb 구성에서 이미 지정한 동일한 설정을 사용하여 이러한 설정이 사용할 때 발생하는 결과를 확인할 수 있습니다.

이 명령을 GitLab 호스트에서 실행하면 GitLab 호스트와 LDAP 간의 장애물이 없음을 확인하는 데도 도움이 됩니다.

예를 들어, 다음 GitLab 구성을 고려하십시오:

gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' # 이 블록을 아래 'EOS'와 함께 닫는 것을 잊지 마십시오
   main: # 'main'은 이 LDAP 서버의 GitLab 'provider ID'입니다
     label: 'LDAP'
     host: '127.0.0.1'
     port: 389
     uid: 'uid'
     encryption: 'plain'
     bind_dn: 'cn=admin,dc=ldap-testing,dc=example,dc=com'
     password: 'Password1'
     active_directory: true
     allow_username_or_email_login: false
     block_auto_created_users: false
     base: 'dc=ldap-testing,dc=example,dc=com'
     user_filter: ''
     attributes:
       username: ['uid', 'userid', 'sAMAccountName']
       email:    ['mail', 'email', 'userPrincipalName']
       name:       'cn'
       first_name: 'givenName'
       last_name:  'sn'
     group_base: 'ou=groups,dc=ldap-testing,dc=example,dc=com'
     admin_group: 'gitlab_admin'
EOS

bind_dn 사용자를 찾기 위해 다음 ldapsearch를 실행할 수 있습니다:

ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
  -w Password1 \
  -p 389 \
  -h 127.0.0.1 \
  -b "dc=ldap-testing,dc=example,dc=com"

bind_dn, password, port, host, 및 base는 모두 gitlab.rb에 구성된 것과 동일합니다.

start_tls 암호화를 사용하여 ldapsearch 사용

이전 예제는 포트 389에서 평문으로 LDAP 테스트를 수행합니다. start_tls 암호화를 사용하는 경우, ldapsearch 명령에 다음을 포함해야 합니다:

  • -Z 플래그.
  • LDAP 서버의 FQDN.

TLS 협상 중에 LDAP 서버의 FQDN이 해당 인증서와 평가되기 때문에 이를 포함해야 합니다:

ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
  -w Password1 \
  -p 389 \
  -h "testing.ldap.com" \
  -b "dc=ldap-testing,dc=example,dc=com" -Z

simple_tls 암호화를 사용하여 ldapsearch 사용

simple_tls 암호화를 사용하는 경우(보통 포트 636에서), ldapsearch 명령에 다음을 포함해야 합니다:

  • -H 플래그와 포트를 가진 LDAP 서버 FQDN.
  • 전체 구성된 URI.
ldapsearch -D "cn=admin,dc=ldap-testing,dc=example,dc=com" \
  -w Password1 \
  -H "ldaps://testing.ldap.com:636" \
  -b "dc=ldap-testing,dc=example,dc=com"

자세한 내용은 공식 ldapsearch 문서를 참조하세요.

AdFind (Windows) 사용

AdFind 유틸리티(Windows 기반 시스템에서)를 사용하여 LDAP 서버에 접근할 수 있고 인증이 올바르게 작동하는지 테스트할 수 있습니다. AdFind는 Joe Richards가 만든 무료 소프트웨어 유틸리티입니다.

모든 객체 반환

필터 objectclass=*를 사용하여 모든 디렉토리 객체를 반환할 수 있습니다.

adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f (objectClass=*)

필터를 사용하여 단일 객체 반환

객체 이름이나 전체 DN지정하여 단일 객체를 검색할 수도 있습니다. 이 예제에서는 객체 이름만 CN=Leroy Fox를 지정합니다.

adfind -h ad.example.org:636 -ssl -u "CN=GitLabSRV,CN=Users,DC=GitLab,DC=org" -up Password1 -b "OU=GitLab INT,DC=GitLab,DC=org" -f "(&(objectcategory=person)(CN=Leroy Fox))"

Rails 콘솔

경고:
Rails 콘솔을 사용하면 데이터를 쉽게 생성, 읽기, 수정 및 삭제할 수 있습니다. 명령을 정확히 나열된 대로 실행해야 합니다.

Rails 콘솔은 LDAP 문제를 디버그하는 데 유용한 도구입니다. 명령을 직접 실행하고 GitLab이 이에 어떻게 반응하는지를 볼 수 있습니다.

Rails 콘솔 사용 방법에 대한 지침은 이 가이드를 참조하세요.

디버그 출력 활성화

이것은 GitLab이 무엇을 하고 있는지, 어떤 것과 함께 하고 있는지를 보여주는 디버그 출력을 제공합니다.

이 값은 지속되지 않으며, rails 콘솔에서 이 세션에 대해서만 활성화됩니다.

rails 콘솔에서 디버그 출력을 활성화하려면, rails 콘솔에 들어가서 다음을 실행하세요:

Rails.logger.level = Logger::DEBUG

그룹, 하위 그룹, 구성원 및 요청자와 관련된 모든 오류 메시지 가져오기

그룹, 하위 그룹, 구성원 및 요청자와 관련된 오류 메시지를 수집합니다.

이는 웹 인터페이스에 나타나지 않을 수 있는 오류 메시지를 캡처합니다.

특히 LDAP 그룹 동기화와 구성원 및 하위 그룹의 사용자와 관련된 예기치 않은 동작 문제를 해결하는 데 도움이 될 수 있습니다.

# 그룹 및 하위 그룹 찾기
group = Group.find_by_full_path("parent_group")
subgroup = Group.find_by_full_path("parent_group/child_group")

# 그룹 및 하위 그룹 오류
group.valid?
group.errors.map(&:full_messages)

subgroup.valid?
subgroup.errors.map(&:full_messages)

# 구성원 및 요청자에 대한 그룹 및 하위 그룹 오류
group.requesters.map(&:valid?)
group.requesters.map(&:errors).map(&:full_messages)
group.members.map(&:valid?)
group.members.map(&:errors).map(&:full_messages)
group.members_and_requesters.map(&:errors).map(&:full_messages)

subgroup.requesters.map(&:valid?)
subgroup.requesters.map(&:errors).map(&:full_messages)
subgroup.members.map(&:valid?)
subgroup.members.map(&:errors).map(&:full_messages)
subgroup.members_and_requesters.map(&:errors).map(&:full_messages)