ユーザー・アクセス管理

「ユーザー・アクセス管理」 ページでは、管理者ロールのユーザーが、すべてのユーザーの REST API キーおよび追加の特権 (パーティション管理など) を管理できます。 このページには、すべてのユーザーが、そのロール、付与されている追加特権、およびアクティブな REST API キーと期限切れの REST API キーの数とともにリストされます。

IBM Storage Insights により、管理者とモニター ユーザーはパーティションの移行と管理を実行できます。 IBM Storage Insights はパーティション管理のアクセスを制御し、追加特権の概念を使用してセキュリティを強化します。 管理者ユーザーは、ユーザーアクセス管理ページで、パーティション管理オプションを使用して、ユーザーの追加権限を設定できます。 このページでは、管理者ユーザーは、ユーザーの追加特権を管理したり、API 鍵を生成、取り消し、およびローテート/更新したりすることができます。 このページには、すべてのユーザーが、追加特権の状況、ロール、アクティブおよび期限切れの API キーの数、およびその他の詳細とともにリストされます。

追加特権の管理

IBM Storage Insights 管理者のみが、Manage additional privileges オプションにアクセスできます。 管理者ユーザーは、自分自身に割り当てることも、他の管理者やモニター・ユーザーに割り当てることもできます。 パーティション管理 機能を使用できるのは、管理者とモニターのユーザーのみです。 ログインした管理者およびモニター ユーザーは、自分のアカウントの Partition Management アクセス ステータスを確認することもできます。

「追加特権の管理 (Manage additional privileges)」 オプションを使用すると、管理者はユーザーの特権を管理したり、ユーザーが 「パーティション管理」 機能を使用することを許可または制限したりすることができます。 ユーザーに対して パーティション管理 特権を許可または制限する手順は、以下のとおりです。
  1. 管理者認証情報を使用して、IBM Storage Insights にログインします。
  2. 「構成」 > 「ユーザー・アクセス管理」に移動します。
  3. 垂直ドットが 3 つあるオーバーフロー・メニューをクリックし、ユーザーのメニューから 「追加特権の管理 (Manage additional privileges)」 オプションを選択します。
  4. 「追加特権の管理」 ページで、 「区画管理」 チェック・ボックスを選択または選択解除します。
    注: ユーザーの役割が管理者からモニターに削減された場合、そのユーザーの 「パーティション管理」 特権は制限されます。 ユーザーの役割がモニターから管理者にアップグレードされた場合、 「パーティション管理」 特権は変更されません。
  5. 「保存」をクリックします。

REST API の管理

このページでは、REST API にアクセスできるため、お客様の運用ダッシュボードと統合するためのストレージ・システム構成およびパフォーマンス・データの消費が容易になります。 IBM Storage Insights REST API は、REST の原則に従うことで、統合運用管理者を含む外部アプリケーションにスムーズな統合経路を提供します。 これらのAPIは予測可能なリソース指向のURLを使用し、フォームエンコードされたリクエストボディを受け入れ、JSONエンコードされたレスポンスを生成し、標準の HTTP レスポンスコード、認証方法、および動詞に準拠しています。 また、着信要求のバーストを管理するための安全機能を組み込んで、システム全体の安定性を向上させます。 IBM Storage Insights 管理者および監視担当者は、REST API を効率的に使用して、指定されたテナント内の関連データを取得することができます。

IBM Storage Insights REST API はさまざまな統合に使用できます。 ユース・ケースには、以下のようなものがあります。
  • ストレージ・システムの正常性、容量、およびパフォーマンスの統計を Integrated Operations Dashboard と統合します。
  • ストレージ・システムから生成されたアラートおよび通知をインシデント管理システムと統合します。
  • セキュリティー・アラートを SOAR ツール (セキュリティー・オーケストレーション、自動化、および対応) と統合して、サイバー・レジリエンシー・ワークフローの自動化を実現します。
IBM Storage Insights REST APIの使い方には、3つの簡単なステップがあります:
  1. API キーを作成します。
  2. API キーを使用してトークンを生成します。
  3. トークンを使用して REST API にアクセスします。
ユーザーの追加特権の管理、新規 API 鍵の生成、および API 鍵の取り消しとローテート/更新について説明します。

REST API キーの生成

「ユーザー・アクセス管理」 ダッシュボードにアクセスすると、既に作成されている REST API キーのリストが表示されます。

REST API は、管理者のみが生成できます。 REST API を生成するためのステップは、以下のとおりです。
  1. 管理者認証情報を使用して、IBM Storage Insights にログインします。
  2. 「構成」 > 「ユーザー・アクセス管理」にナビゲートします。
  3. 「ユーザー・アクセス管理」 ページで、鍵を生成するユーザーの 3 つの垂直ドットがあるオーバーフロー・メニューをクリックし、 「REST API 鍵の作成 (Create REST API Key)」を選択します。
  4. 以下のフィールドに詳細を入力します。
    • タグ(オプション) :オプションのタグを入力してください。 例えば、タグを使ってAPIキーの目的を特定することができる。
    • 時間単位 (Unit of time): API キーをユーザーに提供するまでの時間制限を選択します。 オプションには、「日」、「1 年」、および「2 年」があります。
    • 期間/日: 「時間単位」 フィールドで「日/日」オプションを選択した場合に、ユーザーに API キーを提供するまでの日数を示します。
  5. 「API キーの生成」 ボタンをクリックします。
  6. 「API キー」 フィールドの右隅にある 「コピー」 ボタンから API キーをコピーします。
  7. E メールまたはその他の適切な方法を使用して、API キーをユーザーと共有します。
注: API キーが初めて生成された場合、または既に生成されている API キーのリストがある場合、API キーを生成するプロセスは変わりません。

REST API 鍵の取り消し

「鍵アクセスの取り消し (Revoke key access)」 オプションを使用すると、管理者は、API 鍵へのアクセス権限を既に持っているユーザーから API 鍵のアクセス権限を削除できます。 アクセス権限を取り消すには、以下のステップを実行します。
  1. 管理者認証情報を使用して、IBM Storage Insights にログインします。
  2. 設定 ]→[ ユーザーアクセス管理] に移動します。
  3. 取り消したいアクセス権を持つユーザーをリストから選択します。
  4. リストの上部にある 「キー・アクセスの取り消し (Revoke key access)」 をクリックするか、3 つの垂直ドットがあるオーバーフロー・メニューをクリックして、選択したユーザーの行で 「アクセスの取り消し (Revoke access)」 を選択します。
    注: 一度に複数のユーザーを選択して、アクセス権限を取り消すことができます。
  5. ポップアップ・ウィンドウで 「鍵アクセスの取り消し」 をクリックします。
注: 「REST API キー」 列の下の API キー・カウントをクリックして、ユーザーの API キー・アクセスを取り消すこともできます。 API キー・カウントをクリックすると、 「REST API キー」 ウィンドウが表示され、ユーザーに関連付けられているすべてのキーの詳細が示されます。 API 鍵を取り消すには、鍵を選択して 「取り消し」 をクリックします。

REST API キーのローテーション/更新

「ローテート (Rotate)」 オプションを使用すると、管理者は、鍵が失われた場合に新しい REST API 鍵をユーザーに提供し、鍵の期間が切れた場合には 「更新 (Renew)」 を行うことができます。 鍵アクセスをローテート/更新するには、以下の手順を実行します。
  1. 管理者認証情報を使用して、IBM Storage Insights にログインします。
  2. 設定 ]→[ ユーザーアクセス管理] に移動します。
  3. 「REST API キー」 列で、ユーザーの REST API キー・カウントをクリックします。 「REST API キー」 ウィンドウが表示され、ユーザーのすべての API キーの詳細が示されます。 「REST API 鍵 (REST API Keys)」 ウィンドウには、 「取り消し」「鍵のローテート/更新 (Rotate/Renew Key)」、および 「鍵のコピー (Copy Key)」 の各オプションがあります。
    注: カウント付きの緑色のアイコンはユーザーのアクティブな API キーの数を示し、カウント付きの赤色のアイコンはユーザーの期限切れの API キーを示します。
  4. APIキーを選択し、 Rotate/Renew Keyをクリックします。 以下のフィールドに詳細を入力します。
    1. タグ(オプション) :オプションのタグを入力してください。 例えば、タグを使ってAPIキーの目的を特定することができる。
    2. 時間単位 (Unit of time): API キーをユーザーに提供するまでの時間制限を選択します。 オプションには、「日」、「1 年」、および「2 年」があります。
    3. 期間/日: 「時間単位」 フィールドで「日/日」オプションを選択した場合に、ユーザーに API キーを提供するまでの日数を示します。
    注: ユーザーが複数の API キーを選択した場合、 「キーのローテート/更新 (Rotate/Renew Key)」 オプションと 「キーのコピー (Copy Key)」 オプションは無効になります。
  5. 「作成 +」 ボタンをクリックして、新しい鍵を生成します。 既存の API キーが無効であり、新しいキーが生成されます。
  6. 「コピー」 ボタンをクリックして、新しい鍵をコピーします。

API トークンの生成

IBM Storage Insights GUI で API キーを生成した後、IBM Storage Insights Token API を実行して API トークンを作成する必要があります。 残りの IBM Storage Insights REST API を実行するには、API トークンが必要です。 トークンAPIを実行するには、生成されたAPIキーをx-api-keyヘッダーに設定する必要があります。 トークンAPIの詳細については、 Swagger ドキュメントを参照のこと。

重要 IBM Storage Insights REST APIを実行するには、REST API Swagger ドキュメントを参照してください。 REST APIはプロユーザーとフリーユーザーの両方に対応していますが、フリーユーザーの利用範囲は限られています。

API トークンを生成したら、残りの IBM Storage Insights REST API を実行できます。 他のREST APIを実行する際には、APIトークンをx-api-tokenヘッダーに設定する必要があります。

重要: IBM Storage Insights Token APIは、15分で有効期限が切れるAPIトークンを作成します。 この有効期限は構成できません。

REST API ストリングのビルド

REST API クライアントによっては、REST API ストリングを自分で作成する場合があります。 REST API ストリングは、REST API パスと照会パラメーターで構成されます。 照会パラメーターは、API 呼び出しに追加情報およびフィルターを追加するために使用されます。 「?」を使用して、照会パラメーターをキーと値のペアとして REST API パスに追加できます。 (疑問符) 文字。 '&' を使用して複数のパラメーターを追加できます。 (アンパーサンド) 文字。 REST API ストリング・フォーマットを以下に示します。
https://<REST API PATH>?<parameter1>=<value1>&<parameter2>=<value2>&<parameter3>=<value3>&....
例:
https://insights.ibm.com/restapi/v1/tenants/01eb8cb2-d32d-1e60-88ae-c35e5b3b9751/storage-systems/3b82a330-b90e-11eb-8322-49470b9950db/metrics?types=used_capacity&duration=7d
上記の例では、
  • insights.ibm.com/restapi/v1/tenants/01eb8cb2-d32d-1e60-88ae-c35e5b3b9751/storage-systems/3b82a330-b90e-11eb-8322-49470b9950db/metrics は API パスです。
  • types=used_capacityduration=7d は、2 つの照会パラメーターです。

上記の例では、REST API 呼び出しは、指定されたパラメーター ( type および duration) に基づいて、特定のストレージ・システムのメトリック・データをフィルタリングします。 REST APIの詳細については、 Swaggerドキュメントを参照してください。

Python を使用して IBM Storage Insights REST API にアクセスする

Python アプリケーションでは、IBM Storage Insights REST API サービスと対話できます。 CLI コマンドは、サービスの REST API を通じて IBM Storage Insights 機能を使用します。

前提条件
  • サンプル・アプリケーションには、 Python 3.6+ ランタイム環境が必要です。
  • ZIP ファイルをダウンロードして、Python で IBM Storage Insights REST API を呼び出すプロセスを示すサンプル コードを確認してください。 ZIP ファイルには、Python インストールの前提条件も含まれています。
  • 必要な依存関係をインストールします。
    pip install -r requirements.txt
  • IBM Storage Insights テナントIDを検索します。

    インスタンスのテナントID。 IBM Storage Insights インスタンスのテナントID。 IBM Storage InsightsURL が https://insights.ibm.com/gui/ abcd-efgh-ijkl-mnop-xyz のように見える場合、 URL の最後の部分、 abcd-efgh-ijkl-mnop-xyz があなたのテナントIDです。

  • IBM Storage Insights REST API キーを取得します。
  • Python スクリプトを実行する前に取得した値で構成ファイル config.ini を更新します。
サンプル Python コード:
import argparse
import json
import os
from datetime import datetime
import click

from ibm_si_rest import si_rest

TOKEN_FILE = 'token.json' # store API token till expiry

def parse_arguments():
    parser = argparse.ArgumentParser(description='IBM Storage Insights REST API.')

    subparsers = parser.add_subparsers(dest='command', help='Choose a REST API to invoke')

    # list of storage systems
    parser_list_storage_systems = subparsers.add_parser('list_storage_systems', help='List storage systems')
    parser_list_storage_systems.add_argument('--system-type', help='Type of the storage system, e.g., block, filer, '
                                                                   'object')
    # list of volumes
    parser_list_storage_system_vol = subparsers.add_parser('list_storage_system_vol', help='List volumes of storage '
                                                                                           'systems')
    parser_list_storage_system_vol.add_argument('--system-uuid', help='UUID of the storage system')

    # list of alerts
    parser_list_alerts = subparsers.add_parser('list_alerts', help='List alerts for a tenant')
    parser_list_alerts.add_argument('--duration', help='Alerts requested for particular duration')
    parser_list_alerts.add_argument('--severity', help='Alerts requested for particular severity')

    # list of notifications
    parser_list_notifications = subparsers.add_parser('list_notifications', help='List notifications for a tenant')
    parser_list_notifications.add_argument('--duration', help='Notifications requested for particular duration')
    parser_list_notifications.add_argument('--severity', help='Notifications requested for particular severity')

    return parser, parser.parse_args()

def get_token(rest_api_host, api_key, tenant_id):
    """Fetch API token and save it locally till it expires"""
    try:
        if os.path.exists(TOKEN_FILE):
            with open(TOKEN_FILE, 'r') as token_file:
                stored_token = json.load(token_file)
                token_expiry = datetime.utcfromtimestamp(stored_token['result']['expiration']/1000.0)
                if datetime.utcnow() < token_expiry:
                    click.secho('Token is valid, re-using it', fg='green')
                    return stored_token['result']['token']
                else:
                    # Token expired, get a fresh token
                    click.secho('Token expired, getting a fresh token', fg='red')
                    token_response = si_rest.get_token(rest_api_host, api_key, tenant_id)
                    if token_response:
                        with open(TOKEN_FILE, 'w') as token_file_w:
                            json.dump(token_response, token_file_w)
                        return token_response['result']['token']
                    else:
                        return None
        else:
            # fetch token for the first time
            click.secho('Token not found, fetching token', fg='blue')
            token_response = si_rest.get_token(rest_api_host, api_key, tenant_id)
            if token_response:
                with open(TOKEN_FILE, 'w') as token_file:
                    json.dump(token_response, token_file)
                return token_response['result']['token']
            else:
                return None
    except Exception as ex:
        click.secho("Unexpected error: %s" % str(ex), fg="bright_red")

def process_command():
    parser, args = parse_arguments()

    if args.command == 'list_storage_systems':
        try:
            rest_api_host, api_key, tenant_id = si_rest.setup()
            token = get_token(rest_api_host, api_key, tenant_id)
            if token is None:
                raise Exception('Token creation failed')
            storage_systems = si_rest.list_storage_systems(rest_api_host, token, tenant_id, args.system_type)
            click.secho('Found (%d) storage systems' % len(storage_systems['data']), fg='green')
        except Exception as ex:
            click.secho("Unexpected error: %s" % str(ex), fg="bright_red")

    elif args.command == 'list_storage_system_vol':
        try:
            if args.system_uuid:
                rest_api_host, api_key, tenant_id = si_rest.setup()
                token = get_token(rest_api_host, api_key, tenant_id)
                if token is None:
                    raise Exception('Token creation failed')
                system_vols = si_rest.list_storage_system_volumes(rest_api_host, token, tenant_id, args.system_uuid)
                system_vols_data = []
                if system_vols and system_vols['data'] and len(system_vols['data']) > 0:
                    system_vols_data = system_vols['data']
                while system_vols and system_vols['data']:
                    if 'links' in system_vols:
                        next_link = next((link for link in system_vols['links'] if link['params']['rel'] == "next"), None)
                        if next_link:
                            click.secho('Fetching next set of volumes (%s)' % next_link['uri'], fg="green")
                            system_vols = si_rest.list_storage_system_volumes(rest_api_host, token, tenant_id, args.system_uuid,
                                                                              next_link['uri'])
                            if system_vols is not None and system_vols['data'] is not None and len(system_vols['data']) > 0:
                                system_vols_data.extend(system_vols['data'])
                        else:
                            break
                    else:
                        break

                click.secho('Found (%d) volumes' % len(system_vols_data), fg='green')
            else:
                click.secho('Please provide system uuid', fg='red')
        except Exception as ex:
            click.secho("Unexpected error: %s" % str(ex), fg="bright_red")

    elif args.command == 'list_alerts':
        try:
            rest_api_host, api_key, tenant_id = si_rest.setup()
            token = get_token(rest_api_host, api_key, tenant_id)
            if token is None:
                raise Exception('Token creation failed')
            alerts = si_rest.list_tenant_alerts(rest_api_host, token, tenant_id, args.duration, args.severity)
            alerts_data = []
            if alerts and alerts['data'] and len(alerts['data']) > 0:
                alerts_data = alerts['data']
            while alerts and alerts['data']:
                if 'links' in alerts:
                    next_link = next((link for link in alerts['links'] if link['params']['rel'] == "next"), None)
                    if next_link:
                        click.secho('Fetching next set of alerts (%s)' % next_link['uri'], fg="green")
                        alerts = si_rest.list_tenant_alerts(rest_api_host, token, tenant_id, args.duration, args.severity,
                                                        next_link['uri'])
                        if alerts is not None and alerts['data'] is not None and len(alerts['data']) > 0:
                            alerts_data.extend(alerts['data'])
                    else:
                        break
                else:
                    break

            click.secho('Found (%d) alerts' % len(alerts_data), fg='green')
        except Exception as ex:
            click.secho("Unexpected error: %s" % str(ex), fg="bright_red")

    elif args.command == 'list_notifications':
        try:
            rest_api_host, api_key, tenant_id = si_rest.setup()
            token = get_token(rest_api_host, api_key, tenant_id)
            if token is None:
                raise Exception('Token creation failed')
            notifications = si_rest.list_tenant_notifications(rest_api_host, token, tenant_id, args.duration, args.severity)
            notifications_data = []
            if notifications and notifications['data'] and len(notifications['data']) > 0:
                notifications_data = notifications['data']
            while notifications and notifications['data']:
                if 'links' in notifications:
                    next_link = next((link for link in notifications['links'] if link['params']['rel'] == "next"), None)
                    if next_link:
                        click.secho('Fetching next set of notifications (%s)' % next_link['uri'], fg="green")
                        notifications = si_rest.list_tenant_notifications(rest_api_host, token, tenant_id, args.duration,
                                                                      args.severity,
                                                                      next_link['uri'])
                        if notifications and notifications['data'] and len(notifications['data']) > 0:
                            notifications_data.extend(notifications['data'])
                    else:
                        break
                else:
                    break

            click.secho('Found (%d) notifications' % len(notifications_data), fg='green')
        except Exception as ex:
            click.secho("Unexpected error: %s" % str(ex), fg="bright_red")

    else:
        parser.print_help()

if __name__ == '__main__':
    process_command()