ALLSSU

AWS OpenID Connect(OIDC)를 통한 CI/CD 임시 자격 증명 검색

CI/CD에서 엑세스키를 사용하는 대신 OpenID Connect(OIDC)를 사용하는 장단점과, Gitlab CI에서 OIDC를 통해 임시로 AWS 보안 자격 증명(Temporary security credentials)을 얻는 방법

2024년 4월 19일 금 09:13

Gitlab, OpenID, AWS 로고

결론부터

Gitlab CI, Github Actions, circleci, Jenkins와 같은 CI/CD 도구들을 사용할 때, AWS를 비롯한 클라우드 사용을 위해서는 자격 증명(Identities)을 얻어야 한다. AWS에서 Access Key로 CLI를 사용할 수 있지만, 여러 사람이 사용하는 CI 도구에 키를 등록해 놓으면 키 노출 위험이 발생한다. 이 위험을 없애기 위해 OIDC(OpenID Connect)를 사용해서 인증하는 방법을 찾아서 적용해 봤다.

엑세스키를 사용하는 것보다는 난이도가 높지만, Gitlab CI 및 AWS IAM에서는 OIDC를 사용하기 편하게 제공하고 있다. AWS에서 발급받은 OIDC Provider, Audience, Role를 Gitlab CI에서 매칭해서 사용하기만 하면 된다.

Aceess Key를 사용할 때와, OIDC를 사용할 때 항목별 비교

구분 AWS Access Key AWS IAM OIDC
키 노출 위험 있음 없음
CI 제어 수준 낮음 높음
개발 난이도 비교적 낮음 비교적 높음

AWS Access Key를 통한 자격 증명 사용

AWS IAM에서 사용자와 권한을 생성하고, 발급된 Access Key(Access Key ID, Secret Access Key)를 Gitlab CI에 등록하면 Gitlab CI 스크립트에서 AWS를 즉시 사용할 수 있다.

Gitlab CI를 통해 러너를 실행할 때, AWS의 자격증명을 얻기 위해 Gitlab CI에서는 AWS 관련 환경변수를 제공한다. CI/CD 환경변수에서 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION를 세팅하면 별다른 CI 스크립트 없이 AWS CLI를 사용할 수 있다.

Gitlab CI에 등록한 Access Key 환경변수 이미지

장점

  • 구성하기 쉽고 간단하다. Gitlab에서 관리하는 환경변수에 등록하기 때문에, CI 스크립트에서 추가로 설정할 부분 없이 자동으로 인증된다.

단점

  • 엑세스키(access key id + secret access key)의 노출 위험이 있다. 권한만 있다면 Gitlab CI 설정에서 언제든지 등록되어 있는 엑세스키를 다시 볼 수 있기 때문에, 보안에 취약할 수 있다. 엑세스키 관련된 환경변수는 AWS에서 생성하듯이 한번 등록하고 나면 다시 못 보게 하면 더 좋을 것 같은데, 등록된 키를 다시 확인할 수 있다는 점에서 키가 노출될 위험이 있다고 판단된다.

AWS OIDC Provider을 통한 임시 자격 증명 사용

AWS IAM OIDC를 생성한 다음에 OpenID Connect를 신뢰하도록 설정(OIDC fingerprint 등록) 한다. 클라이언트(리파지토리 또는 애플리케이션)에 맞는 Audience(aud)를 생성하고, 클라이언트별로 사용할 역할(Role)을 분리해 놓으면 리파지토리마다 다른 권한을 획득할 수 있다. 리파지토리별로 다른 OIDC 권한으로 접근하면, OIDC 사용자의 신원을 체크할 수 있도록 한다.

AWS IAM에 등록된 OIDC Provider의 ROLE ARN(aud 별 Role)을 리파지토리마다 Gitlab CI에 환경변수로 등록해 놓으면 AWS STS를 통해 쉽게 AWS CLI 접근 권한을 획득할 수 있다. Gitlab CI에 등록한 ROLE_ARN 환경변수 이미지

CI 스크립트에서 IAM Role이 포함된 AWS STS를 사용하거나, Credential Chain에서 Web Identity 인증으로 접근하도록 설정해 준다. 러너가 실행되는 환경에서 임시 자격 증명을 얻고, 그 자격 증명으로 AWS CLI를 실행하게 된다.

이렇게 설정하면 ROLE_ARN은 노출되더라도 AWS에 설정한 ROLE ARN이기 때문에 별문제가 없다.

장점

  • 엑세스 키를 사용하지 않기 때문에, 키 노출 위험이 없다.
  • OIDC Role에서 Policy의 제어에 따라 임시 자격 증명을 얻을 수 있는 수준을 결정할 수 있다. 예를 들면 특정 리파지토리나, 특정 브랜치 또는 태그만 임시 자격 증명을 획득하는 제어 레벨을 AWS IAM에서 정책을 통해 할 수 있다. 이를 통해 엑세스키를 통해 하지 못하는 제어가 가능하다.

단점

  • 개발 난이도가 엑세스키를 사용하는 것에 비해 높다. OIDC로 임시자격증명을 얻는 과정은 AWS CLI를 사용하거나 CI 스크립트 내에서 코드를 작성해야 하는데, OIDC로 임시 자격 증명을 얻는 메커니즘과 설정에 대한 학습이 필요하다.

AWS OIDC 구성과 Gitlab CI에서 임시 자격 증명 검색

참고 링크

1. AWS IAM OIDC에서 gitlab.com 공급자 등록

먼저, OIDC를 생성하고 Gitlab같은 CI 서비스의 fingerprint를 등록한다. AWS IAM > 자격 증명 공급자(Identity providers)로 들어가서 프로바이더를 생성한다. 생성한 AWS OIDC Provider는 gitlab.com을 신뢰하게 된다.

AWS OIDC Provider를 생성하는 콘솔 이미지. Provider URL을 입력하면 지문(thumbprint)을 얻을 수 있다

2. OIDC audiences(클라이언트 ID 리스트) 추가

OIDC Provider를 https://gitlab.com으로 생성한 후, Audience(aud)는 최소 권한 원칙에 따라 접근할 클라이언트별로 따로 생성해 주는 것이 좋다. 특정 클라이언트만 접근하도록 제어하는 것에도 용이하다.

AWS OIDC에서 Audience를 리스트하는 이미지

3. 역할(IAM Role) 생성 및 신뢰 정책 추가

aud에서 사용할 정책이 들어있는 IAM Role을 생성하고, Trust relationships를 등록한다. 이때, OIDC ARN이 ROLE에 Federated 되어야 ROLE에 등록된 OIDC를 찾아서 인증할 수 있게 된다. AWS ROLE에서 OIDC를 federated하는 신뢰 정책 이미지

사용할 역할(IAM Role)에 따라 AWS 리소스에 접근할 수 있는 권한이 다른데, Role마다 Permission을 지정해서 사용하면 된다. Gitlab CI yaml 스크립트 파일에는 아래와 같이 설정하면 web identity token이 설정돼서, 임시 자격 증명을 얻고 AWS CLI를 사용할 수 있다.

Policy Statement에서 Condition을 설정해주면 리파지토리 단위나 브랜치, 태그 단위까지 제어가 가능하다. 이 부분은 엑세스키를 사용했을 때는 제어하기 힘든 부분이다.

4. Gitlab CI 설정

# .gitlab-ci.yml

stages:
  - test

deploy:
  stage: test
  image: registry.gitlab.com/gitlab-org/cloud-deploy/aws-base:latest
  id_tokens:
    OIDC_TOKEN:
      aud: https://user-audience.test
  before_script:
    - |
      mkdir -p ~/.aws
      echo "${OIDC_TOKEN}" > /tmp/web_identity_token
      echo -e "[default]\nrole_arn=${ROLE_ARN}\nweb_identity_token_file=/tmp/web_identity_token" > ~/.aws/config
  script:
    - aws ec2 describe-instances
deploy.id_tokens.OIDC_TOKEN.aud는 AWS에서 생성한 OIDC Provider의 aud여야 한다. 다를 경우 접근이 되지 않음

gitlab.com에서는 Aud에 맞는 OIDC 프로바이더 접근해서, 허락된 AWS Role을 통해 리파지토리, 브랜치, 태그를 검증하고 AWS CLI를 실행하게 된다.

Gitlab CI 스크립트에서 id_tokensGitlab CI에서 JWT를 CI/CD 작업에 추가할 수 있도록 만든 JWT 환경변수인데, OIDC_TOKEN이라는 변수명으로 AWS에서 생성한 OIDC aud를 비교적 간단하게 사용할 수 있다. web identity token을 ~/.aws/config 파일에 세팅한 뒤, AWS CLI를 사용하면 미리 생성해 둔 역할(AWS ROLE)에 맞는 리소스를 제어할 수 있다.

만약 .gitlab-ci.yml에 등록된 aud가 IAM OIDC Provider의 audience 리스트에 없으면, 다음과 같이 에러가 발생한다.

OIDC aud를 찾지 못했을 때의 에러

AWS CDK에서는 에러가 나는데?

위의 코드 예제처럼 ~/.aws/config 파일을 사용해서 프로필을 설정하면, 아래와 같이 에러가 발생한다.

Unable to resolve AWS account to use. It must be either configured when you define your CDK Stack, or through the environment

이때는, AWS STS를 호출해서 임시 자격 증명을 러너에 세팅해서 사용하면 된다.

# .gitlab-ci.yml

stages:
  - test

deploy:
  stage: test
  image: node:20-alpine
  id_tokens:
    OIDC_TOKEN:
      aud: https://user-audience.test
  before_script:
    - apk add --no-cache aws-cli
    - npm install
    - npm install -g aws-cdk
    - > # 러너에 임시자격증명을 세팅(OIDC)
      export $(printf "AWS_ACCESS_KEY_ID=%s AWS_SECRET_ACCESS_KEY=%s AWS_SESSION_TOKEN=%s"
      $(aws sts assume-role-with-web-identity
      --role-arn ${ROLE_ARN}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token ${OIDC_TOKEN}
      --duration-seconds 900
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
    - aws sts get-caller-identity
  script:
    - cdk diff