セキュリティ

SAMLメタデータとは:EntityDescriptorの読み方と署名証明書の更新手順

SAMLメタデータとは:EntityDescriptorの読み方と署名証明書の更新手順

SAMLメタデータは、IdPとSPが互いのentityID、通信先のURL、署名と暗号化に使う公開鍵を書き出して交換するXML文書です。この記事では、OASISのSAML 2.0 Metadata仕様に沿ってEntityDescriptorから順に要素の意味を読み解き、メタデータから証明書を取り出して期限を監視するコードを示します。SAML連携が止まる典型である署名証明書の更新について、新旧の鍵を重ねて切り替える手順と、メタデータをURLで自動取得するかファイルで交換するかの判断も扱います。

まとめ:SAMLメタデータの中身と証明書更新で外さない要点

メタデータの中身は、エンティティを識別するentityID、役割ごとのDescriptor、その中の通信先エンドポイントと鍵の4つに整理できます。IdPならSingleSignOnService、SPならAssertionConsumerServiceが必須で、鍵はKeyDescriptorに1本ずつ入ります。

運用で事故が起きるのは鍵の更新です。新しい証明書を先にメタデータへ追加し、相手が新旧両方を受け付ける状態を作ってから署名を切り替え、最後に古い鍵を消す。この順番を守れば停止は起きません。

相手がメタデータURLを公開しているなら、24時間以内の間隔で定期取得して取り込む構成を基本にします。ファイルを手で受け渡す運用は、取得経路が無い閉域環境に限ってください。

SAMLメタデータの役割とIdP・SPが交換するXMLの全体像

SAMLの定義と認証フローはSAMLとは?認証フロー・IdP/SPの仕組みとOAuth・OIDCとの使い分けを実装視点で解説で扱っています。ここでは、連携を始める前に交わすメタデータそのものに絞ります。

EntityDescriptorとentityIDの1024文字上限が決める識別の単位

メタデータの仕様は、2005年3月15日にOASIS標準となったSAML V2.0 Metadata仕様です。ルート要素は1つのエンティティを表すEntityDescriptorで、必須属性はentityIDだけ。仕様はentityIDの型をURIとし、最大1024文字に制限しています。

任意属性として、メタデータの有効期限を示すvalidUntilと、受け取り側がキャッシュしてよい最大期間を示すcacheDurationが付きます。複数のエンティティを1ファイルにまとめる場合は、親要素のEntitiesDescriptorで束ねます。学認のようなフェデレーションが配る数百エンティティ分のメタデータはこの形式です。

entityIDは実在するURLである必要はありません。ただし仕様4.1節は、entityIDの場所にメタデータを置いて公開する方式(Well-Known Location)を定めています。この方式を使うならentityIDはURNではなくURLにし、置くXMLのルートはentityIDが一致するEntityDescriptorにする決まりです。

IdP用とSP用で分かれるSSODescriptorの子要素と必須項目

EntityDescriptorの直下には、役割ごとのDescriptorが入ります。Web SSOで使うのは次の2つです。

要素 使う側 必須の子要素 署名に関する属性(省略時false)
IDPSSODescriptor IdP SingleSignOnService 1つ以上 WantAuthnRequestsSigned
SPSSODescriptor SP ACS 1つ以上 認証要求の署名宣言・アサーションの署名要求

表のACSはAssertionConsumerServiceの略称で、SPが認証結果を受け取るエンドポイントを指します。SPの署名欄では、AuthnRequestsSignedを「認証要求の署名宣言」、WantAssertionsSignedを「アサーションの署名要求」と表記しています。宣言と要求では属性の意味が異なるため、設定時はそれぞれの正式な属性名に対応させて確認してください。

どちらのDescriptorもprotocolSupportEnumeration属性が必須で、SAML 2.0のエンティティならurn:oasis:names:tc:SAML:2.0:protocolを含めなければなりません。共通の子要素として、KeyDescriptor、SingleLogoutService、NameIDFormatを0個以上持てます。1つのエンティティがIdPとSPの両方を兼ねる場合は、2つのDescriptorを並べて書きます。

IdPメタデータとSPメタデータを要素ごとに読む手順と確認箇所

受け取ったメタデータは、エンドポイント、鍵、署名の要求、名前と属性の順に読むと、設定画面のどの項目に対応するかが追いやすくなります。

IdPのSSOとSPのACSで確認するBindingとLocationの対応

エンドポイント要素は、Binding属性で受け渡し方式、Location属性でURLを示します。IdPのSingleSignOnServiceはHTTP-RedirectとHTTP-POSTの2本を並べる形が一般的で、SPは自分が送る方式に合うLocationを選んで認証要求を送ります。

SPのAssertionConsumerServiceはindex属性が必須の型(IndexedEndpointType)です。既定のACSの決まり方は仕様2.2.3節に順序付きで定義されています。isDefault="true"の最初の要素、無ければisDefaultをfalseにしていない最初の要素、それも無ければ先頭の要素です。ステージングと本番のACSを1つのメタデータに同居させると、この規則で意図しない方へ返ることがあります。環境ごとにentityIDごと分けてください。

KeyDescriptorのuse属性で分かれる署名用と暗号化用の鍵

KeyDescriptorは公開鍵を運ぶ要素で、中のds:X509Certificateにbase64の証明書が入ります。use属性はsigningかencryptionの2値で、仕様上は任意です。省略した鍵をどう扱うかは実装で解釈が割れやすいため、生成する側はuseを必ず明示してください。

読む側で見るべきは本数です。署名用が2本以上並んでいれば、相手は鍵の切り替え期間に入っています。2026年11月5日にMicrosoft Entra IDの共通フェデレーションメタデータを取得したところ、IDPSSODescriptorにはuse="signing"のKeyDescriptorが5本並んでいました。SP側が先頭の1本しか取り込まない実装だと、IdPが別の鍵で署名した時点で検証に失敗します。

IdPとSPの署名要求属性で確認する認証要求とアサーションの署名

署名の要求は、メタデータの真偽値属性で相手に伝えます。IdP側のWantAuthnRequestsSignedがtrueなら、SPは認証要求(AuthnRequest)に署名しなければなりません。SP側のAuthnRequestsSignedは「自分は要求に署名して送る」という宣言、WantAssertionsSignedは「アサーション自体への署名を求める」という要求です。

3つとも省略時はfalseです。IdPがWantAuthnRequestsSigned=”true”を出しているのにSP側が署名鍵を設定していないと、SSOは最初の要求の段階で拒否されます。アサーションの署名位置と検証順序はSAMLアサーションとは:XML構造の読み方と署名・Audience・有効期限の検証実装で詳しく扱っています。

NameIDFormatと要求属性の定義で確認する利用者情報の約束

NameIDFormatは、そのエンティティが扱える利用者識別子の形式をURIで列挙する要素です。IdPがemailAddressとpersistentを並べていれば、SPはどちらかを選んで要求できます。SPメタデータのAttributeConsumingServiceは、SPが必要とする属性をRequestedAttributeで列挙する要素で、isDefaultをtrueにできるのは1つだけと仕様が定めています。

実務ではAttributeConsumingServiceを読まずに、IdPの管理画面で属性を手入力する製品が大半です。メタデータに書いた要求属性が自動で反映されると期待せず、属性名の対応表を別に作ってIdP管理者と突き合わせてください。NameIDFormatが合わずにログインが落ちる場合の切り分けはSAML NameIDFormatとメタデータの不一致でSSOが失敗する原因の切り分けにまとめています。

メタデータから証明書と期限を取り出すPythonとopensslの手順

証明書の期限切れは、メタデータを開いて目で追うと見落とします。鍵を機械的に取り出し、期限を監視ジョブで判定する形にします。

標準ライブラリだけでKeyDescriptorをPEMに書き出すコード

次のスクリプトは、メタデータファイルからentityID、validUntil、エンドポイント一覧を表示し、KeyDescriptorの証明書を1本ずつPEMファイルへ書き出します。Python標準ライブラリだけで動き、追加のインストールは要りません。

import sys
import textwrap
import xml.etree.ElementTree as ET

NS = {
    "md": "urn:oasis:names:tc:SAML:2.0:metadata",
    "ds": "http://www.w3.org/2000/09/xmldsig#",
}

def main(path):
    root = ET.parse(path).getroot()
    print("entityID     :", root.get("entityID"))
    print("validUntil   :", root.get("validUntil"))
    print("cacheDuration:", root.get("cacheDuration"))
    n = 0
    for role in ("IDPSSODescriptor", "SPSSODescriptor"):
        for desc in root.findall("md:" + role, NS):
            print("[" + role + "]")
            for ep in desc:
                if ep.get("Location"):
                    name = ep.tag.split("}")[1]
                    binding = (ep.get("Binding") or "").rsplit(":", 1)[-1]
                    print("  ", name, binding, ep.get("Location"))
            for kd in desc.findall("md:KeyDescriptor", NS):
                b64 = "".join(kd.find(".//ds:X509Certificate", NS).text.split())
                n += 1
                out = "key%d-%s.pem" % (n, kd.get("use", "both"))
                with open(out, "w") as f:
                    f.write("-----BEGIN CERTIFICATE-----\n")
                    f.write("\n".join(textwrap.wrap(b64, 64)) + "\n")
                    f.write("-----END CERTIFICATE-----\n")
                print("   KeyDescriptor use=%s -> %s" % (kd.get("use", "(省略)"), out))

if __name__ == "__main__":
    main(sys.argv[1])

python md_keys.py idp-metadata.xmlで実行します。前述のEntra IDの共通メタデータに対して実行すると、SingleLogoutService、SingleSignOnServiceのHTTP-RedirectとHTTP-POST、署名用の鍵5本が順に表示され、key1-signing.pemからkey5-signing.pemまでが書き出されます。ルートがEntitiesDescriptorのフェデレーション用メタデータでは、対象のEntityDescriptorを先に絞り込んでから渡してください。

openssl x509の-checkendで期限30日前を検知する監視設定

書き出したPEMの期限は、OpenSSLのopenssl-x509マニュアルにある-checkendで判定します。指定した秒数以内に期限が切れるなら終了コード1、切れないなら0を返すため、cronや監視ジョブの判定にそのまま使えます。

#!/bin/sh
# メタデータを取得し、署名用の鍵が30日(2592000秒)以内に切れるなら通知する
curl -fsS -o idp-metadata.xml "https://idp.example.com/saml/metadata"
python3 md_keys.py idp-metadata.xml
for f in key*-signing.pem key*-both.pem; do
  [ -f "$f" ] || continue
  openssl x509 -in "$f" -noout -subject -enddate
  if ! openssl x509 -in "$f" -noout -checkend 2592000; then
    echo "WARN: $f は30日以内に期限切れ" >&2
  fi
done

注意点は、署名用の鍵が複数あるときに古い1本の期限切れ警告が出続けることです。相手が新しい鍵で署名を始めていれば、その警告は無害。警告が出た時点で、新しい鍵が同じメタデータに並んでいるかを確認する手順を運用手順書に入れておきます。

署名証明書のローテーションでSSOを止めずに進める手順と鍵の重ね方

証明書の更新でSSOが止まる原因は、ほぼ「相手が新しい鍵をまだ知らない状態で署名を切り替えた」の1つに集約されます。

OASISのメタデータ相互運用仕様が定める署名鍵の扱いと期限の解釈

OASISが2019年10月24日に標準化したSAML V2.0 Metadata Interoperability Profile 1.0は、メタデータの鍵の扱いを明文化しています。2.6.1節は、ロール内のKeyDescriptorにある鍵をすべて有効として扱い、X.509のパス検証を含む追加の検査をしてはならないという規定です。2.5.1節は、証明書が期限切れでも許容し、期限内であることは推奨に留めています。

同じ2.5節は、将来使う署名鍵を前もってメタデータに含めてよいこと、切り替え完了後は古い鍵を削除すべきこと、漏えいした鍵は必ず削除することを定めます。鍵は1本ずつ別のKeyDescriptorに入れる決まりです。つまり「新しい鍵を先に並べ、使い終わった鍵を後で消す」が仕様の想定する更新方法で、証明書の期限日はSAMLの検証上の締め切りではありません。締め切りを決めるのは、IdPが署名に使う鍵を切り替える日です。

Entra IDの3年証明書を新旧並行で切り替える際の操作と確認の5工程

IdP側の操作例として、Microsoft Learnのフェデレーション証明書の管理を見ます。Entra IDはSAML連携の設定時に3年間有効な自己署名証明書を作り、期限の60日前、30日前、7日前に通知メールを送ります。通知先は管理者を含めて最大5件です。

  1. SAML署名証明書の画面で新しい証明書を作成し、旧証明書と期間が重なる期限で保存する(この時点では非アクティブ)
  2. SPが求める形式(Base64やフェデレーションメタデータXML)で新しい証明書をダウンロードする
  3. SP側に新しい証明書を追加し、旧証明書と並べて受け付ける状態にする
  4. Entra IDで新しい証明書を「アクティブにする」へ切り替える
  5. アプリにサインインして確認し、旧証明書をSPとEntra IDの両方から削除する

SPが1本の証明書しか登録できない製品だと、手順3と4を同時に行うしかなく、その間はログインが失敗します。この場合に作業時間を確保するのは、利用の少ない時間帯です。Microsoftは同じページで、SaaS事業者に対して少なくとも24時間ごとのメタデータ監視と、プライマリとセカンダリの2本の署名証明書を受け付ける実装を推奨しています。

python3-samlで新旧の署名鍵を並行して受け付ける取得と登録の設定

SPを自前で実装している場合、手順3を可能にするのは複数証明書の登録です。python3-saml(PyPIの最新は2023年10月公開の1.16.0系、2026年11月時点)は、READMEで鍵の切り替え期間に複数の証明書を受けるx509certMultiを案内しています。この設定を使うとx509certは無視されます。

from onelogin.saml2.idp_metadata_parser import OneLogin_Saml2_IdPMetadataParser

# 取得先は管理者が登録したIdPのメタデータURLに限る(利用者の任意入力は受けない)
METADATA_URL = "https://idp.example.com/saml/metadata"

idp_data = OneLogin_Saml2_IdPMetadataParser.parse_remote(METADATA_URL, validate_cert=True)
settings = OneLogin_Saml2_IdPMetadataParser.merge_settings(base_settings, idp_data)

# 鍵が複数あるときに期待する形(署名用は配列で新旧を並べる)
# "idp": {
#   "entityId": "https://idp.example.com/saml",
#   "x509certMulti": {
#     "signing": ["<旧証明書のbase64>", "<新証明書のbase64>"],
#     "encryption": ["<暗号化用証明書のbase64>"]
#   }
# }

取り込み後は、settingsのidpにx509certMultiが入り、署名用に鍵が2本以上並んでいるかを必ず確かめてください。1本しか入っていなければ、切り替えの瞬間に検証が落ちます。

メタデータURL自動取得とファイル交換を使い分ける判断基準と見送る条件

ここまでの手順を踏まえ、メタデータの受け渡し方式を条件付きで決めます。

メタデータのURL自動取得を採用する条件とSSRFを防ぐ取得先の制限

相手がメタデータURLを公開していて、SP側から外部へHTTPSで出られるなら、URL自動取得を採用します。取得間隔は24時間以内、取得失敗時は前回のメタデータを使い続けて通知を出す作りにします。鍵の更新を相手の作業日に合わせる必要がなくなるのが最大の利点です。

見送る条件は2つあります。1つは外部へ出られない閉域環境で、この場合はファイル交換に切り替え、前述の期限監視を必ず併用します。もう1つは、SaaSの利用企業ごとに管理画面からメタデータURLを入力させる設計です。python3-samlのREADMEも、メタデータ解析はURLを一切検証しないため、第三者がURLを入力できる環境ではSSRF対策を別途入れるよう注意しています。取得先はHTTPSに限り、社内アドレスやクラウドのメタデータ用アドレスへの接続を拒否するまでは、この入力欄を公開しないでください。

メタデータ署名とvalidUntilを付けるべき場面と過剰になる場面

メタデータ自体への署名(ds:Signature)とvalidUntilは、学認のような第三者が多数のエンティティを配布するフェデレーションでは付けるべきです。受け取る側は配布元の署名を検証し、期限切れのメタデータを拒否できます。

一方、1社のIdPと自社SPを1対1で結ぶ構成では過剰です。HTTPSで相手のドメインから直接取得していれば改ざん経路は限られ、validUntilを付けると更新漏れでSSOが止まる要因が1つ増えます。この構成では署名もvalidUntilも付けず、cacheDurationで再取得の間隔だけを示せば足ります。

KeycloakのようなOSSでIdPを立てるか、IDaaSに任せるかで、メタデータの生成と鍵更新の手間は大きく変わります。製品の選び方はKeycloakとは?Oktaとの違いと連携手順|Auth0・Cognito比較で導入を判断【2026年10月】で比較しているので、製品選定時の参照先にしてください。既存の業務システムや会員基盤へSAML連携を組み込み、証明書更新まで含めた運用を設計したい場合は、認証基盤・ID管理システム開発として方式選定から実装まで対応しています。

よくある質問

SAMLメタデータの設定と運用で、繰り返し出てくる質問を仕様書の記述に沿って整理しました。

SAMLメタデータには何が書かれていますか?

エンティティを識別するentityID、IdPかSPかを示すDescriptor、その中のSSOやACSなどのエンドポイントURLとBinding、署名と暗号化に使う公開鍵(KeyDescriptor)、扱えるNameIDFormatが主な中身です。任意で有効期限のvalidUntil、組織名や連絡先も書けます。

SAMLメタデータの証明書が期限切れになるとどうなりますか?

Metadata Interoperability Profileに従う実装は、証明書の期限を検証に使わないため、鍵が同じなら期限切れでも動き続けます。止まるのは、IdPが新しい鍵で署名を始めたのにSPが旧い鍵しか持っていない場合です。Entra IDのように期限切れの証明書で署名しなくなるIdPもあるため、期限前の切り替えが前提です。

SAMLメタデータはどこから取得しますか?

IdP製品は管理画面に「フェデレーションメタデータURL」などの名前でURLを表示しています。Entra IDなら共通メタデータとアプリごとのメタデータがあり、SAML連携にはアプリ単位のものを使います。仕様上はentityIDのURLにメタデータを置く方式も定義されていますが、対応していない製品も多い方式です。

SPのメタデータは自分で書く必要がありますか?

手書きは避け、SAMLライブラリや製品の生成機能を使ってください。python3-samlには設定からSPメタデータを生成して検証する機能があります。手書きすると名前空間やindexの付け忘れで、IdP側の取り込みが失敗しやすくなります。

メタデータのentityIDとAudienceが一致しないとどうなりますか?

IdPはSPのentityIDをアサーションのAudienceに入れ、SPは自分のentityIDと完全一致するかを検証するため、末尾のスラッシュ1文字の差でもログインが拒否されます。CognitoのようにentityIDの書式が決まっているサービスもあり、設定例はCognito SAML連携の手順:Entra IDでSSOを組む設定と属性マッピングで示しています。

関連記事

お気に入りに入れた記事の一覧

一創の公式 SNS

X では毎朝の新着記事と IT ニュースの速報を、YouTube・TikTok・Instagram・LinkedIn・Facebook では記事の解説動画を配信しています。

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.11.03 テックブログ クラブツーリズム不正アクセス:約432万件の対象確認と偽メールの見分け方・流出検知の設計
  2. 2026.11.04 テックブログ CVE-2026-119977:WordPress更新中のRCEと安全な更新手順
  3. 2026.10.29 テックブログ ソニー生命の情報漏洩38.5万件|ログインできない理由、再開状況と窓口の電話番号
  4. 2026.11.03 テックブログ ノジマ不正アクセスで約700万件漏えい:対象確認・窓口と乗っ取り注文を止める実装
  5. 2026.11.02 テックブログ アララの不正アクセス:メール約7,700万件の持ち出しと契約企業が行うAPIキー再設定・代替送信・連名報告

RELATED POSTS 関連記事

目次