すべてのプロダクト
Search
ドキュメントセンター

Application Real-Time Monitoring Service:Grafana ダッシュボードをセルフマネージド Web アプリケーションに埋め込む

最終更新日:Mar 12, 2026

Application Real-Time Monitoring Service (ARMS) の Grafana ダッシュボードを Web アプリケーションに埋め込み、ユーザーが Grafana コンソールに切り替えたり別途ログインしたりすることなく、モニタリングデータを直接表示できるようにします。

重要

Grafana Shared Edition のページのみが埋め込みをサポートします。Dedicated Edition および Expert Edition のページはこの機能をサポートしていません。

仕組み

ご利用の Web アプリケーションは、セキュリティトークンサービス (STS) を通じて一時的な認証情報を取得し、Alibaba Cloud のフェデレーションエンドポイントでログイントークンと交換したうえで、ログイン不要の URL を構築して Grafana ダッシュボードをロードします。

Workflow diagram

この認証フローには以下の 4 つのコンポーネントが関与します。

コンポーネント役割
RAM ユーザーSTS を呼び出す権限を持つサービスアカウント
RAM ロールARMS コンソールへのアクセス権を付与します。RAM ユーザーはこのロールを偽装して、一時的な認証情報を取得します。
STS 一時認証情報AssumeRole 操作によって返される短期有効な AccessKey ペアおよびセキュリティトークン
ログイントークンSTS 認証情報から交換されたフェデレーショントークン。ログイン不要の URL の構築に使用されます。

前提条件

作業を開始する前に、以下の要件を満たしていることを確認してください。

  • Alibaba Cloud アカウントまたは管理者権限を持つ RAM ユーザー

  • 少なくとも 1 つのダッシュボードを含む ARMS Grafana ワークスペース

  • API 呼び出しが可能なバックエンドサーバーを備えたセルフマネージド Web アプリケーション

手順 1:RAM ユーザーを作成し、STS 権限を付与する

Web サーバーが STS を呼び出すために使用する専用の RAM ユーザーを作成します。

  1. RAM コンソールにログインします。

  2. 左側のナビゲーションペインで、Identities > Users を選択します。

  3. Users ページで、Create User をクリックします。

    Create User button

  4. User Account Information セクションで、Logon Name および Display Name を設定します。Access Mode セクションで、Console Access を選択し、OK をクリックします。

    重要

    RAM は新しいユーザーに対して自動的に AccessKey ペアを生成します。RAM コンソールでは AccessKey Secret は一度しか表示されません。ダイアログを閉じる前に、必ずコピーして安全な場所に保存してください。

  5. Users ページで、作成した RAM ユーザーを見つけ、Actions 列の Add Permissions をクリックします。

    説明

    複数の RAM ユーザーに一度に権限を付与する場合は、ユーザーを選択してページ下部の Add Permissions をクリックします。

    Add Permissions

  6. Grant Permission パネルの Policy セクションで、AliyunSTSAssumeRoleAccess を検索して追加し、Grant permissions をクリックします。

  7. Close をクリックします。

手順 2:RAM ロールを作成し、ARMS 権限を付与する

ARMS コンソールへのアクセスを提供する RAM ロールを作成します。ステップ 1 の RAM ユーザーは、このロールを偽装して一時的な認証情報を取得します。

  1. 信頼された Alibaba Cloud アカウント向けの RAM ロールを作成します

  2. RAM ロールに権限を付与します。以下のいずれかのポリシーをアタッチします。

    ポリシーアクセスレベル
    AliyunARMSFullAccessARMS に対する完全な読み取り/書き込みアクセス
    AliyunARMSReadOnlyAccessARMS に対する読み取り専用アクセス

手順 3:STS から一時認証情報を取得する

Web サーバー上で AssumeRole 操作を呼び出し、一時的な AccessKey ペアおよび STS トークンを取得します。

AssumeRole は以下のいずれかの方法で呼び出すことができます。

  • OpenAPI Explorer — ブラウザでインタラクティブに呼び出しをテストできます。

  • RAM SDK for Java — バックエンドコードに呼び出しを統合します。

以下の例では RAM SDK for Java を使用しています。プレースホルダーを実際の値に置き換えてください。

String accessKey = "<your-access-key-id>";       // RAM ユーザーの AccessKey ID
String accessSecret = "<your-access-key-secret>"; // RAM ユーザーの AccessKey Secret
String roleArn = "<your-role-arn>";               // RAM ロールの ARN
プレースホルダー説明参照先
<your-access-key-id>RAM ユーザーの AccessKey ID手順 1 で保存済み。「AccessKey ペアの作成
<your-access-key-secret>RAM ユーザーの AccessKey Secret手順 1 で保存済み
<your-role-arn>RAM ロールの Alibaba Cloud リソースネーム (ARN)以下に示す RAM コンソール内

RAM ロールの ARN を確認する

  1. RAM コンソールの左側ナビゲーションペインで、Identities > Roles を選択します。

  2. 対象の RAM ロール名をクリックします。

  3. Basic Information セクションで、ARN の値をコピーします。

    Example ARN

手順 4:ログイントークンを取得する

Alibaba Cloud のフェデレーションエンドポイントで GetSigninToken 操作を呼び出し、STS 一時認証情報をログイントークンと交換します。

重要

STS トークンには特殊文字が含まれる場合があります。リクエスト送信前に、トークンの値を URL エンコードしてください。

フェデレーションエンドポイントに GET リクエストを送信します。

https://signin.alibabacloud.com/federation?Action=GetSigninToken
    &AccessKeyId=<temporary-access-key-id>
    &AccessKeySecret=<temporary-access-key-secret>
    &SecurityToken=<url-encoded-sts-token>
パラメーター
AccessKeyIdAssumeRole によって返された一時的な AccessKey ID
AccessKeySecretAssumeRole によって返された一時的な AccessKey Secret
SecurityTokenAssumeRole によって返された URL エンコード済みの STS トークン
説明

ご利用の Web アプリケーションが仮想ネットワークオペレーターによってデプロイされている場合は、リクエストに &TicketType=mini を追加してください。

手順 5:ログイン不要の URL を構築する

ログイントークンと Grafana ダッシュボードの URL を組み合わせて、別途ログインせずにダッシュボードをロードできるログイン不要の URL を生成します。

説明

ログイントークンの有効期限は 3 時間です。中断なくアクセスを提供するため、ページリクエストごとに新しいトークンを生成してください。

ダッシュボード URL の取得

  1. ARMS Grafana コンソールで対象のダッシュボードを開きます。

  2. ブラウザのアドレスバーから URL をコピーします。

kiosk モードによる Grafana UI の制御

ダッシュボード URL に kiosk パラメーターを追加して、ナビゲーション要素を非表示にできます。

パラメーター効果
kiosk=tv左側のナビゲーションウィンドウを非表示にします。
kiosk上部のナビゲーションバーと左側のナビゲーションウィンドウの両方を非表示にします。
kiosk=tv2ナビゲーション要素を非表示にしますが、右上隅のタイムセレクターは表示したままにします。

ログイン不要の URL の構築

ログイントークンとダッシュボード URL を使用して、ログイン不要の URL を構築します。

http://signin.alibabacloud.com/federation?Action=Login
    &LoginUrl=<your-fallback-url>
    &Destination=<grafana-dashboard-url>
    &SigninToken=<logon-token>
パラメーター説明
LoginUrlログイン失敗時にユーザーがリダイレクトされるフォールバック URL(HTTP 302)
Destinationkiosk パラメーターを含む Grafana ダッシュボードの URL
SigninToken手順 4 で取得したログイントークン

結果の確認

ブラウザでログイン不要の URL を開きます。認証情報の入力を求められることなく Grafana ダッシュボードがロードされます。kiosk パラメーターを指定した場合は、期待通りのナビゲーション要素が非表示になっていることを確認してください。

iframe URL の完全なサンプルコードを表示する

/*
Copyright 2022 Alibaba Cloud.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.aliyun.arms.unifydemo.unifydemo;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.net.URLEncoder;

/**
 * @author XX
 * @version V1.0.0
 * @dept XX-XX
 * @date 2025/7/2 16:10
 * @description
 */
public class GrafanaIframeUrlGenerator {
    private static final String signInHost = "https://signin.aliyun.com";
    private static final String loginUrl = "https://www.aliyun.com";

    private static final String loginUri = "/federation?Action=Login&LoginUrl=%s&Destination=%s&SigninToken=%s";

    private static final String signInTokenUri = "/federation?Action=GetSigninToken&AccessKeyId=%s&AccessKeySecret=%s&SecurityToken=%s&TicketType=%s";

    public static void main(String[] args) {
        try {
            // アカウントおよびロールに基づいてパラメーターを設定します。仮想ネットワークオペレーターの場合、Grafana URL に 4service を追加します。
            String destination = "https://gnew4servims.console.alibabacloud.com/d/1098370038******-53945-422/ack-pro-apiserver?orgId=9&refresh=60s";
            String regionId = "cn-hangzhou"; // 必要に応じてこのパラメーターを設定します。
            String accessKey = "";  // アカウントおよびロールに基づいてこのパラメーターを設定します。アカウントには STS 用の AliyunSTSAssumeRoleAccess 権限が必要です。
            String secretKey = ""; // アカウントおよびロールに基づいてこのパラメーターを設定します。
            // 注意: アカウントおよびロールに基づいてこのパラメーターを設定します。ロールには AliyunARMSReadOnlyAccess 読み取り専用権限が必要です。権限が不十分な場合、アクセスは失敗します。
            String role="acs:ram::109837003******:role/armsreadonlyforgrafanaiframe";

            /*
             * 手順 1
             * */
            // パラメーターを設定し、ロール ARN を指定して、STS トークンの権限をさらに制限するポリシーを設定します。 // acs:ram::$accountID:role/$roleName
            // AssumeRole リクエストを構築します。
            AssumeRoleResponse.Credentials key = getCredentials(regionId, accessKey, secretKey, role, "role-" + System.currentTimeMillis());

            /*
             * 手順 2
             * ログイントークンを取得します。
             * */
            String token = getLoginToken(key, destination);

            /*
             * 手順 3
             * ログイン不要の URL を取得します。
             * */
            String url = getUrl(token, destination);

            /*
             * 手順 4
             * リダイレクト URL。
             * */
            System.out.println(url);
        } catch (Error e) {
            e.printStackTrace();
        }
    }


    private static AssumeRoleResponse.Credentials getCredentials(String regionId, String accessKey, String secretKey, String roleArn, String roleSessionName) {

        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKey, secretKey);


        IAcsClient client = new DefaultAcsClient(profile);

        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setSysMethod(MethodType.POST);
        request.setRoleArn(roleArn);
        request.setRoleSessionName(roleSessionName);
        request.setDurationSeconds(3600L);
        try {
            AssumeRoleResponse response = client.getAcsResponse(request);
            return response.getCredentials();
        } catch (Exception e) {
            throw new RuntimeException("AssumeRoleService load ErrCode:" + e.getMessage());
        }
    }


    public static String getLoginToken(AssumeRoleResponse.Credentials key, String destination) {
        String token = "";
        if (key == null) {
            return "";
        }
        String ticketType = "normal";
        if (destination == null || destination.trim().length() == 0 || destination.contains("4service")) {
            ticketType = "mini";
        }
        String signInTokenUrl = "";
        try {
            signInTokenUrl = signInHost + String.format(signInTokenUri,
                    URLEncoder.encode(key.getAccessKeyId(), "utf-8"),
                    URLEncoder.encode(key.getAccessKeySecret(), "utf-8"),
                    URLEncoder.encode(key.getSecurityToken(), "utf-8"),
                    URLEncoder.encode(ticketType, "utf-8"));
        } catch (Exception e) {
            throw new RuntimeException("SigninTokenService build signInTokenUrl error:" + e.getMessage());
        }
        final CloseableHttpClient httpClient = HttpClients.createDefault();
        try {
            HttpGet signInGet = new HttpGet(signInTokenUrl);
            HttpResponse httpResponse = httpClient.execute(signInGet);
            String signInToken = "";
            if (httpResponse.getStatusLine().getStatusCode() != 200) {
                throw new RuntimeException("SigninTokenService failed to retrieve signInToken!");
            }
            String signInRes = EntityUtils.toString(httpResponse.getEntity());
            signInToken = JSON.parseObject(signInRes).getString("SigninToken");
            if (signInToken == null) {
                throw new RuntimeException("SigninTokenService signInToken is empty while signInRes is:" + signInRes);
            }
            return signInToken;
        } catch (Exception e) {
            throw new RuntimeException("SigninTokenService get signInToken error:" + e.getMessage());
        }
    }

    public static String getUrl(String token, String destination) {
        String url = "";
        try {
            url = signInHost + String.format(loginUri,
                    URLEncoder.encode(loginUrl, "utf-8"),
                    URLEncoder.encode(destination, "utf-8"),
                    URLEncoder.encode(token, "utf-8"));
        } catch (Exception e) {
            throw new RuntimeException("SigninUrlService build getUrl error:" + e.getMessage());
        }
        return url;
    }
}