5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS IAMのOIDC認可を理解する 〜 GitLab CI/CDからAWSのマネージメントコンソールにログイン案内を出してみる

Last updated at Posted at 2025-06-06

今回はAWS IAMでサポートされている OIDCプロバイダー機能 について見ていきます。

AWS IAM の OpenID Connect 連携機能とは、どのような機能か?

何ができる?

  • 特定のIdPから発行されたIDトークンをAWSにわたすことで、AWS上のロールの引受(sts:AssumeRole)ができます
    • 事前準備後にAWS STSのAPIにIDトークンを提示することによりAWSのロールに対応した一時的な AccessKeyId SecretAccessKey SessionToken を得ることができます
  • ちゃんとオンラインで繋がる発行主体(IdP)と、それが発行したIDトークンがあれば、AWS側はOIDC中の認証やコールバックなど一切関知しません(本機能に関係ありません)

いつ使う?

  • たとえば、GitLabやGitHubにはCI/CDビルド中にIDトークンを発行する機能があります。 CI/CDビルド中に一時的にAWSサービスを、アクセスキーの事前共有無しで利用したい場合に使えます
    • IAMドキュメントに、引受を許可できるIDトークンの内容について細かい条件指定をすることができます
      • GitLab/GitHub発行のIDトークンであれば、IDトークン中にリポジトリ名・ブランチ名等があるので、それらを sts:AssumeRole 時の条件にすることができます。これにより、特定リポジトリのリリースブランチのビルドのみAWS IAM許可といった動作が可能になります
  • 他にもIDトークンを発行する主体があればいいので、色々応用方法があるかもしれません
    • 別のIdPからのOIDCコールバックだけをもらってAWSにIDトークンを中継するサイトを作れば、IdPからAWSのマネージメントコンソールにSSOログインさせるということも可能です。マネージメントコンソールのURLの発行方法は本記事にて解説します

何ができない?

  • AWS上でOIDC認証によるSSOログインを直接提供する機能ではありません
  • AWSマネージメントコンソールのIAMユーザのログインをOIDCで直接代用する機能でもありません
  • IDトークンの提示でIAMの認可(sts:AssumeRole)を受けられるだけです
  • ユーザーごとにSSOを行いたい場合は、IAM Identity CenterでSAML連携を設定したほうが良いです

IDトークン⇔IAMロール連携機能 という名前だったら分かりやすいのになあと感じています。(私だけ?)

GitLab CI/CD でIDトークンを発行してAWSマネジメントコンソールのURLを表示してみる

利用例として、実際にGitLab CI/CD中で発行されたIDトークンを用いてAWS上の認可(sts:AssumeRole)を受けたいと思います。それだけだとつまらないので、認可情報を用いて、AWSマネージメントコンソールにログインできるURLを生成してみたいと思います。

要するにGitLab CI/CDが動いたら、AWSマネージメントコンソールへのURLをコンソール吐き出すCIを作ってみます。

AWS上の設定

OIDCプロバイダの追加

IAM > ID プロバイダ から プロバイダを追加 にて以下のプロバイダを追加します。

  • プロバイダのタイプ: OpenID Connect
  • プロバイダのURL: https://your-gitlab.example.com
    • 最後にスラッシュを追加しないように注意
  • 対象者(audience): 任意。ここでは your_audience_is_here (あとで追加削除可能)

IAMロールの追加

続いてOIDCプロバイダに紐づくIAMロールを作成します。

  • 名前: 任意
  • 許可ポリシー: 任意
  • 信頼関係: 以下のようなJSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::<your_account_id>:oidc-provider/<your_provider_url>"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "<your_provider_url>:aud": "your_audience_is_here"
                }
            }
        }
    ]
}

上記では条件としてaudクレームにのみ条件がかかっていますが、GitLabの場合、IDトークンに載っている以下のようなクレームについて条件をつけてリポジトリやブランチを識別するとよいでしょう。

  • project_path: プロジェクト名(パス付き)
  • ref: ブランチ名など

GitLab上の設定

GitLab CI/CD上でOIDCトークンを発行するには id_tokens: を設定すれば指定した環境変数にIDトークンが追加されるようになります。

.gitlab-ci.yml
stages:
  - aws

issue-aws-console-url:
  stage: aws
  image: ghcr.io/astral-sh/uv:0.7.10-python3.13-bookworm
  id_tokens:
    MY_ID_TOKEN:
      aud: your_audience_is_here
  script:
    # uv コマンドで main.py スクリプトを実行
    - uv run main.py

上記のCI中で実行される main.py は以下です。CI中に示されているIDトークンを用いて、AWSから一時認証トークンを得て(それだけでもAWSの操作は可能です)、トークンから一時ログインURLを生成しています。

main.py
# /// script
# requires-python = ">=3.13"
# dependencies = ["boto3>=1.38.28", "requests>=2.32.3"]
# ///

import boto3
import requests
import urllib
import datetime
import json
import os

# パラメータ
id_token = os.environ["MY_ID_TOKEN"] # .gitlab-ci.yml で指定した環境変数
role_arn = "arn:aws:iam::<your_aws_account>:role/<your_role_name>"
issuer = "https://your-gitlab.example.com"
region = "ap-northeast-1"

sts_client = boto3.client('sts', region_name=region)

# IDトークンからSTSのクレデンシャルを取得
assume_response = sts_client.assume_role_with_web_identity(
    RoleArn=role_arn,
    RoleSessionName='GitLabOIDCSession',
    WebIdentityToken=id_token
)
assume_creds = assume_response['Credentials']
session_data = {
    "sessionId": assume_creds["AccessKeyId"],
    "sessionKey": assume_creds["SecretAccessKey"],
    "sessionToken": assume_creds["SessionToken"],
}

# STSのクレデンシャルからログインエンドポイント用の情報を取得
aws_federated_signin_endpoint = "https://signin.aws.amazon.com/federation"
fed_response = requests.get(
    aws_federated_signin_endpoint,
    params={
        "Action": "getSigninToken",
        "SessionDuration": str(datetime.timedelta(hours=12).seconds),
        "Session": json.dumps(session_data),
    },
)
# (※ この時点でAWSの操作自体は可能)

# ログインエンドポイント用の情報からURLを作成&出力
signin_token = json.loads(fed_response.text)
query_string = urllib.parse.urlencode(
    {
        "Action": "login",
        "Issuer": issuer,
        "Destination": "https://console.aws.amazon.com/",
        "SigninToken": signin_token["SigninToken"],
    }
)
federated_url = f"{aws_federated_signin_endpoint}?{query_string}"

print("AWS Management Console is here:")
print(federated_url)

uvの実行については Pythonの開発用適当ツールの作成・実行はuvを使うのがオススメ という記事を参考にしてください

上記のGitLab CI/CDでの実行結果は以下のようになります。

実行結果
$ uv run main.py
Downloading botocore (13.0MiB)
 Downloading botocore
Installed 11 packages in 54ms

AWS Management Console is here:
https://signin.aws.amazon.com/federation?Action=login&Issuer=....すごく長いURL...

実際に発行されたURLをクリックするとAWSコンソールに移動できました!

image.png

画面中ではロールに認可されている操作が可能です。

上記例は単純に技術検証としてログインURLをCIに出力しているのであって、実際に同様のことを行う場合は十分にセキュリティに配慮してください

まとめ

以下について、動作するところまでざっくり確認しました。

  • AWS IAMにおけるIDトークン連携機能
  • GitLab CI/CD上のIDトークン発行機能 (id_tokens:)
  • それらを用いたAWSのサービスの認可の発行 (sts:AssumeRole)
  • 認可情報を用いたAWSマネージメントコンソールへの一時ログインURLの発行

CI/CDからAmazon ECRにDockerイメージをプッシュしたりする場合など、アクセスキーの事前共有よりもこの手法のほうが安全と思われるので、積極的に使いたいところです。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?