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

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed, GitLab Dedicated
  • GitLab 13.4 및 GitLab Runner 13.4에서 도입되었습니다.
  • file 설정은 GitLab 14.1 및 GitLab Runner 14.1에서 도입되었습니다.
  • VAULT_NAMESPACE 설정은 GitLab 14.9 및 GitLab Runner 14.9에서 도입되었습니다.

시크릿은 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을 선택했습니다.

Vault로 인증하는 방법은 ID 토큰을 사용하십시오. HashiCorp Vault로의 인증 및 시크릿 읽기 자습서에서 ID 토큰으로의 인증에 대해 자세히 알아보세요.

HashiCorp Vault를 사용하려면 먼저 Vault 서버를 구성해야 합니다.

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에서 시크릿을 읽습니다.

참고: 모든 구독 수준에서 사용할 수 있는 이 기능의 버전에 대한 자습서를 읽어보세요. 이를 통해 Vault로 시크릿을 쓰고 삭제하는 기능과 여러 시크릿 엔진을 지원합니다.

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"
    
  3. Vault 서버에서 특정 경로 및 작업에 대한 액세스를 허용하거나 거부하기 위해 정책을 구성하십시오. 이 예는 프로덕션 환경에서 필요한 시크릿 세트에 대한 읽기 액세스를 부여하는 것을 보여줍니다.

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

    참고: 이러한 값을 사용자 인터페이스에서 제공하는 지원은 이 이슈에서 추적됩니다.

CI 작업에서 Vault 비밀을 사용하기

Tier: 프리미엄, 얼티밋 Offering: GitLab.com, Self-managed, GitLab Dedicated
  • GitLab 13.4 및 GitLab Runner 13.4에 도입되었습니다.

볼트 서버 구성를 완료한 후, vault 키워드를 사용하여 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 변수에 직접 저장됩니다.

지원되는 구문에 대한 자세한 정보는 .gitlab-ci.yml 참조를 읽어보세요.

볼트 서버 역할 구성하기

CI 작업이 인증을 시도하면 역할을 지정합니다. 역할을 사용하여 다양한 정책을 그룹화할 수 있습니다. 인증이 성공하면 해당 정책이 생성된 볼트 토큰에 연결됩니다.

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

바운드 클레임을 사용자 역할보호된 브랜치과 같은 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

경고: 제공된 특성 중 하나를 통해 역할을 프로젝트나 네임스페이스에 제한하세요. 이러한 제한이 없을 경우, 이 GitLab 인스턴스에서 생성된 모든 JWT가 이 역할을 사용하여 인증될 수 있습니다.

ID 토큰 JWT 클레임의 전체 목록은 Authenticating and Reading Secrets With HashiCorp Vault 튜토리얼의 How It Works 섹션을 참조하세요.

또한 시간 제한, IP 주소 범위 및 사용 횟수와 같은 결과 Vault 토큰에 대한 일부 특성을 지정할 수 있습니다. 모든 옵션에 대한 전체 목록은 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에 액세스하기위한 사용자 정의 인증서 제공 및 GitLab 인증서 대신 Vault 서버 인증서를 같은 Secret에 추가해야 합니다. GitLab 인스턴스가 자체 서명된 인증서를 사용하는 경우 둘 다 추가할 수 있어야 합니다.
      2. 다음 내용을 values.yaml 파일에 추가하세요:

        ## <SECRET_NAME> 및 <VAULT_CERTIFICATE>를 실제 값으로 교체하세요.
        
        certsSecretName: <SECRET_NAME>
        
        envVars:
          - name: VAULT_CACERT
            value: "/home/gitlab-runner/.gitlab-runner/certs/<VAULT_CERTIFICATE>"