Posted at

Python初心者が、ISE ERS API を利用してスクリプトを書いてみた

More than 1 year has passed since last update.


はじめに

Cisco製品には様々な製品でAPIが用意されていますが、今回はISEのERS(External RESTful Services) APIを利用してPython(ver3.6.3)スクリプトを作成してみました。


ISE ERS(External RESTful Services) API について

ガイドはこちら


事前準備

ISE ERS(External RESTful Services) APIを利用するためには、まず初めにISEの管理画面から、Administration->System->SettingsのERS Settingsで、ERSを有効にする必要があります。

さらに、Administration->Sytem->Admin AccessのAdmin Uers設定で、ESR APIへアクセスするための管理者IDとパスワードを作成します。



Admin Groupsは、ERS Adminを選択します。

APIについては、上記のCCOガイドに詳細な記載がないので、ERSを有効にした後、https://(ise ip address):9060/ers/sdkに作成した管理者IDとパスワードでアクセスするとAPIの詳細やスクリプト例を確認することができます。


想定するユースケース

ユーザ様から、ISEが高機能なことは理解しているのだけど、管理者用のUIが(英語だし)複雑で使いにくい、もっとシンプルにUIをカスタマイズしたい、あるいは既存のシステムと連携させたい、という声をよくお聞きします。そういった場合に活用できるのがAPIです。

今回は、大学様や病院様での使用が多い有線のMacアドレス認証でのISEの利用を想定し、ISEの管理者UIにアクセスすることなくAPI経由で、ISEが管理している端末情報を取得するスクリプトを作成します。取得結果は、txtファイルに保存すると同時に、SparkのbotからSparkのRoomに結果をPostすることとします。


利用するAPI

Endpoint API (GET-All)

Request:

Method: GET

URI: https://(ise ip address):9060/ers/config/endpoint
HTTP 'Content-Type' Header:application/json

Response:

JSON

{
"SearchResult" : {
"total" : 2,
"resources" : [ {
"id" : "id1",
"name" : "name1",
"description" : "description1"
}, {
"id" : "id2",
"name" : "name2",
"description" : "description2"
} ],
"nextPage" : {
"rel" : "next",
"href" : "link-to-next-page",
"type" : "application/xml"
},
"previousPage" : {
"rel" : "previous",
"href" : "link-to-previous-page",
"type" : "application/xml"
}
}
}

EndPoints Identity Group (GET-By-Id)

Request:

Method: GET

URI: https://(ise ip address):9060/ers/config/endpointgroup/{id}
HTTP 'Content-Type' Header:application/json

Response:

JSON

{
"EndPointGroup" : {
"id" : "id",
"name" : "name",
"description" : "description",
"systemDefined" : true
}
}


スクリプト解説


STEP0: Basic認証ヘッダを作成する

import base64

user='ersadmin'  ## ISEのERS Adminのユーザ名
password='Password123' ## ISEのERS Adminのパスワード

creds = str.encode(':'.join((user, password)))
auth_header = bytes.decode(base64.b64encode(creds))


STEP1: Pythonのrequestモジュールを使用して端末情報を取得する

 import requests

import json

iseip='X.X.X.X' ## ISEのIPアドレス
url = "https://"+iseip+":9060/ers/config/"
url_endpoint = url+"endpoint"
headers = {
'accept': "application/json",
'authorization': 'Basic ' + header, ## STEP0で生成したbasic認証ヘッダー
'cache-control': "no-cache",
}

##全ての端末情報をjson形式で取得
response = requests.get( url_endpoint, verify=False,headers=headers).json()

##ディクショナリのキーを指定し、必要な情報を取り出す
o_json = json.dumps(response["SearchResult"]["resources"])


注意点

response = requests.get( uri,verify=False,headers)

SSL証明書が正しくない場合にはデフォルトでSSL認証エラーを出すため、正しい証明書を入れるか、verify=Falseでverifyを無効にしない場合、[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failedのエラーが返されます。verify=Falseを書いた場合も、下記のWarningが出ます。

/usr/lib/python3.6/site-packages/urllib3/connectionpool.py:858: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

InsecureRequestWarning)

Warningは、下記で無効にし出力させないようにすることができます。

import urllib3

from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)


STEP2: 結果をファイルに保存

import datetime

now = datetime.datetime.now()
file_name = "{0:%Y%m%d.%H%M}".format(now) ##ファイル名に作成した時間を記録
f = open(file_name + "_endpoints_list.txt","w")
for x in message: ##STEP1でリスト化した要素を改行を入れながらファイルに記述
x2 = x.replace('\\n','\n')
f.write(str(x2))
f.close()


STEP3: SparkのbotからRoomにAPI経由で取得結果をpost

SPARK APIについては、developerサイトで詳細な情報を得られます。今回はMessages APIを利用して取得した情報をpostします。


スクリプト全体


get-all-internal-endpoint.py

import requests

import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)
import base64
import json
import sys
import datetime

iseip='X.X.X.X' ## ISEのIPアドレス

ACCESS_TOKEN="***********" ## SPARK botのアクセストークン
ROOM_ID="*********" ## SPARKのROOM ID

def get_authheader():
user='ersadmin'  ## ISEのERS Adminのユーザ名
password='Password123' ## ISEのERS Adminのパスワード

creds = str.encode(':'.join((user, password)))
auth_header = bytes.decode(base64.b64encode(creds))
return auth_header

APIAuth = get_authheader()

def get_endpoint_info(header):
url = "https://"+iseip+":9060/ers/config/"
url_endpoint = url+"endpoint"
url_endpointgroup = url+"endpointgroup"

##ヘッダー情報
headers = {
'accept': "application/json",
'authorization': 'Basic ' + header,
'cache-control': "no-cache",
}

##全ての端末情報を取得
response = requests.get( url_endpoint, verify=False,headers=headers).json()
o_json = json.dumps(response["SearchResult"]["resources"])

msg=[]
## 取得した端末情報から、macアドレス情報と端末が所属するグループIDを取得
for item in response["SearchResult"]["resources"]:
href = item["link"]["href"]
response_href = requests.get(href, verify=False,headers=headers).json()
r = json.dumps(response_href["ERSEndPoint"]["groupId"])
gid = r.split('"')
   ## 所属するグループIDからグループ名を取得
gname_url = url_endpointgroup+"/"+gid[1]
gname_r = requests.get( gname_url, verify=False,headers=headers).json()
gname = json.dumps(gname_r["EndPointGroup"]["name"])
gname2 = gname.replace('"','')
   
   ##端末のmacアドレス情報と端末が所属するグループ名をリスト化
msg.append('mac address:'+ item["name"]+', identity group name:'+gname2+'\\n')
return msg

## Sparkへ結果をpost
def postMsg(roomId, markdown): 
accessToken_hdr= 'Bearer '+ACCESS_TOKEN
spark_header={'Authorization':accessToken_hdr,'Content-Type': 'application/json;charset=utf-8'} ##ヘッダーの作成
the_data = '{"roomId":"' + roomId + '","markdown":"' + markdown +'"}' ## 使用するbotのroom IDと、postする情報を指定
uri = 'https://api.ciscospark.com/v1/messages' ## Messgae API URI

resp=requests.post(uri,data=the_data,headers=spark_header)
print (resp)

if __name__ == '__main__':
APIAuth = get_authheader()
message=get_endpoint_info(APIAuth)
num=len(message)

## Sparkへリストのままpostできないため、要素を連結
m=''
for x in message:
m += x+'\\n'

## 取得結果をテキストファイルに保存
now = datetime.datetime.now()
file_name = "{0:%Y%m%d.%H%M}".format(now)
f = open(file_name + "_endpoints_list.txt","w")
for x in message:
x2 = x.replace('\\n','\n')
f.write(str(x2))
f.close()

data ='Total number of endpoints managed by ISE is :'+' '+ str(num)+'\\n\\n'+ m

postMsg(ROOM_ID,data)



実行結果

[root@localhost naogawa]# python3 ./get-all-internal-endpoint.py 

<Response [200]>
[root@localhost naogawa]# ls
20171204.0652_endpoints_list.txt get-all-internal-endpoint.py
[root@localhost naogawa]# cat 20171204.0652_endpoints_list.txt
mac address:00:00:5E:00:01:01, identity group name:Profiled
mac address:00:0C:29:73:CB:DA, identity group name:Profiled
mac address:00:0C:29:8F:93:85, identity group name:Profiled
mac address:00:0C:29:94:E1:39, identity group name:Profiled
mac address:00:0C:29:BB:CE:BD, identity group name:Profiled
mac address:00:0C:29:C9:B1:CA, identity group name:Profiled
mac address:00:0C:29:D0:AC:AC, identity group name:Profiled
mac address:00:0C:29:F3:30:B6, identity group name:Profiled
mac address:00:24:97:CE:DF:A0, identity group name:Profiled
mac address:00:38:DF:20:49:48, identity group name:Profiled
mac address:00:38:DF:3E:3C:F0, identity group name:Profiled
mac address:00:A3:D1:88:B9:00, identity group name:Profiled
mac address:00:B0:64:FC:D6:65, identity group name:Profiled
mac address:00:B0:64:FC:D6:99, identity group name:Profiled
mac address:00:B0:64:FD:05:84, identity group name:Profiled
mac address:1C:DF:0F:1D:7F:D6, identity group name:Profiled
mac address:2C:86:D2:8B:B7:C0, identity group name:Profiled
mac address:2C:86:D2:FE:C8:C0, identity group name:Profiled
mac address:50:7A:55:DD:C1:EF, identity group name:Profiled
mac address:58:8D:09:08:98:68, identity group name:Profiled
[root@localhost naogawa]#


最後に

APIを活用すれば、ユーザ様の様々な要件に柔軟に対応することができます。ぜひ、APIの活用をご検討ください。