らくがきちょう

なんとなく ~所属組織/団体とは無関係であり、個人の見解です~

Terraform で ACI 上に L3out/OSPF の Tenant を作成する (2021/09/01 版)

以前に以下のメモを書きました。

今回は上記を整理し、以下の方針で .tf ファイルを書き直しました。

  • 通信制御 (Contract) は以下の方針とする
    • VRF は Policy Control Enforcement PreferenceEnforced を設定する (デフォルト値)
    • L3Out 〜 EPG 間の通信は Standard Contract を利用する
  • L3Out は以下の方針とする
    • L3Out では OSPF を設定する
    • OSPF Network Type は Point-to-Point を設定する
  • L3Out からの BD Subnet 広報は以下の設定を利用する
    • BD で Associated L3Out を設定する
    • BD Subnet Scope を Advertised Externally に設定する

検証環境

今回は以下のバージョンを利用しました。

構成図

今回は以下の構成を Terraform で設定します。

f:id:sig9:20210829234642p:plain

.tf ファイル

credential.tf

username, password, url は環境に合わせて変更します。

terraform {
  required_providers {
    aci = {
      source  = "CiscoDevNet/aci"
      version = "0.7.1"
    }
  }
}

provider "aci" {
  username = "admin"
  password = "password"
  url      = "https://10.0.0.1"
  insecure = true
}

tenant.tf

# Tenant
resource "aci_tenant" "tenant1" {
  name = "Tenant1"
}

# VRF
resource "aci_vrf" "vrf1" {
  tenant_dn   = "${aci_tenant.tenant1.id}"
  name        = "Vrf1"
}

l3out.tf

# OSPF Interface Policy
resource "aci_ospf_interface_policy" "ospf_if_p2p" {
  tenant_dn    = "${aci_tenant.tenant1.id}"
  name         = "Point-to-Point"
  cost         = "unspecified"
  nw_t         = "p2p"
  prio         = "1"
  pfx_suppress = "inherit"
  hello_intvl  = "10"
  dead_intvl   = "40"
  rexmit_intvl = "5"
  xmit_delay   = "1"
}

# Domain
data "aci_l3_domain_profile" "l3dom" {
  name = "ExtRoutedDom"
}

# L3Out
resource "aci_l3_outside" "l3out1" {
  tenant_dn                    = "${aci_tenant.tenant1.id}"
  name                         = "L3Out1"
  relation_l3ext_rs_ectx       = "${aci_vrf.vrf1.id}"
  relation_l3ext_rs_l3_dom_att = "${data.aci_l3_domain_profile.l3dom.id}"
}

resource "aci_l3out_ospf_external_policy" "l3out1_ospf" {
  l3_outside_dn = "${aci_l3_outside.l3out1.id}"
  area_cost     = "1"
  area_ctrl     = "redistribute,summary"
  area_id       = "0.0.0.0"
  area_type     = "regular"
}

resource "aci_logical_node_profile" "l3out1_lnprof1" {
  l3_outside_dn = "${aci_l3_outside.l3out1.id}"
  name          = "L3Out1_NodeProf"
}

resource "aci_logical_node_to_fabric_node" "l3out1_lnode1" {
  logical_node_profile_dn  = "${aci_logical_node_profile.l3out1_lnprof1.id}"
  tdn                      = "topology/pod-1/node-201"
  rtr_id                   = "10.0.254.201"
  rtr_id_loop_back         = "no"
}

resource "aci_logical_interface_profile" "l3out1_lifprof1" {
  logical_node_profile_dn = "${aci_logical_node_profile.l3out1_lnprof1.id}"
  name                    = "L3Out1_IntProf"
}

resource "aci_l3out_path_attachment" "lifprof1_port1" {
  logical_interface_profile_dn = "${aci_logical_interface_profile.l3out1_lifprof1.id}"
  target_dn                    = "topology/pod-1/paths-201/pathep-[eth1/1]"
  if_inst_t                    = "ext-svi"
  addr                         = "10.0.101.2/30"
  autostate                    = "enabled"
  encap                        = "vlan-101"
  mtu                          = "1500"
}

resource "aci_l3out_ospf_interface_profile" "ospf_if_prof1" {
  logical_interface_profile_dn = "${aci_logical_interface_profile.l3out1_lifprof1.id}"
  relation_ospf_rs_if_pol      = "${aci_ospf_interface_policy.ospf_if_p2p.id}"
  auth_key                     = ""
}

# External EPG
resource "aci_external_network_instance_profile" "l3out1_epg1" {
  l3_outside_dn       = "${aci_l3_outside.l3out1.id}"
  name                = "ExtEpg1"
  relation_fv_rs_cons = ["${aci_contract.contract1.id}"]
}

resource "aci_l3_ext_subnet" "l3out1_subnet1" {
  external_network_instance_profile_dn = "${aci_external_network_instance_profile.l3out1_epg1.id}"
  ip                                   = "0.0.0.0/0"
  scope                                = ["import-security"]
}

contract.tf

# Filter
resource "aci_filter" "filter1" {
    tenant_dn = "${aci_tenant.tenant1.id}"
    name      = "Filter1"
}

resource "aci_filter_entry" "entry1" {
    name      = "0010"
    filter_dn = "${aci_filter.filter1.id}"
    ether_t   = "unspecified"
}

# Contract
resource "aci_contract" "contract1" {
    tenant_dn = "${aci_tenant.tenant1.id}"
    name      = "Contract1"
}

# Subject
resource "aci_contract_subject" "subject1" {
    contract_dn                  = "${aci_contract.contract1.id}"
    name                         = "Subject1"
    relation_vz_rs_subj_filt_att = ["${aci_filter.filter1.id}"]
}

bd.tf

L3Out から BD Subnet を広報する為に以下の設定を行います。

  • aci_bridge_domainrelation_fv_rs_bd_to_out を設定する (Associated L3Out)
  • aci_subnetscopepublic に設定する (Advertised Externally)
# BD
resource "aci_bridge_domain" "bd1" {
  tenant_dn                = "${aci_tenant.tenant1.id}"
  name                     = "Bd1"
  relation_fv_rs_ctx       = "${aci_vrf.vrf1.id}"
  relation_fv_rs_bd_to_out = ["${aci_l3_outside.l3out1.id}"]
}

resource "aci_subnet" "bd1_subnet" {
  parent_dn = "${aci_bridge_domain.bd1.id}"
  ip        = "10.0.102.254/24"
  scope     = ["public"]
}

epg.tf

# Application Profile
resource "aci_application_profile" "ap1" {
  tenant_dn = "${aci_tenant.tenant1.id}"
  name      = "Ap1"
}

# Domain
data "aci_physical_domain" "physdom" {
  name = "PhysDom"
}

# EPG
resource "aci_application_epg" "epg1" {
  application_profile_dn = "${aci_application_profile.ap1.id}"
  name                   = "Epg1"
  relation_fv_rs_bd      = "${aci_bridge_domain.bd1.id}"
}

resource "aci_epg_to_domain" "epg1_physdom" {
  application_epg_dn = "${aci_application_epg.epg1.id}"
  tdn                = "${data.aci_physical_domain.physdom.id}"
}

resource "aci_epg_to_static_path" "egp1_port1" {
  application_epg_dn = "${aci_application_epg.epg1.id}"
  tdn                = "topology/pod-1/paths-202/pathep-[eth1/1]"
  encap              = "vlan-102"
}

resource "aci_epg_to_contract" "epg1_contract1" {
  application_epg_dn = "${aci_application_epg.epg1.id}"
  contract_dn        = "${aci_contract.contract1.id}"
  contract_type      = "provider"
}