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를 선택했습니다.

ID 토큰을 사용하여 Vault 인증을 하세요. HashiCorp Vault로의 인증 및 시크릿 읽기 튜토리얼에는 ID 토큰으로의 인증에 대한 자세한 정보가 포함되어 있습니다.

GitLab과 HashiCorp Vault를 사용하는 흐름은 다음 다이어그램에 요약되어 있습니다:

GitLab 및 HashiCorp 간의 흐름

  1. Vault 및 시크릿을 구성합니다.
  2. JWT를 생성하고 CI 작업에 제공합니다.
  3. Runner에서 HashiCorp Vault에 연락하고 JWT를 사용하여 인증합니다.
  4. HashiCorp Vault가 JWT를 확인합니다.
  5. HashiCorp Vault가 바운드된 클레임을 확인하고 정책을 첨부합니다.
  6. HashiCorp Vault가 토큰을 반환합니다.
  7. Runner가 HashiCorp Vault에서 시크릿을 읽습니다.
note
이 기능의 버전과 관련하여 HashiCorp Vault로의 인증 및 시크릿 읽기 튜토리얼을 읽으십시오. 이 기능은 모든 구독 레벨에서 사용할 수 있으며, Vault로의 시크릿 작성 및 삭제를 지원하며 여러 시크릿 엔진을 지원합니다.

아래의 vault.example.com URL을 Vault 서버의 URL로, gitlab.example.com을 GitLab 인스턴스의 URL로 바꿔주어야 합니다.

Vault 시크릿 엔진

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

시크릿 엔진 secrets:engine:nameRunner 버전 자세한 정보
KV 시크릿 엔진 - 버전 2 kv-v2 13.4 kv-v2는 명시적으로 지정된 엔진 유형이 없을 때 GitLab Runner가 사용하는 기본 엔진입니다.
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 서버에 GitLab 인스턴스의 OIDC Discovery URL 제공하여 Vault가 JSON Web Token(JWT)을 인증할 때 공개 서명 키를 가져오도록 합니다:

   $ vault auth enable jwt

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

    vault policy write myproject-production - <<EOF
    # 'ops/data/production/*' 경로에 대한 읽기 전용 권한
    
    path "ops/data/production/*" {
      capabilities = [ "read" ]
    }
    EOF
    
  2. Vault 서버에서 프로젝트나 네임스페이스에 역할을 제한하여 역할을 구성합니다. 이 페이지의 Vault 서버 역할 구성에서 설명된 대로 역할을 제한합니다.
  3. 다음의 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 네임스페이스입니다.
      • Vault의 경우 네임스페이스가 지정되지 않으면 루트(“/”) 네임스페이스가 사용됩니다.
      • Vault 오픈 소스의 경우 이 설정은 무시됩니다.
      • HashiCorp Cloud Platform (HCP) Vault의 경우 네임스페이스가 필요합니다. 예: VAULT_NAMESPACE=admin.
    note
    이러한 값을 사용자 인터페이스에서 제공하는 지원은 이 이슈에서 추적됩니다.

CI 작업에서 Vault 시크릿 사용

Tier: 프리미엄, 얼티밋 Offering: GitLab.com, 온프레미스, GitLab 전용

당신의 Vault 서버를 구성한 후, vault keyword를 사용하여 Vault에 저장된 시크릿을 정의함으로써 Vault에 저장된 시크릿을 사용할 수 있습니다.

job_using_vault:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://vault.example.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://vault.example.com
  DATABASE_PASSWORD:
    vault: production/db/password@ops
    file: false
    token: $VAULT_ID_TOKEN

이 예제에서 시크릿 값은 직접 DATABASE_PASSWORD 변수에 넣어서 해당 값을 보유하고 있는 파일을 가리키지 않습니다.

다른 시크릿 엔진 사용

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

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

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

이 예에서 시크릿 값은 artifactory/production/jfrogaccess_token에서 얻어집니다. generic 시크릿 엔진은 kv-v1, AWS, Artifactory와 같은 다른 Vault 시크릿 엔진에 사용할 수 있습니다.

Vault 서버 롤 설정

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

Bound claims는 JWT 클레임과 일치하는 사전 정의된 값입니다. Bound claims를 사용하여 고유한 GitLab 사용자, 특정 프로젝트 또는 특정 Git 참조에 대해 실행되는 작업에 액세스를 제한할 수 있습니다. 필요한 만큼 많은 bounded claims를 가질 수 있지만, 모두 일치해야만 인증이 성공합니다.

bounded claims를 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_audiences": "https://vault.example.com",
  "bound_claims_type": "glob",
  "bound_claims": {
    "project_id": "42",
    "ref_protected": "true",
    "ref_type": "tag",
    "ref": "auto-deploy-*"
  }
}
EOF

경고: 제공된 클레임인 project_idnamespace_id 같은 클레임을 사용하여 역할을 프로젝트나 네임스페이스로 제한하세요. 이러한 제한 없이 이 GitLab 인스턴스에서 생성된 모든 JWT가 이 역할을 사용하여 인증될 수 있습니다.

ID 토큰 JWT 클레임의 전체 목록은 HashiCorp Vault를 사용한 시크릿 인증 및 읽기 자습서의 작동 방식 섹션을 읽어보세요.

또한, 시간제한, IP 주소 범위, 사용 횟수 같은 일부 Vault 토큰에 대한 속성을 지정할 수 있습니다. 옵션의 전체 목록은 JSON 웹 토큰 방법에 대한 Vault 문서인 롤 만들기에서 확인할 수 있습니다.

자체 서명 Vault 서버 사용

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 이미지를 만들어야 합니다.
  • VAULT_CACERT 환경 변수를 사용하여 GitLab Runner가 해당 인증서를 신뢰하도록 구성합니다:
    • 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>"
        

문제 해결

resolving secrets: secret not found: MY_SECRET 오류

GitLab이 보금자리에서 시크릿을 찾지 못할 때, 다음과 같은 오류 메시지를 받을 수 있습니다:

ERROR: Job failed (system failure): resolving secrets: secret not found: MY_SECRET

CI/CD 작업에서 vault 값을 올바르게 구성했는지 확인하세요.

vault CLI와 함께 kv 명령을 사용하여 Vault CLI를 사용하여 시크릿을 검색하여 CI/CD 구성에서 vault 값의 구문을 결정하는 데 도움이 됩니다. 예를 들어, 시크릿을 검색하려면:

$ vault kv get -field=password -namespace=admin -mount=ops "production/db"
this-is-a-password