Terraform cloud agent を Cisco L3 Switch にインストして社内インフラをIaC


# はじめに
この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2021 （一枚目） の 5日目として投稿しています。

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
2021年版: https://qiita.com/advent-calendar/2021/cisco <=== ここ
2021年版(2枚目): https://qiita.com/advent-calendar/2021/cisco2

延べ50名！有志すごい！

# これはなに？

- みんな大好きTerraformのマネージドサービスである[Terraform cloud](https://www.terraform.io/cloud)
- Terraform cloudの [Docker Agent](https://www.terraform.io/docs/cloud/agents/index.html) を [Cisco Catalyst9300](https://www.cisco.com/c/ja_jp/products/switches/catalyst-9300-series-switches/index.html) の[App-hosting機能](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/176/b_176_programmability_cg/m_176_prog_app_hosting.html)でインスト
- ファイアウォール内にあるキャンパスコントローラーである [Cisco DNA Center](https://www.cisco.com/c/ja_jp/products/cloud-systems-management/dna-center/index.html) や認証ポリシーサーバーである [Cisco Identy Services Engine (ISE)](https://www.cisco.com/c/ja_jp/products/security/identity-services-engine/index.html) の設定（一部）をTerraform cloud経由で管理する例
- Terraform cloudのトリガーは動作確認のためコマンド


※一般的な Docker エージェントをCiscoのLAN向け固定構成型フラッグシップスイッチであるCatalyst 9300にインストールして設定して動作確認する仕方の参考にもなれば幸いです。

## 構成

![SS 2021-12-03 16.00.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/28d4e790-00ea-59ad-f38c-2748ce6fcef5.png)

## デモ
デモの録画をキャプション付けて公開しました。（音が出ますのでご注意ください！）
※直リンクは[こちら](https://www.youtube.com/watch?v=_gxRLwkdHyk)です。
<iframe width="560" height="315" src="https://www.youtube.com/embed/_gxRLwkdHyk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

### 動画のタイムライン
- 0:15 Catalyst9300の設定など
- 1:00 TFコンソールでCat9300上のAgentを確認
- 1:40 設定変更前のISEの内部IDの確認
- 1:50 設定変更前のDNACでのサイト設定の確認
- 2:06 社内へのVPNを切断
- 2:25 Terraformの設定を確認
- 2:39 Terraformの設定を確認（ISE）
- 2:55 Terraformの設定を確認（DNAC）
- 3:13 Terraform applyを実行
- 3:30 Terraform cloud上で実行状況の確認
- 4:45 ISEにIDを作成しているログをTerraformで確認
- 4:55 DNACにサイトを追加しているログをTerraformで確認
- 5:31 DNACとISEの設定を確認するためVPN接続
- 6:10 DNACに新たにサイトが追加されていることを確認
- 6:15 ISEに新たにIDが追加されていることを確認

# 設定
さっそく設定をみていきます。

## 1. Terraform cloud

Terraform cloudにサインアップして､OrganizationおよびWorkspaceを作ります。今回は検証用に発行していただいたライセンスを利用しました。もし興味がありましたら､HashiCorpの担当者までコンタクトください😀
https://app.terraform.io/

![SS 2021-12-01 16.01.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/36b751e9-7771-6d95-b915-af8f24fb25d4.png)

ローカル環境（自分のデスクトップまたはサーバー）とterraform cloudを結びつけておきます。このあたりの流れはだいぶ省略しますが､興味ある方はググってください。

こちらのコマンドをローカルでうつといい感じにリダイレクトしてくれます。

~~~bash
terraform login
~~~

または､手動でウェブコンソールから取得した自分のTokenを､以下のファイルとして書いておけば良さそうです。

~~~bash
$ cat ~/.terraform.d/credentials.tfrc.json
{
  "credentials": {
    "app.terraform.io": {
      "token": "<クラウドから取得した自分のトークン>"
    }
  }
}%     
~~~

## 2. Terraform cloud agent on Cisco L3スイッチ

現行のCisco L3スイッチであるCatalyst 9300の[App-hosting機能](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/176/b_176_programmability_cg/m_176_prog_app_hosting.html)を利用します。
シスコが提供する以外のアプリケーションを載せるためには､専用のUSB接続のSSDが必要になります。IOS XE 17.6.1 を利用します。

~~~cisco:cisco
Cat9300TMT03W#sho inventory 
NAME: "c93xx Stack", DESCR: "c93xx Stack"
PID: C9300-24P         , VID: V02  , SN: FCW2240D0RY

NAME: "Switch 1", DESCR: "C9300-24P"
PID: C9300-24P         , VID: V02  , SN: FCW2240D0RY

NAME: "Switch 1 - Power Supply A", DESCR: "Switch 1 - Power Supply A"
PID: PWR-C1-715WAC     , VID: V03  , SN: LIT22372265

NAME: "usbflash1", DESCR: "usbflash1-1" <---これ
PID: SSD-120G          , VID: 3.10 , SN: STP230311VB


Cat9300TMT03W#
Cat9300TMT03W#sho ver | i IOSXE
Cisco IOS Software [Bengaluru], Catalyst L3 Switch Software (CAT9K_IOSXE), Version 17.6.1, RELEASE SOFTWARE (fc6)
*    1 41    C9300-24P          17.06.01          CAT9K_IOSXE           INSTALL
~~~

terraform cloud agentのコンテナをdocker hubから取得し､Catalyst9300のapp-hosting機能を使うためにtarファイルにします。

~~~bash:mac
$ docker pull hashicorp/tfc-agent
Using default tag: latest
latest: Pulling from hashicorp/tfc-agent
<snip>
$ docker save hashicorp/tfc-agent:latest -o tfc-agent.tar 
$ ls
tfc-agent.tar <--- これ
~~~

Terraformのサイトで､Agent用のTokenを作成しておきます。TFC_AGENT_TOKENを作ってメモしておきます。
![SS 2021-12-01 10.30.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/ba5395d8-31dc-bec7-1462-fc15ccf68d64.png)

show app-hosting resourceコマンドで､スイッチ上にホストするアプリケーションが使えるリソースが確認できます。今回の例では､既にguestshellコンテナが動いていますが､その隣にTerraform cloud agentを立ち上げることにします。

~~~cisco:cisco
Cat9300TMT03W#sh app-hosting resource 
CPU:
  Quota: 25(Percentage) 
  Available: 22(Percentage)
VCPU:
  Count: 2
Memory:
  Quota: 2048(MB)
  Available: 1792(MB)
Storage space:
  Total: 112547(MB)
  Available: 100395(MB)

Cat9300TMT03W#
Cat9300TMT03W#sh app-hosting list 
App id                                   State
---------------------------------------------------------
guestshell                               RUNNING

Cat9300TMT03W#
~~~

Cisco IOS XEのコマンド例です。内部のSVI VLAN11が､物理ポートと内部のアプリケーション用仮想ポートに繋がっているイメージです。別の記事でも詳しく書いていますので､興味があればそちらも参照ください。
参考） [Catalyst 9300 Docker 上で ThousandEyes Agent の起動と設定](https://qiita.com/kikuta2055/items/9175c2bb828a34b4511e)

~~~cisco:cisco
interface Vlan11
 ip address 10.71.154.33 255.255.255.248
~~~

IOS XE コマンドの中に､Docker起動オプションとして先に取得したTFC_AGENT_TOKENを書きます。

~~~cisco:cisco
app-hosting appid tfc_agent
 app-vnic AppGigabitEthernet trunk
  vlan 11 guest-interface 0
   guest-ipaddress 10.71.154.35 netmask 255.255.255.248
 app-default-gateway 10.71.154.33 guest-interface 0
 app-resource docker
  run-opts 1 "-e TFC_AGENT_TOKEN=<Terraformサイトで取得した値>"
  run-opts 2 "-e TFC_AGENT_NAME=Cat9300TMT03W hashicorp/tfc-agent"
 name-server0 64.104.14.184
~~~

さて､上の設定でアプリケーションホスティングの環境は整いました。次はコマンドでtfc-agent.tarをインストールします。以下の例では､ウェブサーバー上に置いたtfc-agent.tarを直接インストールしていますが､一度スイッチのフラッシュにコピーしておくとより安全でしょう。

~~~cisco:cisco
Cat9300TMT03W#app-hosting install appid tfc_agent package http://<ipaddr>/tfc-agent.tar       
Installing package 'http://<ipaddr>/tfc-agent.tar' for 'tfc_agent'. Use 'show app-hosting list' for progress.
~~~

しばらく待つと､以下のようにログが出力され､デプロイ完了です。

~~~cisco:cisco
Cat9300TMT03W#sh app-hosting list 

Nov 30 2021 05:43:07.789 UTC: %IM-5-IOX_URL_COPY_MSG: Switch 1 R0/0: ioxman: URL Copy: Success to copy http://<ipaddr>/tfc-agent.tar to usbflash1:/apps/tfc-agent.tar.
Nov 30 2021 05:43:19.006 UTC: %IM-6-INSTALL_MSG: Switch 1 R0/0: ioxman: app-hosting: Install succeeded: tfc_agent installed successfully Current state is DEPLOYEDApp id                                   State
---------------------------------------------------------
tfc_agent                                DEPLOYED <---ここ
guestshell                               RUNNING
~~~

Catalyst9300上でのコンテナのライフサイクルは以下の流れで管理されます。インストール後､明示的にアクティベート､スタートする必要があります。このあたりは [マニュアルに詳しい記載](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/176/b_176_programmability_cg/m_176_prog_app_hosting.html#id_74345)があります。

- install/uninstall <--> activate/deactivate <--> start/stop

~~~
Cat9300TMT03W#app-hosting ?
  activate      Application activate <--- 2. これ
  clear         Clear console/aux connection
  connect       Application connect
  data          Application data
  deactivate    Application deactivate <--- 
  debug         debug
  install       Application install <--- 1. これ
  move          Move File
  settings      Application settings
  start         Application start <--- 3. これ
  stop          Application stop <---
  uninstall     Application uninstall <--- 
  upgrade       Application upgrade
  verification  Application signature verification setting (global)
~~~

順番に､アクティベート､スタートします。

~~~cisco:cisco
Cat9300TMT03W#app-hosting activate appid tfc_agent 
tfc_agent activated successfully
Current state is: ACTIVATED

Cat9300TMT03W#
Cat9300TMT03W#app-hosting start appid tfc_agent    
tfc_agent started successfully
Current state is: RUNNING
~~~

無事に動作しはじめると､RUNNINGステータスになります。

~~~cisco:cisco
Cat9300TMT03W#show app-hosting list
App id                                   State
---------------------------------------------------------
tfc_agent                                RUNNING <--- 無事に動き出しました🎉
guestshell                               RUNNING

Cat9300TMT03W#
~~~

Terraformのコンソールでもエージェントがコンタクトしてきていることが確認できました。

![SS 2021-12-01 10.34.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/430be6b6-66d2-0544-663e-de7baf53133c.png)

参考までに､L3スイッチ内部でTerraform cloud agentが利用しているリソースや仮想ネットワークの設定を確認できます。このコマンドは Cisco IOS XE app-hostingを試す際には確認用によく使います。

~~~cisco:cisco
Cat9300TMT03W#show app-hosting detail appid tfc_agent
App id                 : tfc_agent
Owner                  : iox
State                  : RUNNING
Application
  Type                 : docker
  Name                 : hashicorp/tfc-agent
  Version              : latest
  Description          : 
  Author               : 
  Path                 : usbflash1:/apps/tfc-agent.tar
  URL Path             : http://<ipaddr>/tfc-agent.tar
Activated profile name : default

Resource reservation
  Memory               : 409 MB
  Disk                 : 10 MB
  CPU                  : 1480 units
  CPU-percent          : 20 %
  VCPU                 : 1

Platform resource profiles
  Profile Name                  CPU(unit)  Memory(MB)  Disk(MB)
  --------------------------------------------------------------

Attached devices
  Type              Name               Alias
  ---------------------------------------------
  serial/shell     iox_console_shell   serial0
  serial/aux       iox_console_aux     serial1
  serial/syslog    iox_syslog          serial2
  serial/trace     iox_trace           serial3

Network interfaces
   ---------------------------------------
eth0:
   MAC address         : 52:54:dd:be:f6:18
   IPv4 address        : 10.71.154.35
   IPv6 address        : ::
   Network name        : mgmt-bridge-v11


Docker
------
Run-time information
  Command              : hashicorp/tfc-agent
  Entry-point          : /home/tfc-agent/bin/tfc-agent
  Run options in use   : -e TFC_AGENT_TOKEN=<your_token> -e TFC_AGENT_NAME=Cat9300TMT03W hashicorp/tfc-agent
  Package run options  : 
Application health information
  Status               : 0
  Last probe error     : 
  Last probe output    : 


Cat9300TMT03W#
~~~

## 3. Terraformの設定
Terraformの設定は最低限に抑えています。DNAC､ISEともにTerraform Providerが公開されていますので､設定内容に興味がある方はこの辺り（[DNAC](https://github.com/cisco-en-programmability/terraform-provider-dnacenter)､[ISE](https://github.com/CiscoISE/terraform-provider-ciscoise) ）を参照ください。

以下の三つのファイルをローカルで作成し､実行しています。

- main.tf ... Terraform cloudへの接続と､DNACとISE用のProviderの読み込み
- ise.tf ... Cisco ISEに追加するID情報
- dnac.tf ... Cisco DNACに追加するサイト情報

尚､クラウドを使わない場合だとterraform.tfvarsで変数を管理するのが普通だと思いますが､その辺りはクラウドに登録しておけるので不要です。
例）https://app.terraform.io/app/kikuta/workspaces/cisco-sollab-01/variables

![SS 2021-12-05 3.27.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/157325/2452a06b-aeb6-45ce-a36a-50a8d58a749c.png)


~~~terraform:main.tf
terraform {
  backend "remote" {
    organization = "kikuta"
    workspaces {
      name = "cisco-sollab-01"
    }
  }
}

terraform {
  required_providers {
    ciscoise = {
      source  = "CiscoISE/ciscoise"
      version = "0.0.2-beta"
    }
    dnacenter = {
      source  = "cisco-en-programmability/dnacenter"
      version = "0.0.3"
    }
  }
}
~~~

ISE: ネットワークで認証されるユーザーをISE内部DBに追加（例：Qiita999を追加） 

~~~terraform:ise.tf
variable "TF_VAR_ISE_username" {
  type = string
}
variable "TF_VAR_ISE_password" {
  type = string
}
variable "TF_VAR_ISE_URL" {
  type = string
}

provider "ciscoise" {
  username = var.TF_VAR_ISE_username
  password = var.TF_VAR_ISE_password
  base_url = var.TF_VAR_ISE_URL

  debug = "true"
  ssl_verify = "false"
  use_api_gateway = "false"
  use_csrf_token = "false"
}

resource "ciscoise_internal_user" "example_1" {
  provider = ciscoise
  item {
    change_password = "true"
    description         = "Managed by terraform cloud"
    enabled             = "true"
    enable_password     = "QiitaisK00l!"
    password            = "QiitaisK00l!"
    name                = "Qiita999"
    first_name          = "Kazumasa"
    last_name           = "Ikuta"
    expiry_date_enabled = "false"
    email               = "kikuta@cisco.com"
  }
}

data "ciscoise_internal_user" "response" {
  depends_on = [
    ciscoise_internal_user.example_1
  ]
}

output "ciscoise_internal_user_response" {
  value = data.ciscoise_internal_user.response
}
~~~

DNAC:　DNACで管理される「サイト」を新たに追加（例：Aichiを追加）

~~~terraform:dnac.tf
variable "TF_VAR_DNAC_username" {
  type = string
}
variable "TF_VAR_DNAC_password" {
  type = string
}
variable "TF_VAR_DNAC_URL" {
  type = string
}

provider "dnacenter" {
  username = var.TF_VAR_DNAC_username
  password = var.TF_VAR_DNAC_password
  base_url = var.TF_VAR_DNAC_URL
  debug = "true"
  ssl_verify = "false"
}

resource "dna_site" "area" {
  provider = dnacenter
  item {
    type        = "area"
    name        = "Aichi"
    parent_name = "Global"
  }
}

resource "dna_site" "building" {
  provider   = dnacenter
  depends_on = [dna_site.area]
  item {
    type        = "building"
    name        = "Nishiki Park Bldg"
    parent_name = "Global/Aichi"
    address     = "Nishiki, Nagoya, Aichi"
    latitude    = 35.17328858432372
    longitude   = 136.90092843701123
  }
}

resource "dna_site" "floor" {
  provider   = dnacenter
  depends_on = [dna_site.building]
  item {
    type        = "floor"
    name        = "Floor 1"
    parent_name = "Global/Aichi/Nishiki Park Bldg"
    rf_model    = "Free Space"
    height      = 100.1
    length      = 100.2
    width       = 100.1
  }
}
~~~

# 動作確認

今回は､ローカル環境からコマンドでTerraform cloudをトリガーしていますが､Terraform cloudとGithubをつないで､DNACやISEの設定もGithubにまとめてしまうともっとIaCぽくなりますね。

~~~
terraform init
terraform plan
terraform apply -auto-approve
~~~

# 所感

企業ネットワーク基盤の設備（DNACやISE､およびそれらが管理するスイッチ､無線､ルーター類）はファイアウォール内にある前提です。境界内のエージェントとクラウドのトンネルを活用することで境界外部から境界内部の構成をコードで管理してみる､ということを強調したかったので､あえてDemo動画でも､VPNを切断したり接続したりするプロセスを入れています。

Terraformがルーターやスイッチを直接操作する､というのではなく､ネットワークコントローラー類(今回はDNACやISE)のAPIとやり取りし､コントローラー類がネットワーク装置とやり取りする､というアーキテクチャもきれいですね。

Terraformはパブリッククラウド管理では､ほぼデファクトの一つとして定着していますが､このように境界内部（LANやプライベートクラウド）でも使えるユースケースが普及していくと､境界内外を一貫した方法でIaCできる可能性があると感じました。今回のDemoは全体のほんの一部ですが､これにCisco ACI環境やパブリッククラウド環境を追加することは容易であり､マルチクラウド､ハイブリッドエンタープライズのIaCの一つの姿として､またCI/CDの基盤としても有効ではないでしょうか。

DNACやISEについては､まだまだTerraformで多くのことができるわけではないので､この辺りはProviderが強化されることを期待しつつ､他にも有効なユースケースがないか､他にもいい感じにTerraformが管理できる境界内管理ツールがないか､もう少し調べてみたいと思いました。

Catalyst9300にDockerアプリケーションを簡単に載せられることは大きな可能性がありますが､Terraform cloud agentはその一つだと思いました。他にも､「これ載せたら面白いよね？！」というアイデアや気づきがありましたら､ぜひコメントまたはDMいただけると嬉しいです！

2022年へのカウントダウン､シスコジャパン有志によるアドベントカレンダー､もうしばらくお楽しみください♪ここまで読んでいただきましてどうもありがとうございました。2022年も､どうぞよろしくお願い致します。

# 参考

## Cisco製品関連
- [Cisco Catalyst 9300シリーズスイッチ](https://www.cisco.com/c/ja_jp/products/switches/catalyst-9300-series-switches/index.html)
- [Cisco DNA Center](https://www.cisco.com/c/ja_jp/products/cloud-systems-management/dna-center/index.html)
- [Cisco Identity Services Engine](https://www.cisco.com/c/ja_jp/products/security/identity-services-engine/index.html)
- [Programmability Configuration Guide, Cisco IOS XE Bengaluru 17.6.x
](https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/prog/configuration/176/b_176_programmability_cg/m_176_prog_app_hosting.html)

## Terraform Cloud および Terraform Provider関連

- [Terraform Cloud](https://www.terraform.io/cloud)
- [Terraform Provider for Cisco DNA Center](https://github.com/cisco-en-programmability/terraform-provider-dnacenter)
- [terraform-provider-ciscoise](https://github.com/CiscoISE/terraform-provider-ciscoise)
- [Cisco EN Programmability](https://registry.terraform.io/providers/cisco-en-programmability/dnacenter/latest)
- [Cisco ISE](https://registry.terraform.io/providers/CiscoISE/ciscoise/latest)

# 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。