AWS에서 OpenID Connect를 구성해 임시 자격 증명 가져오기

AWS에서 OpenID Connect를 구성해 임시 자격 증명 가져오기

GitLab CI/CD job에서 JWT를 사용해서, 비밀을 저장하지 않고 AWS에서 임시 자격 증명을 가져오는 방법을 함께 알아볼게요. 이를 위해 GitLab과 AWS 사이의 ID 페더레이션을 위해 OpenID Connect (OIDC)를 구성해야 합니다. OIDC로 GitLab을 통합하기 위한 배경과 요구 사항은 클라우드 서비스 연결하기를 참고하세요.

출처: 문서

본문

  • 티어(Tier): Free, Premium, Ultimate
  • 제공 방식(Offering): GitLab.com, GitLab Self-Managed, GitLab Dedicated

CI_JOB_JWT_V2GitLab 17.0에서 제거되었어요. 대신 ID 토큰을 사용하세요.

이 튜토리얼을 완료하려면:

  1. ID 공급자 추가하기
  2. 역할과 신뢰 구성하기
  3. 임시 자격 증명 가져오기

ID 공급자 추가하기

이 지침에 따라 AWS에서 GitLab을 IAM OIDC 공급자로 만들어요.

다음 정보를 포함하세요:

  • Provider URL: GitLab 인스턴스 주소(예: https://gitlab.com 또는 http://gitlab.example.com). 이 주소는 공개적으로 접근 가능해야 해요. 공개되어 있지 않다면 비공개 GitLab 인스턴스 구성 방법을 참고하세요.
  • Audience: 요청한 보안 토큰을 사용할 대상 서비스의 논리적 이름. - AWS OIDC 통합에서 이는 일반적으로 IAM OIDC ID 공급자에 구성된 audience 값(흔히 sts.amazonaws.com 또는 GitLab 인스턴스 URL)과 일치해요. - 이 값은 AWS가 검증해서 토큰이 특정 ID 공급자를 대상으로 의도된 것임을 확인해요. AWS ID 공급자 참조가 일치하면 https://gitlab.com이나 GitLab 인스턴스 URL을 사용해도 동작할 수 있지만, 의미상으로는 오해의 소지가 있어요. audience는 토큰을 검증하고 수락하는 서비스를 나타내야 합니다.

역할과 신뢰 구성하기

ID 공급자를 만든 뒤에는 GitLab 리소스에 대한 접근을 제한하는 조건과 함께 웹 ID 역할(web identity role)을 구성해요. 임시 자격 증명은 AWS Security Token Service로 얻으므로, Actionsts:AssumeRoleWithWebIdentity로 설정하세요.

특정 그룹, 프로젝트, 브랜치, 태그로 권한 부여를 제한하려면 역할에 대해 사용자 지정 신뢰 정책을 만들 수 있어요. 지원되는 필터링 유형 전체 목록은 클라우드 서비스 연결하기를 참고하세요.

GitLab.com에서 AWS는 gitlab.com OIDC ID 공급자에 대해 namespace_idproject_id를 포함한 추가 조건 키를 지원해요. 역할 신뢰 정책에 이 안정적이고 고유한 식별자에 대한 조건을 포함하세요. 이 식별자들은 경로와 무관하므로, 이들을 참조하는 신뢰 정책은 그룹이나 프로젝트 이름 변경 같은 경로 변화의 영향을 받지 않습니다.

이 추가 조건 키는 gitlab.com OIDC ID 공급자에서만 사용할 수 있어요. GitLab Self-Managed와 GitLab Dedicated에서는 AWS 조건 키로 subaud 클레임만 지원됩니다. 해당 배포에서는 sub(예: gitlab.example.com:sub)를 사용해 신뢰 정책의 범위를 정하고, 선택적으로 aud와 결합하세요.

AWS는 다음 클레임을 조건 키로 지원해요:

클레임 GitLab.com GitLab Self-Managed 및 GitLab Dedicated
sub
aud
namespace_id No
project_id No
user_id No
user_login No
user_email No
user_access_level No
ref_protected No
pipeline_source No
runner_environment No
기타 모든 클레임 No No

project_id는 전역적으로 고유하며 그룹 이름 변경, 프로젝트 이름 변경, 프로젝트 전송을 포함해 프로젝트 수명 전체에 걸쳐 동일하게 유지돼요. namespace_id는 프로젝트가 현재 네임스페이스에 있는 동안 안정적입니다. 프로젝트가 다른 네임스페이스로 전송되면 namespace_id가 변경되어, 이에 고정된 신뢰 정책은 의도적으로 무효화됩니다.

프로젝트의 namespace_idproject_id 값을 찾으려면 프로젝트 설정 페이지나 Projects API를 참고하세요. 조건 키로 사용할 수 있는 클레임 전체 목록은 ID 토큰 페이로드를 참고하세요.

다음 예시 신뢰 정책은 subnamespace_idproject_id와 함께 사용해 GitLab.com의 특정 그룹, 프로젝트, 브랜치에 신뢰를 고정합니다:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::AWS_ACCOUNT:oidc-provider/gitlab.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "gitlab.com:sub": "project_path:mygroup/myproject:ref_type:branch:ref:main",
          "gitlab.com:namespace_id": "12345",
          "gitlab.com:project_id": "67890"
        }
      }
    }
  ]
}

역할을 만든 뒤에는 AWS 서비스(S3, EC2, Secrets Manager)에 대한 권한을 정의하는 정책을 연결해요.

임시 자격 증명 가져오기

OIDC와 역할을 구성한 뒤에는 GitLab CI/CD job이 AWS Security Token Service (STS)에서 임시 자격 증명을 가져올 수 있어요.

assume role:
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://gitlab.example.com
  script:
    # this is split out for correct exit code handling
    - >
      aws_sts_output=$(aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token ${GITLAB_OIDC_TOKEN}
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text)
    - export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s" $aws_sts_output)
    - aws sts get-caller-identity
  • ROLE_ARN: 이 단계에서 정의한 역할 ARN.
  • GITLAB_OIDC_TOKEN: OIDC ID 토큰.

동작 예시

비공개 GitLab 인스턴스 구성하기

  • 티어(Tier): Free, Premium, Ultimate
  • 제공 방식(Offering): GitLab Self-Managed

변경 이력

이 방법은 이해해야 할 보안 고려 사항이 있는 고급 구성 옵션이에요. 프라이빗 GitLab Self-Managed 인스턴스의 OpenID 구성과 공개 키를 S3 버킷 같은 공개적으로 접근 가능한 위치에 정확히 동기화해야 합니다. S3 버킷과 그 안의 파일이 제대로 보안되는지도 확인해야 해요. S3 버킷을 제대로 보호하지 못하면 이 OpenID Connect ID와 연결된 모든 클라우드 계정이 탈취될 수 있습니다.

GitLab 인스턴스가 공개적으로 접근할 수 없다면 AWS에서 OpenID Connect를 구성하는 것이 기본적으로는 불가능해요. 일부 특정 구성을 공개적으로 접근 가능하게 만들면 인스턴스의 OpenID Connect 구성을 가능하게 하는 방법을 쓸 수 있습니다:

  1. GitLab 인스턴스의 인증 세부 정보를 공개적으로 접근 가능한 위치(예: S3 파일)에 저장해요: - 인스턴스의 OpenID 구성을 S3 파일에 호스팅해요. 구성은 /.well-known/openid-configuration, 예: http://gitlab.example.com/.well-known/openid-configuration에서 볼 수 있습니다. 구성 파일의 issuer:jwks_uri: 값을 공개적으로 접근 가능한 위치를 가리키도록 업데이트해요. - 인스턴스 URL의 공개 키를 S3 파일에 호스팅해요. 키는 /oauth/discovery/keys, 예: http://gitlab.example.com/oauth/discovery/keys에서 볼 수 있습니다. 예를 들어: - OpenID 구성 파일: https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com/.well-known/openid-configuration. - JWKS(JSON Web Key Sets): https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com/oauth/discovery/keys. - ID 토큰의 issuer 클레임 iss:와 OpenID 구성의 issuer: 값은 https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com가 됩니다.
  2. 선택 사항. OpenID Configuration Endpoint Validator 같은 OpenID 구성 검증기를 사용해 공개적으로 접근 가능한 OpenID 구성을 검증해요.
  3. ID 토큰에 사용자 지정 issuer 클레임을 구성해요. 기본적으로 GitLab ID 토큰은 issuer 클레임 iss:가 GitLab 인스턴스 주소로 설정돼요. 예: http://gitlab.example.com.
  4. issuer URL을 업데이트해요. Linux package (Omnibus) 1. /etc/gitlab/gitlab.rb를 편집해요: gitlab_rails['ci_id_tokens_issuer_url'] = '<public_url_with_openid_configuration_and_keys>' <public_url_with_openid_configuration_and_keys>https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com 같은 URL로 바꿔요. 1. 파일을 저장하고 변경이 반영되도록 GitLab을 재구성해요. Helm chart (Kubernetes) 1. Helm 값을 내보내요: helm get values gitlab > gitlab_values.yaml 1. gitlab_values.yaml을 편집해요: global: appConfig: ciIdTokens: issuerUrl: '<public_url_with_openid_configuration_and_keys>' <public_url_with_openid_configuration_and_keys>https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com 같은 URL로 바꿔요. 1. 파일을 저장하고 새 값을 적용해요: helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab Docker 1. docker-compose.yml을 편집해요: version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | gitlab_rails['ci_id_tokens_issuer_url'] = '<public_url_with_openid_configuration_and_keys>' <public_url_with_openid_configuration_and_keys>https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com 같은 URL로 바꿔요. 1. 파일을 저장하고 GitLab을 재시작해요: docker compose up -d Self-compiled (source) 1. /home/git/gitlab/config/gitlab.yml을 편집해요: production: &base ci_id_tokens: issuer_url: '<public_url_with_openid_configuration_and_keys>' <public_url_with_openid_configuration_and_keys>https://example-oidc-configuration-s3-bucket.s3.eu-north-1.amazonaws.com 같은 URL로 바꿔요. 1. 파일을 저장하고 변경이 반영되도록 GitLab을 재구성해요.
  5. ci:validate_id_token_configuration Rake 작업을 실행해서 CI/CD ID 토큰 구성을 검증해요.

문제 해결 (Troubleshooting)

오류: Not authorized to perform sts:AssumeRoleWithWebIdentity

이 오류가 보이면:

An error occurred (AccessDenied) when calling the AssumeRoleWithWebIdentity operation:
Not authorized to perform sts:AssumeRoleWithWebIdentity

여러 이유로 발생할 수 있어요:

  • 클라우드 관리자가 프로젝트를 GitLab과 OIDC를 사용하도록 구성하지 않았어요.
  • 역할이 브랜치나 태그에서 실행되도록 제한되어 있어요. 조건부 역할 구성을 참고하세요.
  • 와일드카드 조건을 사용할 때 StringEquals 대신 StringLike를 사용했어요. 관련 이슈를 참고하세요.

Could not connect to openid configuration of provider 오류

AWS IAM에서 Identity Provider를 추가한 뒤 다음 오류가 발생할 수 있어요:

Your request has a problem. Please see the following details.
  - Could not connect to openid configuration of provider: `https://gitlab.example.com`

이 오류는 OIDC ID 공급자의 issuer가 순서가 맞지 않거나 중복·추가 인증서를 포함한 인증서 체인을 제시할 때 발생해요.

GitLab 인스턴스의 인증서 체인을 확인하세요. 체인은 도메인 또는 issuer URL로 시작해 중간 인증서를 거쳐 루트 인증서로 끝나야 해요. gitlab.example.com을 GitLab 호스트 이름으로 바꿔 다음 명령으로 인증서 체인을 검토하세요:

echo | /opt/gitlab/embedded/bin/openssl s_client -connect gitlab.example.com:443

Couldn't retrieve verification key from your identity provider 오류

다음과 같은 오류를 받을 수 있어요:

  • An error occurred (InvalidIdentityToken) when calling the AssumeRoleWithWebIdentity operation: Couldn't retrieve verification key from your identity provider, please reference AssumeRoleWithWebIdentity documentation for requirements

이 오류는 다음 때문일 수 있어요:

  • ID 공급자(IdP)의 .well_known URL과 jwks_uri가 공개 인터넷에서 접근할 수 없음.
  • 사용자 지정 방화벽이 요청을 차단함.
  • IdP의 API 요청이 AWS STS 엔드포인트에 도달하는 데 5초 이상 지연됨.
  • STS가 IdP의 .well_known URL이나 jwks_uri에 너무 많은 요청을 함.

이 오류에 대한 AWS Knowledge Center 문서에 문서화된 대로, .well_known URL과 jwks_uri를 해석할 수 있도록 GitLab 인스턴스가 공개적으로 접근 가능해야 해요. 예를 들어 GitLab 인스턴스가 오프라인 환경에 있다는 이유로 이것이 불가능하다면, 비공개 GitLab 인스턴스 구성 방법을 참고하세요.

더 알아보기 (Learn more)