はじめに
この記事はシスコの同志による Advent Calendar の一部として投稿しています。
他の記事は、Cisco Systems Japan Advent Calendar 2017からご覧いただけます。
12月中日の今日は、VIRL/Cisco Modeling Lab(CML)を使って、ISEのない環境でのTrustSecの使い方について模索してみました。
また、ラボ環境ではIOX XE 16.6.1のCSR1000vで、簡単なpythonスクリプトとEEM(Embedded Event Manager)を設定し、"なんちゃってNaaS/NaaE(Network as a Sensor/Enforcer)"も作ってみました。
CMLとは
CMLは、UCSサーバなどのサーバ上で構築されるサンドボックス環境で、エンジニアが共有のサーバリソースを使い、簡単にネットワークトポロジの設計、設定、検証を行うことのできるシミュレーション製品です。Cisco VIRLとの違いは、商用目的のため、マルチユーザ・大規模での利用を想定しており、TACサポートも付属している点などが挙げられます。詳しくはリンクをご参照ください。
TrustSecとは
TrustSecは、VLANやACLに代わる次世代分類・アクセス制御技術です。16ビット長のSGT(Scalable/Security/Source Group Tag)を使ったグルーピングをベースに、適用したポイントでアクセス制御を行うことができます。SGTがScalableと呼ばれる所以は、SGTはACLだけでなく、QoS、PBR、Zone-based FW、ACI/ISEと連携させることでSGT-EPG変換が可能など用途が多岐にわたるからです。
SGT(ポリシータグ)の伝搬
SGTはポリシー制御を行うために使われるため、ISEを使って自動的に制御を行うにしても、ISEを使わずにスタティックに制御するにしてもTrustSecを使う際の肝となります。そのため、どうやって伝搬するかを考えることはとても大事になります。転送方法は、転送フレームまたはパケットにSGTを埋め込み配信を行う方法(Inline Tagging)と、転送とSGT配信を分離し、SGT配信は別途行う方法=SXP(SGT eXchange Protocol), pxGrid(platform eXchange Grid)=があります。今回は後者については省略し、別の機会に書きたいと思います。
- Inline Tagging
TrustSecはISEと連携した認証ベースの分類・制御が一般的ですが、自動化に特化したDNA CenterやISEといった製品を導入できない環境でもTrustSecを使って管理負担を削減できるということをこの記事を通して、少しでも説明できたらと思っています。
本題:デモ
##シナリオ
#####1. LISPを使ったSGTの伝搬
#####2. SGT-based PBR
#####3. pythonとEEMを使った"なんちゃってNaaS/NaaE"
検証環境とトポロジー
###検証に使用した機器およびソフトウェアバージョン
- CSR1000v, IOS XE Software Version 16.6.1 x6台
- IOSv Software Version 15.6.(2)T x12台
- L2 IOSc Software Version 15.2 x3台
###ホスト情報
|ホスト名|IPアドレス|マスク|I/F|VLAN/SGT|DGW|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| SalesA|172.25.10.1|/25|G0/1|10|172.25.10.126(G4.10)|
| SE1|172.25.20.1|/25|G0/1|20|172.25.20.126(G4.20)|
| IT|172.25.30.1|/24|G0/1|30|172.25.30.1(G4.30)|
| Marketing|172.25.40.1|/24|G0/1|40|172.25.40.1(G4.40)|
| SalesA2|172.25.10.129|/25|G0/1|10|172.25.10.254(G4.10)|
| SE2|172.25.20.129|/25|G0/1|20|172.25.10.254(G4.20)|
| TAC|172.25.50.1|/24|G0/1|50|172.25.50.254(G4.50)|
| Lab|172.25.60.1|/24|G0/1|60|172.25.60.254(G4.60)|
| SaleB|172.25.70.1|/24|G0/1|70|172.25.70.254(G4.70)|
| Finance|172.25.80.1|/24|G0/1|80|172.25.80.254(G4.80)|
| Service|172.25.90.1|/24|G0/1|90|172.25.90.254(G4.90)|
#解説:1. LISPを使ったSGTの伝搬
はじめにLISPを使った場合、パケットのどの部分にSGTが挿入されているかを見ていきます。まず、軽くおさらいですが、LISP(Locator/ID Separation Protocol)は、Locator情報とエンドポイントID情報を分けて扱い、それらをマッピングした情報をサーバに保管し、必要に応じて問い合わせすることで、ルータのルーティングテーブルの削減やモビリティを向上してくれるオープンスタンダードのプロトコルです。Ciscoのキャンパスファブリックデザインでは、LISPがVXLAN、TrustSecとともに採用されているため、LISPへの理解はとても重要です。では、早速LISPの設定を行います。キーポイントは、config-lisp-srv-ipv4コンフィグモードでsgtを有効化することです。?コマンドの結果を見ると以下のように説明されています。
sgt Enable security group tag propagation in LISP
encapsulated traffic
以下、xTR1の設定例です。このような設定を検証環境では、xTR2, 3にも行いました。
router lisp
locator-set HQ
172.25.101.1 priority 1 weight 1
172.25.102.1 priority 1 weight 1
instance-id 0
service ipv4
eid-table default
database-mapping 172.25.10.0/24 locator-set HQ
database-mapping 172.25.20.0/24 locator-set HQ
database-mapping 172.25.30.0/24 locator-set HQ
database-mapping 172.25.40.0/24 locator-set HQ
database-mapping 172.25.50.0/24 locator-set HQ
database-mapping 172.25.60.0/24 locator-set HQ
itr map-resolver 172.25.104.1
itr
etr map-server 172.25.104.1 key CiscoHQ hash-function sha2
etr
sgt
exit-service-ipv4
!
exit-instance-id
!
loc-reach-algorithm rloc-probing
exit-router-lisp
以下は、MSMR(Map Server/Map Resolver)の設定例です。
router lisp
service ipv4
map-server
map-resolver
exit-service-ipv4
site HQ
authentication-key CiscoHQ
eid-record 172.25.10.0/24
eid-record 172.25.20.0/24
eid-record 172.25.30.0/24
eid-record 172.25.40.0/24
eid-record 172.25.50.0/24
eid-record 172.25.60.0/24
exit-site
!
site Branch
authentication-key CiscoBranch
eid-record 172.25.70.0/24
eid-record 172.25.80.0/24
eid-record 172.25.90.0/24
exit-site
!
exit-router-lisp
今回はLISPの説明が主目的ではないので、この時点で上記の設定などを経て、LISP Site-to-Site通信が可能になったとします。次に、xTR1, 2のEgress InterfaceからWiresharkでキャプチャリングしたLISPデータパケットを見ていきます。
このように、config-lisp-srv-ipv4コンフィグモードでsgtを有効化することで、サイト間でSGTを伝搬できることがわかりました。
#解説:2. SGT-based PBR(Policy-based Routing)
まず、軽くおさらいすると、PBRはルーティングテーブルの情報ではなく、ユーザ定義のルールに従って、トラフィックを分散させたり、制御できる技術です。ポリシーに関しては、一般的にプロトコル、ポート番号、インターフェースなど様々なものを使用できますが、今回はSGTを使ったケースについて説明します。SGT-based PBRの利点は、SGT-based PBRは設定が非常に簡単な点、ユーザ単位・ロールなどのセキュリティグループ単位でルーティングパスを選択できる点が挙げられます。
設定の説明に入る前に、環境上SGT-based PBRを設定しない場合、OSPFの等コストロードバランシングによって外部へ抜けるルートが選択されています。
SGT-based PBR設定前のInter1ルータのルート
では、この太字で書いた172.25.70.1宛のルートをxTR2ではなく、xTR1を常に通るようにInter1ルータを設定していきます。
まずは、route-mapの設定をはじめ、SGT=10なら、xTR1を通るように定義します。
route-map SGT_PBR permit 10
match security-group source tag 10
set ip next-hop 172.25.11.254
このルートマップポリシーをIngress Interfaceに割り当てます。
interface GigabitEthernet4.10
ip policy route-map SGT_PBR
SGT-based PBR設定後のInter1ルータのルート
次に、Inter2ルータの設定も変更します。まずはPBR設定前のルートを確認します。
SGT-based PBR設定前のInter2ルータのルート
今度はSource SGTだけでなく、Destination SGTも指定することで、もう少し細かくパス選択できます。ポリシーは、Source SGT=10、かつ、Destination SGT=70 or 90ならxTR2を、Source SGT=10、かつ、Destination SGT=80ならxTR1を通るようにInter2ルータで定義します。
route-map SGT_PBR permit 10
match security-group source tag 10
match security-group destination tag 70 90
set ip next-hop 172.25.12.254
route-map SGT_PBR permit 20
match security-group source tag 10
match security-group destination tag 80
set ip next-hop 172.25.22.254
ルートマップを作成したら、Ingress Interfaceにポリシーを割り当てます。
interface GigabitEthernet4.10
ip policy route-map SGT_PBR
SGT-based PBR設定後のルート
これでInter1ルータ、Inter2ルータともに、ランダムで選択されていたルートでなく、自己定義のルートを選択できるようになりました。
#解説:3. pythonとEEMを使った"なんちゃってNaaS/NaaE"
最後のシナリオは、検知イベントをトリガーに、ルータが自動で特定のホストを隔離するEEMを実行し、別のネットワークとの通信をできなくすることが目的です。EEMの詳細はリンク1, リンク2, リンク3などをご参照ください。また、ただ単にCLI上でEEMのaction cli commandを何十行も書けば同じような結果を得ることができますが、それだと面白みがないので、IOS XEでguestshellをホスティングし、pythonスクリプトを作って、EEMのコマンドライン的には6行で終わるようにしたいと思います。
このシナリオでは、便宜上SalesA1が隔離されるように設定しているので、まずは現時点での全体との疎通を確認します。
注:今回はActionの記述をpythonで作ることを注力しているので、eventのトリガーについては書いていません。別の機会でEEMに関しては書きたいと思います。
イベント検知前のSaleA1と他のエンドポイントとの疎通性
次に、EEMに設定する用のpythonスクリプトをguestshell上のviを使って作っていきます。guestshellの有効化に関する情報はリンク4、リンク5などをご参照ください。
まず、guestshellが有効になっていることをEEMを設定する予定のInter1ルータで確認します。
Inter1#sh app-hosting list
App id State
------------------------------------------------------
guestshell RUNNING
確認ができました。次に、guestshellを起動し、pythonスクリプトを保存する用のディレクトリを作成し、移動します。
Inter1#guestshell
[guestshell@guestshell ~]$ cd /flash
[guestshell@guestshell flash]$ mkdir yunambu
[guestshell@guestshell flash]$ cd yunambu
[guestshell@guestshell yunambu]$
次に、そのまま.pyファイルのviを起動してスクリプトを書いていきます。用意したスクリプトは全部で3つで、いずれもコンフィグの実行をメインとした非常にシンプルなスクリプトです。guestshell上のpythonとCLIがやり取りするには、CLI上で
ip http server
を必ず有効化している必要があります。
- vi Tagging255.py
・異常検知後にまず実行されるスクリプトで、現在インターフェースに紐づけられているSGT=10を外し、172.25.10/24のネットワークをSGT=10とし、悪意のあるユーザに対して隔離用のSGT=255を割り当てます。
#!/usr/bin/python
# -*-coding: utf-8 -*-
import sys
from cli import cli,clip,configure,configurep
print('This script is going to reassign SGT of interface %s')
configurep([
"interface gi4.10",
"no cts role-based sgt-map sgt 10",
"exit",
"cts role-based sgt-map 172.25.10.1 sgt 255",
"cts role-based sgt-map 172.25.10.0/24 sgt 10"
])
print('New security group has been created and assigned for a specific host.')
- vi CreateRule.py
・SGT=255用の制御ポリシーを作成します。
#!/usr/bin/python
# -*-coding: utf-8 -*-
import sys
from cli import cli,clip,configure,configurep
print('This script is going to create a new security group policy for quarantinee
.')
configurep([
"ip access-list role-based QuarantinePolicy",
"deny ip",
"deny ahp",
"deny nos",
"deny pcp",
"exit"
])
print('New group policy has been created.')
- vi PolicyAssign.py
・SGT=255からの通信を全てのSGTに紐づけて遮断します。全ての設定が終わったら、ポリシーの割り当てが正しいかを確認します。
#!/usr/bin/python
# -*-coding: utf-8 -*-
import sys
from cli import configurep,executep
print('This script is going to map the security group and the rule for quarantine')
configurep([
"cts role-based enforcement",
"cts role-based permissions from 255 to 0 QuarantinePolicy",
"cts role-based permissions from 255 to 10 QuarantinePolicy",
"cts role-based permissions from 255 to 20 QuarantinePolicy",
"cts role-based permissions from 255 to 30 QuarantinePolicy",
"cts role-based permissions from 255 to 40 QuarantinePolicy",
"cts role-based permissions from 255 to 50 QuarantinePolicy",
"cts role-based permissions from 255 to 60 QuarantinePolicy",
"cts role-based permissions from 255 to 70 QuarantinePolicy",
"cts role-based permissions from 255 to 80 QuarantinePolicy",
"cts role-based permissions from 255 to 90 QuarantinePolicy",
"end"
])
print('Policy has been assigned to the quarantine network.')
executep("show cts role-based permissions")
スクリプトが完成したら、guestshellを抜けてCLIに戻ります。
次に、EEMの設定を行います。今回は実際にエンドポイントのルータから攻撃を仕掛けるのが難しいためeventはnoneで行います。
event manager applet BLK_ATTACK
event none
action 0.0 cli command "enable"
action 1.0 cli command "guestshell run python /bootflash/yunambu/Tagging255.py"
action 2.0 cli command "guestshell run python /bootflash/yunambu/CreateRule.py"
action 3.0 cli command "guestshell run python /bootflash/yunambu/PolicyAssign.py"
では、実際に上記のスクリプトが正しく実行されるかテストしてみます。
Inter1#debug event manager action cli
Debug EEM action cli debugging is on
Inter1#event manager run BLK_ATTACK
*Dec 13 17:27:31.322: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : CTL : cli_open called.
*Dec 13 17:27:31.323: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Inter1>
*Dec 13 17:27:31.324: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : IN : Inter1>enable
*Dec 13 17:27:31.435: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Inter1#
*Dec 13 17:27:31.436: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : IN : Inter1#guestshell run python /bootflash/yunambu/CreateRule.py
*Dec 13 17:27:34.236: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : This script is going to create a new security group policy for quarantine.
*Dec 13 17:27:34.236: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 1 SUCCESS: ip access-list role-based QuarantinePolicy
*Dec 13 17:27:34.236: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 2 SUCCESS: deny ip
*Dec 13 17:27:34.237: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 3 SUCCESS: deny ahp
*Dec 13 17:27:34.237: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 4 SUCCESS: deny nos
*Dec 13 17:27:34.238: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 5 SUCCESS: deny pcp
*Dec 13 17:27:34.238: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 6 SUCCESS: exit
*Dec 13 17:27:34.238: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : New group policy has been created.
*Dec 13 17:27:34.239: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT :
*Dec 13 17:27:34.239: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT :
*Dec 13 17:27:34.240: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Inter1#
*Dec 13 17:27:34.240: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : IN : Inter1#guestshell run python /bootflash/yunambu/CreateRule.py
*Dec 13 17:27:36.993: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : This script is going to create a new security group policy for quarantine.
*Dec 13 17:27:36.993: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 1 SUCCESS: ip access-list role-based QuarantinePolicy
*Dec 13 17:27:36.993: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 2 SUCCESS: deny ip
*Dec 13 17:27:36.994: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 3 SUCCESS: deny ahp
*Dec 13 17:27:36.994: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 4 SUCCESS: deny nos
*Dec 13 17:27:36.994: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 5 SUCCESS: deny pcp
*Dec 13 17:27:36.995: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 6 SUCCESS: exit
*Dec 13 17:27:36.995: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : New group policy has been created.
*Dec 13 17:27:36.995: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT :
*Dec 13 17:27:36.996: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT :
*Dec 13 17:27:36.996: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Inter1#
*Dec 13 17:27:36.996: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : IN : Inter1#guestshell run python /bootflash/yunambu/PolicyAssign.py
Inter1#
*Dec 13 17:27:40.239: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : This script is going to map the security group and the rule for quarantine
*Dec 13 17:27:40.239: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 1 SUCCESS: cts role-based enforcement
*Dec 13 17:27:40.240: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 2 SUCCESS: cts role-based permissions from 255 to 0 QuarantinePolicy
*Dec 13 17:27:40.241: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 3 SUCCESS: cts role-based permissions from 255 to 10 QuarantinePolicy
*Dec 13 17:27:40.241: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 4 SUCCESS: cts role-based permissions from 255 to 20 QuarantinePolicy
*Dec 13 17:27:40.242: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 5 SUCCESS: cts role-based permissions from 255 to 30 QuarantinePolicy
*Dec 13 17:27:40.243: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 6 SUCCESS: cts role-based permissions from 255 to 40 QuarantinePolicy
*Dec 13 17:27:40.243: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 7 SUCCESS: cts role-based permissions from 255 to 50 QuarantinePolicy
*Dec 13 17:27:40.244: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 8 SUCCESS: cts role-based permissions from 255 to 60 QuarantinePolicy
*Dec 13 17:27:40.244: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 9 SUCCESS: cts role-based permissions from 255 to 70 QuarantinePolicy
*Dec 13 17:27:40.245: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 10 SUCCESS: cts role-based permissions from 255 to 80 QuarantinePolicy
*Dec 13 17:27:40.245: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 11 SUCCESS: cts role-based permissions from 255 to 90 QuarantinePolicy
*Dec 13 17:27:40.246: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Line 12 SUCCESS: end
*Dec 13 17:27:40.247: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : Policy has been assigned to the quarantine network.
*Dec 13 17:27:40.247: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : IPv4 Role-based permissions from group 255 to group Unknown (configured):
*Dec 13 17:27:40.248: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : QuarantinePolicy
*Dec 13 17:27:40.248: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : IPv4 Role-based permissions from group 255 to group 10 (configured):
*Dec 13 17:27:40.249: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : QuarantinePolicy
*Dec 13 17:27:40.249:
Inter1#%HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : IPv4 Role-based permissions from group 255 to group 20 (configured):
*Dec 13 17:27:40.250: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : OUT : QuarantinePolicy
*Dec 13 17:27:40.251: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : CTL : 20+ lines read from cli, debug output truncated
*Dec 13 17:27:40.251: %HA_EM-6-LOG: BLK_ATTACK : DEBUG(cli_lib) : : CTL : cli_close called.
*Dec 13 17:27:40.254:
*Dec 13 17:27:40.254: tty is now going through its death sequence
全て正しく実行されました。次に、最初に確認したSalesA1が隔離されているかを確認します。
イベント検知後のSaleA1と他のエンドポイントとの疎通性
他のエンドポイントとの疎通は一切取れなくなり、隔離が成功しています。実環境では、SyslogやSNMPをはじめ、インターフェースやIP SLAと連携することでログやトラフィックに応じて隔離ポリシーを実行することが可能です。
#まとめ
- VIRL/CMLで、ISEなしのスタティックTrustSecを実装
- config-lisp-srv-ipv4(ipv6も可)モードLISP内にSGTを格納して伝搬が可能
- TrustSecはマルチパーパスで使用できるため、トータルで見てコンフィグ回数や管理ポイントを減らすことが可能
- ISEがない環境でも、EEMとうまく連携させることで、制約は多いが、エンジニアがログなどを追って変更管理することなく自動化が可能
- 今回は触れなかったが、IOS XEでREST APIを使えば、自動化や可視化などますます実現可能に