사용자 액세스 관리

‘사용자 액세스 관리’ 페이지에서는 관리자 역할 사용자가 모든 사용자의 REST API 키를 관리할 수 있습니다. 이 페이지에는 모든 사용자와 해당 사용자의 역할, 그리고 유효한 REST API 키와 만료된 REST API 키의 수가 나열되어 있습니다.

이 페이지를 통해 관리자는 API 키를 생성, 취소, 순환 또는 갱신할 수 있습니다. 이 페이지에는 모든 사용자와 해당 사용자의 역할, 활성 및 만료된 API 키 수, 그 외 세부 정보가 나열되어 있습니다.

REST API 관리

이 페이지에서는 고객 운영 대시보드와의 통합을 위해 스토리지 시스템 구성 및 성능 데이터의 이용을 용이하게 하는 REST API에 대한 액세스를 허용합니다. IBM Storage Insights REST API는 REST 원칙을 준수하여 통합 운영 관리자를 비롯한 외부 애플리케이션을 위한 원활한 통합 경로를 제공합니다. HTTP 이 API는 예측 가능한 리소스 지향 URL을 사용하고, 양식 인코딩 요청 본문을 수용하며, JSON 인코딩 응답을 생성하고, 표준 HTTP 응답 코드, 인증 방법, 동사를 준수합니다. 또한 수신 요청의 버스트를 관리하는 안전 장치를 통합하여 전반적인 시스템 안정성을 향상시킵니다. IBM Storage Insights 관리자와 모니터링 담당자는 REST API를 효율적으로 사용하여 지정된 테넌트 내에서 관련 데이터를 검색할 수 있습니다.

IBM Storage Insights REST API는 다양한 통합에 사용할 수 있습니다. 일부 유스 케이스는 다음과 같습니다.
  • 스토리지 시스템 상태, 용량 및 성능 통계를 통합 운영 대시보드와 통합
  • 스토리지 시스템에서 생성된 경보 및 알림을 인시던트 관리 시스템과 통합
  • 사이버 복원력 워크플로우 자동화를 위해 SOAR 도구 (보안 오케스트레이션, 자동화 및 응답) 와 보안 경보 통합
IBM Storage Insights REST API의 사용법은 간단한 세 단계로 이루어져 있습니다:
  1. API키를 작성하십시오.
  2. API키를 사용하여 토큰을 생성하십시오.
  3. 토큰을 사용하여 REST API에 액세스하십시오.
새로운 API 키를 생성하고, API 키를 취소하며, API 키를 순환하거나 갱신하는 방법을 알아보세요:

REST API키 생성

사용자 액세스 관리 대시보드에 액세스하면 이미 작성된 REST API키 목록이 표시됩니다.

REST API는 관리자만 생성할 수 있습니다. REST API를 생성하는 단계는 다음과 같습니다.
  1. 관리자 자격 증명을 사용하여 IBM Storage Insights에 로그인합니다.
  2. 클래식 UI에서 [ 구성 ] > [사용자 액세스 관리] 로 이동합니다.

    현대식 UI에서 ‘설정’ > ‘사용자 액세스 관리 ’로 이동합니다.

  3. 사용자 액세스 관리 페이지에서 키를 생성할 사용자에 대해 세 개의 세로 점이 있는 오버플로우 메뉴를 클릭하고 REST API키 작성을 선택하십시오.
  4. 다음 필드에 세부사항을 입력하십시오.
    • 태그(선택 사항) : 참조를 위해 선택 사항으로 태그를 입력합니다. 예를 들어 태그를 사용하여 API 키의 용도를 식별할 수 있습니다.
    • 시간 단위: 사용자에게 API키를 제공할 때까지의 시간 한계를 선택하십시오. 옵션에는 일, 1년및 2년이 포함됩니다.
    • 지속 기간/일: 시간 단위 필드에서 일 수 옵션을 선택한 경우 사용자에게 API키를 제공할 때까지의 일 수를 표시합니다.
  5. ‘만들기 +’ 버튼을 클릭하세요.
  6. API키 필드의 오른쪽 구석에 있는 복사 단추에서 API키를 복사하십시오.
  7. 이메일 또는 기타 적합한 방법을 통해 사용자와 API키를 공유하십시오.
참고: API키를 생성하는 프로세스는 처음 생성되거나 이미 생성된 API키 목록이 있는 경우에도 동일하게 유지됩니다.

REST API키 취소

키 액세스 권한 취소 옵션을 사용하면 관리자가 이미 액세스 권한이 있는 사용자로부터 API키의 액세스 권한을 제거할 수 있습니다. 액세스를 취소하려면 다음 단계를 완료하십시오.
  1. 관리자 자격 증명을 사용하여 IBM Storage Insights에 로그인합니다.
  2. 클래식 UI에서 [ 구성 ] > [사용자 액세스 관리] 로 이동합니다.

    현대식 UI에서 ‘설정’ > ‘사용자 액세스 관리 ’로 이동합니다.

  3. 액세스 권한을 취소할 사용자를 목록에서 선택하십시오.
  4. 클래식 UI에서는 목록 상단의 ‘키 액세스 취소’를 클릭하거나, 세 개의 수직 점으로 표시된 오버플로 메뉴를 클릭한 후, 선택한 사용자의 행에서 ‘액세스 취소’를 선택하세요.

    현대식 UI에서는 목록 상단에 있는 ‘키 액세스 취소’를 클릭하세요.

    주: 한 번에 여러 사용자를 선택하여 액세스를 취소할 수 있습니다.
  5. 팝업 창에서 키 액세스 취소 를 클릭하십시오.
참고: REST API키 열에서 API키 개수를 클릭하여 사용자에 대한 API키 액세스를 취소할 수도 있습니다. API키 개수를 클릭하면 사용자와 연관된 모든 키의 세부사항과 함께 REST API키 창이 표시됩니다. 키를 선택하고 취소 를 클릭하여 API키를 취소하십시오.

REST API 키 순환/갱신

회전 옵션을 사용하면 관리자가 사용자에게 새 REST API키를 제공할 수 있습니다 (유실되는 경우). 또한 키의 지속 기간이 만료되는 경우 갱신 할 수 있습니다. 키 액세스를 회전/갱신하려면 다음 단계를 완료하십시오.
  1. 관리자 자격 증명을 사용하여 IBM Storage Insights에 로그인합니다.
  2. 클래식 UI에서 [ 구성 ] > [사용자 액세스 관리] 로 이동합니다.

    현대식 UI에서 ‘설정’ > ‘사용자 액세스 관리 ’로 이동합니다.

  3. REST API키 열에서 사용자의 REST API키 수를 클릭하십시오. REST API키 창이 사용자에 대한 모든 API키의 세부사항과 함께 표시됩니다. REST API키 창은 취소, 키 순환/갱신키 복사 옵션을 제공합니다.
    참고: 개수가 있는 초록색 아이콘은 사용자의 활성 API키 수를 지정하고 개수가 있는 빨간색 아이콘은 사용자의 만료된 API키를 지정합니다.
  4. API 키를 선택하고 키 회전/갱신을 클릭합니다. 다음 필드에 세부사항을 입력하십시오.
    1. 태그(선택 사항) : 참조를 위해 선택 사항으로 태그를 입력합니다. 예를 들어 태그를 사용하여 API 키의 용도를 식별할 수 있습니다.
    2. 시간 단위: 사용자에게 API키를 제공할 때까지의 시간 한계를 선택하십시오. 옵션에는 일, 1년및 2년이 포함됩니다.
    3. 지속 기간/일: 시간 단위 필드에서 일 수 옵션을 선택한 경우 사용자에게 API키를 제공할 때까지의 일 수를 표시합니다.
    참고: 사용자가 여러 API키를 선택하는 경우 키 회전/갱신키 복사 옵션을 사용할 수 없습니다.
  5. 작성+ 단추를 클릭하여 새 키를 생성하십시오. 기존 API키가 올바르지 않으며 새 키가 생성됩니다.
  6. 복사 단추를 클릭하여 새 키를 복사하십시오.

API 토큰 생성

IBM Storage Insights GUI에서 API 키를 생성한 후, IBM Storage Insights 토큰 API를 실행하여 API 토큰을 생성해야 합니다. 나머지 IBM Storage Insights REST API를 실행하려면 API 토큰이 필요합니다. 토큰 API를 실행하려면 생성된 API 키를 x-api-key 헤더에 설정해야 합니다. 토큰 API에 대한 자세한 내용은 Swagger 문서를 참조하십시오.

중요: IBM Storage Insights REST API Swagger 문서를 활용하여 REST API를 실행할 수 있습니다. REST API는 프로 및 무료 사용자 모두에게 지원되지만 무료 사용자의 범위는 제한되어 있습니다.

API 토큰을 생성한 후, 나머지 IBM Storage Insights REST API를 실행할 수 있습니다. 다른 REST API를 실행할 때는 x-api-token 헤더에 API 토큰을 설정해야 합니다.

중요: IBM Storage Insights 토큰 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 는 두 개의 조회 매개변수입니다.

이전 예제에서 REST API 호출은 지정된 매개변수 ( typeduration) 를 기반으로 특정 스토리지 시스템에 대한 지표 데이터를 필터링합니다. 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를 찾습니다.

    IBM Storage Insights 인스턴스의 테넌트 ID입니다. 예를 들어, IBM Storage Insights URL 의 URL이 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()