開発用にAmazon Managed Grafana を Keycloak の SAML 認証で構築する

記事タイトルとURLをコピーする

こんにちは。
アプリケーションサービス本部、DevOps担当の兼安です。
Amazon Managed Grafana で可視化基盤を構築する際、認証をどうするかは避けて通れない問題です。
本記事では、開発・検証環境で IAM Identity Center が使えないケースにおいて、オープンソースの IdP である Keycloak を EC2 上に構築し、SAML 2.0 で Amazon Managed Grafana と連携する方法を解説します。

本記事のターゲット

本記事はGrafanaとKeycloakおよびSAMLなどの認証系技術基礎知識がある方を想定しています。
ご了承ください。

本記事の検証環境

ソフトウェア バージョン
Amazon Managed Grafana 10.4
Keycloak 26.2.5
OS(Keycloak EC2) Amazon Linux 2023
Java(Keycloak 実行環境) Amazon Corretto 21

KeycloakはAmazon EC2で起動し、HTTPSは自己署名証明書を使用します。

Amazon Managed Grafanaとその認証

Amazon Managed Grafana は、AWS がフルマネージドで提供する Grafana のホスティングサービスです。
インフラ管理が不要で、スケーリングやパッチ適用を AWS が行ってくれるため、可視化に集中できます。

認証方式としては以下の 2 つをサポートしています。

認証方式 概要 ユースケース
AWS IAM Identity Center(旧 AWS SSO) AWS Organizations 配下のユーザーを一元管理 組織全体での統一認証
SAML 2.0 外部の IdP(Keycloak、Okta、Azure AD 等)と連携 既存 IdP の活用、Organizations 非所属環境

以降、本記事では、Amazon Managed GrafanaをManaged Grafanaと記載します。
AWS IAM Identity CenterをIdentity Centerと記載します。

AWS IAM Identity Centerはアカウントインスタンスでは使用できない

IAM Identity Center には 2 種類の構築方法があります。

インスタンスタイプ 有効化方法 用途 Managed Grafana 対応
Organizations インスタンス AWS Organizations の管理アカウントで有効化 メンバーアカウント全体で SSO を提供 ✅ 対応
アカウントインスタンス 単一アカウントで有効化 AWS アプリケーション(Kiro 等)向け ❌ 非対応

Managed Grafana は Organizations インスタンスの Identity Center のみをサポートしています。
つまり、以下のようなケースでは Identity Center を認証に使えません。

  • 個人の検証用アカウント(Organizations 未所属)
  • メンバーアカウントで Organizations インスタンスの設定権限がない場合

このような制約から、開発・検証環境でManaged Grafana + Identity Centerを構築するのは少々ハードルが高いです。

開発用環境としてAmazon Managed Grafana+Keycloakを考える

ハードルが高いとはいえ、環境がないと開発はできません。
これに対して本記事では、開発用としてManaged Grafana+Keycloakの環境を作ってみます。
Keycloakであれば、SAML対応しているのでManaged Grafanaと連携させることができます。

Keycloak を EC2 上で動かし、SAML 2.0 IdP として Managed Grafana に接続する構成とします。

graph LR
    User[ユーザー<br/>ブラウザ] -->|HTTPS| MG[Amazon Managed Grafana<br/>SAML SP]
    MG -->|SAML 2.0| KC[Keycloak EC2<br/>Elastic IP:8443]

    subgraph AWS Cloud
        subgraph VPC
            subgraph Public Subnet
                KC
            end
        end
        MG
    end

Amazon Managed Grafana+Keycloak環境の構築の流れ

全体の構築は以下のステップで進めます。

  1. Managed Grafana ワークスペースの起動
  2. Keycloak を EC2で起動、自己署名証明書でHTTPS化
  3. Keycloak Realm を設定し、ユーザーを追加
  4. Keycloak からメタデータ XML を取得
  5. メタデータ XML を AWS CLI で Managed Grafana に設定

本記事のポイントは3から5の手順のため、1と2の手順は割愛させていただきます。

Keycloak の起動直後は Realm がまだ存在しないため、SAML メタデータ XML を取得できません。
そのため、Keycloak の Realm 設定完了後に AWS CLI で Managed Grafana の SAML 設定を行う 2 ステップ構成になっています。

KeycloakとAmazon Managed Grafanaを連携する際の注意点

Managed Grafanaと Keycloakを認証連携させるにはKeycloakのSAML メタデータ URLをHTTPSでフェッチできることが必要です。
しかし、開発環境において正式な証明書まで取るのはレアだと思いますので、本構成では Keycloak に自己署名証明書(keytool で生成)を使用します。
自己署名証明書の場合、メタデータ URLの検証時に証明書チェーンの検証に失敗し context deadline exceeded エラーが発生します。
このエラーを回避するため、SAML メタデータを事前にXML形式で取得しておき、それを直接Managed Grafanaに渡すという方法があります。

これはCLIで行うことができます。

# メタデータ XML を取得(-k で自己署名証明書の検証をスキップ)
METADATA_XML=$(curl -sk "https://<KeycloakのIPアドレス>:8443/realms/grafana/protocol/saml/descriptor")

# Managed Grafana の SAML 認証設定を更新
# idpMetadata.xml に直接 XML を渡すことで、Grafana が URL をフェッチしに行く必要がなくなる
aws grafana update-workspace-authentication \
  --workspace-id "<ワークスペースID>" \
  --authentication-providers SAML \
  --saml-configuration '...(メタデータXMLとassertionAttributesを含むJSON)...'

Keycloakの自己署名証明書の補足

今回の構成を作るには、自己署名証明書を作成する際、SAN(Subject Alternative Name)に Elastic IP を含める必要があります。
EC2 起動時のセットアップで IMDSv2 経由で Public IP を取得し、keytool-ext "SAN:c=DNS:localhost,IP:${PUBLIC_IP}" に指定する必要があります。

SAML Assertion Attributes のマッピングについて

Keycloak の SAML Response に含まれる属性を、Managed Grafana がどのフィールドにマッピングするかを aws grafana update-workspace-authentication--saml-configuration で指定します。
以下のように設定することにより、Keycloak 側でユーザーに admin ロールを割り当てるだけで、Grafana に Admin 権限でログインできます。

Grafana 属性 SAML Attribute Name 用途
email email ユーザーのメールアドレス
login login ログインユーザー名
name displayName 表示名
role Role Grafana ロール(Admin/Editor/Viewer)

これらの設定は後述の「CLIでAmazon Managed GrafanaとKeycloakを連携させる」セクションで実際に CLI から投入します。

Amazon Managed Grafanaワークスペースから連携に必要な情報の取得

Keycloak Realm を設定する前に、Managed Grafana ワークスペースから SAML 連携に必要な情報を取得しておきます。

ACS URL と Entity ID はワークスペースのエンドポイントから導出できます。
エンドポイントはAWSマネジメントコンソールで確認できます。

Managed Grafana のエンドポイント

エンドポイントを元に、SAML ACS URL と Entity ID を組み立てます。
コマンドで表すとこうですね。

# SAML ACS URL と Entity ID を組み立て
# エンドポイントは https:// を含む完全な URL(例: https://g-XXXXXXXXXX.grafana-workspace.ap-northeast-1.amazonaws.com)
SAML_ACS_URL="<エンドポイント>/saml/acs"
SAML_ENTITY_ID="<エンドポイント>/saml/metadata"

echo "SAML ACS URL: $SAML_ACS_URL"
echo "SAML Entity ID: $SAML_ENTITY_ID"

出力例:

SAML ACS URL: https://g-XXXXXXXXXX.grafana-workspace.ap-northeast-1.amazonaws.com/saml/acs
SAML Entity ID: https://g-XXXXXXXXXX.grafana-workspace.ap-northeast-1.amazonaws.com/saml/metadata

これらの値を次からの Keycloak 設定作業で使用します。

KeycloakにRealm・Client・ユーザーを作成

SSM Session Manager などで Keycloak の EC2 に接続し、kcadm.sh(Keycloak Admin CLI)で Realm・Client・ユーザーを作成します。
まずはRealmとClientを作ります。

# Keycloak Admin CLI(kcadm.sh)のパスを設定
# kcadm.sh は Keycloak に同梱されている管理用 CLI ツールで、Realm・Client・User の操作を行える
export KCADM=/opt/keycloak-26.2.5/bin/kcadm.sh

# truststore 設定(自己署名証明書対応 — これを先にやらないと PKIX エラーになる)
$KCADM config credentials --server https://localhost:8443 --realm master --user admin --password admin

# grafana Realm 作成
$KCADM create realms -s realm=grafana -s enabled=true

# SAML Client 作成(SAML_ACS_URL と SAML_ENTITY_ID は前の手順で取得した値を使用)
$KCADM create clients -r grafana \
  -s "clientId=$SAML_ENTITY_ID" \
  -s protocol=saml \
  -s enabled=true \
  -s "redirectUris=[\"$SAML_ACS_URL\"]" \
  -s "adminUrl=$SAML_ACS_URL" \
  -s 'attributes={"saml.assertion.signature":"true","saml_name_id_format":"username","saml.server.signature":"true","saml.client.signature":"false","saml.force.post.binding":"true"}'

次に、SAML Client に Protocol Mapper を追加します。
Protocol Mapper は、Keycloak のユーザー属性(email やロール)を SAML Assertion の Attribute としてマッピングするための設定です。
前述の assertionAttributes で Managed Grafana 側が期待する属性名と一致させる必要があります。

作成した SAML Client の UUID を取得し、それを使って Mapper を登録します。
私が試した限りKeycloak 26.x でこの設定を行なう場合は kcadm.shprotocol-mappers/models コマンドではなく、REST API を直接叩く必要があるようです。

# アクセストークンを取得
TOKEN=$(curl -sk -X POST "https://localhost:8443/realms/master/protocol/openid-connect/token" \
  -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" | \
  jq -r '.access_token')

# SAML Client の UUID を取得(clientId = SAML_ENTITY_ID で検索)
CLIENT_UUID=$(curl -sk "https://localhost:8443/admin/realms/grafana/clients?clientId=$SAML_ENTITY_ID" \
  -H "Authorization: Bearer $TOKEN" | jq -r '.[0].id')

# email mapper
curl -sk -X POST "https://localhost:8443/admin/realms/grafana/clients/$CLIENT_UUID/protocol-mappers/models" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"email","protocol":"saml","protocolMapper":"saml-user-attribute-mapper","config":{"user.attribute":"email","friendly.name":"email","attribute.name":"email","attribute.nameformat":"Basic"}}'

# login mapper(username を login 属性としてマッピング)
curl -sk -X POST "https://localhost:8443/admin/realms/grafana/clients/$CLIENT_UUID/protocol-mappers/models" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"login","protocol":"saml","protocolMapper":"saml-user-attribute-mapper","config":{"user.attribute":"username","friendly.name":"login","attribute.name":"login","attribute.nameformat":"Basic"}}'

# displayName mapper(firstName を displayName 属性としてマッピング)
curl -sk -X POST "https://localhost:8443/admin/realms/grafana/clients/$CLIENT_UUID/protocol-mappers/models" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"displayName","protocol":"saml","protocolMapper":"saml-user-attribute-mapper","config":{"user.attribute":"firstName","friendly.name":"displayName","attribute.name":"displayName","attribute.nameformat":"Basic"}}'  

# role mapper(attribute.name は "Role" 大文字 — assertionAttributes.role に合わせる)
curl -sk -X POST "https://localhost:8443/admin/realms/grafana/clients/$CLIENT_UUID/protocol-mappers/models" \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"name":"role","protocol":"saml","protocolMapper":"saml-role-list-mapper","config":{"single":"true","attribute.nameformat":"Basic","attribute.name":"Role"}}'

最後にロールとテストユーザーを作成します。

# Realm ロールを作成
$KCADM create roles -r grafana -s name=admin

# テストユーザー作成
$KCADM create users -r grafana -s username=grafana-admin -s email=admin@example.com \
  -s firstName=Grafana -s lastName=Admin -s emailVerified=true -s enabled=true
$KCADM set-password -r grafana --username grafana-admin --new-password <パスワード> --temporary=false

# Realm ロールをユーザーに割り当て
$KCADM add-roles -r grafana --username grafana-admin --rolename admin

Realm ロールを作成の補足

ここで重要なのは Client ロールではなく Realm ロールとして作成することです。
saml-role-list-mapper はデフォルトで Realm ロールを SAML Assertion にマッピングします。
Client ロールとして作成すると Assertion に含まれず、Grafana 側でロールが認識されません。

CLIでAmazon Managed GrafanaとKeycloakを連携させる

Keycloak の Realm 設定が完了したら、Managed Grafana の SAML 設定を行います。
この設定はManaged Grafana のGUIからでもできますが、今回はCLIで行います。
前述の assertionAttributes のマッピングもここで一括して設定します。
この項のコマンドは、Keycloakの端末で行う必要はなく、AWSのコマンドが実行できればどこでもOKです。
CloudShell などでも良いでしょう。
ただし、Grafanaワークスペースのアップデート系ポリシーが必要なことに注意してください。

まずワークスペースIDを特定します。
ワークスペースIDはGrafanaのワークスペースの画面のURLの末尾です。

https://<リージョン>.console.aws.amazon.com/grafana/home?region=<リージョン>#/workspaces/<ワークスペースID>

次にCLIでSAML メタデータ XML を取得して、Managed Grafana にセットします。

# 1. SAML メタデータ XML を取得(自己署名証明書のため -k で検証スキップ)
METADATA_XML=$(curl -sk "https://<KeycloakのIPアドレス>:8443/realms/grafana/protocol/saml/descriptor")

# 2. jq で JSON を組み立て(XML 内の特殊文字を正しくエスケープする)
SAML_CONFIG=$(jq -n --arg xml "$METADATA_XML" '{
  "idpMetadata": {"xml": $xml},
  "assertionAttributes": {
    "email": "email",
    "login": "login",
    "name": "displayName",
    "role": "Role"
  },
  "roleValues": {
    "admin": ["admin"],
    "editor": ["editor"]
  },
  "loginValidityDuration": 1440
}')

# 3. SAML 認証を設定
aws grafana update-workspace-authentication \
  --workspace-id "<ワークスペースID>" \
  --authentication-providers SAML \
  --saml-configuration "$SAML_CONFIG"

assertionAttributes は Keycloak 側の Protocol Mapper で設定した attribute name と一致させる必要があります。
roleValues.admin["admin"] を指定することで、Keycloak の admin ロールを持つユーザーが Grafana Admin としてログインできます。

設定が完了すると、Managed Grafanaの画面で、SAMLが有効になります。

Managed Grafanaの画面で、SAMLが有効になる

動作確認

一連の設定終了後、ブラウザで Managed Grafana URL にアクセスすると、「Sign in with SAML」があるのでこれをクリックします。
Keycloak のログイン画面にリダイレクトされるので、ログインします。
Grafana ダッシュボードが表示されれば成功です。

Grafanaに「Sign in with SAML」が出る

Keycloakでadminロールを付与したユーザーでログインすると、Grafanaでも管理者メニューが出ます。
これはマッピングで、KeycloakとGrafanaのロールを結びつけているからです。

ロールの結び付けによりGrafanaで管理者メニューが出る


今回はご紹介したかった方法は以上です。
皆様の開発においてお役に立てば幸いです。

参考リンク

兼安 聡(執筆記事の一覧)

アプリケーションサービス本部 DS3課
2026 Japan AWS Ambassadors
2024-2026 Japan AWS Top Engineers
2024-2026 Japan AWS All Certifications Engineers
2025-2026 AWS Community Builders
Certified ScrumMaster
PMP
広島在住です。今日も明日も修行中です。
X(旧Twitter)