0
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?

SPIFFE OIDC Federationを用いたAWS IAMロール連携(IRSA相当)の実現

Last updated at Posted at 2025-04-14

背景と目的

Kubernetes上のアプリケーション(Pod)がAWSのサービス(例:S3やDynamoDB)にアクセスする際、これまではIAMユーザのアクセスキーをシークレットとして埋め込む方法が一般的でした。しかし、この方法では資格情報のローテーションや漏洩リスクといった課題があります (AWS OIDC Authentication with SPIFFE)。こうした課題に対応するため、AWSは**IAM Roles for Service Accounts (IRSA)**と呼ばれる仕組みを提供しています。IRSAでは、KubernetesのサービスアカウントにIAMロールを関連付け、Podがサービスアカウントトークンを用いてAWSに対して認証し、必要なIAM権限を一時的に得ることができます (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。このアプローチにより、Podに長期的なAWS認証情報を配置せずに済み、安全性が向上しました。

しかしIRSAはAWS固有の実装であり、AWS環境にロックインされるという側面があります。マルチクラウド環境やベンダーロックインを避けたい場合、クラウドごとに異なるワークロードアイデンティティ連携を構成しなければなりません。例えば、GCPではWorkload Identity Federation、Azureではフェデレーション資格情報といった独自の仕組みが必要になります。SPIFFE(Secure Production Identity Framework for Everyone)はこの問題に対するオープンスタンダードの解決策です。SPIFFEは分散システムにおけるワークロードアイデンティティを一元的に発行・管理するための仕様であり、異種環境間でサービスにアイデンティティをブートストラップすることが可能です (SPIFFE Overview)。本記事では、SPIFFEの実装であるSPIREを用いて、AWSのIRSAと同等の機能をベンダーロックインなしに実現する方法について解説します。具体的には、SPIFFEのOIDC Federation機能を利用し、Kubernetes上のワークロードにSPIFFE発行のJWTを付与してAWS IAMロールを取得する手順と仕組みを紹介します。これにより、AWS以外のクラウド(GCPなど)でも同様のアプローチを応用でき、統一的な認証基盤を構築できます。

そもそもSPIFFEとは?

SPIFFEのドキュメントのOverviewには次のような記述があります。

SPIFFE Overview

An overview of the SPIFFE specification

SPIFFE, the Secure Production Identity Framework for Everyone, is a set of open-source standards for securely identifying software systems in dynamic and heterogeneous environments. Systems that adopt SPIFFE can easily and reliably mutually authenticate wherever they are running.

Distributed design patterns and practices such as micro-services, container orchestrators, and cloud computing have led to production environments that are increasingly dynamic and heterogeneous. Conventional security practices (such as network policies that only allow traffic between particular IP addresses) struggle to scale under this complexity. A first-class identity framework for workloads in an organization becomes necessary.

Further, modern developers are expected to understand and play a role in how applications are deployed and managed in production environments. Operations teams require deeper visibility into the applications they are managing. As we move to a more evolved security stance, we must offer better tools to both teams so they can play an active role in building secure, distributed applications.

SPIFFE is a set of open-source specifications for a framework capable of bootstrapping and issuing identity to services across heterogeneous environments and organizational boundaries. The heart of these specifications is the one that defines short lived cryptographic identity documents – called SVIDs via a simple API. Workloads can then use these identity documents when authenticating to other workloads, for example by establishing a TLS connection or by signing and verifying a JWT token.

You can read more about how the SPIFFE APIs are defined and used in the Concepts guide.

翻訳すると、

# SPIFFE概要

SPIFFEの仕様の概要

**SPIFFE**(Secure Production Identity Framework for Everyone)は、
動的で異種環境においてソフトウェアシステムを安全に識別するためのオープンソース標準規格のセットです。
SPIFFEを採用したシステムは、実行場所を問わず、簡単かつ確実に相互認証ができます。

マイクロサービス、コンテナオーケストレーター、クラウドコンピューティングなどの分散設計パターンと実践により、本番環境はますます動的で多様になっています。
特定のIPアドレス間のトラフィックのみを許可するネットワークポリシーなどの従来のセキュリティ対策は、この複雑さの下でスケールすることが難しくなっています。
組織内のワークロードのためのファーストクラスのアイデンティティフレームワークが必要になります。

さらに、現代の開発者はアプリケーションが本番環境でどのようにデプロイされ管理されるかを理解し、
その役割を担うことが期待されています。
運用チームは、管理しているアプリケーションへのより深い可視性を必要としています。
より進化したセキュリティ姿勢に移行するにつれて、
両チームが安全な分散アプリケーションの構築に積極的な役割を果たせるよう、
より良いツールを提供する必要があります。

SPIFFEは、異種環境や組織の境界を越えてサービスにアイデンティティをブートストラップし発行できるフレームワークのためのオープンソース仕様のセットです。
これらの仕様の中心は、**単純なAPI**を通じて短寿命の暗号化アイデンティティドキュメント(**SVID**と呼ばれる)を定義するものです。
ワークロードは、TLS接続の確立やJWTトークンの署名と検証などにより、他のワークロードに対する認証時にこれらのアイデンティティドキュメントを使用できます。

SPIFFE APIがどのように定義され使用されるかについての詳細は、**コンセプト**ガイドで読むことができます。

となります。つまり、ひとことで言うと、SPIFFEは「異種分散環境で動作するソフトウェア同士が互いを安全に識別・認証するためのオープンスタンダード」です。

SPIFFEおよびOIDC Federationの基礎知識

SPIFFE (Secure Production Identity Framework for Everyone)は、マイクロサービスやマルチクラウド環境におけるワークロードのためのアイデンティティフレームワークです。SPIFFEでは各ワークロードに一意の識別子(SPIFFE ID)を付与し、それを証明するドキュメントとしてSVID (SPIFFE Verifiable Identity Document)を発行します (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。SVIDはX.509証明書形式またはJWTトークン形式で発行でき、後者を特にJWT-SVID
と呼びます。SPIFFEの公式実装が**SPIRE (SPIFFE Runtime Environment)**であり、SPIREを用いることでKubernetesを含む様々な環境で自動的にワークロードにアイデンティティを配布できます (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。

OIDC Federationとは、OpenID Connectプロトコルを用いてアイデンティティプロバイダとリソースプロバイダ(AWSなど)間の信頼関係を構築することを指します。具体的には、OIDC対応のトークン発行者(Issuer)を用意し、その公開情報(OIDC DiscoveryドキュメントJWKS: JSON Web Key Set)をリソースプロバイダ側で登録しておくことで、リソースプロバイダは外部発行のトークンを検証・受け入れることができます。AWSではIAMの「OIDCアイデンティティプロバイダ」を作成して外部のOIDC Issuerを登録し、STS (Security Token Service)を通じて外部トークンを一時的な認証情報に交換する仕組みを提供しています。KubernetesのIRSA機能はまさにこのOIDC Federationを利用しており、EKSクラスタのサービスアカウントトークンIssuerをAWS IAMにOIDCプロバイダとして登録することで、PodがそのトークンでSTS経由でIAMロールを引き受けられるようになっています (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。

SPIREはバージョン1.0以降でOIDC Discovery機能をサポートしており、SPIREサーバが発行するJWT-SVIDを外部システムに認証連携させることができます。SPIREのOIDC Discovery Provider(OIDCディスカバリプロバイダ)は、SPIREサーバの公開鍵をOIDCの形式で提供するサービスです (
SPIFFE | AWS OIDC Authentication
)。具体的には、SPIREサーバに設定したJWT Issuer(後述)に対応するURL上で、.well-known/openid-configurationjwks_uriを提供し、外部からSPIREの署名鍵情報(JWKS)やIssuer情報を取得できるようにします。このOIDC Discovery Providerを利用することで、AWSなどの外部サービスはSPIREが発行したJWT-SVIDをOIDCトークンとして検証可能になります。結果として、ワークロードは自分の持つSPIFFE IDを証明するJWTを提示するだけでAWS等に認証され、IAMロールなどの権限を取得できるようになります (
SPIFFE | AWS OIDC Authentication
)(ワークロード自身にAWS資格情報を埋め込む必要がなくなります)。

まとめると、本記事で扱うソリューションでは「SPIREがKubernetes上のワークロードに発行するJWT-SVID」と「AWS IAM OIDCプロバイダによるトラスト」が橋渡しされます。これにより、Kubernetesのサービスアカウントに依存せず(=クラスタ固有のIssuerに依存せず)統一的なワークロードアイデンティティでAWSリソースへのアクセスを実現できます。次章ではまずAWS IRSAとSPIFFEを組み合わせる意義について掘り下げ、その後具体的なシステム構成と実装方法を説明します。

AWS IRSAの課題とSPIFFEによる代替案の意義

AWS IRSAはKubernetes上のPodに対してAWSリソースへの細かなアクセス制御を提供する強力な機能です (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。しかし、IRSAはAWS環境(特にEKS)に特化した仕組みであり、以下のような課題があります。

  • ベンダーロックイン: IRSAはAWSのIAMおよびEKSのサービスアカウントに依存するため、他のクラウド(GCPやAzure)やオンプレミス環境ではそのまま利用できません。マルチクラウド環境で同様の機能を実現するには、クラウドごとに異なる設定やツール(GCPのWorkload Identity Federation、AzureのマネージドID連携など)を学習・管理する必要があります。
  • Kubernetesクラスター依存: IRSAはクラスターごとにOIDCプロバイダを登録し、サービスアカウントごとにIAMロールを作成する必要があります。複数クラスタ間でアイデンティティを共有したり、一貫したID管理を行うことが難しく、クラスター単位の管理負担が発生します。
  • 拡張性と柔軟性の制限: IRSAではPodの所属するサービスアカウントがIAMロール紐付けの単位となります。これはシンプルですが、場合によってはより細かな識別(例えばアプリケーションのロールや環境に基づいたID付与)を行いたいケースがあります。その場合、サービスアカウントの作り方に依存せず柔軟にIDを割り当てられる仕組みが望まれます。

SPIFFE/SPIREを用いたアプローチは、これらの課題を解決する代替案となります。SPIFFEによるワークロードIDはクラウドやプラットフォームに依存せず一意性を保てるため、クロスプラットフォームでの利用が可能です (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。たとえばSPIREで「spiffe://example.org/app/web」というIDを発行すれば、それをAWS IAM、GCP IAM、Azure ADいずれにも認識させ、共通のアプリケーションIDとして権限を付与できます。これは各クラウドのサービスアカウントやマシンアカウントをそれぞれ管理する場合と比べ、運用上大きな利点があります。

さらに、SPIFFE IDは自由なスコープで定義できるため粒度の細かいアイデンティティ管理が可能です (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。Kubernetesのネームスペースやサービスアカウント単位だけでなく、ワークロードの役割や属性に応じてSPIFFE ID命名を工夫すれば、よりセキュアなアクセス制御ポリシーを記述できます。加えて、SPIREはワークロード毎に短期間で有効期限が切れるSVIDを発行・自動更新するため、認証情報のローテーションが自動化されセキュリティ向上も期待できます。

要するに、SPIFFEによるOIDC Federationを活用すれば「IRSAのメリット(Podに秘密情報を置かずIAMロールを利用)を享受しつつ、AWS専用ではないオープンな形でマルチクラウドにまたがるワークロード認証を統一できる」という意義があります。この仕組みはAWSに限らず他のクラウドにも展開可能であり、クラウド間で一貫したゼロトラストセキュリティモデルを実現する基盤となりえます。

システム構成と必要コンポーネント

それでは、SPIFFE OIDC Federationを用いてAWS IAMロールを利用するためのシステム全体構成を概観します。主要なコンポーネントと役割は以下のとおりです。

  • Kubernetesクラスタ(バージョン1.31以降): ワークロード(Pod)が稼働する環境です。本手法ではKubernetes上にSPIREをデプロイし、PodにSPIFFE IDを付与します。KubernetesのProjected ServiceAccount Token機能(BoundServiceAccountTokenVolume)は既定で有効化されている必要があります(Kubernetes 1.21+ではデフォルトで有効 (詳解: IAM Roles for Service Accounts | Amazon Web Services ブログ))。今回はAWS上のクラスタを例に説明しますが、クラスタ自体はEKSである必要はなく、自己管理クラスタでも動作します。

  • SPIREサーバ (SPIFFE ID 発行者): Kubernetesクラスタ内にデプロイされたSPIREサーバです。クラスタ全体の信頼ドメイン(例: example.org)に対する認証局として振る舞い、ワークロード毎のSPIFFE IDに対応するSVIDを発行します。後述するOIDC Discovery Provider機能を有効にすることで、このSPIREサーバがOIDCプロバイダ(Issuer)として振る舞い、外部に対して自身のJWKSや発行トークン情報を提供します。

  • SPIREエージェント: 各ノード上にデプロイされるSPIREエージェント(DaemonSet)。ワークロードがSPIFFE IDを受け取るためのローカルエージェントです。エージェントはノード起動時に自身をSPIREサーバに証明し、サーバから信頼されたノードとして認識されます。PodからのSVIDリクエストに応答し、サーバから受け取ったJWT-SVIDをPodに渡します(SPIFFE Workload APIを介した動作)。

  • SPIRE OIDC Discovery Provider: SPIREサーバと一緒に動作する補助サービスで、SPIREサーバが発行するJWTを外部検証可能にするためのOIDCエンドポイントを提供します (
    SPIFFE | AWS OIDC Authentication
    )。具体的には、設定されたドメイン名(例: oidc-discovery.example.org)でリクエストを受け、.well-known/openid-configurationやJWKS(JSON Web Key Set)を返すHTTP(S)サービスです。OIDC Discovery ProviderはSPIREサーバの公開鍵情報をJWKSとして提供し、Issuer(発行者)のURLやサポートする署名アルゴリズムなどを開示します。AWS側から見ると、このコンポーネントが外部OIDCプロバイダそのものとなります。

  • Ingress/ロードバランサ & DNS: OIDC Discovery Providerに外部(インターネット)からアクセスするために、KubernetesのIngressまたはサービスのロードバランサを利用します。OIDC Discoveryエンドポイント用のドメイン名(例えばoidc-discovery.example.org)に対してDNSのAレコードを作成し、その名前がIngress/ELB経由でSPIRE OIDC Discovery Providerサービスへ到達するように構成します (
    SPIFFE | AWS OIDC Authentication
    )。この通信はHTTPSで行われるため、OIDC Discovery Providerには有効なTLS証明書が必要です。本記事ではLet's Encryptによる自動証明書発行(ACME)機能を使用しますが、必要に応じて独自に証明書を発行・適用することも可能です (
    AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
    )。

  • AWS IAM OIDCアイデンティティプロバイダ: AWS IAM側の設定要素で、外部のOIDC Providerを信頼するためのエントリです。ここでIssuerとして前述のSPIRE OIDC Discovery Providerのドメイン(例: https://oidc-discovery.example.org)を登録し、さらに受け入れるAudience(クライアントIDに相当)を指定します (
    SPIFFE | AWS OIDC Authentication
    )。この設定により、AWSは指定されたIssuerから発行され、自分が許可するAudienceを含むOIDCトークンを信頼しうるようになります。後段で作成するIAMロールの信頼ポリシーにおいて、このOIDCプロバイダをプリンシパルとして指定します。

  • AWS IAMロール(およびIAMポリシー): Podが最終的に引き受けるIAMロールです。通常のIAMロールと同様にAWS上のリソースアクセス権限をIAMポリシーで紐付けて定義します。ここでは例としてS3バケット読み書き権限を付与したロールを作成します (
    SPIFFE | AWS OIDC Authentication
    )。このロールには**信頼関係 (Trust Relationship)の設定において先のOIDCプロバイダを信頼先として登録し、更に条件 (Condition)**で許容するトークンのクレーム(例えばAudienceやSubject)を制限します。具体的には、sts:AssumeRoleWithWebIdentityアクションを許可する際に、トークンの発行元が先述のOIDCプロバイダであり、Audienceが指定の文字列、Subjectが特定のSPIFFE IDであることを要求します (
    SPIFFE | AWS OIDC Authentication
    ) (
    SPIFFE | AWS OIDC Authentication
    )。この条件によって、期待したSPIFFE IDを持つワークロード以外はそのIAMロールを引き受けられないようになります(後述の例を参照)。

以上が主要な構成要素です。全体の流れとしては、**「SPIRE (Kubernetes上)」がアイデンティティを発行し、「OIDC Discovery Provider」がその公開情報を提供し、「AWS IAM」**がそれを信頼して一時的な認証情報を発行する、というステップになります。次の章では、このシステムを構築する具体的な手順を段階的に説明します。

実装ステップ

それでは、SPIREによるOIDC Federationを構成し、AWS IAMロールをPodから利用できるようにするまでの手順を順を追って見ていきます。ここではAWS上で動作するKubernetesクラスタを想定しつつ説明します(クラスター自体はKubernetes 1.31+であれば種類は問いません)。なお、以下ではSPIREサーバとエージェントをKubernetes上にデプロイする方法を扱いますが、公式のHelmチャートやYAMLマニフェストが用意されています (使用 JWT-SVID 做为访问 Vault 的凭据-腾讯云开发者社区-腾讯云)。必要に応じて公式チュートリアルリポジトリ(spiffe/spire-tutorials)の該当ディレクトリからマニフェストを取得してください (
SPIFFE | AWS OIDC Authentication
)。

1. SPIREサーバ&エージェントのデプロイ

まず、SPIREをKubernetesクラスタ上にインストールします。公式クイックスタートによれば、SPIRE用のネームスペース(通常「spire」)とサービスアカウント、クラスターロールなどを作成し、SPIREサーバをStatefulSet、SPIREエージェントをDaemonSetとしてデプロイします (Azure AD workload identity federation with SPIFFE and SPIRE | Identity in the cloud) (Azure AD workload identity federation with SPIFFE and SPIRE | Identity in the cloud)。ここでは詳細なマニフェストは割愛しますが、Helmを使用する場合はhelm install、YAMLを適用する場合はkubectl applyで提供されたマニフェスト一式をデプロイしてください。デプロイ後、以下のコマンドでSPIREサーバとエージェントのPodが正常に稼働していることを確認します。

$ kubectl get pods -n spire
NAME             READY   STATUS    RESTARTS   AGE
spire-server-0   1/1     Running   0          1m
spire-agent-xxxxx 1/1    Running   0          1m
...

SPIREサーバはデフォルト設定ではJWT-SVID発行機能が有効ですが、AWSでのOIDC Federationに適合させるためにいくつか設定変更が必要です。具体的にはSPIREサーバの設定ファイル(ConfigMap経由で提供)の中でJWT issuer鍵の種類を調整します。Issuerは後ほどAWS側に登録するOIDCプロバイダのURLと一致させる必要があるため、例えばjwt_issuer = "https://oidc-discovery.example.org"のように設定します。また、AWS IAMは楕円曲線署名(EC鍵)のJWTをサポートしないため、SPIREサーバの署名鍵をRSAに指定します (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。ConfigMap内でca_key_type = "rsa-2048"を設定しておくことで、JWT-SVID署名にRSA 2048ビット鍵が使われるようになります (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
)。これらの設定を反映させるにはSPIREサーバPodを再起動します(マニフェスト適用時に自動でローリングアップデートされます)。

次に、SPIREエージェントがKubernetesノードを正しく認証し、またワークロードにIDを発行できるようエントリの登録を行います。SPIREサーバに対してCLI経由でエントリを作成し、特定のKubernetesサービスアカウントにSPIFFE IDを割り当てます。例えば、デフォルトネームスペースのdefaultサービスアカウントにspiffe://example.org/ns/default/sa/defaultというSPIFFE IDを与えるには、以下のようにSPIREサーバのCLIを実行します(spire-server Pod内でのコマンド実行例) (使用 JWT-SVID 做为访问 Vault 的凭据-腾讯云开发者社区-腾讯云)。

$ kubectl exec -n spire spire-server-0 -- \
    /opt/spire/bin/spire-server entry create \
    -spiffeID spiffe://example.org/ns/default/sa/default \
    -parentID spiffe://example.org/ns/spire/sa/spire-agent \
    -selector k8s:ns:default \
    -selector k8s:sa:default

上記では、-selectorオプションにより「Kubernetesのdefaultネームスペースかつdefaultサービスアカウントを持つPod」に対し、このSPIFFE IDを付与するルールを登録しています。parentIDにはSPIREエージェント(ノード)のSPIFFE IDを指定し、このエージェント経由で発行されることを示しています (使用 JWT-SVID 做为访问 Vault 的凭据-腾讯云开发者社区-腾讯云)。このエントリ登録によって、後でデプロイするワークロードPodはSPIREからJWT-SVID (spiffe://example.org/ns/default/sa/default)を取得できるようになります。

2. SPIRE OIDC Discovery Providerの設定と公開

SPIREサーバとエージェントの準備ができたら、OIDC Federation用にSPIREのDiscovery Providerを起動します。まずSPIREサーバの設定に、OIDC Discoveryに関する情報を追加します。具体的には、SPIREサーバのConfigMapにOIDCプロバイダ用の設定セクションを含めます。公式チュートリアルでは別途oidc-dp-configmap.yamlというConfigMapを用意し、OIDC Discovery Provider用のパラメータ(IssuerのURLやACME利用のメールアドレス等)を設定しています (
SPIFFE | AWS OIDC Authentication
)。主な設定項目は次のとおりです。

  • ディスカバリドメイン (issuer URL): 先述のMY_DISCOVERY_DOMAINに相当する値です。例としてoidc-discovery.example.orgを使用します。この値がOIDCプロバイダの公開URLとなり、後でAWSにも登録します。
  • ACMEメールアドレス: Let's Encryptによる証明書発行のためにメールアドレスを指定します (
    SPIFFE | AWS OIDC Authentication
    )。実際にメールが送られることはありませんが、Let's Encryptの利用規約上、有効なメールアドレスを設定する必要があります (
    SPIFFE | AWS OIDC Authentication
    )。
  • その他: 必要に応じてOIDC Discovery Providerの挙動設定(ログレベルやヘルスチェック用ポートなど)を行います。通常デフォルト値で問題ありません。

ConfigMapの準備ができたら、SPIREサーバのStatefulSetにOIDC Discovery Providerコンテナを追加します。公式の手順では、spire-serverのPod内でspire-oidcというコンテナをサイドカーとして動かす構成になっています (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。提供されたYAMLマニフェスト(例: server-statefulset.yaml)では2つ目のコンテナとしてgcr.io/spiffe-io/oidc-discovery-providerイメージが定義されており、これがOIDC Discovery Provider本体です。以下のコマンドで、修正済みのConfigMapとStatefulSetを適用し、SPIREサーバPodを更新します (使用 JWT-SVID 做为访问 Vault 的凭据-腾讯云开发者社区-腾讯云)。

$ kubectl apply \
    -f server-configmap.yaml \
    -f oidc-dp-configmap.yaml \
    -f server-statefulset.yaml

適用後、SPIREサーバのPodが再作成され、spire-serverコンテナとspire-oidcコンテナの2つが起動していることを確認してください (
SPIFFE | AWS OIDC Authentication
)。kubectl get pods -n spire -l app=spire-server -o jsonpath='{.items[*].spec.containers[*].name}'コマンドを実行すると、spire-server spire-oidcと2つのコンテナ名が並んで返ってくれば成功です (
SPIFFE | AWS OIDC Authentication
)。

次に、OIDC Discovery Providerに外部からアクセスできるようServiceとIngressを構成します。OIDC Discovery Provider用のServiceはNodePortやLoadBalancerでも構いませんが、ここではIngressを用いた例を説明します。server-oidc-service.yamlおよびingress.yaml(Ingressコントローラに合わせ適宜編集)のマニフェストを適用し、OIDC Discoveryのエンドポイントを公開します (
SPIFFE | AWS OIDC Authentication
)。Ingressのホスト名には前述のディスカバリドメイン(例: oidc-discovery.example.org)を指定し、Service spire-oidcのポート(通常80)にルーティングします。

Ingress/LoadBalancerが作成されたら、そのエンドポイント(IPアドレスまたはCNAME)を確認し、該当ドメインのDNSレコードを登録します (
SPIFFE | AWS OIDC Authentication
)。例えば、Ingressの外部IPが203.0.113.10であれば、DNSプロバイダでoidc-discovery.example.org. A 203.0.113.10というレコードを追加します。AWSのIAM側からこのドメインに名前解決・HTTPSアクセスが可能である必要があるため、パブリックに解決できるDNSを使用してください (
SPIFFE | AWS OIDC Authentication
)。DNS設定後、実際にブラウザやcurlhttps://oidc-discovery.example.org/.well-known/openid-configurationにアクセスし、OIDC設定が取得できることを確認すると良いでしょう。初回アクセス時にOIDC Discovery ProviderがLet's Encryptを通じた証明書取得(ACMEチャレンジ)を自動で行います。取得には数十秒程度かかる場合があります。証明書が正常に発行されHTTPSでアクセスできるようになれば、OIDCプロバイダの準備は完了です。

3. AWS側の設定: OIDCアイデンティティプロバイダの登録

続いて、AWS IAMに対して先ほど構築したSPIRE OIDCプロバイダを登録します。AWSマネジメントコンソールのIAMセクションから行う場合、「アイデンティティプロバイダ > プロバイダの作成」を選択し、以下の情報を入力します (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。

  • プロバイダの種類: OpenID Connect
  • プロバイダのURL: https://oidc-discovery.example.org(先ほどIngress経由で公開したOIDCドメイン名にhttps://を付けたもの)。入力後に「次のステップ」を押すと、AWSがこのURLにアクセスしてOIDC Discoveryドキュメントに到達できるか検証します (
    SPIFFE | AWS OIDC Authentication
    )。アクセスできない場合はDNSやIngress設定を再確認してください。
  • クライアントID (オーディエンス): OIDCトークンのaudクレームとして期待する文字列を指定します。ここでは例としてmys3という文字列を使用します (
    SPIFFE | AWS OIDC Authentication
    )。この値は後でワークロードがJWT-SVIDを取得する際に使用するAudienceと一致させる必要があります。

情報を入力し検証が通ったらプロバイダを作成します。作成後、IAMの「アイデンティティプロバイダ」にoidc-discovery.example.orgが登録され、対応するARN(例: arn:aws:iam::<AWSアカウントID>:oidc-provider/oidc-discovery.example.org)が発行されます。これでAWS側はoidc-discovery.example.orgから発行され、Audienceがmys3であるOIDCトークンを受け入れる準備ができました。

4. IAMポリシーとIAMロールの作成・設定

次に、実際にPodが取得するIAMロールと、そのロールに付与するIAMポリシーを作成します。まずIAMポリシーですが、アクセスを許可したいAWSリソースに応じてカスタムポリシーを定義します。例えば今回はS3アクセスをシナリオとして、特定のS3バケットに対する読み書きを許可するポリシーを作成します (
SPIFFE | AWS OIDC Authentication
)。以下は例となるポリシーJSONの一部です(実際の環境に合わせバケット名等を書き換えてください)。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::<MY_BUCKET_NAME>",
        "arn:aws:s3:::<MY_BUCKET_NAME>/*"
      ]
    }
  ]
}

上記のようなポリシーを作成し、名前を例えばoidc-federation-test-policyとして保存します (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。次にIAMロールを作成します。ロールの作成では信頼されたエンティティの種類として「ウェブアイデンティティ」(Web Identity)を選択し、先ほど登録したOIDCプロバイダを指定します (
SPIFFE | AWS OIDC Authentication
)。具体的には、プロバイダ一覧からoidc-discovery.example.org(先ほどのIssuer FQDN)が選択肢に現れるので選び、オーディエンス(クライアントID)としてmys3を選択します (
SPIFFE | AWS OIDC Authentication
)。続いてアタッチするポリシーとして、先ほど作成したoidc-federation-test-policyを選択します (
SPIFFE | AWS OIDC Authentication
)。ロール名を適宜(例: oidc-federation-test-role)設定しロールを作成します (
SPIFFE | AWS OIDC Authentication
)。

ロールが作成できたら、最後に信頼関係の条件追加を行います。作成直後のIAMロールは、「任意のSubjectを持つトークンであればAudienceが一致すれば許容する」状態になっています。これを絞り込み、特定のSPIFFE ID(Subject)を持つJWT-SVIDに限定します (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。IAMロールの詳細画面で「信頼関係」タブを開き、「信頼関係の編集」をクリックします。信頼ポリシーのJSONを直接編集できるので、ConditionセクションにStringEqualsの条件を追加します。具体的には、次のようなJSONフラグメントを追加します(既存のaud条件のカンマ区切りに注意) (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。

"Condition": {
    "StringEquals": {
        "oidc-discovery.example.org:aud": "mys3",
        "oidc-discovery.example.org:sub": "spiffe://example.org/ns/default/sa/default"
    }
}

上記では、トークンの発行元ドメイン(oidc-discovery.example.org)におけるaudクレームがmys3であり、subクレームがspiffe://example.org/ns/default/sa/defaultであることを要求しています (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)。subには先ほどSPIREで登録したワークロードのSPIFFE IDを指定します。これにより、「defaultネームスペースのdefaultサービスアカウント」というSPIFFE IDを持つトークンだけがこのIAMロールをAssumeできるようになります。信頼ポリシー全体は次のようになります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::<AWSアカウントID>:oidc-provider/oidc-discovery.example.org"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc-discovery.example.org:aud": "mys3",
          "oidc-discovery.example.org:sub": "spiffe://example.org/ns/default/sa/default"
        }
      }
    }
  ]
}
``` ([
SPIFFE | AWS OIDC Authentication
](https://spiffe.io/docs/latest/keyless/oidc-federation-aws/#:~:text=%7B%20%22Version%22%3A%20%222012,discovery.example.org%22)) ([
SPIFFE | AWS OIDC Authentication
](https://spiffe.io/docs/latest/keyless/oidc-federation-aws/#:~:text=,discovery.example.org%3Asub%22%3A%20%22spiffe%3A%2F%2Fexample.org%2Fns%2Fdefault%2Fsa%2Fdefault%22%20%7D%20%7D))

編集を保存すると、この変更が全リージョンに反映されるまで12分程度かかります ([
SPIFFE | AWS OIDC Authentication
](https://spiffe.io/docs/latest/keyless/oidc-federation-aws/#:~:text=6,minute%20or%20two%20to%20propagate))。以上でAWS側の設定は完了です。ここまでのステップにより、AWS IAMは「特定のSPIFFE IDを持つJWT-SVIDに対し、`oidc-federation-test-role`を引き受けさせる」準備が整いました。

**5. ワークロードのデプロイと動作確認**

最後に、実際のKubernetes上のワークロードがAWSリソースにアクセスできることを検証します。先ほどSPIREに登録したSPIFFE ID(`spiffe://example.org/ns/default/sa/default`)を持つPodをデプロイしましょう。シンプルな例として、適当なコンテナイメージ(busyboxなど)を使い、defaultサービスアカウントで起動するPodをデプロイします。以下のようなDeploymentマニフェストを用意します(要点のみ記載)。

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-client
spec:
  replicas: 1
  selector:
    matchLabels: { app: test-client }
  template:
    metadata:
      labels: { app: test-client }
    spec:
      serviceAccountName: default  # default SAを使用
      containers:
      - name: client
        image: amazonlinux:2
        command: ["sleep", "3600"]

上記は単に長時間スリープするPodで、AWS CLIをインストールしておけば後述のテストに利用できます。デプロイ後、PodがRunningになったらシェルに入ります。

$ kubectl exec -it deploy/test-client -- /bin/bash

次に、Pod内からSPIREエージェントを通じてJWT-SVIDを取得します。SPIREエージェントのUnixソケット(/run/spire/sockets/agent.sock)に対してspire-agent api fetch jwtコマンドを使うことで、指定したAudienceを持つJWTを取得できます。AudienceにはAWS側で設定したmys3を指定します。なお、spire-agentクライアントツールはPod内にインストール済みであることが前提です(公式チュートリアルのclientコンテナにはバイナリが含まれています (
SPIFFE | AWS OIDC Authentication
))。

# /opt/spire/bin/spire-agent api fetch jwt -audience mys3 -socketPath /run/spire/sockets/agent.sock

上記コマンドを実行すると、2行目に長いJWT文字列が出力されます(1行目はメタ情報)。そのままでは扱いにくいので、次のようにファイルに保存します (
SPIFFE | AWS OIDC Authentication
)。

# /opt/spire/bin/spire-agent api fetch jwt -audience mys3 -socketPath /run/spire/sockets/agent.sock | sed -n '2p' > /tmp/token
# echo "Token length: $(wc -c < /tmp/token)"
Token length: 954

ファイル/tmp/tokenにJWTが格納されました。このJWTの中身(デコード)は、ヘッダーに署名アルゴリズムや鍵ID、ペイロードにiss(Issuer), sub(Subject), aud(Audience)などのクレームが含まれているはずです。実際にjwt.ioなどのツールで中身を確認すると、isshttps://oidc-discovery.example.orgsubspiffe://example.org/ns/default/sa/defaultaudmys3となっているのが分かります(expは数分後のタイムスタンプ) (
SPIFFE | AWS OIDC Authentication
) (lfs482-labs/lab-08-oidc-discovery/README.md at main · lftraining/lfs482-labs · GitHub)。つまり我々が意図した通りのトークンが発行されています。

続いて、このトークンを用いてAWSに認証し、一時クレデンシャルを取得してみます。AWS CLIを使用する場合、環境変数AWS_ROLE_ARNに先ほど作成したIAMロールのARNを、AWS_WEB_IDENTITY_TOKEN_FILEにトークンファイルのパスを設定することで、自動的にAssumeRoleWithWebIdentityによる認証フローが実行されます (
SPIFFE | AWS OIDC Authentication
)。今回はS3バケットのオブジェクトを取得してみます。環境変数を設定した上でaws s3 cpコマンドを実行します。

# export AWS_ROLE_ARN="arn:aws:iam::<AWSアカウントID>:role/oidc-federation-test-role"
# export AWS_WEB_IDENTITY_TOKEN_FILE="/tmp/token"
# aws s3 cp s3://<MY_BUCKET_NAME>/test.txt /tmp/test.txt
download: s3://oidc-federation-test-bucket/test.txt to ./test.txt

上記のように、download: ... to ./test.txtという出力が得られ、ファイルが正常にコピーできていることが確認できます (
SPIFFE | AWS OIDC Authentication
)。/tmp/test.txtの中身を表示して、期待通りS3上のファイルの内容が取得できているか検証してください (
SPIFFE | AWS OIDC Authentication
)。これで、Kubernetes上のPodがSPIRE経由で取得したJWT-SVIDを用いてAWSのIAMロールを引き受け、S3アクセスができたことになります。

なお、JWT-SVIDの有効期限は短く(デフォルトで数分程度)設定されています (
SPIFFE | AWS OIDC Authentication
)。今回のテストでは手動で取得・利用しましたが、実運用においてはトークンのリフレッシュ機構を組み込む必要があります。例えば、Pod内でサイドカーやスクリプトを用いて定期的にspire-agent api fetch jwtを呼び出し、新しいトークンを環境変数や一時ファイルに更新する、といった方法が考えられます。またAWS SDKを使用する場合、credential_processオプションを使用してカスタムコマンド(例えばSquare社が公開しているspiffe-aws-assume-roleツール (AWS OIDC Authentication with SPIFFE) (AWS OIDC Authentication with SPIFFE))でトークンを受け渡す実装も可能です。いずれにせよ、今回構築した信頼関係により、アプリケーションは明示的なAWSキーを持たずに**“自分のSPIFFE IDを証明するだけ”**でAWSリソースにアクセスできるようになりました。

Federation後の認証フロー解説

上記の実装手順により、SPIREとAWS間でOIDC Federationによる信頼関係が構築されました。最後に、この連携が実際に動作する際の認証フローをあらためて整理します。

  1. ワークロードの起動とSPIFFE ID付与: Kubernetes上でPodが起動すると、SPIREエージェントはPodの属性(ネームスペースやサービスアカウントなど)を検出し、SPIREサーバに認証要求を行います。SPIREサーバは事前に登録されたエントリに基づき、そのPodに対応するSPIFFE ID(例:spiffe://example.org/ns/default/sa/default)を確認します。エージェントはSPIREサーバからそのSPIFFE IDに対応するSVIDを受け取り、Podに供給します。通常はx.509-SVID(証明書)も発行されますが、本フローではJWT-SVID(短命のJWTトークン)が重要となります。

  2. JWT-SVIDの要求と取得: Pod内のアプリケーション(またはユーティリティ)がAWSアクセスを必要とするとき、SPIREエージェントのWorkload APIに対してJWT-SVIDの発行をリクエストします。リクエストにはAudienceを指定でき、ここではAWS側で設定した識別子(例:mys3)をAudienceとします。SPIREエージェントはSPIREサーバにJWT-SVID発行を要求し、サーバは署名用秘密鍵でトークンを発行します。このトークンのIssuerは先ほど設定したhttps://oidc-discovery.example.org、SubjectはワークロードのSPIFFE ID、Audienceは要求されたmys3となります (lfs482-labs/lab-08-oidc-discovery/README.md at main · lftraining/lfs482-labs · GitHub)。完成したJWT-SVIDはエージェント経由でPodに渡されます。

  3. AWS STS(AssumeRoleWithWebIdentity)へのトークン提示: アプリケーションは取得したJWTトークンをAWSに提示して、一時的な認証情報(クレデンシャル)をリクエストします。具体的にはAWS STSのAssumeRoleWithWebIdentity APIを呼び出し、パラメータとして先ほどのIAMロールARNとJWTトークンを渡します。AWS CLIやSDKを使う場合、前述のように環境変数やcredential_processでこの処理が抽象化されます (AWS OIDC Authentication with SPIFFE)。AWS側では、受け取ったトークンのIssuerを元に該当するOIDCプロバイダ設定を自動検出し(今回登録したoidc-discovery.example.org)、トークン検証を行います。具体的には、AWSはoidc-discovery.example.orgに対して.well-known/openid-configurationを取得し、記載されたjwks_uriからJWKS(公開鍵セット)を取得します。このJWKSにはSPIREサーバが現在利用中のJWT署名公開鍵が含まれており、トークンの署名検証が行われます (AWS OIDC Authentication with SPIFFE)。署名が正当であり、かつトークンのクレーム(Issuer、Audience、Subject)がIAMロールの信頼ポリシー条件に合致すれば (
    SPIFFE | AWS OIDC Authentication
    )、AWS STSはそのIAMロールをPodに対して引き受けさせます(AssumeRole成功)。

  4. 一時的なAWSクレデンシャルの取得と利用: STSのレスポンスとして、一時的なAWSクレデンシャル(一意のアクセスキーID、シークレット、およびセッショントークン)が発行されます。AWS CLIやSDKの場合、このクレデンシャルは内部的に取得・適用され、以後そのSDKクライアントはIAMロールの権限でAWSサービスを操作できます。今回の例ではS3の読み書きが許可されたロールだったため、Pod内のAWS CLIはこのクレデンシャルを用いてaws s3 cp等のコマンドを実行し、S3バケットからオブジェクトを取得できました (
    SPIFFE | AWS OIDC Authentication
    )。発行されたクレデンシャルには有効期限があり、デフォルトでは1時間程度で失効します(JWT-SVID自体の有効期間は数分と短いため、長時間動作させるには途中で再度JWT-SVID取得とAssumeRoleを行う必要があります)。

以上が一連のフローです。まとめると、**「Pod → SPIREからJWT取得 → AWSに提示 → AWSが検証・一時クレデンシャル付与 → AWSサービスアクセス」**という手順となります (AWS OIDC Authentication with SPIFFE)。このフローにおいて、アプリケーション開発者はAWSの長期キーを扱う必要がなく、裏側でSPIREとAWS IAMが連携して認証を成立させています。まさにIRSAと同様のメリット(シークレットレスな認証)が得られつつ、それを支えているのはAWS固有の仕組みではなくSPIFFEというオープンな基盤になっています。

他クラウドへの応用についての補足

本記事では主にAWSを例に説明しましたが、SPIFFE OIDC Federationは他の主要クラウドにも応用可能です。各クラウドベンダーはオンプレミスや他クラウドのワークロードに対してOIDCフェデレーションによる認証を提供し始めており、SPIREをその外部OIDCプロバイダとして利用できます。

  • Google Cloud Platform (GCP): GCPではWorkload Identity Federationにより、外部OIDCトークンをGoogle Cloudの一時認証情報に交換できます (Workload Identity Federation | IAM Documentation - Google Cloud)。具体的には、GCPのIAMでWorkload Identity PoolOIDCプロバイダを作成し、IssuerにSPIREのOIDC Discoveryエンドポイント(例: https://oidc-discovery.example.org)を登録します。そして、特定のGoogleサービスアカウントに対して許可する外部主体(External Subject)としてSPIFFE IDを条件に含めることで、SPIRE発行JWTからGCPサービスアカウントのトークンへの交換が可能になります。たとえば、あるサービスアカウントの権限をSPIFFE IDspiffe://example.org/myappに紐付けて許可し、ワークロード側ではそのJWT-SVIDをOAuth2のトークンエンドポイントに提示して短期のGoogleアクセス トークンを取得するといった流れです (Workload Identity Federation for On-Premise Workloads with SPIFFE | by Christoph Grotz | Google Cloud - Community | Medium)。実装上は、SPIREのjwt_issuerをGCSバケットのURLに設定し(またはIngressで公開し)、そのバケット上に.well-known/openid-configurationとJWKSファイルを配置するなどの方法でIssuerを公開する例も報告されています (Workload Identity Federation for On-Premise Workloads with SPIFFE | by Christoph Grotz | Google Cloud - Community | Medium)。

  • Microsoft Azure: Azure(正確にはMicrosoft Entra IDこと旧Azure AD)でも外部OIDCアイデンティティとのフェデレーションをサポートしています (Workload identity federation - Microsoft Entra Workload ID)。AzureではFederated Identity Credentialという仕組みを使い、アプリ登録したサービスプリンシパル(またはマネージドID)に対して信頼するIssuer、Subject、Audienceを登録できます。SPIREのOIDC DiscoveryエンドポイントをIssuerとして登録し、対象のSPIFFE IDをSubjectに、Azure側で任意の識別子をAudienceに設定すれば、対応するJWT-SVIDでAzureのアクセストークンを取得できます。注意点として、Azure ADはJWKS内の公開鍵にuse: "sig"属性が含まれていることを要求するため、SPIREのOIDCプロバイダ設定でこの属性を有効にする必要があります (Azure AD workload identity federation with SPIFFE and SPIRE | Identity in the cloud)(SPIRE OIDC Discovery Provider v1.1.2以降では対応済み (Azure AD workload identity federation with SPIFFE and SPIRE | Identity in the cloud))。設定が適切になされば、例えばPodがSPIFFE JWTを取得してAzureのOAuth2トークンエンドポイントに対してオンビヘフ(on-behalf-of)フローを実行し、Azureリソースへのトークンを受け取ることが可能です。

このように、SPIFFEによるOIDC Federationはクラウドごとに多少設定こそ異なるものの、基本的な考え方は共通しています。いずれも**「クラウド側にSPIRE(SPIFFE)を認証基盤として信頼させる」**ことで、ワークロードは各種クラウドのAPIにシークレットレスでアクセスできるようになります。一度SPIREを導入しておけば、マルチクラウド環境におけるワークロード認証を統一的に扱える点は大きなメリットです。

まとめと今後の展望

本記事では、SPIFFE/SPIREのOIDC Federation機能を活用し、AWSにおいてIRSA(IAM Roles for Service Accounts)と同等の仕組みをベンダーロックインなしに実現する方法を解説しました。背景としてIRSAの登場と課題、SPIFFEの概要に触れ、SPIREとAWS IAMの連携手順を公式ドキュメントに準じて詳細に示しました。Kubernetes上のワークロードにSPIFFE IDを付与し、OIDCプロバイダとして公開、それをAWS IAMが信頼することで、ワークロードは自らのアイデンティティでAWSリソースアクセスが可能になります。鍵となるポイントを振り返ります。

  • SPIFFE IDによる統一アイデンティティ: ワークロード毎にSPIFFE IDを発行し、それを各クラウドで認識させることでマルチクラウド環境の認証連携がシンプルになります。AWS IRSAに限らず、GCPやAzureでも同様の仕組みを適用可能であることを確認しました。
  • OIDC Federationの活用: オープン標準であるOIDCを用いることで、AWS IAMなど既存の認証基盤にSPIREを統合できます。AWSではOIDCプロバイダとしてSPIREを登録し、STSによるAssumeRoleを通じてAWS一時クレデンシャルを取得しました (AWS OIDC Authentication with SPIFFE)。
  • セキュリティと運用上の注意: JWT-SVIDや一時クレデンシャルは短期間で失効するため、自動リフレッシュの仕組みが必要です (
    SPIFFE | AWS OIDC Authentication
    )。またIAMロールの信頼ポリシーではSubject(SPIFFE ID)で厳格に絞り込むことで、不正なトークンによるロール取得を防ぎました (
    SPIFFE | AWS OIDC Authentication
    )。運用時には証明書失効やキー交換(SPIREサーバのJWT署名鍵ローテーション)のタイミングにも留意し、AWS側に設定したJWKSが最新に保たれているか確認することが重要です。

最後に、今後の展望として、SPIFFEがクラウドネイティブ業界で果たす役割はますます大きくなると考えられます。Kubernetes自体も将来的にSPIFFE標準を受け入れ、ネイティブにワークロードID管理を統合する可能性があります。また、Zero Trustセキュリティの文脈でも、SPIFFEによる相互認証やアイデンティティフェデレーションは重要なピースとなっています。現在は各クラウドごとにOIDC連携設定が必要でしたが、将来的にはマルチクラウド環境全体でSPIFFEを中核とした統一認証管理ができるようなエコシステムが成熟していくでしょう。

本記事が、SPIFFE/SPIREを用いたベンダーロックインのない認証連携構築の一助となれば幸いです。公式ドキュメント(SPIFFEサイトのAWS OIDC Federation解説 (
SPIFFE | AWS OIDC Authentication
)など)も参照しつつ、ぜひ自身の環境で試してみてください。SPIFFEを活用することで、クラウドをまたいだアイデンティティ管理とセキュアな認可の実現に大きく前進できるでしょう。

参考資料: SPIFFE/SPIRE公式ドキュメント (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
) (
SPIFFE | AWS OIDC Authentication
)、AWS公式ブログ (詳解: IAM Roles for Service Accounts | Amazon Web Services ブログ)、SPIFFE活用例(Square社ブログ (AWS OIDC Authentication with SPIFFE)、John Harrisブログ (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
) (
AWS IAM with SPIFFE & SPIRE · ~/projects/johnharris.io
))など。各種設定の詳細は公式リファレンスも合わせて参照してください。

0
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
0
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?