GitLab Runner で OpenID Connect を使用して AWS にアクセスしてみた

2022.07.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

概要

GitHub Actions が OpenID Connect をサポートしていますが、 GitLab でも同様にサポートしています。

AWS IAM OIDC Provider に gitlab を登録し、credentials を発行することなく aws にアクセスすることを検証します。

参考

https://docs.gitlab.com/ee/ci/cloud_services/aws/

やってみた

まず、AWS IAM OIDC Provider に gitlab を登録します。

Provider URL には https://gitlab.com (最後のスラッシュはいりません!!!), 対象者 にも https://gitlab.com (sts.amazonaws.com ではありません!!!) を設定します。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  GitLabThumbprint:
    Type: String

Resources:
  GitLabOIDCProvider:
    Type: AWS::IAM::OIDCProvider
    Properties:
      Url: https://gitlab.com
      ClientIdList:
        - https://gitlab.com
      ThumbprintList:
        - !Ref GitLabThumbprint

ID Provider を登録したあとは、そのプロバイダを信頼した Role を作成します。

例として s3 bucket にアクセスできる Role を作成する CloudFormation Template を用意しました。

ポイントは AssumeRole WithWebIdentity を許可すること, sub のフォーマットが github actions の repo: とは違い project_path: になっている点です。

AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  GitLabProject:
    Type: String

Resources:
  GitLabRunnerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/gitlab.com
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                gitlab.com:sub: !Sub project_path:${GitLabProject}:ref_type:branch:ref:main
      Policies:
        - PolicyName: s3access
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action: s3:GetObject
                Resource:
                  - !Sub arn:aws:s3:::${Bucket}/*
              - Effect: Allow
                Action: s3:ListBucket
                Resource:
                  - !Sub arn:aws:s3:::${Bucket}
  Bucket:
    Type: AWS::S3::Bucket

Outputs:
  GitLabRunnerRoleArn:
    Value: !GetAtt GitLabRunnerRole.Arn
  Bucket:
    Value: !Ref Bucket

では実際に動作を確認するため、gitlab-ci.yaml を用意します。

---
image: public.ecr.aws/sam/build-go1.x
variables:
  AWS_DEFAULT_REGION: $AWS_DEFAULT_REGION
  AWS_IAM_ROLE: $AWS_IAM_ROLE
  AWS_S3_BUCKET: $AWS_S3_BUCKET
deploy:
  stage: deploy
  environment:
    name: development
  script:
    - >
      STS=($(aws sts assume-role-with-web-identity
      --role-arn ${AWS_IAM_ROLE}
      --role-session-name "GitLabRunner-${CI_PROJECT_ID}-${CI_PIPELINE_ID}"
      --web-identity-token "${CI_JOB_JWT_V2}"
      --duration-seconds 3600
      --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]'
      --output text))
    - export AWS_ACCESS_KEY_ID="${STS[0]}"
    - export AWS_SECRET_ACCESS_KEY="${STS[1]}"
    - export AWS_SESSION_TOKEN="${STS[2]}"
    - aws s3 ls s3://${AWS_S3_BUCKET}/

AWS_IAM_ROLE, AWS_S3_BUCKET は variables 経由で設定するようにします。

web-identity-token 用の CI_JOB_JWT_V2 が発行されるので、こちらを利用します。

余談ですが、 gitlab は環境ごとに変数の値を設定できます。また、 protected branch のみ使用できる変数といった設定も可能です。

実行できました。