LDAP 조직 데이터
Backstage 카탈로그는 LDAP 호환 서비스에서 직접 조직 데이터(사용자와 그룹)를 가져오도록 설정할 수 있어요. 그 결과는 조직 설정을 그대로 반영한 User 및 Group 종류 엔티티의 계층 구조예요.
출처: 문서
본문
Backstage 카탈로그는 LDAP 호환 서비스에서 직접 조직 데이터(사용자와 그룹)를 가져오도록 설정할 수 있어요. 그 결과는 조직 설정을 그대로 반영한 User 및 Group 종류 엔티티의 계층 구조예요.
지원 벤더
Backstage는 일반적으로 OpenLDAP 호환 벤더와 Active Directory, FreeIPA를 지원해요. 지원되지 않는 것 같은 벤더를 사용 중이라면 이슈를 등록해 주세요.
설치
이 제공자는 기본으로 설치되지 않으므로 백엔드 패키지에 @backstage/plugin-catalog-backend-module-ldap에 대한 종속성을 추가해야 해요.
Backstage 루트 디렉터리에서
yarn --cwd packages/backend add @backstage/plugin-catalog-backend-module-ldap
다음으로 app-config.yaml에 기본 구성을 추가하세요.
app-config.yaml
catalog: providers: ldapOrg: default: target: ldaps://ds.example.net bind: dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net secret: ${LDAP_SECRET} schedule: frequency: PT1H timeout: PT15M
마지막으로 다음 줄을 추가해 백엔드를 업데이트하세요.
packages/backend/src/index.ts
backend.add(import('@backstage/plugin-catalog-backend'));backend.add(import('@backstage/plugin-catalog-backend-module-ldap'));
구성
다음 구성은 회사 LDAP 서버에서 그룹과 사용자를 가져오는 설정이 어떻게 생길 수 있는지 보여주는 작은 예시예요.
사용자와 그룹은 배열로 여러 dn 항목에 대해 구성할 수 있어요.
catalog: providers: ldapOrg: default: target: ldaps://ds.example.net bind: dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=net secret: ${LDAP_SECRET} users: - dn: ou=people,ou=example,dc=example,dc=net options: filter: (uid=*) map: description: l set: metadata.customField: 'hello' groups: - dn: ou=access,ou=groups,ou=example,dc=example,dc=net options: filter: (&(objectClass=some-group-class)(!(groupType=email))) map: description: l set: metadata.customField: 'hello'
이 구성 블록들은 옵션이 많으므로, 블록 안의 각 "root" 키를 따로 설명할게요.
note
서로 다른 LDAP 서버에서 사용자와 그룹을 가져오고 싶다면 이름이 다른 여러 제공자를 정의할 수 있습니다.
같은 서버에서 가져와야 한다면, 같은 제공자 안에 users와 groups 블록을 배열로 여러 개 정의할 수 있습니다.
같은 블록에서 온 항목들은 memberOf 속성을 기준으로 그룹 멤버십을 감지할 수 있습니다.
사용자만 또는 그룹만 가져오고 싶다면 groups 또는 users 블록을 생략할 수 있습니다.
target
이것은 대상 서버의 URL이며, 보통 SSL이 활성화된 서버는 ldaps://ds.example.net, SSL이 없는 경우 ldap://ds.example.net 형식이에요.
target.tls.keys
TLS 옵션의 keys는 LDAP 서버와 연결을 설정하는 데 포함되는 개인 키가 들어 있는 PEM 형식 파일의 위치를 지정해요. 아래의 Google Secure LDAP Service 예시를 참고하세요.
target.tls.certs
TLS 옵션의 certs는 LDAP 서버와 연결을 설정하는 데 포함되는 인증서 체인이 들어 있는 PEM 형식 파일의 위치를 지정해요. 아래의 Google Secure LDAP Service 예시를 참고하세요.
bind
bind 블록은 플러그인이 서버에 대해 어떻게 바인딩(본질적으로 인증)해야 하는지 지정해요. 다음 필드를 가져요.
dn: uid=ldap-reader-user,ou=people,ou=example,dc=example,dc=netsecret: ${LDAP_SECRET}
dn은 플러그인이 자신으로 인증하는 사용자의 전체 LDAP Distinguished Name이에요. 현재는 일반 사용자 기반 인증만 지원돼요.
secret은 같은 사용자의 비밀번호예요. 이 예시에서는 백엔드가 시작될 때 설정되어야 하는 환경 변수 LDAP_SECRET 형태로 주어져요.
users
users 블록은 사용자의 읽기와 해석을 관장하는 설정을 정의해요. 그 필드는 아래 별도 섹션에서 설명해요.
users.dn
사용자가 저장된 DN, 예: ou=people,ou=example,dc=example,dc=net.
users.options
모든 사용자를 읽을 때 서버에 쿼리를 보낼 때 사용할 검색 옵션이에요. 모든 옵션이 기본값과 함께 아래에 표시되지만, 모두 선택 사항이에요.
options: # One of 'base', 'one', or 'sub'. scope: one # The filter is the one that you commonly will want to specify explicitly. It # is a string on the standard LDAP query format. Use it to select out the set # of users that are of actual interest to ingest. For example, you may want # to filter out disabled users. filter: (uid=*) # The attribute selectors for each item, as passed to the LDAP server. attributes: ['*', '+'] # This field is either 'false' to disable paging when reading from the # server, or an object on the form '{ pageSize: 100, pagePause: true }' that # specifies the details of how the paging shall work. paged: false
users.set
이 선택 사항은 (a.b.c 형식의) JSON 경로를 여러 개 지정하고 그 경로에 하드코딩된 값을 설정하게 해줘요. 예를 들어 생성된 엔티티에 네임스페이스 등을 하드코딩하려면 유용할 수 있어요.
set: # Just an example; the key and value can be anything metadata.namespace: 'ldap'
users.map
잘 알려진 엔티티 필드에서 LDAP 속성 이름으로의 매핑이에요. 여기서 각 LDAP 결과 항목의 속성을 어떻게 해석하고 해당 엔티티 필드로 옮길지 정의할 수 있어요. 모든 옵션이 기본값과 함께 아래에 표시되지만, 모두 선택 사항이에요.
선택 매핑을 생략해도 여전히 그 기본값을 사용해 복사돼요. 예를 들어 displayName 필드를 구성에 넣지 않아도, 제공자는 여전히 cn 속성을 엔티티 필드 spec.profile.displayName으로 복사해요.
map: # The name of the attribute that holds the relative # distinguished name of each entry. rdn: uid # The name of the attribute that shall be used for the value of # the metadata.name field of the entity. name: uid # The name of the attribute that shall be used for the value of # the metadata.description field of the entity. description: description # The name of the attribute that shall be used for the value of # the spec.profile.displayName field of the entity. displayName: cn # The name of the attribute that shall be used for the value of # the spec.profile.email field of the entity. email: mail # The name of the attribute that shall be used for the value of # the spec.profile.picture field of the entity. picture: <nothing, left out> # The name of the attribute that shall be used for the values of # the spec.memberOf field of the entity. memberOf: memberOf
groups
groups 블록은 그룹의 읽기와 해석을 관장하는 설정을 정의해요. 그 필드는 아래 별도 섹션에서 설명해요.
groups.dn
그룹이 저장된 DN, 예: ou=people,ou=example,dc=example,dc=net.
groups.options
모든 그룹을 읽을 때 서버에 쿼리를 보낼 때 사용할 검색 옵션이에요. 모든 옵션이 기본값과 함께 아래에 표시되지만, 모두 선택 사항이에요.
options: # One of 'base', 'one', or 'sub'. scope: one # The filter is the one that you commonly will want to specify explicitly. It # is a string on the standard LDAP query format. Use it to select out the set # of groups that are of actual interest to ingest. For example, you may want # to filter out disabled groups. filter: (&(objectClass=some-group-class)(!(groupType=email))) # The attribute selectors for each item, as passed to the LDAP server. attributes: ['*', '+'] # This field is either 'false' to disable paging when reading from the # server, or an object on the form '{ pageSize: 100, pagePause: true }' that # specifies the details of how the paging shall work. paged: false
groups.set
이 선택 사항은 (a.b.c 형식의) JSON 경로를 여러 개 지정하고 그 경로에 하드코딩된 값을 설정하게 해줘요. 예를 들어 생성된 엔티티에 네임스페이스 등을 하드코딩하려면 유용할 수 있어요.
set: # Just an example; the key and value can be anything metadata.namespace: 'ldap'
groups.map
잘 알려진 엔티티 필드에서 LDAP 속성 이름으로의 매핑이에요. 여기서 각 LDAP 결과 항목의 속성을 어떻게 해석하고 해당 엔티티 필드로 옮길지 정의할 수 있어요. 모든 옵션이 기본값과 함께 아래에 표시되지만, 모두 선택 사항이에요.
선택 매핑을 생략해도 여전히 그 기본값을 사용해 복사돼요. 예를 들어 displayName 필드를 구성에 넣지 않아도, 제공자는 여전히 cn 속성을 엔티티 필드 spec.profile.displayName으로 복사해요. 대상 필드가 display name처럼 선택 사항이라면 임포터는 누락된 속성을 받아들이고 대상 필드를 설정하지 않은 채로 둬요. 대상 필드가 엔티티의 name처럼 필수라면, 소스 속성이 없으면 검증이 실패해요.
map: # The name of the attribute that holds the relative # distinguished name of each entry. This value is copied into a # well known annotation to be able to query by it later. rdn: cn # The name of the attribute that shall be used for the value of # the metadata.name field of the entity. name: cn # The name of the attribute that shall be used for the value of # the metadata.description field of the entity. description: description # The name of the attribute that shall be used for the value of # the spec.type field of the entity. type: groupType # The name of the attribute that shall be used for the value of # the spec.profile.displayName field of the entity. displayName: cn # The name of the attribute that shall be used for the value of # the spec.profile.email field of the entity. email: <nothing, left out> # The name of the attribute that shall be used for the value of # the spec.profile.picture field of the entity. picture: <nothing, left out> # The name of the attribute that shall be used for the values of # the spec.parent field of the entity. memberOf: memberOf # The name of the attribute that shall be used for the values of # the spec.children field of the entity. members: member
선택적 벤더 구성
모듈이 LDAP 벤더를 자동으로 감지하지 못하는 경우, 선택적인 vendor 구성 섹션을 사용해 dn과 uuid 설정의 위치와 대소문자 구분 설정을 재정의할 수 있어요.
vendor.dnAttributeName
각 항목의 DN을 저장하는 속성의 이름을 명시적으로 정의할 수 있어요.
vendor.uuidAttributeName
각 항목의 UUID를 저장하는 속성의 이름을 명시적으로 정의할 수 있어요.
vendor.dnCaseSensitive
사용자/그룹 매핑의 대소문자 구분 문제를 무시할 수 있게 해줘요. true로 설정하면 수집이 사용자/멤버를 그들의 dn, member, 또는 memberOf 값의 대소문자와 무관하게 그룹에 연결해요.
vendor: # Attribute name override for the distinguished name (DN) of an entry. dnAttributeName: dn # Attribute name override for the unique identifier (UUID) of an entry. uuidAttributeName: uuid # Attribute to force values provided from dn and members/memberOf values all to lowercase. # This is to resolve potential user/group mapping issues if case differences on dn strings. dnCaseSensitive: true
제공자 커스터마이즈하기
수집된 엔티티를 커스터마이즈하고 싶다면 제공자가 사용자와 그룹에 대한 트랜스포머를 전달하게 할 수 있어요.
트랜스포머는 ldapOrgEntityProviderTransformsExtensionPoint를 확장해 구성할 수 있어요. 예시는 다음과 같아요.
packages/backend/src/index.ts
import { createBackendModule } from '@backstage/backend-plugin-api';import { ldapOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-ldap';import { myUserTransformer, myGroupTransformer } from './transformers';backend.add( createBackendModule({ pluginId: 'catalog', moduleId: 'ldap-extensions', register(env) { env.registerInit({ deps: { ldapTransformers: ldapOrgEntityProviderTransformsExtensionPoint, }, async init({ ldapTransformers }) { ldapTransformers.setUserTransformer(myUserTransformer); ldapTransformers.setGroupTransformer(myGroupTransformer); }, }); }, }),);