InfoGrab DocsInfoGrab Docs

Secrets Manager GraphQL API

요약

Secrets Manager는 ee/app/graphql/ 아래의 GraphQL 타입, 뮤테이션, 리졸버로 데이터와 동작을 노출합니다. 타입은 ee/app/graphql/types/secrets_management/에 있습니다.

Secrets Manager는 ee/app/graphql/ 아래의 GraphQL 타입, 뮤테이션, 리졸버로 데이터와 동작을 노출합니다. 모든 뮤테이션과 리졸버는 아래에 설명하는 오류 처리와 인가 관련 사항을 공통으로 따릅니다.

타입#

타입은 ee/app/graphql/types/secrets_management/에 있습니다.

타입 GraphQL 이름 기반
ProjectSecretsManagerType ProjectSecretsManager ProjectSecretsManager 레코드. effective_status에서 가져온 status와 엄격한 읽기 전용 모드를 위한 read_only 필드를 노출합니다.
GroupSecretsManagerType GroupSecretsManager GroupSecretsManager 레코드.
ProjectSecretType ProjectSecret OpenBao 응답으로 만든 ActiveModel::Model 시크릿.
GroupSecretType GroupSecret 그룹 시크릿용으로 같은 방식.
SecretRotationInfoType SecretRotationInfo ProjectSecretRotationInfo 또는 GroupSecretRotationInfo. 인가는 이 타입이 아니라 부모 시크릿 타입이 처리합니다.
ProjectSecretsPermissionType ProjectSecretsPermission 프로젝트 시크릿 권한. SecretsPermissionInterface를 포함합니다.
GroupSecretsPermissionType GroupSecretsPermission 그룹 권한용으로 같은 방식.
EntitlementType SecretsManagerEntitlement SecretsManagement::Entitlement 값 객체. 자격 상태를 참고합니다.
EnrollmentType SecretsManagerEnrollment SecretsManagement::NamespaceEnrollment 또는 인스턴스 전체 등록.

ee/app/graphql/types/secrets_management/secrets_permission_interface.rb의 SecretsPermissionInterface는 두 권한 타입에 principal, actions, grantedBy, expiredAt 필드를 추가하는 공유 ActiveSupport::Concern입니다.

권한 관련 지원 타입은 ee/app/graphql/types/secrets_management/permissions/에 있습니다. PrincipalType, PrincipalInputType, PrincipalTypeEnum, ActionEnum, SecretPermissionType입니다.

열거형#

열거형 값
ProjectSecretsManagerStatusEnum, GroupSecretsManagerStatusEnum BaseSecretsManagerStatusEnum을 기반으로 합니다.
SecretStatusEnum 타임스탬프로부터 계산한 시크릿의 라이프사이클 상태.
SecretRotationStatusEnum OVERDUE, APPROACHING, OK.
EntitlementStateEnum SecretsManagement::Entitlement 상태를 그대로 반영합니다.
EntitlementBlockedReasonEnum 자격의 blocked_reason 값을 그대로 반영합니다.
WriteActionDenialReasonEnum 자격 문제로 뮤테이션이 거부될 때 reason 필드에 반환되며, ProjectSecretsManagerType과 GroupSecretsManagerType의 writeDenialReason 필드에도 반환됩니다.

타입의 인가#

타입은 authorize로 Rails 정책 권한을 선언합니다. 예를 들어 ProjectSecretType에는 authorize :read_project_secrets가 있습니다. 일부 타입은 authorize_granular_token도 선언합니다. 이는 개인 액세스 토큰이 GraphQL API로 해당 타입을 읽으려면 가져야 하는 세분화된 토큰 권한을 지정합니다. 예를 들어 ProjectSecretsManagerType은 authorize_granular_token permissions: :read_secrets_manager, boundary: :project, boundary_type: :project를 선언합니다. SecretRotationInfoType처럼 객체별 정책이 없는 타입은 rubocop:disable Graphql/AuthorizeTypes 주석으로 인가 검사를 비활성화하고 부모 타입의 인가에 의존합니다.

뮤테이션#

뮤테이션은 ee/app/graphql/mutations/secrets_management/에 영역별로 묶여 있습니다.

프로젝트 및 그룹 Secrets Manager#

뮤테이션 파일 GraphQL 이름 Rails 권한 서비스
project_secrets_managers/initialize.rb ProjectSecretsManagerInitialize :provision_secrets_manager ProjectSecretsManagers::InitializeService
project_secrets_managers/deprovision.rb ProjectSecretsManagerDeprovision :admin_project_secrets_manager ProjectSecretsManagers::InitiateDeprovisionService
group_secrets_managers/initialize.rb GroupSecretsManagerInitialize :provision_secrets_manager GroupSecretsManagers::InitializeService
group_secrets_managers/deprovision.rb GroupSecretsManagerDeprovision :deprovision_secrets_manager GroupSecretsManagers::InitiateDeprovisionService

프로젝트 및 그룹 시크릿#

뮤테이션 파일 GraphQL 이름 Rails 권한
project_secrets/create.rb ProjectSecretCreate :create_project_secrets
project_secrets/update.rb ProjectSecretUpdate :update_project_secrets
project_secrets/delete.rb ProjectSecretDelete :delete_project_secrets
group_secrets/create.rb GroupSecretCreate :create_secret
group_secrets/update.rb GroupSecretUpdate :update_secret
group_secrets/delete.rb GroupSecretDelete :delete_secret

프로젝트 시크릿 뮤테이션과 그룹 시크릿 뮤테이션은 몇 가지 사소한 점이 다릅니다.

차이점 프로젝트 그룹
리졸버 include include ResolvesProject include ResolvesGroup
find_object 인수 project_path: group_path:
범위별 인수 branch (String) protected (Boolean)
반환 필드 project_secret group_secret
생성 시 내부 이벤트 이름 create_ci_secret create_group_ci_secret

시크릿 값을 받는 GraphQL 인수의 이름은 secret이지만 서비스 호출 매개변수의 이름은 value입니다. 이름 변경은 resolve에서 이루어지며, 예를 들어 project_secrets/create.rb의 .execute(value: secret, ...)가 그렇습니다. 시크릿 값을 받는 새 뮤테이션에는 모두 이 관례를 따릅니다.

권한#

뮤테이션 파일 GraphQL 이름
project_secrets_permissions/update.rb ProjectSecretsPermissionUpdate
project_secrets_permissions/delete.rb ProjectSecretsPermissionDelete
group_secrets_permissions/update.rb GroupSecretsPermissionUpdate
group_secrets_permissions/delete.rb GroupSecretsPermissionDelete

자격, 체험판, 등록#

뮤테이션 파일 GraphQL 이름
enable_add_on.rb SecretsManagerEnableAddOn
instance_enable_add_on.rb SecretsManagerInstanceEnableAddOn
start_trial.rb SecretsManagerStartTrial
instance_start_trial.rb SecretsManagerInstanceStartTrial
refresh_entitlement.rb SecretsManagerRefreshEntitlement
instance_refresh_entitlement.rb SecretsManagerInstanceRefreshEntitlement
enrollment/namespace_enroll.rb NamespaceSecretsManagerEnroll
enrollment/namespace_unenroll.rb NamespaceSecretsManagerUnenroll
enrollment/instance_enroll.rb InstanceSecretsManagerEnroll
enrollment/instance_unenroll.rb InstanceSecretsManagerUnenroll

이 뮤테이션이 무엇을 바꾸는지는 각 상태가 허용하는 동작을 참고합니다.

리졸버#

리졸버는 ee/app/graphql/resolvers/secrets_management/에 있습니다.

리졸버 용도
ProjectSecretsManagerResolver, GroupSecretsManagerResolver 프로젝트 또는 그룹의 Secrets Manager 상태를 가져옵니다.
ProjectSecretsResolver, GroupSecretsResolver 시크릿을 나열합니다. lookahead를 사용해 쿼리가 선택하지 않으면 로테이션 정보 로딩을 건너뜁니다.
ProjectSecretResolver, GroupSecretResolver 시크릿 하나를 가져옵니다.
ProjectSecretsCountResolver, GroupSecretsCountResolver 시크릿 개수를 셉니다.
ProjectSecretsPermissionsResolver, GroupSecretsPermissionsResolver 권한을 나열합니다.
ProjectSecrets::ListNeedingRotationResolver, GroupSecrets::ListNeedingRotationResolver 로테이션 기한이 되었거나 임박한 시크릿을 나열합니다.
Permissions::SecretPermissionsResolver 더 새로운 권한 타입을 통해 시크릿 권한을 나열합니다.
OpenbaoHealthResolver OpenBao 서버 상태를 확인합니다.
NamespaceEnrollmentResolver, InstanceEnrollmentResolver 등록 상태를 가져옵니다.
InstanceEntitlementResolver 인스턴스 수준의 자격을 가져옵니다.

Lookahead 최적화#

ProjectSecretsResolver와 GroupSecretsResolver는 extras [:lookahead]를 받으며, 쿼리가 요청할 때만 목록 서비스에 로테이션 정보를 포함하도록 요청합니다.

def resolve(lookahead:, project_path:)
  result = ListService.new(project, current_user)
    .execute(include_rotation_info: include_rotation_info?(lookahead))
end

def include_rotation_info?(lookahead)
  lookahead.selection(:nodes).selects?(:rotation_info) ||
    lookahead.selection(:edges).selection(:node).selects?(:rotation_info)
end

공유 뮤테이션 및 리졸버 concern#

모든 뮤테이션과 리졸버는 오류 처리 concern을 포함해야 합니다. 두 concern 모두 ee/lib/secrets_management/graphql_error_handling.rb의 SecretsManagement::GraphqlErrorHandling에 한 번 정의된 같은 ErrorWrapper로 resolve를 감쌉니다.

Concern 모듈 포함하는 곳
뮤테이션 오류 처리 SecretsManagement::MutationErrorHandling (ee/app/graphql/mutations/concerns/secrets_management/mutation_error_handling.rb) OpenBao 또는 Secrets Manager 서비스를 사용하는 뮤테이션. CustomersDot만 호출하는 체험판, 추가 기능, 자격 새로 고침 뮤테이션은 포함하지 않습니다.
리졸버 오류 처리 SecretsManagement::ResolverErrorHandling (ee/app/graphql/resolvers/concerns/secrets_management/resolver_error_handling.rb) 모든 리졸버.

쓰기 뮤테이션은 두 가지 concern을 더 포함합니다.

Concern 모듈 동작
활성 네임스페이스 확인 SecretsManagement::RequiresActiveNamespace (ee/app/graphql/mutations/concerns/secrets_management/requires_active_namespace.rb) raise_if_namespace_inactive!를 추가하며, 보관되었거나 삭제 대기 중인 그룹 또는 프로젝트에 대한 쓰기를 차단합니다.
쓰기 자격 적용 SecretsManagement::EnforcesWriteEntitlement (ee/app/graphql/mutations/concerns/secrets_management/enforces_write_entitlement.rb) 자격이 쓰기를 거부할 때 구조화된 reason과 함께 쓰기를 즉시 중단하는 ready? 훅을 추가합니다. enforces_write_entitlement_for :payload_key, find_by: :project_path(또는 :group_path)로 사용을 선택합니다.

시크릿 삭제 뮤테이션은 EnforcesWriteEntitlement를 포함하지 않습니다. 권한 삭제 뮤테이션과 프로비저닝 해제 뮤테이션은 포함합니다.

인가#

뮤테이션이나 리졸버의 인가는 최대 세 가지 검사를 조합합니다.

  1. authorize :ability_name. resolve 메서드의 authorized_find!로 검사하는 Rails 정책 권한입니다.
  2. authorize_granular_token permissions: ..., boundary_argument: ..., boundary_type: ...(:instance처럼 고정된 경계에는 boundary:). 개인 액세스 토큰이 가져야 하는 세분화된 토큰 권한을 지정합니다. 여러 권한을 나열할 수 있으며, 예를 들어 instance_enable_add_on.rb는 페이로드가 자격도 반환하므로 :enable_secrets_manager_add_on과 :read_secrets_manager를 모두 요구합니다.
  3. 쓰기 뮤테이션의 enforces_write_entitlement_for. 앞에서 설명했습니다.

SecretsPermissionInterface에서 볼 수 있듯이 필드도 타입 자체의 인가와 별개로 고유한 authorize를 가질 수 있습니다.

오류가 클라이언트에 전달되는 방식#

ee/lib/secrets_management/error_mapping.rb의 SecretsManagement::ErrorMapping은 GraphqlErrorHandling이 포함하며, 원시 OpenBao 오류를 클라이언트에 노출하지 않습니다.

  • 권한 오류나 정확히 "not found"인 메시지는 raise_resource_not_available_error!가 됩니다.
  • check-and-set 불일치는 "This resource was recently modified. Refresh the page and try again to avoid overwriting newer changes."가 됩니다.
  • 그 밖의 오류는 "Internal server error."가 되며, 메시지에서 시크릿 경로를 먼저 가린 뒤 Gitlab::ErrorTracking.track_exception으로 보고됩니다.

뮤테이션의 자체 resolve 메서드도 이 rescue 경로와 별개로, 사용자에게 보여 주는 구조화된 오류를 GraphQL 응답에 직접 반환합니다.

if result.success?
  { project_secret: result.payload[:secret], errors: [] }
else
  { project_secret: nil, errors: error_messages(result, [:secret]) }
end

프론트엔드 GraphQL 문서#

프론트엔드 쿼리와 뮤테이션은 ee/app/assets/javascripts/ci/secrets/graphql/ 아래에 있습니다.

  • 쿼리: ee/app/assets/javascripts/ci/secrets/graphql/queries/. 예를 들어 get_project_secrets.query.graphql과 get_project_secret_manager_status.query.graphql이 있습니다.
  • 뮤테이션: ee/app/assets/javascripts/ci/secrets/graphql/mutations/. 예를 들어 create_project_secret.mutation.graphql과 enable_secret_manager.mutation.graphql이 있습니다.

이 문서를 사용하는 Vue 컴포넌트는 Secrets Manager 프론트엔드 개발을 참고합니다.

새 뮤테이션 체크리스트#

  1. 뮤테이션이 호출하는 서비스가 아직 없다면 만듭니다.
  2. ee/app/graphql/mutations/secrets_management/{scope}/{action}.rb에 뮤테이션 파일을 만듭니다.
  3. 필요한 concern을 포함합니다. ResolvesProject 또는 ResolvesGroup, 뮤테이션이 OpenBao 또는 Secrets Manager 서비스를 사용한다면 SecretsManagement::MutationErrorHandling, 쓰기라면 SecretsManagement::RequiresActiveNamespace와 SecretsManagement::EnforcesWriteEntitlement입니다.
  4. 다른 진입점도 서비스를 실행한다면 서비스에서 내부 이벤트를 추적합니다. 예를 들어 InitializeServiceHelpers가 활성화 이벤트를 추적하므로 체험판 및 추가 기능 뮤테이션도 이를 발생시킵니다.
  5. 뮤테이션을 가장 가까운 기존 대응 뮤테이션과 비교합니다. 예를 들어 그룹 뮤테이션의 프로젝트 버전이나 과금 뮤테이션의 EnableAddOn입니다. 같은 concern, 인가, 기능 검사를 포함하거나, 포함하지 않는 이유를 기록합니다.
  6. EE::ProjectPolicy 또는 EE::GroupPolicy의 기존 권한으로 authorize :ability_name을 설정하거나 새 권한을 추가합니다.
  7. 개인 액세스 토큰에 필요한 권한과 그 boundary_type으로 authorize_granular_token을 설정합니다.
  8. 쓰기 뮤테이션이라면 enforces_write_entitlement_for :payload_key, find_by: :project_path(또는 :group_path)를 호출합니다.
  9. ee/app/graphql/ee/types/mutation_type.rb에서 다른 SecretsManagement 뮤테이션 옆에 mount_mutation으로 뮤테이션을 마운트합니다.
  10. 뮤테이션이 새 이벤트를 추적한다면 config/events/ 아래에 내부 이벤트 정의를 추가합니다.
  11. ee/app/assets/javascripts/ci/secrets/graphql/mutations/ 아래에 프론트엔드 .mutation.graphql 파일을 만듭니다.
  12. bundle exec rake gitlab:graphql:compile_docs로 GraphQL 참조 문서와 스키마를 다시 생성하며, 스키마 덤프도 업데이트하려면 bundle exec rake gitlab:graphql:update_all을 사용합니다.
  13. ee/spec/requests/api/graphql/secrets_management/ 아래에 요청 스펙을 추가합니다. Secrets Manager 테스트를 참고합니다.
  14. ee/spec/frontend/ci/secrets/ 아래에 프론트엔드 스펙을 추가합니다.

Secrets Manager GraphQL API

GitLab v19.5
원문 보기

요약

Secrets Manager는 ee/app/graphql/ 아래의 GraphQL 타입, 뮤테이션, 리졸버로 데이터와 동작을 노출합니다. 타입은 ee/app/graphql/types/secrets_management/에 있습니다.

Secrets Manager는 ee/app/graphql/ 아래의 GraphQL 타입, 뮤테이션, 리졸버로 데이터와 동작을 노출합니다. 모든 뮤테이션과 리졸버는 아래에 설명하는 오류 처리와 인가 관련 사항을 공통으로 따릅니다.

타입#

타입은 ee/app/graphql/types/secrets_management/에 있습니다.

타입 GraphQL 이름 기반
ProjectSecretsManagerType ProjectSecretsManager ProjectSecretsManager 레코드. effective_status에서 가져온 status와 엄격한 읽기 전용 모드를 위한 read_only 필드를 노출합니다.
GroupSecretsManagerType GroupSecretsManager GroupSecretsManager 레코드.
ProjectSecretType ProjectSecret OpenBao 응답으로 만든 ActiveModel::Model 시크릿.
GroupSecretType GroupSecret 그룹 시크릿용으로 같은 방식.
SecretRotationInfoType SecretRotationInfo ProjectSecretRotationInfo 또는 GroupSecretRotationInfo. 인가는 이 타입이 아니라 부모 시크릿 타입이 처리합니다.
ProjectSecretsPermissionType ProjectSecretsPermission 프로젝트 시크릿 권한. SecretsPermissionInterface를 포함합니다.
GroupSecretsPermissionType GroupSecretsPermission 그룹 권한용으로 같은 방식.
EntitlementType SecretsManagerEntitlement SecretsManagement::Entitlement 값 객체. 자격 상태를 참고합니다.
EnrollmentType SecretsManagerEnrollment SecretsManagement::NamespaceEnrollment 또는 인스턴스 전체 등록.

ee/app/graphql/types/secrets_management/secrets_permission_interface.rb의 SecretsPermissionInterface는 두 권한 타입에 principal, actions, grantedBy, expiredAt 필드를 추가하는 공유 ActiveSupport::Concern입니다.

권한 관련 지원 타입은 ee/app/graphql/types/secrets_management/permissions/에 있습니다. PrincipalType, PrincipalInputType, PrincipalTypeEnum, ActionEnum, SecretPermissionType입니다.

열거형#

열거형 값
ProjectSecretsManagerStatusEnum, GroupSecretsManagerStatusEnum BaseSecretsManagerStatusEnum을 기반으로 합니다.
SecretStatusEnum 타임스탬프로부터 계산한 시크릿의 라이프사이클 상태.
SecretRotationStatusEnum OVERDUE, APPROACHING, OK.
EntitlementStateEnum SecretsManagement::Entitlement 상태를 그대로 반영합니다.
EntitlementBlockedReasonEnum 자격의 blocked_reason 값을 그대로 반영합니다.
WriteActionDenialReasonEnum 자격 문제로 뮤테이션이 거부될 때 reason 필드에 반환되며, ProjectSecretsManagerType과 GroupSecretsManagerType의 writeDenialReason 필드에도 반환됩니다.

타입의 인가#

타입은 authorize로 Rails 정책 권한을 선언합니다. 예를 들어 ProjectSecretType에는 authorize :read_project_secrets가 있습니다. 일부 타입은 authorize_granular_token도 선언합니다. 이는 개인 액세스 토큰이 GraphQL API로 해당 타입을 읽으려면 가져야 하는 세분화된 토큰 권한을 지정합니다. 예를 들어 ProjectSecretsManagerType은 authorize_granular_token permissions: :read_secrets_manager, boundary: :project, boundary_type: :project를 선언합니다. SecretRotationInfoType처럼 객체별 정책이 없는 타입은 rubocop:disable Graphql/AuthorizeTypes 주석으로 인가 검사를 비활성화하고 부모 타입의 인가에 의존합니다.

뮤테이션#

뮤테이션은 ee/app/graphql/mutations/secrets_management/에 영역별로 묶여 있습니다.

프로젝트 및 그룹 Secrets Manager#

뮤테이션 파일 GraphQL 이름 Rails 권한 서비스
project_secrets_managers/initialize.rb ProjectSecretsManagerInitialize :provision_secrets_manager ProjectSecretsManagers::InitializeService
project_secrets_managers/deprovision.rb ProjectSecretsManagerDeprovision :admin_project_secrets_manager ProjectSecretsManagers::InitiateDeprovisionService
group_secrets_managers/initialize.rb GroupSecretsManagerInitialize :provision_secrets_manager GroupSecretsManagers::InitializeService
group_secrets_managers/deprovision.rb GroupSecretsManagerDeprovision :deprovision_secrets_manager GroupSecretsManagers::InitiateDeprovisionService

프로젝트 및 그룹 시크릿#

뮤테이션 파일 GraphQL 이름 Rails 권한
project_secrets/create.rb ProjectSecretCreate :create_project_secrets
project_secrets/update.rb ProjectSecretUpdate :update_project_secrets
project_secrets/delete.rb ProjectSecretDelete :delete_project_secrets
group_secrets/create.rb GroupSecretCreate :create_secret
group_secrets/update.rb GroupSecretUpdate :update_secret
group_secrets/delete.rb GroupSecretDelete :delete_secret

프로젝트 시크릿 뮤테이션과 그룹 시크릿 뮤테이션은 몇 가지 사소한 점이 다릅니다.

차이점 프로젝트 그룹
리졸버 include include ResolvesProject include ResolvesGroup
find_object 인수 project_path: group_path:
범위별 인수 branch (String) protected (Boolean)
반환 필드 project_secret group_secret
생성 시 내부 이벤트 이름 create_ci_secret create_group_ci_secret

시크릿 값을 받는 GraphQL 인수의 이름은 secret이지만 서비스 호출 매개변수의 이름은 value입니다. 이름 변경은 resolve에서 이루어지며, 예를 들어 project_secrets/create.rb의 .execute(value: secret, ...)가 그렇습니다. 시크릿 값을 받는 새 뮤테이션에는 모두 이 관례를 따릅니다.

권한#

뮤테이션 파일 GraphQL 이름
project_secrets_permissions/update.rb ProjectSecretsPermissionUpdate
project_secrets_permissions/delete.rb ProjectSecretsPermissionDelete
group_secrets_permissions/update.rb GroupSecretsPermissionUpdate
group_secrets_permissions/delete.rb GroupSecretsPermissionDelete

자격, 체험판, 등록#

뮤테이션 파일 GraphQL 이름
enable_add_on.rb SecretsManagerEnableAddOn
instance_enable_add_on.rb SecretsManagerInstanceEnableAddOn
start_trial.rb SecretsManagerStartTrial
instance_start_trial.rb SecretsManagerInstanceStartTrial
refresh_entitlement.rb SecretsManagerRefreshEntitlement
instance_refresh_entitlement.rb SecretsManagerInstanceRefreshEntitlement
enrollment/namespace_enroll.rb NamespaceSecretsManagerEnroll
enrollment/namespace_unenroll.rb NamespaceSecretsManagerUnenroll
enrollment/instance_enroll.rb InstanceSecretsManagerEnroll
enrollment/instance_unenroll.rb InstanceSecretsManagerUnenroll

이 뮤테이션이 무엇을 바꾸는지는 각 상태가 허용하는 동작을 참고합니다.

리졸버#

리졸버는 ee/app/graphql/resolvers/secrets_management/에 있습니다.

리졸버 용도
ProjectSecretsManagerResolver, GroupSecretsManagerResolver 프로젝트 또는 그룹의 Secrets Manager 상태를 가져옵니다.
ProjectSecretsResolver, GroupSecretsResolver 시크릿을 나열합니다. lookahead를 사용해 쿼리가 선택하지 않으면 로테이션 정보 로딩을 건너뜁니다.
ProjectSecretResolver, GroupSecretResolver 시크릿 하나를 가져옵니다.
ProjectSecretsCountResolver, GroupSecretsCountResolver 시크릿 개수를 셉니다.
ProjectSecretsPermissionsResolver, GroupSecretsPermissionsResolver 권한을 나열합니다.
ProjectSecrets::ListNeedingRotationResolver, GroupSecrets::ListNeedingRotationResolver 로테이션 기한이 되었거나 임박한 시크릿을 나열합니다.
Permissions::SecretPermissionsResolver 더 새로운 권한 타입을 통해 시크릿 권한을 나열합니다.
OpenbaoHealthResolver OpenBao 서버 상태를 확인합니다.
NamespaceEnrollmentResolver, InstanceEnrollmentResolver 등록 상태를 가져옵니다.
InstanceEntitlementResolver 인스턴스 수준의 자격을 가져옵니다.

Lookahead 최적화#

ProjectSecretsResolver와 GroupSecretsResolver는 extras [:lookahead]를 받으며, 쿼리가 요청할 때만 목록 서비스에 로테이션 정보를 포함하도록 요청합니다.

def resolve(lookahead:, project_path:)
  result = ListService.new(project, current_user)
    .execute(include_rotation_info: include_rotation_info?(lookahead))
end

def include_rotation_info?(lookahead)
  lookahead.selection(:nodes).selects?(:rotation_info) ||
    lookahead.selection(:edges).selection(:node).selects?(:rotation_info)
end

공유 뮤테이션 및 리졸버 concern#

모든 뮤테이션과 리졸버는 오류 처리 concern을 포함해야 합니다. 두 concern 모두 ee/lib/secrets_management/graphql_error_handling.rb의 SecretsManagement::GraphqlErrorHandling에 한 번 정의된 같은 ErrorWrapper로 resolve를 감쌉니다.

Concern 모듈 포함하는 곳
뮤테이션 오류 처리 SecretsManagement::MutationErrorHandling (ee/app/graphql/mutations/concerns/secrets_management/mutation_error_handling.rb) OpenBao 또는 Secrets Manager 서비스를 사용하는 뮤테이션. CustomersDot만 호출하는 체험판, 추가 기능, 자격 새로 고침 뮤테이션은 포함하지 않습니다.
리졸버 오류 처리 SecretsManagement::ResolverErrorHandling (ee/app/graphql/resolvers/concerns/secrets_management/resolver_error_handling.rb) 모든 리졸버.

쓰기 뮤테이션은 두 가지 concern을 더 포함합니다.

Concern 모듈 동작
활성 네임스페이스 확인 SecretsManagement::RequiresActiveNamespace (ee/app/graphql/mutations/concerns/secrets_management/requires_active_namespace.rb) raise_if_namespace_inactive!를 추가하며, 보관되었거나 삭제 대기 중인 그룹 또는 프로젝트에 대한 쓰기를 차단합니다.
쓰기 자격 적용 SecretsManagement::EnforcesWriteEntitlement (ee/app/graphql/mutations/concerns/secrets_management/enforces_write_entitlement.rb) 자격이 쓰기를 거부할 때 구조화된 reason과 함께 쓰기를 즉시 중단하는 ready? 훅을 추가합니다. enforces_write_entitlement_for :payload_key, find_by: :project_path(또는 :group_path)로 사용을 선택합니다.

시크릿 삭제 뮤테이션은 EnforcesWriteEntitlement를 포함하지 않습니다. 권한 삭제 뮤테이션과 프로비저닝 해제 뮤테이션은 포함합니다.

인가#

뮤테이션이나 리졸버의 인가는 최대 세 가지 검사를 조합합니다.

  1. authorize :ability_name. resolve 메서드의 authorized_find!로 검사하는 Rails 정책 권한입니다.
  2. authorize_granular_token permissions: ..., boundary_argument: ..., boundary_type: ...(:instance처럼 고정된 경계에는 boundary:). 개인 액세스 토큰이 가져야 하는 세분화된 토큰 권한을 지정합니다. 여러 권한을 나열할 수 있으며, 예를 들어 instance_enable_add_on.rb는 페이로드가 자격도 반환하므로 :enable_secrets_manager_add_on과 :read_secrets_manager를 모두 요구합니다.
  3. 쓰기 뮤테이션의 enforces_write_entitlement_for. 앞에서 설명했습니다.

SecretsPermissionInterface에서 볼 수 있듯이 필드도 타입 자체의 인가와 별개로 고유한 authorize를 가질 수 있습니다.

오류가 클라이언트에 전달되는 방식#

ee/lib/secrets_management/error_mapping.rb의 SecretsManagement::ErrorMapping은 GraphqlErrorHandling이 포함하며, 원시 OpenBao 오류를 클라이언트에 노출하지 않습니다.

  • 권한 오류나 정확히 "not found"인 메시지는 raise_resource_not_available_error!가 됩니다.
  • check-and-set 불일치는 "This resource was recently modified. Refresh the page and try again to avoid overwriting newer changes."가 됩니다.
  • 그 밖의 오류는 "Internal server error."가 되며, 메시지에서 시크릿 경로를 먼저 가린 뒤 Gitlab::ErrorTracking.track_exception으로 보고됩니다.

뮤테이션의 자체 resolve 메서드도 이 rescue 경로와 별개로, 사용자에게 보여 주는 구조화된 오류를 GraphQL 응답에 직접 반환합니다.

if result.success?
  { project_secret: result.payload[:secret], errors: [] }
else
  { project_secret: nil, errors: error_messages(result, [:secret]) }
end

프론트엔드 GraphQL 문서#

프론트엔드 쿼리와 뮤테이션은 ee/app/assets/javascripts/ci/secrets/graphql/ 아래에 있습니다.

  • 쿼리: ee/app/assets/javascripts/ci/secrets/graphql/queries/. 예를 들어 get_project_secrets.query.graphql과 get_project_secret_manager_status.query.graphql이 있습니다.
  • 뮤테이션: ee/app/assets/javascripts/ci/secrets/graphql/mutations/. 예를 들어 create_project_secret.mutation.graphql과 enable_secret_manager.mutation.graphql이 있습니다.

이 문서를 사용하는 Vue 컴포넌트는 Secrets Manager 프론트엔드 개발을 참고합니다.

새 뮤테이션 체크리스트#

  1. 뮤테이션이 호출하는 서비스가 아직 없다면 만듭니다.
  2. ee/app/graphql/mutations/secrets_management/{scope}/{action}.rb에 뮤테이션 파일을 만듭니다.
  3. 필요한 concern을 포함합니다. ResolvesProject 또는 ResolvesGroup, 뮤테이션이 OpenBao 또는 Secrets Manager 서비스를 사용한다면 SecretsManagement::MutationErrorHandling, 쓰기라면 SecretsManagement::RequiresActiveNamespace와 SecretsManagement::EnforcesWriteEntitlement입니다.
  4. 다른 진입점도 서비스를 실행한다면 서비스에서 내부 이벤트를 추적합니다. 예를 들어 InitializeServiceHelpers가 활성화 이벤트를 추적하므로 체험판 및 추가 기능 뮤테이션도 이를 발생시킵니다.
  5. 뮤테이션을 가장 가까운 기존 대응 뮤테이션과 비교합니다. 예를 들어 그룹 뮤테이션의 프로젝트 버전이나 과금 뮤테이션의 EnableAddOn입니다. 같은 concern, 인가, 기능 검사를 포함하거나, 포함하지 않는 이유를 기록합니다.
  6. EE::ProjectPolicy 또는 EE::GroupPolicy의 기존 권한으로 authorize :ability_name을 설정하거나 새 권한을 추가합니다.
  7. 개인 액세스 토큰에 필요한 권한과 그 boundary_type으로 authorize_granular_token을 설정합니다.
  8. 쓰기 뮤테이션이라면 enforces_write_entitlement_for :payload_key, find_by: :project_path(또는 :group_path)를 호출합니다.
  9. ee/app/graphql/ee/types/mutation_type.rb에서 다른 SecretsManagement 뮤테이션 옆에 mount_mutation으로 뮤테이션을 마운트합니다.
  10. 뮤테이션이 새 이벤트를 추적한다면 config/events/ 아래에 내부 이벤트 정의를 추가합니다.
  11. ee/app/assets/javascripts/ci/secrets/graphql/mutations/ 아래에 프론트엔드 .mutation.graphql 파일을 만듭니다.
  12. bundle exec rake gitlab:graphql:compile_docs로 GraphQL 참조 문서와 스키마를 다시 생성하며, 스키마 덤프도 업데이트하려면 bundle exec rake gitlab:graphql:update_all을 사용합니다.
  13. ee/spec/requests/api/graphql/secrets_management/ 아래에 요청 스펙을 추가합니다. Secrets Manager 테스트를 참고합니다.
  14. ee/spec/frontend/ci/secrets/ 아래에 프론트엔드 스펙을 추가합니다.