markdown # CI에서 외부 시크릿 사용하기

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-Managed, GitLab Dedicated

시크릿은 CI 작업이 작업을 완료하는 데 필요한 민감한 정보를 나타냅니다. 이러한 민감한 정보는 API 토큰, 데이터베이스 자격 증명 또는 개인 키와 같은 항목일 수 있습니다. 시크릿은 시크릿 제공 업체에서 제공됩니다.

CI/CD 변수는 항상 작업에 제시되는 반면, 시크릿은 작업에서 명시적으로 필요합니다. 구문에 대한 자세한 정보는 GitLab CI/CD 파이프라인 구성 참조를 참조하십시오.

GitLab은 다음 시크릿 관리 제공 업체를 지원합니다:

  1. HashiCorp의 Vault
  2. Google Cloud Secret Manager
  3. Azure Key Vault

GitLab은 첫 번째 지원 제공 업체로 HashiCorp의 Vault를 선택했으며, 첫 번째 지원되는 시크릿 엔진으로 KV-V2를 선택했습니다.

GitLab과 Vault 간의 흐름은 다음과 같습니다:

  1. Vault 및 시크릿을 구성하십시오.
  2. JWT를 생성하고 CI 작업에 제공하십시오.
  3. 러너가 HashiCorp Vault에 연락하여 JWT를 사용하여 인증합니다.
  4. HashiCorp Vault가 JWT를 확인합니다.
  5. HashiCorp Vault가 바운드된 클레임을 확인하고 정책을 적용합니다.
  6. HashiCorp Vault가 토큰을 반환합니다.
  7. 러너가 HashiCorp Vault에서 시크릿을 읽습니다.
note
HashiCorp Vault와의 인증 및 시크릿 읽기 자습서를 읽어보세요. 이는 모든 구독 수준에서 사용할 수 있으며 Vault로 시크릿을 작성하고 삭제할 수 있으며 여러 시크릿 엔진을 지원합니다.

Vault 시크릿 엔진

GitLab 러너에서 지원하는 Vault 시크릿 엔진은 다음과 같습니다:

시크릿 엔진 secrets:engine:name러너 버전 세부 정보
KV 시크릿 엔진 - 버전 2 kv-v2 13.4 kv-v2는 명시적으로 지정된 엔진 유형이 없을 경우 GitLab 러너가 사용하는 기본 엔진입니다.
KV 시크릿 엔진 - 버전 1 kv-v1 또는 generic 13.4 generic 키워드 지원은 GitLab 15.11에서 소개되었습니다.
AWS 시크릿 엔진 generic 16.11  
Hashicorp Vault Artifactory Secrets Plugin generic 16.11 이 시크릿 백엔드는 JFrog Artifactory 서버(5.0.0 이상)와 통신하며 지정된 스코프로 액세스 토큰을 동적으로 제공합니다.

Vault 서버 구성

Vault 서버를 구성하려면 다음 단계를 수행하십시오:

  1. Vault 서버가 버전 1.2.0 이상에서 실행 중인지 확인하십시오.
  2. 다음 명령을 실행하여 인증 방법을 활성화합니다. 이는 Vault 서버에 OIDC Discovery URL 및 GitLab 인스턴스의 공개 서명 키를 가져와 JWT 인증 시 검증하기 위한 것입니다:

    $ vault auth enable jwt
       
    $ vault write auth/jwt/config \
      oidc_discovery_url="https://gitlab.example.com" \
      bound_issuer="gitlab.example.com"
    
  3. Vault 서버에서 특정 경로 및 작업에 대한 액세스 권한을 부여하거나 금지하기 위해 정책을 구성하십시오. 다음 예는 프로덕션 환경에서 필요한 시크릿 세트에 대한 읽기 액세스를 부여합니다:

    vault policy write myproject-production - <<EOF
    # 'ops/data/production/*' 경로에 대한 읽기 전용 권한
       
    path "ops/data/production/*" {
      capabilities = [ "read" ]
    }
    EOF
    
  4. Vault 서버에 프로젝트 또는 네임스페이스에 역할을 제한하는 역할을 구성하십시오. 이에 대한 자세한 내용은 이 페이지의 Vault 서버 역할 구성을 참조하십시오.
  5. 다음과 같은 CI/CD 변수를 생성하여 Vault 서버에 대한 세부 정보를 제공하십시오:
    • VAULT_SERVER_URL - https://vault.example.com:8200와 같이 Vault 서버의 URL입니다. 필수 사항입니다.
    • VAULT_AUTH_ROLE - 선택 사항입니다. 인증을 시도할 때 사용할 역할입니다. 역할이 지정되지 않으면 Vault는 인증 방법을 구성할 때 기본 역할을 사용합니다.
    • VAULT_AUTH_PATH - 선택 사항입니다. 인증 방법이 마운트된 경로로, 기본값은 jwt입니다.
    • VAULT_NAMESPACE - Vault Enterprise 네임스페이스(https://developer.hashicorp.com/vault/docs/enterprise/namespaces)로, 시크릿 및 인증을 위해 사용합니다. 네임스페이스가 지정되지 않으면 Vault는 root(“ / “로) 네임스페이스를 사용합니다. 이 설정은 Vault 오픈 소스에서는 무시됩니다.
    note
    이러한 값을 사용자 인터페이스에서 제공하는 지원은 이 이슈에서 추적되고 있습니다.

CI 작업에서 Vault 시크릿 사용

Tier: Premium, Ultimate Offering: GitLab.com, Self-Managed, GitLab Dedicated

Vault 서버를 구성한 후, Vault에 저장된 시크릿을 정의함으로써 사용할 수 있습니다:

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.com
  secrets:
    DATABASE_PASSWORD:
      vault: production/db/password@ops  # 시크릿 `ops/data/production/db`를 필드 `password`로 변환
      token: $VAULT_ID_TOKEN

이 예시에서:

  • production/db - 시크릿.
  • password - 필드.
  • ops - 시크릿 엔진이 마운트된 경로.

GitLab이 Vault에서 시크릿을 가져온 후 값은 임시 파일에 저장됩니다. 이 파일에 대한 경로는 DATABASE_PASSWORD라는 CI/CD 변수에 저장되며, 이는 파일 유형의 변수와 유사합니다.

기본 동작을 덮어쓰려면 file 옵션을 명시적으로 설정하십시오:

secrets:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.com
  DATABASE_PASSWORD:
    vault: production/db/password@ops
    file: false
    token: $VAULT_ID_TOKEN

이 예시에서 시크릿 값은 파일에 저장하는 대신 DATABASE_PASSWORD 변수에 직접 넣습니다.


## 다른 시크릿 엔진 사용

기본적으로 `kv-v2` 시크릿 엔진이 사용됩니다. 다른 엔진을 사용하려면 구성에서 `vault` 아래에 `engine` 섹션을 추가하세요.

예를 들어, Artifactory에 대한 시크릿 엔진 및 경로를 설정하는 경우:

```yaml
job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.com
  secrets:
    JFROG_TOKEN:
      vault:
        engine:
          name: generic
          path: artifactory
        path: production/jfrog
        field: access_token
      file: false

이 예에서 시크릿 값은 artifactory/production/jfrog에서 access_token 필드로 얻어집니다. generic 시크릿 엔진은 kv-v1, AWS, Artifactory 및 기타 유사한 보트 시크릿 엔진에 사용할 수 있습니다.

보트 서버 역할 구성

CI 작업이 인증을 시도할 때 역할을 지정합니다. 역할을 사용하여 다른 정책을 그룹화할 수 있습니다. 인증이 성공하면 이러한 정책들이 생성된 보트 토큰에 첨부됩니다.

Bound claims는 미리 정의된 값으로 JWT 클레임과 일치합니다. 바운드 클레임을 사용하면 특정 GitLab 사용자, 특정 프로젝트 또는 특정 Git 참조에 대한 액세스를 제한할 수 있습니다. 필요한 만큼 많은 바운드 클레임을 가질 수 있지만, 모두가 일치해야만 인증이 성공합니다.

바운드 클레임을 GitLab 기능과 결합하여 사용자 역할보호된 브랜치과 같은 GitLab 기능과 결합하면 특정 사용 사례에 맞게 이러한 규칙을 맞춤화할 수 있습니다. 이 예에서는 인증이 프로덕션 릴리스에 사용되는 패턴과 일치하는 보호된 태그를 실행하는 작업에 대해서만 허용됩니다.

$ vault write auth/jwt/role/myproject-production - <<EOF
{
  "role_type": "jwt",
  "policies": ["myproject-production"],
  "token_explicit_max_ttl": 60,
  "user_claim": "user_email",
  "bound_claims_type": "glob",
  "bound_claims": {
    "project_id": "42",
    "ref_protected": "true",
    "ref_type": "tag",
    "ref": "auto-deploy-*"
  }
}
EOF
caution
project_id 또는 namespace_id와 같은 제공된 클레임을 사용하여 역할을 프로젝트나 네임스페이스로 제한하세요. 이러한 제한 없이 이 GitLab 인스턴스에서 생성된 JWT는 이 역할을 사용하여 인증할 수 있습니다.

ID 토큰 JWT 클레임의 전체 디렉터리은 How It Works 섹션의 HashiCorp Vault로 인증 및 시크릿 읽기 튜토리얼에서 확인할 수 있습니다.

또한 결과 보트 토큰에 대해 시간 제한, IP 주소 범위 및 사용 횟수와 같은 일부 속성을 지정할 수 있습니다. 옵션의 전체 디렉터리은 JSON 웹 토큰 방법에 대한 보트 역할 생성의 Vault 문서에서 확인할 수 있습니다.

자체 서명 보트 서버 사용

보트 서버에 자체 서명된 인증서를 사용하는 경우 작업 로그에 다음 오류가 표시됩니다:

ERROR: Job failed (system failure): resolving secrets: initializing Vault service: preparing authenticated client: checking Vault server health: Get https://vault.example.com:8000/v1/sys/health?drsecondarycode=299&performancestandbycode=299&sealedcode=299&standbycode=299&uninitcode=299: x509: certificate signed by unknown authority

이 오류를 해결하려면 두 가지 옵션이 있습니다:

  • 자체 서명된 인증서를 GitLab Runner 서버의 CA 리포지터리에 추가합니다. Helm 차트를 사용하여 GitLab Runner를 배포한 경우 고유한 GitLab Runner 이미지를 만들어야 합니다.
  • GitLab Runner를 구성하여 인증서를 신뢰하도록 VAULT_CACERT 환경 변수를 사용하세요:
    • GitLab Runner를 관리하기 위해 systemd를 사용하는 경우 GitLab Runner를 위한 환경 변수 추가 방법을 참조하세요.
    • Helm 차트를 사용하여 GitLab Runner를 배포한 경우:
      1. GitLab에 액세스하려면 사용자 정의 인증서 제공 및 Vault 서버 인증서를 GitLab의 인증서 대신 추가하세요. GitLab 인스턴스도 자체 서명된 인증서를 사용하는 경우 두 가지를 동일한 Secret에 추가할 수 있어야 합니다.
      2. 다음과 같은 줄을 values.yaml 파일에 추가하세요:

        ## 실제로 사용한 값으로 <SECRET_NAME> 및 <VAULT_CERTIFICATE>를 모두 바꿉니다.
               
        certsSecretName: <SECRET_NAME>
               
        envVars:
          - name: VAULT_CACERT
            value: "/home/gitlab-runner/.gitlab-runner/certs/<VAULT_CERTIFICATE>"