AWS版Catalyst 9800-CLの検証環境を、必要なタイミングで即座に構築して、不要になったらコスト削減のために破棄したかったのでTerraformでデプロイする方法を書き留めます。
検証時の環境情報
筆者はAWS Cloud 9上のTerraformで検証を行いました。
ec2-user:~/environment $ terraform --version Terraform v1.5.2 on linux_amd64 Your version of Terraform is out of date! The latest version is 1.5.3. You can update by downloading from https://www.terraform.io/downloads.html ec2-user:~/environment $
設計方針
検証用途であるためコスト削減を重視してシングル構成にしております。
無線APからWLCであるCatalyst 9800-CLへのJoinはInternet経由を想定しております。
無線APにはWLCのInternet側のPublic IP Addressを通知する必要があるため、デプロイ時のUser DataでPublic IP Addressの情報を渡しています。デプロイ後に手動設定する場合は、環境固有のPublic IP Addressの確認が必要になるため手間を省く意図です。
Terraformの設定
書き換えが必要な個所
- SSH 公開鍵が
public_key
の値に指定されているので、使用者の公開鍵 (例:cat ~/.ssh/id_rsa.pub
)に書き換えてください。
public_key = "ssh-rsa ABCDEF...."
環境に応じてチューニングが必要になる個所
Catalyst 9800-CLのVersionは v17.9.1 (
C9800-CL-17-9-1.*
)を明示的に指定しているため適宜書き換えてください。通信要件は使用する機能に合わせて精査してください。
v17.9.1 の場合はRelease NoteのNetwork Protocols and Port Matrix
から確認できます。
ログイン情報
Username | 認証方式 | ログイン方式 |
---|---|---|
ec2-user | SSH公開鍵認証 | SSH |
admin | パスワード認証 (ランダム文字列生成) | SSH, Web UI |
admin のパスワードはTerraformの実行時にランダムに生成する方針としています。
下記のように terraform output
を実行するとパスワードの確認が可能です。
ec2-user:~/environment $ terraform output output-admin-password = "<2]3SCqTN8zH9wN*pT" output-wlc01-login-url = "https://***.***.***.***/" output-wlc01-public-ip = "***.***.***.***" ec2-user:~/environment $
設定ファイル全体
terraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 4.0" } } } provider "aws" { region = "ap-northeast-1" default_tags { tags = { ENV = "TEST" } } } data "aws_region" "current" {} resource "aws_key_pair" "keypair" { key_name = "keypair_for_terraform" # TODO: CHANGE KEYPAIR public_key = "ssh-rsa ABCDEF...." } resource "random_password" "login-password" { length = 18 special = true override_special = "!#$%&*()-_=+[]{}<>:" # Exclude question mark } data "aws_ami" "c9800-cl" { #most_recent = true owners = ["aws-marketplace"] filter { name = "name" #values = ["C9800-CL*"] values = ["C9800-CL-17-9-1.*"] } filter { name = "product-code" values = ["38id0enmqvbjcm7sexk3394kx"] } filter { name = "state" values = ["available"] } } resource "aws_vpc" "myvpc" { cidr_block = "172.31.0.0/16" enable_dns_hostnames = true tags = { Name = "myvpc" } } resource "aws_subnet" "subnet-public-1a" { vpc_id = aws_vpc.myvpc.id cidr_block = "172.31.0.0/24" availability_zone = "ap-northeast-1a" map_public_ip_on_launch = true tags = { Name = "subnet-public-1a" } } resource "aws_internet_gateway" "igw" { vpc_id = aws_vpc.myvpc.id } resource "aws_route_table" "rt-public" { vpc_id = aws_vpc.myvpc.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.igw.id } tags = { Name = "rt-public" } } resource "aws_route_table_association" "rtassoc-public-1a" { subnet_id = aws_subnet.subnet-public-1a.id route_table_id = aws_route_table.rt-public.id } # Network Communication Requirements # # Release Notes for Cisco Catalyst 9800 Series Wireless Controller, Cisco IOS XE Cupertino 17.9.x - Cisco # https://www.cisco.com/c/en/us/td/docs/wireless/controller/9800/17-9/release-notes/rn-17-9-9800.html#Cisco_Reference.dita_fd1a1a9f-282c-4d1e-8948-166cb824fb8f # Refer to "Network Protocols and Port Matrix" resource "aws_security_group" "secgrp-public" { name = "secgrp-public" description = "For Public Subnet" vpc_id = aws_vpc.myvpc.id ingress { description = "ICMP Echo Request" from_port = 8 to_port = 0 protocol = "icmp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "SSH" from_port = 0 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } # Ingress (Inbound) ingress { description = "CAPWAP Control" from_port = 0 to_port = 5246 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "CAPWAP Data" from_port = 0 to_port = 5247 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "CAPWAP MCAST" from_port = 0 to_port = 5248 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "Mobility Control" from_port = 16666 to_port = 16666 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } #ingress { # description = "Telnet" # from_port = 0 # to_port = 23 # protocol = "tcp" # cidr_blocks = ["0.0.0.0/0"] #} #ingress { # description = "HTTP" # from_port = 0 # to_port = 80 # protocol = "tcp" # cidr_blocks = ["0.0.0.0/0"] #} ingress { description = "HTTPS & REST API" from_port = 0 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "Client Policies (AP-AP)" from_port = 0 to_port = 16670 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "SNMP Agent (SNMP Polling)" from_port = 0 to_port = 161 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "TFTP" from_port = 0 to_port = 69 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } ingress { description = "Mobility" from_port = 16667 to_port = 16667 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] } #ingress { # description = "NetConf" # from_port = 0 # to_port = 830 # protocol = "tcp" # cidr_blocks = ["0.0.0.0/0"] #} ingress { description = "Device Discovery" from_port = 0 to_port = 32222 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } # Egrerss (Outbound) #egress { # description = "Mobility Control" # from_port = 16666 # to_port = 16666 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "SNMP Trap" # from_port = 0 # to_port = 162 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "RADIUS Authentication" # from_port = 0 # to_port = 1812 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "RADIUS Accounting" # from_port = 0 # to_port = 1813 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "TACACS+" # from_port = 0 # to_port = 49 # protocol = "tcp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "Mobility" # from_port = 16667 # to_port = 16667 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "NTP Server" # from_port = 0 # to_port = 123 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "Syslog" # from_port = 0 # to_port = 514 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "NetFlow" # from_port = 0 # to_port = 9996 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} #egress { # description = "NMSP / Cisco Connected Mobile Experiences (CMX)" # from_port = 0 # to_port = 16113 # protocol = "udp" # cidr_blocks = ["0.0.0.0/0"] #} egress { description = "Any" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "secgrp-public" } } resource "aws_network_interface" "eni-wlc01-gi1" { subnet_id = aws_subnet.subnet-public-1a.id security_groups = [aws_security_group.secgrp-public.id] source_dest_check = false tags = { Name = "eni-wlc01-gi1" } } resource "aws_eip" "eip-wlc01" { vpc = true network_interface = aws_network_interface.eni-wlc01-gi1.id depends_on = [aws_internet_gateway.igw] tags = { Name = "eip-wlc01" } } resource "aws_instance" "wlc01" { ami = data.aws_ami.c9800-cl.image_id # Available Instance Types: c5.xlarge or c5.2xlarge or c5.4xlarge instance_type = "c5.xlarge" key_name = aws_key_pair.keypair.id network_interface { network_interface_id = aws_network_interface.eni-wlc01-gi1.id device_index = 0 } user_data = <<EOF ios-config-1="username admin privilege 15 password 0 ${random_password.login-password.result}" ios-config-2="hostname wlc01" ios-config-3="wireless management interface GigabitEthernet1" ios-config-4=" public-ip ${aws_eip.eip-wlc01.public_ip}" EOF tags = { Name = "wlc01" } } output "output-wlc01-public-ip" { description = "Public IP Address for wlc01" value = aws_eip.eip-wlc01.public_ip } output "output-wlc01-login-url" { description = "Login URL for wlc01" value = "https://${aws_eip.eip-wlc01.public_ip}/" } output "output-admin-password" { description = "admin user's password" value = nonsensitive(random_password.login-password.result) }
デプロイ方法
設定ファイルを
main.tf
として保存します。Terraformの実行環境を準備 (初期化)します。
terraform init
- 構成が意図したものであり、エラーが出ないかを事前に確認します。
terraform plan
- 実際にデプロイします。
terraform apply
- ログイン情報が分からなくなったら
output
の情報を出力します。
terraform output
Web UIからログインすると
Configuration Setup Wizard
の状態になるため、検証に必要となる設定を続けてください。2023年07月頃のAWS版Catalyst 9800-CLでは、AWS対応Versionの全てがデプロイ時に選択できるわけではありません。そのため、APがWLCにJoinするにはUpgradeが必要になる可能性があります。
リソースの後始末 (検証環境の破棄)
- 検証を終えたら不要なリソースは削除します。
terraform destroy