tech.guitarrapc.cóm

Technical updates

NuGet Trusted PublishingでOIDCを使ってトークンレスでCIからNuGetパッケージを公開する

NuGet Trusted Publishingが2025年9月22日に公開され、OpenID Connect (OIDC)を使ってトークンレスでCIからNuGetパッケージを公開できるようになりました。

今回は、NuGet Trusted Publishingを使ってGitHub ActionsからトークンレスでNuGetパッケージを公開するメリットと手順を解説します。NuGet Trusted Publishingは積極的に使っていきましょう。

NuGet Trusted Publishingとは

従来、NuGetパッケージを公開するには、APIキーを発行してdotnet nuget pushコマンドに渡す必要がありました。 このようなAPI認証はシンプルなため長年利用されてきましたが、ここ数年は複数の課題が指摘されています。

  • APIキーが長期間有効であるため、漏洩リスクが高い
  • APIキーのローテーションが手動であり、運用コストが高い (最長1年)
  • CI/CD環境にAPIキーを安全に保存する必要がある
  • APIキーが漏れたらだれでもどこからでもパッケージを公開できてしまう

APIキー認証の問題はNuGetに限らず、多くのパッケージシステムで共通した課題といえます。例えば利用者が特に多いnpmは、パッケージ作者から詐取したAPIキーを使ってマルウェア入りパッケージを公開する事件が何度も発生しています。npmにおけるパッケージAPI認証の課題に対するGitHubの対策は「TOTPからPasskeyベースへの移行 (認証のフィッシング対策強化)」と「OIDCを使ったトークンレスパッケージ公開(Trusted Publishing)」です。npmにおいてTrusted Publishingが先行していているので、本記事と合わせて読むと参考になる記事を紹介します

本記事で紹介するNuGet Trusted Publishingは、細かい違いはあるものの、おおむねnpm Trusted Publishingと同様の仕組みをNuGetに導入した考えて差し支えないでしょう。

OIDCを使ったトークンレスパッケージ公開は何を解決するのか

OIDCを使ったトークンレスパッケージ公開は、API管理を不要にすることが最大の利点です。「手元からパッケージ公開せず、基本的にパッケージ公開はCI/CDからのみ行う」、という前提を置く限りかなり有効な手法といえます。

  • APIキーが短時間のみ有効な自動発行されたトークンに置き換わるため、漏洩時のリスクが大幅に低減される
  • ユーザーによるAPIキーローテーションが不要になる
  • CI/CD環境にAPIキーを保存する必要がなくなる
  • GitHub ActionsなどのOIDC対応CI/CD環境からのみパッケージを公開できるように制限できる

ただし、OIDCを使ったトークンレスパッケージ公開には以下のような制約もあります。

  • CI/CD環境からのみパッケージを公開できる (手元からOIDCでパッケージ公開はできない)
  • CI/CD環境とパッケージシステムの両方がOIDCに対応している必要がある

また、OIDCを使ったトークンレスパッケージ公開を導入しても、以下のようなリスクは残ります。

  • CI/CD環境へ不正アクセスされた場合、パッケージを公開されるリスクがある
  • あくまでもパッケージ公開の認証を強化するものであり、パッケージ内容の改ざんやマルウェア混入を防止するものではない

OIDCを使った基本的な仕組みについては、業界で取り組んでいるOpenSSFイニシアチブ)を参照するとフローや概念がよくわかります。

alt text

NuGet Trusted Publishingの概要

Trusted PublishingはOIDCを使ってパッケージ公開時のサービス認証を行う仕組みです。NuGet Trusted Publishingでは、事前に登録されたCI/CD環境からリクエストに限り、短時間のみ有効なトークンを発行してパッケージ公開を許可します。このため、ユーザーが直接APIキーを管理する必要はありませんが、コマンドにはdotnet nuget publish -k "token"のように短命なトークンを渡すことになります。

OIDCを使った認証フローは次の通りです。

  1. CI/CD環境がOIDCトークンを発行
  2. CI/CD環境がOIDCトークンを使ってnuget.orgから短時間のみ有効なパッケージ公開トークンを取得
  3. CI/CD環境がパッケージ公開トークンを使ってNuGetパッケージを公開

OIDCには事前認証が必要なため、Trusted Publishingを利用する = NuGetで信頼設定を行う、GitHub Actionsは指定した設定で実行することを意味します。

  • nuget.orgでTrusted Publishingのポリシーを設定
  • CI/CDはポリシーに沿った設定でNuGetパッケージ公開

NuGet Trusted Publishingは、CI/CD環境としてGitHubに対応していますが他のCI/CD環境は対応していません。1

設定方法

NuGet Trusted Publishingを設定する手順を見ていきましょう。

nuget.orgでTrusted Publishingのポリシーを設定

Nugetにログインして、アカウントメニュー -> Trusted Publishingを開きます。

trusted publishing

Createをクリックして、Trusted Publishingポリシーを作成します。下は私の管理しているSkiaSharp.QrCodeリポジトリの設定例です。

  • ポリシー名は任意の名前でOK。識別しやすいようにリポジトリ名などを入れておくとよさそう
  • Package OwnerはNuGetのアカウントを指定。ここでOrgアカウントを選択すれば、NuGet Orgアカウントのパッケージが対象となる
  • Repository OwnerはGitHubのリポジトリ所有者名を指定。GitHub Orgのパッケージなら、GitHub Organization名を指定
  • Repository Nameはリポジトリ名を指定
  • Workflow Fileは、GitHub Actionsワークフローのファイル名を指定。注意書きにあるように、.github/workflows/以下の「ファイル名」のみを指定

Policy

CI/CDワークフローの設定

CI/CDワークフローと言ってもGithub Actionsにしか対応していないので、GitHub Actionsワークフローです。

  • ワークフローファイル名は、NuGet Trusted Publishingポリシーで指定したWorkflow Fileと一致させる必要がある
  • Nuget/loginアクションを実行するジョブのPermissionsにid-token: writeの権限を付与するのがポイント。AWSやGoogle Cloud、AzureといったほかのOIDCデプロイと同じように、OIDCトークン発行のために必要
  • NuGetの短命トークン取得には、NuGet/loginアクションを使うのが推奨。nuget.orgからパッケージ公開トークンを取得し、ステップ変数にセットしてくれる

サンプルのワークフローrelease.yamlは次の通りです。この例では、git tagでバージョンタグをプッシュしたときにパッケージを公開するようにしています。

name: Publish NuGet package

on:
  push:
    tags:
      - 'v*.*.*' # バージョンタグをプッシュしたときに実行

jobs:
  publish:
    permissions:
      contents: read
      id-token: write # OIDCトークン発行のために必要
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
    # ビルド & パック
    - name: dotnet pack
      run: dotnet pack -c Release -o ./bin
    # NuGet/loginアクションでOIDCトークンを使って短命トークンを取得
    - name: NuGet Login
      uses: NuGet/login@d22cc5f58ff5b88bf9bd452535b4335137e24544 # v1.0.0
      id: login
      with:
        user: my-nuget-username # NuGetのユーザー名を指定、Orgアカウントでもユーザー名となる
    # 取得した短命トークンを使ってパッケージを公開
    - name: Push package
      run: dotnet nuget push ./bin/*.nupkg --api-key "${{ steps.login.outputs.NUGET_API_KEY }}" --source https://api.nuget.org/v3/index.json

ワークフローを実行

タグをプッシュすれば、GitHub ActionsがトリガーされてOIDCを使ってNuGetパッケージが公開されます。

制約

2025年10月1日時点で、Reusable WorkflowでNuGet/Loginを使った場合に、NuGetで登録したポリシーを見つけられないことを確認しています。Reusable Workflowを使わずに、直接ワークフローに記述する場合は問題ないので、こちらを利用することをお勧めします。

Error: Token exchange failed (401): No matching trust policy owned by user '***' was found.

NuGet/loginのIssueで報告してありますが、これはNuGet側で対応しないといけなさそうな気配があるのでしばらくかかりそうです。

再現ワークフローは次の通り

# `.github/workflows/nuget-push.yaml@main`
name: Push NuGet
on:
  workflow_call:

jobs:
  create-release:
    permissions:
      contents: write
      id-token: write # required for NuGet Trusted Publish
    runs-on: ubuntu-24.04
    timeout-minutes: 10
    steps:
      - name: NuGet login (OIDC → temp API key)
        uses: NuGet/login@d22cc5f58ff5b88bf9bd452535b4335137e24544 # v1.1.0
        id: login
        with:
          user: my-nuget-user
# 呼び出し元ワークフロー
name: Build-Release

on:
  workflow_dispatch:

jobs:
  dummy:
    permissions:
      contents: write
      id-token: write # required for NuGet Trusted Publish
    uses: .github/workflows/nuget-push.yaml@main

まとめ

NuGetのAPI Token認証の課題を解決するTrusted Publishingが公開されました。API Tokenではトークンローテーションや対応パッケージの指定といったわずらわしさがありましたが、Trusted Publishingを使えばリポジトリごとにOIDCで認証できるため、認証管理がかなりシンプルになります。

とはいえ、認証の境界ラインがGitHub ActionsなどのCI/CD環境に移動するため、CI/CD環境のセキュリティがザルだと意味がありません。CI/CD環境のセキュリティ対策をしっかり行った上で、Trusted Publishingを導入することをお勧めします。2025年現在ならGitHub 2FAからSMSは削除し、Passkeyベースの認証に移行するのがよいでしょう。


  1. 2025年10月時点