GitLab CI/CD에서 AWS Secrets Manager 시크릿 사용하기

GitLab CI/CD에서 AWS Secrets Manager 시크릿 사용하기

AWS Secrets Manager에 저장된 시크릿을 GitLab CI/CD 파이프라인에서 사용하는 방법을 설명하는 문서예요. IAM 역할 인증과 OpenID Connect 인증 두 가지 방식을 모두 지원해요.

간단한 문법부터 시크릿 버전, 계정 간 접근, 시크릿별 설정 재정의까지 다양한 활용법을 코드 예시와 함께 옆에서 설명해 주는 방식으로 정리했어요.

출처: 문서

본문

AWS Secrets Manager에 저장된 시크릿을 GitLab CI/CD 파이프라인에서 사용할 수 있어요.

이력

전제 조건:

  • AWS 계정에서 AWS Secrets Manager에 접근할 수 있어야 해요.
  • 다음 방법 중 하나로 인증을 구성하세요.
    • IAM Role: GitLab Runner 인스턴스에 할당된 IAM 역할을 사용.
    • OpenID Connect: 임시 자격 증명을 가져오려면 AWS에서 OpenID Connect 구성.
  • AWS 구성 정보를 제공하기 위해 프로젝트에 CI/CD 변수를 추가하세요.
    • AWS_REGION: 시크릿이 저장된 AWS 리전.
    • AWS_ROLE_ARN: 가정할 AWS IAM 역할의 ARN (OpenID Connect 사용 시 필수).
    • AWS_ROLE_SESSION_NAME: 선택 사항. 가정된 역할의 사용자 지정 세션 이름.

CI/CD 작업에서 AWS Secrets Manager 시크릿 사용하기

IAM 역할 인증 사용

aws_secrets_manager 키워드로 정의해 AWS Secrets Manager에 저장된 시크릿을 작업에서 사용할 수 있어요.

이 방법은 GitLab Runner 인스턴스에 할당된 IAM 역할을 사용해요. Kubernetes 실행기오토스케일링을 사용할 때는 IAM 역할이 여러분의 러너 매니저(runner manager)에 적용되어 있는지 확인하세요.

전제 조건:

  • GitLab Runner 18.3 이상.

예를 들어:

variables:
  AWS_REGION: us-east-1

database-migration:
  secrets:
    DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: app-secrets/database
        field: 'password'
      file: false
  stage: deploy
  script:
    - echo "Running database migration..."
    - mysql -h $DB_HOST -u $DB_USER -p$DATABASE_PASSWORD
    - echo "Migration completed successfully."

OpenID Connect 인증 사용

보안을 강화하기 위해 OpenID Connect를 사용해 AWS에 인증하고 특정 IAM 역할을 가정할 수 있어요. 기본적으로 러너는 AWS_ID_TOKEN이라는 이름의 ID 토큰을 찾아요. 예를 들어:

variables:
  AWS_REGION: us-east-1
  AWS_ROLE_ARN: 'arn:aws:iam::123456789012:role/gitlab-secrets-role'

database-migration:
  id_tokens:
    AWS_ID_TOKEN:
      aud: 'sts.amazonaws.com'
  secrets:
    DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: app-secrets/database
        field: 'password'
      file: false
  stage: deploy
  script:
    - echo "Connecting to production database..."
    - psql postgresql://$DB_USER:***@$DB_HOST:5432/$DB_NAME -c "SELECT version();"
    - echo "Database connection successful."

token 옵션으로 사용자 지정 토큰을 지정할 수도 있어요. 예를 들어:

variables:
  AWS_REGION: us-east-1
  AWS_ROLE_ARN: 'arn:aws:iam::123456789012:role/gitlab-secrets-role'

database-migration:
  id_tokens:
    CUSTOM_AWS_TOKEN:
      aud: 'sts.amazonaws.com'
  secrets:
    DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: app-secrets/database
        field: 'password'
      token: $CUSTOM_AWS_TOKEN
      file: false
  stage: deploy
  script:
    - echo "Connecting to production database with custom token..."
    - psql postgresql://$DB_USER:***@$DB_HOST:5432/$DB_NAME -c "SELECT version();"
    - echo "Database connection successful."

짧은 형식 문법

시크릿 ID를 문자열로 지정하는 간단한 문법을 사용할 수 있어요. 선택적으로 # 문자로 구분해 필드를 지정할 수 있어요. 예를 들어:

variables:
  AWS_REGION: us-east-1

api-deployment:
  secrets:
    API_KEY:
      aws_secrets_manager: 'app-secrets/api#api_key'
      file: false
    FULL_SECRET:
      aws_secrets_manager: 'app-secrets/api'
      file: false
  stage: deploy
  script:
    - echo "Deploying API with specific field..."
    - curl --header "Authorization: Bearer ***" https://api.example.com/deploy
    - echo "Using full secret..."
    - curl --header "Authorization: Bearer *** $FULL_SECRET | jq --raw-output '.api_key')" https://api.example.com/status

시크릿 버전 관리

AWS Secrets Manager는 시크릿의 여러 버전을 지원해요. version_id 또는 version_stage로 특정 버전을 지정할 수 있어요. 예를 들어:

variables:
  AWS_REGION: us-east-1

production-deployment:
  secrets:
    DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: prod-app-secrets/database
        field: 'password'
        version_stage: 'AWSCURRENT'
      file: false
    STAGING_DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: prod-app-secrets/database
        field: 'password'
        version_id: '01234567-89ab-cdef-0123-456789abcdef'
      file: false
  stage: deploy
  script:
    - echo "Deploying to production with current secret version..."
    - deploy-prod.sh --db-password $DATABASE_PASSWORD
    - echo "Testing with specific secret version..."
    - test-with-version.sh --db-password $STAGING_DATABASE_PASSWORD

계정 간 시크릿 접근

다른 AWS 계정에서 시크릿을 가져오려면 전체 ARN을 사용해야 해요. 예를 들어:

variables:
  AWS_REGION: us-east-1
  AWS_ROLE_ARN: 'arn:aws:iam::123456789012:role/cross-account-secrets-role'

cross-account-deployment:
  id_tokens:
    AWS_ID_TOKEN:
      aud: 'sts.amazonaws.com'
  secrets:
    SHARED_API_KEY:
      aws_secrets_manager:
        secret_id: 'arn:aws:secretsmanager:us-east-1:987654321098:secret:shared-api-keys-AbCdEf'
        field: 'production_key'
      file: false
  stage: deploy
  script:
    - echo "Accessing shared secret from another account..."
    - curl --header "Authorization: Bearer ***" https://shared-api.example.com/deploy

시크릿별 구성 재정의

전역 AWS 설정을 시크릿 단위로 재정의할 수 있어요. 예를 들어:

variables:
  AWS_REGION: us-east-1
  AWS_ROLE_ARN: 'arn:aws:iam::123456789012:role/default-role'

multi-region-deployment:
  id_tokens:
    AWS_ID_TOKEN:
      aud: 'sts.amazonaws.com'
    EU_AWS_TOKEN:
      aud: 'sts.amazonaws.com'
  secrets:
    EU_DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: eu-app-secrets/database
        field: 'password'
        region: 'eu-west-1'
        role_arn: 'arn:aws:iam::123456789012:role/eu-deployment-role'
        role_session_name: 'gitlab-eu-deployment'
      token: $EU_AWS_TOKEN
      file: false
    US_DATABASE_PASSWORD:
      aws_secrets_manager:
        secret_id: us-app-secrets/database
        field: 'password'
      file: false
  stage: deploy
  script:
    - echo "Deploying to EU region..."
    - deploy-to-eu.sh --db-password $EU_DATABASE_PASSWORD
    - echo "Deploying to US region..."
    - deploy-to-us.sh --db-password $US_DATABASE_PASSWORD

이 예시들에서:

  • aud: 연합 자격 증명을 만들 때 사용된 오디언스와 일치해야 하는 오디언스.
  • secret_id: AWS Secrets Manager의 시크릿 이름 또는 ARN. 다른 계정에서 시크릿을 가져오려면 ARN을 사용해야 해요.
  • field: 가져올 JSON 시크릿의 특정 키. 지정하지 않으면 전체 시크릿이 가져와져요. 필드 접근은 평평한(flat) JSON 시크릿(최상위 키만)에서만 지원되며 문자열, 숫자, 불리언 값을 지원해요. 예를 들어:
    • password: password 필드에 접근.
    • api_key: api_key 필드에 접근.
  • token: 인증에 사용할 ID 토큰을 지정. 지정하지 않으면 러너는 AWS_ID_TOKEN이라는 이름의 토큰을 찾아요.
  • version_id: 시크릿의 특정 버전의 고유 식별자. version_idversion_stage를 지정하지 않으면 AWS Secrets Manager는 AWSCURRENT 버전을 반환해요.
  • version_stage: 가져올 시크릿 버전의 스테이징 레이블(예: AWSCURRENT 또는 AWSPENDING). 같은 시크릿에 version_idversion_stage를 둘 다 지정할 수는 없어요.
  • region: 이 특정 시크릿에 대해 전역 AWS_REGION을 재정의.
  • role_arn: 이 특정 시크릿에 대해 전역 AWS_ROLE_ARN을 재정의.
  • role_session_name: 이 특정 시크릿에 대해 전역 AWS_ROLE_SESSION_NAME을 재정의.

GitLab은 AWS Secrets Manager에서 시크릿을 가져와 값을 임시 파일에 저장해요. 이 파일의 경로는 파일 형식 CI/CD 변수와 유사하게 CI/CD 변수에 저장돼요.

문제 해결

AWS로 OIDC를 설정할 때 일반적인 문제는 AWS용 OIDC 문제 해결을 참고하세요.

오류: no EC2 IMDS role found

다음 두 조건이 모두 참일 때 이 오류가 발생할 수 있어요.

Resolving secrets
Resolving secret "MY_AWS_SECRET"...
Using "aws_secrets_manager" secret resolver...
ERROR: Job failed (system failure): resolving secrets: operation error Secrets Manager: GetSecretValue, get identity: get credentials: failed to refresh cached credentials, no EC2 IMDS role found, operation error ec2imds: GetMetadata, canceled, context deadline exceeded

Resolving secrets 단계는 러너 매니저가 처리해요. 이 단계는 EC2 IMDS에 캐시된 IAM 자격 증명에 접근해요. IAM 역할이 러너 매니저에 적용되지 않았다면 Resolving secrets 단계가 실패해요.

이 오류를 해결하려면 올바른 IAM 역할을 러너 매니저에 적용하세요.

러너 매니저가 생성하고 관리하는 러너 파드에 IAM 역할을 적용하는 것으로는 이 문제가 해결되지 않아요.

더 알아보기

AWS와의 OIDC 설정 방법은 AWS용 OIDC 문서에서 자세히 다루고 있어요. GitLab CI/CD에서 다른 시크릿 관리자를 사용하는 방법도 참고하려면 외부 시크릿 사용 문서를 함께 보시면 좋아요.