Azure Route Server と FRRouting の間で BGP ピアを張る
Ubunutu Server 22.04 版も作りました
OS のバージョンが変わっただけでほかに何も変わっていないですが、こちらの repos も参考にどうぞ。
cloud-init
を使って自動化しました
以下の directory にあるので参考にしていただければと。
FRRouting を Ubuntu Server 20.04 にインストールし NVA 化したうえで、Azure Route Server (ARS) と peer が張れる所までは自動化されています。
インフラの準備
ここは適当に Bicep で一発ですね、ちゃちゃっとやってしまいましょう。
以下の Bicep ファイルで以下の内容を作ってくれます。
自作の module については下のほうに置いておきます。
- VNet
- Bastion
- Azure Route Server
- Azure VM
main.bicep
param location01 string = 'eastasia'
param sshKeyRGName string
param isInitialDeploy bool = false
var useExisting = !isInitialDeploy
param publicKeyName string
resource public_key 'Microsoft.Compute/sshPublicKeys@2022-03-01' existing = {
name: publicKeyName
scope: resourceGroup(sshKeyRGName)
}
resource hub00 'Microsoft.Network/virtualNetworks@2022-01-01' = {
name: 'vnet-hub00'
location: location01
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'default'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
{
name: 'AzureBastionSubnet'
properties: {
addressPrefix: '10.0.100.0/24'
}
}
{
name: 'GatewaySubnet'
properties: {
addressPrefix: '10.0.200.0/24'
}
}
{
name: 'RouteServerSubnet'
properties: {
addressPrefix: '10.0.210.0/24'
}
}
]
}
resource defaultsubnet 'subnets' existing = {
name: 'default'
}
}
var bast01Name = 'bast-hub00'
module bast01 '../lib/bastion.bicep' = {
name: bast01Name
params: {
location: location01
bastionName: bast01Name
vnetName: hub00.name
}
}
var rs01Name = 'rs-hub00'
module rs01 '../lib/route-server.bicep' = {
name: rs01Name
params: {
location: location01
routeServerName: rs01Name
vnetName: hub00.name
useExisting: useExisting
bgpConnections: [
{
name: vm_hub00.name
ip: vm_hub00.outputs.privateIP
asn: '65001'
}
]
}
}
var vm01Name = 'vm-hub00'
module vm_hub00 '../lib/ubuntu2004.bicep' = {
name: vm01Name
params: {
location: location01
keyData: public_key.properties.publicKey
subnetId: hub00::defaultsubnet.id
vmName: vm01Name
}
}
NVA の作成
Azure Route Server は BGP で経路を受け取ってそれを Virtual Network Gateway や VNet に影響させるコンポーネントであり、BGP が喋れる何らかの NVA を用意する必要があります。
チュートリアル: Azure Route Server とネットワーク仮想アプライアンスの間のピアリングを構成する では Quagga を使っているようですが、ここでは FRRouting を使っていきます。
NVA として使用するのは上記 Bicep で vm-hub00
と名前を付けた Ubuntu Server 20.04 LTS を利用します。
今回 Bastion を利用しているので、手元の Windows Terminal から Bastion を利用して接続してみます。
--target-resource-id
の指定が長ったらしいのですが、最近の Azure Portal は Azure VM を選択してから、右上の JSON View をクリックすると Resource ID をシュッと出してくれます。
az network bastion ssh --name "bast-hub00" `
--resource-group "simple-ars-nva" `
--target-resource-id "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/xxxxxxxxxxxx/providers/Microsoft.Compute/virtualMachines/vm-hub00" `
--auth-type "ssh-key" `
--username "xxxxxxxx" `
--ssh-key "C:\Users\kasakemi\.ssh\id_rsa"
まずはとりあえず sudo apt update
と sudo apt upgrade
とした後に、sudo reboot
しておきます。
そのあとは、公式の手順 に沿って進めていきます。
記事作成時点での script 配下のとおりです。
いつか使えなくなるかもしれないので一応折りたたんでおきまして、基本は公式の手順を見てください。
frr install
# add GPG key
curl -s https://deb.frrouting.org/frr/keys.asc | sudo apt-key add -
# possible values for FRRVER: frr-6 frr-7 frr-8 frr-stable
# frr-stable will be the latest official stable release
FRRVER="frr-stable"
echo deb https://deb.frrouting.org/frr $(lsb_release -s -c) $FRRVER | sudo tee -a /etc/apt/sources.list.d/frr.list
# update and install FRR
sudo apt update && sudo apt install frr frr-pythontools
よくあるパターンですが、GPG 鍵の追加、パッケージがおいてある場所の追加、sudo apt update
した後に sudo apt install
という感じですね。
FRRouting の設定
FRRouting のインストールまでが終わったので、実際に設定を入れていきます。
FRRouting は Cisco ライクな CLI を持っているのでこれを利用します。
その前に、BGP や OSPF などのプロトコルはそれぞれ機能の有効化/無効化を選ぶようになっており、規定ではすべて無効化されています。
/etc/frr/daemons
を編集し、bgpd=no
となっている個所を bgpd=yes
と編集したのちに、systemctl restart frr
で daemon を再起動します。
sudo sed -i.org 's/bgpd=no/bgpd=yes/' /etc/frr/daemons
sudo systemctl restart frr
そのあと、めんどうなので sudo -s
で上がった後に vtysh
と叩くと FRRouting の CLI で設定が可能になります。
root@vm-hub00:~# vtysh
Hello, this is FRRouting (version 8.3).
Copyright 1996-2005 Kunihiro Ishiguro, et al.
vm-hub00#
実際の設定の入力は conf t
を入力した後からです。
vm-hub00# conf t
vm-hub00(config)#
入力する内容は大まかにこんな感じです。
いくつかの点に気を付けて編集すれば大まかにはコピペで入力できるかと思います。
ip route 10.0.210.0/24 10.0.0.1
!
router bgp 65001
neighbor 10.0.210.4 remote-as 65515
neighbor 10.0.210.4 ebgp-multihop 255
neighbor 10.0.210.5 remote-as 65515
neighbor 10.0.210.5 ebgp-multihop 255
!
address-family ipv4 unicast
neighbor 10.0.210.4 soft-reconfiguration inbound
neighbor 10.0.210.4 route-map rmap-bogon-asns in
neighbor 10.0.210.4 route-map rmap-azure-asns out
neighbor 10.0.210.5 soft-reconfiguration inbound
neighbor 10.0.210.5 route-map rmap-bogon-asns in
neighbor 10.0.210.5 route-map rmap-azure-asns out
exit-address-family
exit
!
bgp as-path access-list azure-asns seq 5 permit _65515_
bgp as-path access-list bogon-asns seq 5 permit _0_
bgp as-path access-list bogon-asns seq 10 permit _23456_
bgp as-path access-list bogon-asns seq 15 permit _1310[0-6][0-9]_|_13107[0-1]_
bgp as-path access-list bogon-asns seq 20 deny _65515_
bgp as-path access-list bogon-asns seq 25 permit ^65
!
route-map rmap-bogon-asns deny 5
match as-path bogon-asns
exit
!
route-map rmap-bogon-asns permit 10
exit
!
route-map rmap-azure-asns deny 5
match as-path azure-asns
exit
!
route-map rmap-azure-asns permit 10
exit
!
-
ip route 10.0.210.0/24 10.0.0.1
Azure Route Server は RouteServerSubnet という別の subnet にあるため、経路が解決可能となるよう Static Route を入れておきます。 -
router bgp 65001
この 65001 という数字は 64512 から 65534 の間で、ある程度好きにきめられます。
これは Private AS Number と呼ばれている、内部ネットワークで自由に使える IP アドレスの AS 番号版という感じです。 -
neighbor 10.0.210.4 remote-as 65515
ここが BGP の一番基本的な設定です。
remote-as
は BGP の通信相手の AS 番号を書きますが、Azure Route Server は常に 65515 で動いています。 -
neighbor 10.0.210.4 ebgp-multihop 255
こまけぇ話は置いておきますが、これがないと BGP で受け取った経路が inactive となってしまいます。
詳しくはググっていただければと思いますが、とりあえず connected な範囲じゃない BGP peer に対してはこれがいるんです、はい。
Azure ならではの事情もあります。 -
neighbor 10.0.210.4 soft-reconfiguration inbound
これはなくてもいいです、あった方がトラブルシュートに役に立つやつです。
これを入れるとshow ip bgp nei x.x.x.x received-routes
で結果がとれるようになります。 -
neighbor 10.0.210.4 route-map rmap-bogon-asns in
とneighbor 10.0.210.4 route-map rmap-azure-asns out
bgp ebgp-requires-policy に記載がありますが、RFC8212 準拠するためにはなんらかの policy を掛けてあげる必要があり、せっかくならということで少しは意味あるものにしています。
前者については Bogon ASN filter policy configuration example を参考にさせていただきました。
だいぶ乱暴な気がするんだよなこれ。
Azure 内部で使っている ASN 65515 を例外扱いしています。
動作確認
うまくいけば show ip bgp nei x.x.x.x
で Establish が見えるかなと思います。
vm-hub00# show ip bgp nei 10.0.210.4
BGP neighbor is 10.0.210.4, remote AS 65515, local AS 65001, external link
BGP version 4, remote router ID 10.0.210.4, local router ID 10.0.0.4
BGP state = Established, up for 00:46:19
Last read 00:00:11, Last write 00:00:19
Hold time is 180, keepalive interval is 60 seconds
Configured conditional advertisements interval is 60 seconds
show ip bgp summary
で簡単なものがまとめてみれます。
Azure Route Server の 2 つの IP アドレスに対して、Up の時間が増えていれば大まかには大丈夫でしょう。
vm-hub00# show ip bgp sum
IPv4 Unicast Summary (VRF default):
BGP router identifier 10.0.0.4, local AS number 65001 vrf-id 0
BGP table version 7
RIB entries 1, using 192 bytes of memory
Peers 2, using 1447 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
10.0.210.4 4 65515 54 53 0 0 0 00:45:12 1 0 N/A
10.0.210.5 4 65515 55 53 0 0 0 00:45:14 1 0 N/A
Total number of neighbors 2
show ip bgp nei x.x.x.x received-routes
で「受け取っている」経路が見れます。
Azure Route Server は規定で「VNet のアドレス範囲全体」を経路広報してきます。
vm-hub00# show ip bgp nei 10.0.210.4 received-routes
BGP table version is 7, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 65001
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/16 10.0.210.4 0 65515 i
Total number of prefixes 1
show ip bgp nei x.x.x.x advertised-routes
で「広報している」経路が見れます。
が、この設定のままでは何も経路広報するものはないので何も出ないかと思います。
vm-hub00# show ip bgp nei 10.0.210.4 advertised-routes
vm-hub00#
例えば、ip route 10.0.0.0/8 10.0.0.1
を追加した後に、router bgp 65001
→ address-family ipv4
→ redistribute static
を追加すると Static Route で設定した経路が BGP で経路広報されていきます。
vm-hub00# show ip bgp nei 10.0.210.4 advertised-routes
BGP table version is 9, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 65001
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/8 0.0.0.0 0 32768 ?
*> 10.0.210.0/24 0.0.0.0 0 32768 ?
Total number of prefixes 2
見てのとおり 10.0.210.0/24 は不要な経路です。
簡単に prefix-filter
でこれを除いておきます。
こんな感じで追加の config を入れておきます。
ip prefix-list PRE01 seq 5 deny 10.0.210.0/24
ip prefix-list PRE01 seq 10 permit any
!
router bgp 65001
address-family ipv4 unicast
redistribute static
neighbor 10.0.210.4 prefix-list PRE01 out
neighbor 10.0.210.5 prefix-list PRE01 out
exit-address-family
exit
!
これにより、10.0.0.0/8 だけが経路広報されるように変わります。
vm-hub00# show ip bgp nei 10.0.210.4 advertised-routes
BGP table version is 9, local router ID is 10.0.0.4, vrf id 0
Default local pref 100, local AS 65001
Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.0.0.0/8 0.0.0.0 0 32768 ?
Total number of prefixes 1
まとめ
この記事はここまでとします。
実際の利用方法についてはまた別の記事にしようかと思います。
今回の真の目的は Bastion を使った SSH のメモと、FRRouting のインストール方法のメモでしたw
module として利用している Bicep ファイルを置いておきます。
bastion.bicep
param location string = 'eastasia'
param bastionName string = 'bast01'
param vnetName string
resource vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = {
name: vnetName
resource azureBastionSubnet 'subnets' existing = {
name: 'AzureBastionSubnet'
}
}
resource pip 'Microsoft.Network/publicIPAddresses@2022-01-01' = {
name: 'pip-${bastionName}'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAllocationMethod: 'Static'
}
}
resource bast01 'Microsoft.Network/bastionHosts@2022-01-01' = {
name: bastionName
location: location
sku: {
name: 'Standard'
}
properties: {
scaleUnits: 2
enableTunneling: true
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: { id: vnet::azureBastionSubnet.id }
publicIPAddress: { id: pip.id }
}
}
]
}
}
route-server.bicep
param location string
param routeServerName string
param vnetName string
param useExisting bool = false
param bgpConnections array = []
resource vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = {
name: vnetName
}
resource subnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' existing = {
parent: vnet
name: 'RouteServerSubnet'
}
resource pip 'Microsoft.Network/publicIPAddresses@2022-01-01' = {
name: 'pip-${routeServerName}'
location: location
sku: {
name: 'Standard'
}
properties: {
publicIPAllocationMethod: 'Static'
}
}
resource rs 'Microsoft.Network/virtualHubs@2022-01-01' = if (!useExisting) {
name: routeServerName
location: location
properties: {
sku: 'Standard'
allowBranchToBranchTraffic: true
}
resource ipconfig 'ipConfigurations' = if (!useExisting) {
name: 'ipconfig'
properties: {
publicIPAddress: { id: pip.id }
subnet: { id: subnet.id }
}
}
}
@batchSize(1)
resource bgp_conn 'Microsoft.Network/virtualHubs/bgpConnections@2022-01-01' = [for peer in bgpConnections: {
parent: rs
name: peer.name
properties: {
peerIp: peer.ip
peerAsn: peer.asn
}
dependsOn: [
rs::ipconfig
]
}]
ubuntu2004.bicep
param location string = 'eastasia'
param subnetId string
param vmName string
param adminUsername string = 'xxxxxxxx'
param keyData string
param enableNetWatchExtention bool = false
var vmNameSuffix = replace(vmName, 'vm-', '')
resource nic 'Microsoft.Network/networkInterfaces@2022-01-01' = {
name: 'nic-${vmNameSuffix}'
location: location
properties: {
ipConfigurations: [
{
name: 'ipconfig1'
properties: {
subnet: {
id: subnetId
}
privateIPAllocationMethod: 'Dynamic'
}
}
]
}
}
resource vm 'Microsoft.Compute/virtualMachines@2022-03-01' = {
name: vmName
location: location
properties: {
hardwareProfile: {
vmSize: 'Standard_B2ms'
}
storageProfile: {
osDisk: {
createOption: 'FromImage'
managedDisk: {
storageAccountType: 'StandardSSD_LRS'
}
deleteOption: 'Delete'
}
imageReference: {
publisher: 'canonical'
offer: '0001-com-ubuntu-server-focal'
sku: '20_04-lts-gen2'
version: 'latest'
}
}
networkProfile: {
networkInterfaces: [
{
id: nic.id
properties: {
deleteOption: 'Delete'
}
}
]
}
osProfile: {
computerName: vmName
adminUsername: adminUsername
linuxConfiguration: {
disablePasswordAuthentication: true
ssh: {
publicKeys: [
{
path: '/home/${adminUsername}/.ssh/authorized_keys'
keyData: keyData
}
]
}
}
}
diagnosticsProfile: {
bootDiagnostics: {
enabled: true
}
}
}
resource netWatchExt 'extensions' = if (enableNetWatchExtention) {
name: 'AzureNetworkWatcherExtension'
location: location
properties: {
autoUpgradeMinorVersion: true
publisher: 'Microsoft.Azure.NetworkWatcher'
type: 'NetworkWatcherAgentLinux'
typeHandlerVersion: '1.4'
}
}
}
resource shutdown 'Microsoft.DevTestLab/schedules@2018-09-15' = {
name: 'shutdown-computevm-${vmName}'
location: location
properties: {
status: 'Enabled'
taskType: 'ComputeVmShutdownTask'
dailyRecurrence: {
time: '00:00'
}
timeZoneId: 'Tokyo Standard Time'
targetResourceId: vm.id
notificationSettings: {
status: 'Disabled'
}
}
}
output vmName string = vm.name
output privateIP string = nic.properties.ipConfigurations[0].properties.privateIPAddress
Discussion