LDAP 문제 해결

- Tier: 무료, 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 공급자 또는 관리자에게 문의하십시오.

Referral 오류

로그에 LDAP search error: Referral이 표시되거나 LDAP 그룹 동기화를 해결하는 경우, 이 오류는 구성 문제를 나타낼 수 있습니다. LDAP 구성 /etc/gitlab/gitlab.rb (옴니버스) 또는 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

다음은 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 체크를 수행하여 LDAP에 연결을 설정할 수 있는 것이 확인되었지만 GitLab에서 사용자를 표시하지 않은 경우, 다음 중 하나가 가장 가능성이 높습니다.

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

이 경우 gitlab.rb에 있는 기존 LDAP 구성을 사용하여 ldapsearch를 사용하여 위의 내용 중 어느 것이 사실인지 확인할 수 있습니다.

사용자가 로그인할 수 없음

사용자는 여러 이유로 로그인에 문제를 겪을 수 있습니다. 시작하기 위해 자신에게 다음 질문을 해보십시오.

  • LDAP에서 구성된 base에 속하는지 확인하십시오. 사용자는 이 base에 속해야합니다.
  • 구성된 user_filter를 통과하는지 확인하십시오. 구성되어 있지 않다면이 질문은 무시할 수 있습니다. 그렇지 않으면 사용자는이 필터를 통과하여 로그인해야합니다.

위의 두 가지가 모두 괜찮다면 문제를 찾아볼 수 있는 다음 장소는 문제가 발생하는 동안 로그 자체입니다.

  • 사용자에게 로그인하도록 요청하고 실패하도록 합니다.
  • 출력을 검토하여 오류 또는 다른 로그인에 관한 메시지를 찾습니다. 이 페이지에서 다른 오류 메시지 중 하나를 볼 수 있으므로 해당 부분을 통해 문제를 해결할 수 있습니다.

로그가 문제의 근본으로 이끄지 못하는 경우 Rails 콘솔을 사용하여 이 사용자를 쿼리하는 데 GitLab이 해당 사용자를 읽을 수 있는지 확인할 수 있습니다.

더 조사하려면 모든 사용자 동기화를 디버깅할 수 있습니다.

사용자가 “유효하지 않은 로그인 또는 암호” 오류를 보는 경우

사용자가 이 오류를 보는 경우, 이것은 Standard 로그인 양식 대신 LDAP 로그인 양식을 사용하여 로그인하려고 시도했기 때문일 수 있습니다.

해결하기 위해 사용자에게 LDAP 사용자 이름과 암호를 LDAP 로그인 양식으로 입력하도록 요청하십시오.

로그인 중의 잘못된 자격 증명

LDAP에서 사용하는 로그인 자격 증명이 정확한지 확인하십시오.

LDAP 계정에 대한 액세스 거부

이슈가 있어 감사자 수준 액세스를 가진 사용자에게 영향을 줄 수 있습니다. Premium/Ultimate에서 일반 사용자 수준으로 다운그레이드하는 경우 감사자 사용자가 로그인을 시도하면 다음 메시지가 표시될 수 있습니다: Access denied for your LDAP account.

해당 사용자의 액세스 수준을 토글링하는 해결책이 있습니다.

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

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

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

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

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

이 오류는 LDAP의 이메일 주소인 email@example.com을 가리킵니다. 이메일 주소는 GitLab에서 고유해야 하며 LDAP은 사용자의 기본 이메일에 연결됩니다(여러 보조 이메일 중 어떤 것이 아닌). 다른 사용자(또는 동일한 사용자)가 email@example.com을 보조 이메일로 설정했기 때문에 이 오류가 발생합니다.

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

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

이를 통해 해당 이메일 주소를 가진 사용자를 확인할 수 있습니다. 여기에서 두 단계 중 하나를 수행해야 합니다:

  • LDAP으로 로그인할 때 이 사용자를 위해 새로운 GitLab 사용자/사용자 이름을 만들어 이 충돌을 제거합니다.
  • LDAP과 함께 사용할 기존 GitLab 사용자/사용자 이름을 사용하려면, 이 이메일을 보조 이메일에서 제거하고 주 이메일로 만들어서 GitLab이 이 프로필을 LDAP 식별에 연결하게 합니다.

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

프로젝트 제한 오류

다음 오류는 제한이나 제약이 활성화되었으나 연결된 데이터 필드에 데이터가 없는 것을 나타냅니다.

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

이를 해결하려면:

  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 console로 이동한 다음 다음을 실행합니다.

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으로 로그인한 모든 사용자를 찾고 각 사용자의 동기화는 현재 GitLab에 존재하는 사용자 이름과 이메일로 시작하는 다음 줄로 시작됩니다.

사용자 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 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 연결 및/또는 쿼리 오류를 확인할 수 있습니다. ```ruby Rails.logger.level = Logger::DEBUG

adapter = Gitlab::Auth::Ldap::Adapter.new(‘ldapmain’) # ‘main’이 LDAP 제공자인 경우 Gitlab::Auth::Ldap::Person.find_by_uid(‘', adapter) ```

그룹 멤버십

Tier: Premium, Ultimate Offering: Self-Managed

권한 부여되지 않은 멤버십

특정 사용자가 GitLab 그룹에 LDAP 그룹 동기화를 통해 추가되어야 하지만 일부 이유로 인해 이루어지지 않는 경우가 있습니다. 이 상황을 디버깅하려면 여러 가지를 확인할 수 있습니다.

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

위의 모든 항목이 좋아 보인다면, Rails 콘솔에서 조금 더 고급 디버깅을 수행하세요.

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

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

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

GitLab 16.8 및 이후에는 이 문제를 해결하려면 그룹 멤버 API 엔드포인트를 사용하여 서비스 계정을 그룹에 초대하고 그룹에서 삭제할 수 있습니다.

관리자 권한 부여되지 않음

관리자 동기화가 구성되었지만 구성된 사용자에 대해 올바른 관리자 권한이 부여되지 않은 경우, 다음 사항이 확인되었는지 확인합니다.

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

위의 모든 항목이 충족되고 사용자에게 여전히 액세스 권한이 부여되지 않는 경우, Rails 콘솔에서 매뉴얼 그룹 동기화를 실행하고 출력을 확인하여 GitLab이 admin_group을 동기화할 때 무슨 일이 일어나는지 확인하세요.

그룹 동기화에 대한 자세한 내용은 이 Rake 작업을 사용하여 모든 그룹을 매뉴얼으로 동기화합니다.

매뉴얼 그룹 동기화의 출력을 통해 GitLab이 LDAP 그룹 멤버십을 LDAP와 동기화할 때 무슨 일이 일어나는지 확인할 수 있습니다. Rails 콘솔에 들어가서 다음을 실행하세요:

Rails.logger.level = Logger::DEBUG

LdapAllGroupsSyncWorker.new.perform

그런 다음 출력을 읽는 방법을 확인하세요.

그룹 동기화 후 콘솔 출력 예

사용자 동기화 출력과 마찬가지로 매뉴얼으로 그룹 동기화의 출력도 매우 상세합니다. 하지만, 많은 유용한 정보가 포함되어 있습니다.

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

Started syncing 'ldapmain' provider for 'my_group' group

다음 항목은 GitLab이 LDAP 서버에서 본 모든 사용자 DN의 배열을 보여줍니다. 이러한 DN은 GitLab 그룹이 아니라 단일 LDAP 그룹의 사용자들입니다. 이 GitLab 그룹에 여러 개의 LDAP 그룹이 연결되어 있는 경우, 각 LDAP 그룹마다 이와 유사한 여러 개의 로그 항목을 볼 수 있습니다. 이 로그 항목에서 LDAP 사용자 DN을 보지 못한다면, LDAP이 조회할 때 사용자를 반환하지 않는 것입니다. 사용자가 LDAP 그룹에 실제로 있는지 확인하세요.

Members in 'ldap_group_1' LDAP group: ["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은 ‘게스트’, 20은 ‘보고자’, 30은 ‘개발자’, 40은 ‘유지자’ 그리고 50은 ‘소유자’를 나타냅니다.
해석된 '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에 해당 ID를 가진 사용자가 없어 워닝을 볼 수 있습니다. 보통 이는 걱정할 일이 아닙니다.

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 동기화는 LDAP 그룹의 생성자를 해당 그룹에서 제거해야 합니다. 그 사용자가 그 그룹에 존재하지 않을 경우, LDAP 동기화를 실행하지 않는 것입니다.

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

사용자 DN과 이메일이 변경된 경우

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

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

다음 스크립트는 해당 사용자의 이메일을 업데이트하여 이들이 차단되지 않거나 계정에 액세스하지 못하도록 합니다.

note
다음 스크립트를 실행하려면, 새로운 이메일 주소가 제거되어서 새로운 계정이어야 합니다. GitLab에서 이메일 주소는 고유해야 합니다.

rails console로 이동하여 다음을 실행합니다:

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

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

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

AzureActivedirectoryV2에서 “유효하지 않은 부여”로 인증할 수 없음

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

인증 실패! 유효하지 않은 자격 증명: OAuth2::Error, invalid_grant.

이 문제는 다음 두 가지가 모두 참인 경우에 발생합니다:

  • SAML이 해당 사용자를 위해 구성된 후에도 LDAP 식별이 아직 존재합니다.
  • 해당 사용자에 대해 LDAP을 비활성화합니다.

로그에서 LDAP 및 Azure 메타데이터를 모두 받았기 때문에 Azure에서 오류가 발생합니다.

개별 사용자의 경우, 관리자 > 식별에서 해당 사용자의 LDAP 식별을 제거하여 이 문제를 해결할 수 있습니다.

여러 개의 LDAP 식별을 제거하고 싶은 경우, Ldapmain에서 "알 수 없는 공급자"로 인해 인증할 수 없습니다 오류의 해결 방법 두 가지 중 하나를 사용하세요.

Ldapmain에서 인증할 수 없는 이유로 “알 수없는 제공자”가 발생했습니다

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

Could not authenticate you from Ldapmain because "Unknown provider (ldapsecondary). available providers: ["ldapmain"]".

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

  • 처음에 mainsecondary가 GitLab 구성의 ldap_servers에 설정됩니다.
  • secondary 설정이 제거되거나 main으로 이름이 변경됩니다.
  • 로그인을 시도하는 사용자에게 secondary에 대한 identify 레코드가 있지만 더 이상 구성되지 않았을 경우 발생합니다.

Rails console을 사용하여 영향을 받는 사용자를 나열하고 그들이 어떤 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 고가용성을 관리하고 별도의 보조 로그인 옵션이 더 이상 필요하지 않을 때 사용됩니다.

note
LDAP 서버가 서로의 복제본이 아닌 경우, 이 해결책은 영향을 받는 사용자가 로그인 할 수 없도록 합니다.

이제 더 이상 구성되지 않은 LDAP 서버에 대한 참조를 이름을 변경하려면 다음을 실행합니다.

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

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

이러한 해결책을 통해 영향을 받는 사용자는 구성된 LDAP 서버를 사용하여 로그인할 수 있으며 GitLab에 의해 새 identity 레코드가 생성됩니다. Rails console에서 ldapsecondary identities를 삭제합니다.

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. 모든 주 LDA 서버가 아닌 GitLab 구성 라인을 제거하거나 주석 처리합니다.
  2. GitLab을 재구성하여 일시적으로 하나의 LDAP 서버만 사용하도록 합니다.
  3. Rails console로 이동하여 라이선스 키를 추가합니다.
  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' # remember to close this block with 'EOS' below
   main:
     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

이렇게 구성된 gitlab.rb에 대해 다음 ldapsearch명령을 실행하여 bind_dn 사용자를 찾을 수 있습니다:

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 사용

이전 예제는 plaintext로 포트 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) 사용

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 console

caution
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)