LDAP 문제 해결

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

관리자라면 다음 정보를 사용하여 LDAP 문제를 해결할 수 있습니다.

공통 문제 및 작업 흐름

연결

연결 거부됨

LDAP 서버에 연결을 시도할 때 Connection Refused 오류 메시지가 표시되면 GitLab에서 사용하는 LDAP portencryption 설정을 검토하십시오. 일반적인 조합은 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' is the GitLab 'provider ID' of this LDAP server
  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

다음 내용은 레일즈 콘솔을 사용하여 LDAP에서 검색을 수행할 수 있게 합니다. 수행하려는 작업에 따라 사용자 또는 그룹을 직접 쿼리하거나 ‘ldapsearch’를 사용하는 것이 더 적절할 수 있습니다.

adapter = Gitlab::Auth::Ldap::Adapter.new('ldapmain')
options = {
    # :base is required
    # .base 또는 .group_base 사용
    base: adapter.config.group_base,

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

    # :attributes is optional
    # 반환받고 싶은 속성
    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 is required
    # .base 또는 .group_base 사용
    base: adapter.config.base,

    # :filter is optional
    # 이 필터에는 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 is optional
    # 반환받고 싶은 속성
    attributes: %w(dn cn memberuid member submember uniquemember memberof)
}
adapter.ldap_search(options)

이 작업 방식에 대한 예는 ‘Adapter’ 모듈을 검토하십시오.

사용자 로그인

사용자를 찾을 수 없음

LDAP 확인했을 때 LDAP에 연결을 설정할 수 있다는 것을 확인했지만 GitLab이 출력에서 LDAP 사용자를 표시하지 않는 경우 다음 중 하나가 대부분 사실일 수 있습니다:

  • bind_dn 사용자에게 사용자 트리를 횡단할 권한이 충분하지 않음
  • 사용자가 구성된 base에 속하지 않음
  • 구성된 user_filter가 사용자에게 액세스를 차단함

이 경우 /etc/gitlab/gitlab.rb의 이미 구성된 LDAP 구성을 사용하여 ldapsearch를 사용하여 위의 항목 중 어느 것이 사실인지 확인할 수 있습니다.

사용자가 로그인할 수 없음

사용자는 다양한 이유로 로그인에 문제를 겪을 수 있습니다. 시작하려면 본인에게 다음 질문 중 몇 가지를 하십시오.

  • 사용자가 LDAP의 구성된 base에 속합니까? 사용자는 이 base에 속해야만 로그인할 수 있습니다.
  • 사용자가 구성된 user_filter를 통과합니까? 만약 설정되어 있지 않으면, 이 질문은 무시해도 됩니다. 설정되어 있다면, 사용자는 또한 이 필터를 통과하여 로그인할 수 있어야 합니다.

위의 내용이 모두 괜찮다면, 문제를 찾아볼 수 있는 다음 장소는 로그 자체입니다.

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

로그가 문제에 대한 근본으로 이끌지 않는다면, rails console을 사용하여 LDAP 서버의 이 사용자를 쿼리해볼 수 있습니다.

더 조사하기 위해 사용자 동기화를 디버깅하는 것도 도움이 될 수 있습니다.

로그인 시 잘못된 자격 증명

LDAP에서 사용된 로그인 자격 증명이 정확한지 확인하려면 다음을 확인하세요:

  • 바인딩하려는 사용자가 사용자 트리를 읽고 탐색할 충분한 권한이 있는지 확인해주세요.
  • user_filter가 그렇지 않게 유효한 사용자를 차단하고 있지는 않은지 체크해주세요.
  • LDAP 설정이 올바른지 확인하고 GitLab이 사용자를 볼 수 있는지 확인하기 위해 LDAP 체크 명령을 실행해주세요.

귀하의 LDAP 계정에 대한 액세스가 거부됨

버그로 인해 감사자 수준 액세스를 가진 사용자에게 영향을 줄 수 있습니다. 프리미엄/얼티밋에서 다운그레이드하는 경우, 로그인을 시도하는 감사자 사용자는 다음 메시지를 볼 수 있습니다: 귀하의 LDAP 계정에 대한 액세스가 걝부되었습니다.

우리에는 영향을 받는 사용자의 액세스 레벨을 토글하는 기반의 해결책이 있습니다:

  1. 왼쪽 사이드바에서 하단에서 관리 영역을 선택하세요.
  2. 개요 > 사용자를 선택하세요.
  3. 영향을 받는 사용자의 이름을 선택하세요.
  4. 오른쪽 상단에서 수정을 선택하세요.
  5. 사용자의 액세스 레벨을 일반 사용자에서 관리자로 변경하세요 (또는 그 반대로).
  6. 페이지 하단에서 변경 사항 저장을 선택하세요.
  7. 오른쪽 상단에서 다시 수정를 선택하세요.
  8. 사용자의 원래 액세스 레벨 (일반 사용자 또는 관리자)를 복원하고 다시 변경 사항 저장을 선택하세요.

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

이메일이 이미 사용 중

사용자는 올바른 LDAP 자격 증명으로 로그인을 시도했지만 액세스가 거부되었고, production.log에 다음과 같은 오류가 표시됩니다.

(LDAP) Error saving user <USER DN> (email@example.com): ["이미 사용 중인 이메일입니다"]

이 오류는 LDAP의 이메일 주소인 email@example.com을 가리킵니다. 이메일 주소는 GitLab과 LDAP에서 고유해야 하며, 사용자의 기본 이메일에 링크되어야 합니다 (가능한 다른 여러 이메일 중). 다른 사용자(또는 동일한 사용자)가 email@example.com 이메일을 부착 이메일로 설정했으며, 따라서 이 오류가 발생합니다.

이 충돌하는 이메일 주소가 어디에서 왔는지 rails console을 사용하여 확인할 수 있습니다. 콘솔에서 다음을 실행합니다.

# 이 주소를 기본 이메일과 부착 이메일 중에서 검색합니다
user = User.find_by_any_email('email@example.com')
user.username

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

  • LDAP으로 로그인할 때 이 충돌을 제거하기 위해 부착 이메일을 제거하십시오.
  • LDAP에서 사용할 기존 GitLab 사용자/사용자 이름을 사용하려면, 이 이메일을 부착 이메일에서 제거하고 기본 이메일로 만들어 GitLab이 해당 프로필을 LDAP ID와 연결할 수 있도록 하십시오.

사용자는 프로필에서 위 두 조치 중 하나를 취할 수 있으며, 관리자도 할 수 있습니다.

프로젝트 한도 오류

다음 오류는 한도나 제한이 활성화되었지만 관련 데이터 필드에는 데이터가 없는 것을 나타냅니다.

  • 프로젝트 제한은 비워 둘 수 없습니다.
  • 프로젝트 제한은 숫자가 아닙니다.

이를 해결하려면:

  1. 왼쪽 사이드바에서 하단에서 관리 영역을 선택하세요.
  2. 설정 > 일반을 선택하세요.
  3. 다음 두 가지를 확장하세요.
    • 계정 및 제한.
    • 회원 가입 제한.
  4. 예를 들어, 기본 프로젝트 한도 또는 회원 가입을 위한 허용된 도메인 필드를 확인하고 관련 값을 구성했는지 확인하세요.

LDAP 사용자 필터 디버그

ldapsearch를 사용하여 구성된 사용자 필터 가 반환해야 하는 사용자를 반환하는지 확인할 수 있습니다.

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.logger.level = Logger::DEBUG

LdapSyncWorker.new.perform

다음으로 출력을 읽는 방법을 확인하세요.

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

수동 사용자 동기화의 출력은 매우 상세하며, 단일 사용자의 성공적인 동기화는 다음과 같이 보일 수 있습니다:

사용자 John, email@example.com 동기화 중
  Identity Load (0.9ms)  SELECT  "identities".* FROM "identities" WHERE "identities"."user_id" = 20 AND (provider LIKE 'ldap%') LIMIT 1
Gitlab::Auth::Ldap::Person을 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으로 로그인한 모든 사용자를 찾고 이들에 대해 반복합니다. 각 사용자의 동기화는 다음과 같이 사용자의 사용자 이름과 이메일로 시작합니다:

사용자 John, email@example.com 동기화 중

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

다음으로, GitLab은 구성된 LDAP 제공업체와의 기존 연결을 위해 identities 테이블을 검색합니다:

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

이 신원 객체에는 GitLab이 LDAP에서 사용자를 찾기 위해 사용하는 DN이 포함되어 있습니다. DN을 찾을 수 없으면 이메일이 대신 사용됩니다. 이 사용자가 LDAP에서 찾았음을 알 수 있습니다:

Gitlab::Auth::Ldap::Person을 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 검색 오류: 오브젝트가 없음

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

  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: 프리미엄, 얼티메이트 Offering: Self-managed

부여되지 않은 멤버십

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

  • LDAP 구성에 group_base가 지정되어 있는지 확인하세요. 이 구성은 그룹 동기화가 올바르게 작동하려면 필요합니다.
  • 올바른 LDAP 그룹 링크가 GitLab 그룹에 추가되었는지 확인하세요.
  • 사용자가 LDAP 식별 정보를 가지고 있는지 확인하세요:
    1. 관리자 사용자로서 GitLab에 로그인합니다.
    2. 왼쪽 사이드바에서 아래쪽에서 관리 영역을 선택하세요.
    3. 왼쪽 사이드바에서 개요 > 사용자를 선택하세요.
    4. 사용자를 검색합니다.
    5. 이름을 선택하여 사용자를 엽니다. 편집을 선택하지 마세요.
    6. 식별 정보 탭을 선택하세요. 여기에 식별자로 LDAP DN이 있어야 합니다. 그렇지 않으면 이 사용자는 아직 LDAP으로 로그인하지 않았으며, 먼저 그렇게 해야 합니다.
  • 그룹이 동기화되기를 기다리거나 구성된 간격 동안 1시간을 기다렸습니다. 프로세스를 가속화하려면 GitLab 그룹 관리 > 멤버로 이동하여 지금 동기화를 누르거나 그룹 동기화 Rake 작업을 실행하세요.

위의 모든 항목이 모두 좋아 보인다면, 좀 더 고급 디버깅으로 넘어갑니다.

  1. 레일즈 콘솔로 이동합니다.
  2. 테스트할 GitLab 그룹을 선택합니다. 이 그룹은 이미 LDAP 그룹 링크가 구성되어 있어야 합니다.
  3. 디버그 로깅을 활성화하고 위에 적힌 GitLab 그룹을 찾아 LDAP과 동기화하세요.
  4. 동기화의 출력을 살펴보세요. 출력을 읽는 방법에 대한 예시 로그 출력을 참조하세요.
  5. 사용자가 추가되지 않는 이유를 여전히 알 수 없는 경우, LDAP 그룹을 직접 쿼리하여 출력된 멤버를 확인하세요.
  6. 출력 중에 사용자의 DN 또는 UID가 있는지 확인하세요. 여기서의 DN 또는 UID 중 하나는 이전에 확인한 LDAP 식별 정보의 ‘식별자’와 일치해야 합니다. 그렇지 않으면 사용자는 LDAP 그룹에 없는 것으로 보입니다.

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

그룹에 대해 LDAP 동기화가 활성화된 상태에서 “초대” 대화상자를 사용하여 새로운 그룹 멤버를 초대할 수 없습니다.

GitLab 16.8 이상에서 이 문제를 해결하려면, 그룹 멤버 API 엔드포인트를 사용하여 서비스 계정을 그룹에 추가 및 제거할 수 있습니다.

관리자 권한이 부여되지 않음

관리자 동기화가 구성되었지만 구성된 사용자에게 올바른 관리자 권한이 부여되지 않은 경우 다음 사항을 확인하세요.

  • group_base`가 구성되어 있는지 확인하세요.
  • gitlab.rb의 구성된 admin_group이 DN이나 배열이 아닌 CN인지 확인하세요.
  • 구성된 admin_group이 구성된 group_base의 범위 내에 있는지 확인하세요.
  • admin_group의 구성원이 이미 LDAP 자격 증명으로 GitLab에 로그인했습니다. GitLab은 이미 LDAP에 연결된 사용자에게만 관리자 액세스를 부여합니다.

위의 모든 사항이 사실이고 사용자에게 여전히 액세스 권한이 없는 경우, 레일즈 콘솔에서 수동 그룹 동기화를 실행하고 출력을 확인하여 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)
=> [["The member's email address is not allowed for this group. Go to the group's &#39;Settings &gt; General&#39; page, and check &#39;Restrict membership by email domain&#39;."]]

이 오류는 관리자가 이메일 도메인으로 그룹 멤버십을 제한하기로 선택했지만 도메인에 오타가 있었음을 보여줍니다. 도메인 설정을 수정한 후 지금 동기화 버튼이 다시 작동했습니다.

Sidekiq 노드에서 누락된 LDAP 구성

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

LDAP는 로컬 LDAP 구성을 필요로 하는 여러 작업들을 비동기적으로 실행하므로 Sidekiq 노드에서 필요합니다:

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

모든 그룹 동기화

참고: 디버깅이 필요하지 않은 경우 수동으로 Rake 작업을 사용하여 모든 그룹을 동기화할 수 있습니다.

수동 그룹 동기화에서의 출력은 GitLab이 LDAP 그룹 멤버십을 동기화할 때 어떻게 작동하는지를 보여줄 수 있습니다. rails console로 들어가서 다음을 실행하세요:

Rails.logger.level = Logger::DEBUG

LdapAllGroupsSyncWorker.new.perform

다음으로, 출력을 읽는 방법을 확인하세요.

그룹 동기화 후 콘솔 출력 예

사용자 동기화와 유사하게, 수동 그룹 동기화의 출력도 매우 상세합니다. 그러나 많은 도움이 되는 정보를 포함하고 있습니다.

실제로 동기화가 시작되는 지점을 나타내는 항목:

'ldapmain' 공급업체의 'my_group' 그룹 동기화 시작

다음 항목은 GitLab이 LDAP 서버에서 본 모든 사용자 DN의 배열을 보여줍니다. 이러한 DN은 단일 LDAP 그룹의 사용자로, GitLab 그룹이 아닙니다. 이 GitLab 그룹에 여러 LDAP 그룹이 연결되어 있는 경우, 각 LDAP 그룹에 대해 이와 유사한 로그 항목을 볼 수 있습니다. 이 로그 항목에서 LDAP 사용자 DN을 확인할 수 없는 경우, 해당 사용자가 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"]

위 항목 다음에 각 LDAP 그룹에 대한 해결된 구성원 액세스 레벨의 해시가 표시됩니다. 이 해시는 GitLab이 이 그룹에 어떤 사용자 DN이 있는지와 어떤 액세스 레벨(역할)을 가지고 있는지를 나타냅니다. 이 해시는 누적되며 추가적인 LDAP 그룹 조회에 따라 DN이 추가되거나 기존 항목이 수정될 수 있습니다. 이 항목의 가장 마지막 발생은 GitLab이 그룹에 추가해야 하는 사용자를 정확히 나타내야 합니다.

참고: 10은 Guest, 20은 Reporter, 30은 Developer, 40은 Maintainer이며 50은 Owner입니다.

'resolved '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 및 이메일이 변경된 경우를 참조하세요.

'uid=john0,ou=people,dc=example,dc=com'를 가진 사용자가 'my_group' 그룹에 액세스해야 하지만
GitLab에는 해당 신원으로 사용자가 없습니다. 사용자가 처음으로 로그인하면 멤버십이 업데이트됩니다.

마지막으로, 이 항목은 이 그룹에 대한 동기화가 완료되었음을 나타내는데:

모든 공급업체의 'my_group' 그룹 동기화가 완료됨

구성된 모든 그룹 링크가 동기화된 후, GitLab은 관리자 또는 외부 사용자를 동기화합니다:

'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 동기화가 그룹의 생성자를 해당 그룹에서 제거하지 못한다면:

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

사용자 DN 및 이메일이 변경됨

만일 주 이메일 DN이 LDAP에서 변경된 경우, GitLab은 사용자의 올바른 LDAP 레코드를 식별할 수 없습니다. 결과적으로 GitLab은 해당 사용자를 차단합니다. GitLab에서 LDAP 레코드를 찾을 수 있도록 기존의 GitLab 프로필을 적어도 다음 중 하나로 업데이트하십시오:

  • 새 주 이메일
  • DN 값

다음 스크립트는 이 사용자들을 차단되거나 계정에 액세스할 수 없지 않도록 모든 사용자에 대한 이메일을 업데이트합니다.

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

rails 콘솔로 이동한 후 다음을 실행하십시오.

# 각 항목에는 기존 사용자 이름 및 새 이메일이 포함되어야 합니다
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을 동기화하려면 UserSync를 실행하십시오.

AzureActivedirectoryV2에서 “유효하지 않은 그랜트”로 인증할 수 없음

LDAP에서 SAML로 전환하는 경우, Azure에서 다음과 같은 오류가 발생할 수 있습니다:

인증 실패! invalid_credentials: OAuth2::Error, invalid_grant.

이 문제는 다음 두 가지 조건이 모두 충족되었을 때 발생합니다: - SAML이 해당 사용자를 위해 구성된 후에도 LDAP ID가 존재합니다. - 이러한 사용자에 대해 LDAP를 비활성화합니다.

로그에는 LDAP 및 Azure 메타데이터가 모두 기록되어 해당 오류가 생성됩니다.

단일 사용자의 경우 관리자 > ID에서 사용자의 LDAP ID를 제거하여 일시적으로 해결할 수 있습니다.

여러 LDAP ID를 제거하려면, Ldapmain에서 "알 수 없는 제공자"로 인증할 수 없음 오류을 위한 해결책 중 하나를 사용하십시오.

“Ldapmain에서 “알 수 없는 제공자”로 인증할 수 없음”

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

Ldapmain에서 "Unknown provider (ldapsecondary). available providers: ["ldapmain"]"로 인증할 수 없습니다.

이 오류는 GitLab 구성에서 변경되거나 제거된 이전에 LDAP 서버로 인증한 사용자를 사용할 때 발생합니다. 예를 들어:

  • 초기에 mainsecondary가 GitLab 구성의 ldap_servers로 설정됩니다.
  • secondary 설정이 제거되거나 main으로 이름이 바뀝니다.
  • 사용자가 secondary에 대한 ID 레코드를 가지고 있지만 더 이상 구성되어 있지 않기 때문에 이 오류가 발생합니다.

Rails 콘솔를 사용하여 영향을 받는 사용자를 나열하고 무슨 LDAP 서버에 대한 ID 레코드를 가지고 있는지 확인할 수 있습니다. 다음을 실행하여 이 오류를 해결할 수 있습니다:

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 레코드 제거

이 솔루션을 사용하면 영향을 받는 사용자가 구성된 LDAP 서버로 로그인할 수 있고 GitLab에서 새 identity 레코드가 생성됩니다. 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 서버 오류

여러 LDAP 서버를 사용하는 경우 유효한 라이선스가 필요합니다. 만료된 라이선스는 다음과 같은 문제를 일으킬 수 있습니다:

  • 웹 인터페이스에서 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. 추가 LDAP 서버를 GitLab 구성에 다시 사용하도록 하고 GitLab을 다시 구성합니다.

사용자가 그룹에서 제거되고 다시 추가됨

그룹 동기화 중 사용자가 그룹에 추가되었다가 다음 동기화에서 제거되고 이러한 과정이 반복된 경우 사용자가 여러 개 또는 중복된 LDAP 식별정보를 가지고 있지 않은지 확인하십시오.

만약 그러한 식별정보 중 하나가 더 이상 사용되지 않는 이전 LDAP 제공자를 위해 추가되었다면, 제거된 LDAP 서버와 관련된 identity 레코드를 제거하십시오.

디버깅 도구

LDAP 확인

LDAP를 확인하는 Rake 태스크는 LDAP에 성공적으로 연결하고 사용자를 읽을 수 있는지 확인하는 데 도움이 되는 유용한 도구입니다.

연결이 되지 않는 경우, 구성에 문제가 있거나 방화벽이 연결을 차단한 것일 가능성이 높습니다.

  • 방화벽이 연결을 차단하거나 LDAP 서버가 GitLab 호스트에 접근 가능한지 확인합니다.
  • Rake 확인 출력에 오류 메시지가 있는지 확인하여 구성 값(특히 host, port, bind_dn, password)이 올바른지 확인합니다.
  • LDAP에 성공적으로 연결되었지만 사용자가 반환되지 않는다면 사용자를 찾을 수 없을 때 해야 할 일을 확인합니다.

GitLab 로그

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

LDAP 조회 중 예상치 못한 오류(구성 오류, 타임아웃)가 발생하면 로그인이 거부되고 메시지는 production.log에 기록됩니다.

ldapsearch

ldapsearch는 LDAP 서버에서 조회를 수행할 수 있는 유틸리티입니다. LDAP 설정을 테스트하고 사용 중인 설정이 예상한 결과를 얻는지 확인하는 데 사용할 수 있습니다.

ldapsearch를 사용할 때는 이미 gitlab.rb 구성에서 지정한 설정을 사용하여 정확히 그 설정을 사용했을 때 어떤 일이 발생하는지 확인할 수 있습니다.

GitLab 호스트에서 이 명령을 실행하여 GitLab 구성과 이미 정의된 설정이 사용될 때 어떤 일이 발생하는지 확인할 수 있습니다.

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

gitlab_rails['ldap_servers'] = YAML.load <<-'EOS' # 아래에 'EOS'로 이 블록을 닫는 것을 기억하세요
   main: # 'main'은 이 LDAP 서버의 GitLab '제공자 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 사용

이전 예에서는 평문으로 LDAP 테스트를 수행하여 포트 389에 연결했습니다. 만약 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) 사용

Windows 기반 시스템에서는 AdFind 유틸리티를 사용하여 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 콘솔

경고: 레일즈 콘솔을 사용하면 데이터를 쉽게 생성, 읽기, 수정, 삭제할 수 있습니다. 명령을 정확히 입력해야 합니다.

레일즈 콘솔은 LDAP 문제를 해결하는 데 도움이 되는 가치 있는 도구입니다. 이를 통해 명령을 실행하고 GitLab이 이러한 명령에 어떻게 응답하는지 확인할 수 있습니다.

레일즈 콘솔을 사용하는 방법에 대한 지침은 이 안내서를 참조하세요.

디버그 출력 활성화

GitLab이 수행하는 작업과 사용된 내용을 보여주는 디버그 출력을 활성화합니다. 이 값은 유지되지 않으며 레일즈 콘솔 세션에서만 활성화됩니다.

레일즈 콘솔에서 디버그 출력을 활성화하려면 레일즈 콘솔을 실행하고 다음을 실행하세요:

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)