Migrating from USG to UCG Ultra.

A friend of mine and I were recently looking into setting up the Unifi SDWAN between our Homelabs, his in Sydney, mine in Perth. We discovered that the Unifi Security Gateway line of Unifi Routers was not supported and a Unifi Cloud Gateway or Dream Machine was required. Being a little trigger happy, he immediately ordered 2 UCG Ultra’s! I had a mild panic as my Homelab is very tightly integrated into the Unifi Security Gateway and the config.gateway.json way of managing the non-supported config (BGP routing, Custom DNSMasq entries being the main ones). After a little digging around, I found that the UCG Ultra, if using the Unifi Early access firmware branch, could do everything that I needed and would probably make support easier and my network faster.

Migration Approach

  1. Develop frr.conf
  2. Upgrade UCG to Early Access Release Channel
  3. Backup and Restore Unifi Config
  4. Create Custom DNS Records
  5. Enable ssh
  6. Enable BGP
  7. Update Port Forwarding and Firewall Rules
  8. Add more BGP config for Proxmox SDN

Develop frr.conf

My thinking here was that the best way to create a valid Free Range Routing config frr.conf that wasn’t going to screw up the UCG was to develop it using the Virtual Router Shell vtysh on a dev machine. So on a spare Debian 12 machine setup:

sudo apt install frr
sudo sed -i -e 's/bgpd\=no/bgpd\=yes/g' /etc/frr/daemons # change bgpd=no to bgpd=yes in /etc/frr/daemons
sudo systemctl enable frr
sudo systemctl start frr

Now we have the BGP binaries setup and a working vtysh to use, we can now start the Virtual Router Shell and create our BGP configuration. To start the Virtual Router Shell:

debtestvm# sudo vtysh

Hello, this is FRRouting (version 8.4.4..
Copyright 1996-2005 Kunihiro Ishiguro, et al.

The Virtual Router Shell uses the Cisco sytle configration syntax. So you can do things like show run to see the running configuration and conf t to “Configure Terminal” and make changes to the configuration.

debtestvm# show run
Building configuration...

Current configuration:
!
frr version 8.4.4
frr defaults traditional
hostname debtestvm
log syslog informational
service integrated-vtysh-config
!
end

Ok, lets get started. Recall the design shared in the post Anycast Reverse Proxy with ExaBGP USG and HAProxy.

Anycast Reverse Proxy diagram

Basic BGP Config

We can see from the diagram that this router is part of BGP Autonomous System 65002. It is peering with 2 BGP neighbors (neighbors), 192.168.2.2 and 192.168.3.3. In this dev environment, this router has no connectivity to those peers but that doesn’t matter, what we are trying achieve is a valid configration file that we can port to our Prod router. Not shown in the diagram is that this router will have the IP 192.168.254.1 so that will be its BGP router-id. Lets start. First we set our local router-id, hostname and domainname; then we enter router config mode for AS 65002 and add basic configuation for our BGP neighbours. Being iBGP, we share the same AS as our neighbors. Don’t forget to commit the changes! wr me or do wr me if you’re config mode:

debtestvm# conf t
debtestvm(config)# router-id 192.168.254.1
debtestvm(config)# hostname Cloud-Gateway-Ultra
debtestvm(config)# domainname mgmt.etse.me
debtestvm(config)# router bgp 65002
debtestvm(config-router)# neighbor 192.168.2.2 remote-as 65002
debtestvm(config-router)# neighbor 192.168.3.3 remote-as 65002
debtestvm(config-router)# do wr me
Note: this version of vtysh never writes vtysh.conf
Building Configuration...
Integrated configuration saved to /etc/frr/frr.conf
[OK]

Prefix Lists

Ok so we have enough configuration now to setup a peering relationship with our neighbours but at this point we are not accepting any IPv4 or IPv6 prefixes from them. Before we do that, we need to put some prefix lists in place that we can use to filter incoming routes to just those that we want and block anything that might cause us routing problems. For our Reverse Proxy use case, this is quite simple as we only want accept one IPv4 address and one IPv6 address (192.168.4.4/32 & 2406:3400:658:105::4:4/128).
To create them, firstly drop out of the router config using exit. We tend to name the prefix lists by the service and the direction. Eg haproxy-in denotes that the routes are for haproxy and the “IN” indicates that we are receiving the routes from a peer, rather than sending them to a peer.

debtestvm(config-router)# exit
debtestvm(config)# ip prefix-list HAProxy-IN seq 5 permit 192.168.4.4/32 
debtestvm(config)# ipv6 prefix-list HAProxy6-IN seq 5 permit 2406:3400:658:105::4:4/128

To apply those prefix lists to our neighbours:

debtestvm(config)# router bgp 65002
debtestvm(config-router)# address-family ipv4 unicast
debtestvm(config-router-af)# neighbor 192.168.2.2 prefix-list HAProxy-IN in
debtestvm(config-router-af)# neighbor 192.168.2.2 soft-reconfiguration inbound
debtestvm(config-router-af)# neighbor 192.168.3.3 prefix-list HAProxy-IN in
debtestvm(config-router-af)# neighbor 192.168.2.2 soft-reconfiguration inbound
debtestvm(config-router-af)# exit
debtestvm(config-router)# address-family ipv6 unicast
debtestvm(config-router-af)# neighbor 192.168.2.2 prefix-list HAProxy6-IN in
debtestvm(config-router-af)# neighbor 192.168.2.2 activate
debtestvm(config-router-af)# neighbor 192.168.3.3 prefix-list HAProxy6-IN in
debtestvm(config-router-af)# neighbor 192.168.3.3 activate
debtestvm(config-router-af)# exit

Notes:

Route Maps

Route Maps can be used for all sorts of things with BGP. In our case, we are simply going to use route maps to tell BGP to prefer the routes receievd from the BGP Peer on our “primary” HAProxy node. We set the local-preference attribute - the higher number is the preferred Peer. First we create the route map, then we apply the route map to the neighbour. Firstly make sure you are in config mode, not config-router mode. The prompt should be debtestvm(config)#.

debtestvm(config-router)# exit
debtestvm(config)# route-map hap01-in permit 5
debtestvm(config-route-map)# set local-preference 200
debtestvm(config-route-map)# exit
debtestvm(config)# route-map hap02-in permit 5
debtestvm(config-route-map)# set local-preference 100
debtestvm(config-route-map)# exit

Now to apply the route maps to the Peers, specifiying that the direction of the routes is in:

debtestvm(config)# router bgp 65002
debtestvm(config-router)# address-family ipv4 unicast
debtestvm(config-router-af)# neighbor 192.168.2.2 route-map hap01-in in
debtestvm(config-router-af)# neighbor 192.168.3.3 route-map hap02-in in
debtestvm(config-router-af)# exit
debtestvm(config-router)# exit
debtestvm(config)# do wr me
Note: this version of vtysh never writes vtysh.conf
Building Configuration...
Integrated configuration saved to /etc/frr/frr.conf
[OK]

Review Config

Now lets have a look at what our final configuration for our HAProxy BGP relationship looks like:

debtestvm(config)# do show run
Building configuration...

Current configuration:
!
frr version 8.4.4
frr defaults traditional
router-id 192.168.254.1
hostname Cloud-Gateway-Ultra
domainname mgmt.etse.me
log syslog informational
service integrated-vtysh-config
!
ip router-id 192.168.254.1
!
router bgp 65002
 neighbor 192.168.2.2 remote-as 65002
 neighbor 192.168.3.3 remote-as 65002
 !
 address-family ipv4 unicast
  neighbor 192.168.2.2 soft-reconfiguration inbound
  neighbor 192.168.2.2 prefix-list HAProxy-IN in
  neighbor 192.168.2.2 route-map hap01-in in
  neighbor 192.168.3.3 route-map hap02-in in
 exit-address-family
 !
 address-family ipv6 unicast
  neighbor 192.168.2.2 activate
  neighbor 192.168.2.2 prefix-list HAProxy6-IN in
  neighbor 192.168.3.3 prefix-list HAProxy6-IN in
 exit-address-family
exit
!
ip prefix-list HAProxy-IN seq 5 permit 192.168.4.4/32
!
ipv6 prefix-list HAProxy6-IN seq 5 permit 2406:3400:658:105::4:4/128
!
route-map hap01-in permit 5
 set local-preference 200
exit
!
route-map hap02-in permit 5
 set local-preference 100
exit
!
end

Backup Dev Config File

Take a copy of the /etc/frr/frr.conf that we have been creating on our dev machine. Eg:

scp /etc/frr/frr.conf user@hostname:~/

Prepare

  1. Configure a Guest Network port on your existing LAN, ensuring that Guest isolation is enabled to block it from seeing the rest of your network.
  2. Plug in the Cloud Gateway Ultra WAN Port to the Guest LAN port
  3. Setup the Unifi Cloud Gateway Ultra as a new temporary Unifi Site

Enable Early Access Release Channel

  1. Access the Management Console at https://192.168.1.1 and login with default creds ubnt/ubnt
  2. Enable Early Access Release Channel: Management UI -> Settings -> Control Plane. Under Unifi OS click on “UCG Ultra” and in the popup menu, change Relase Channel to “Early Access”.
  3. Update the UCG Ultra to the latest Early Access release which (at time of writing) is UCG Ultra: 4.1.13 / Network Application: 9.0.108

Backup and Restore Unifi Config

  1. Take a final backup copy of your Unifi Application via the GUI and download it to your machine. I excluded the history, YMMV.
  2. Power on the Cloud Gateway Ultra and connect laptop to one of the LAN ports.
  3. Access the Management Console at https://192.168.1.1 and login with default creds ubnt/ubnt
  4. Restore the Unifi Network Application Backup from Step 1

Cutover to UCG Ultra

  1. Shutdown the Unifi Network Application LXC / VM
  2. Poweroff the Unifi Security Gateway
  3. Reroute WAN and LAN links from USG to UCG.
  4. Power on UCG
  • At this point, I allowed some time for my network to come back up and did some checks that my devices were working.
  • A ended up restarting my Proxmox VM’s and LXC’s so that that DHCP would re-register their names in DNSMasq

Create Custom DNS Records

  1. Now that the UCG is in Prod, and assuming that your Internet connection came back up, you can manage your Unifi system as https://unifi.ui.com. Login using your UI creds.
  2. Go-to Settings -> Routing -> DNS
  3. Create appropriate entries, as per your config.gateway.json dns forwarding options. Only limitation at tome of writing is CNAME records and PTR records.

Enable SSH Access

  1. Goto Settings -> System -> Advanced
  2. Tick “Device SSH Authentication”
  3. Provide a user name and password to use for ssh. Key based ssh didn’t work for me, not sure why.

Enable BGP

  1. ssh to the UCG Ultra ssh root@192.168.254.1 (note for me, the username supplied in the step above didn’t apply, i needed to use root)
  2. sed -i -e 's/bgpd\=no/bgpd\=yes/g' /etc/frr/daemons to change bgpd=no to bgpd=yes in /etc/frr/daemons
  3. Copy our Dev Config file to the UCG: scp ~/frr.conf root@Cloud-Gateway-Ultra:/etc/frr/frr.conf
  4. systemctl enable frr enable the Free Range Routing service so that it will start automatically on UCG boot.
  5. systemctl start frr start the Free Range Routing service
  6. vtysh use the Virtual Router Shell to confirm that we are receieving routes:
frr# show ip route
Codes: K - kernel route, C - connected, S - static, O - OSPF,
       B - BGP, T - Table, f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

C>* 10.10.0.2/32 is directly connected, tun1, 4d02h54m
C>* 10.64.0.0/24 is directly connected, br64, 5d00h00m
C>* 10.192.0.0/18 is directly connected, br192, 5d00h00m
C>* 10.254.0.0/26 is directly connected, br254, 5d00h00m
K>* 192.168.1.0/24 [0/0] via 10.10.0.2, tun1, 4d02h54m
C>* 192.168.2.0/24 is directly connected, br2, 5d00h00m
C>* 192.168.3.0/24 is directly connected, br3, 5d00h00m
B>* 192.168.4.4/32 [200/100] via 192.168.2.2, br2, weight 1, 5d00h00m
C>* 192.168.254.0/24 is directly connected, br0, 5d00h00m
C>* 220.233.1.69/32 is directly connected, ppp0, 4d02h42m

Note the route prefixed with B which denotes a route learned from BGP: B>* 192.168.4.4/32 [200/100] via 192.168.2.2, br2, weight 1, 5d00h00m

We can look at the IPv6 routes also, once again prefixed with a B - note that there appears to be an issue with weighting on the IPv6 routes, something I need to fix:

frr# show ipv6 route
Codes: K - kernel route, C - connected, S - static, B - BGP,
       T - Table, f - OpenFabric,
       > - selected route, * - FIB route, q - queued, r - rejected, b - backup
       t - trapped, o - offload failure

C>* 2406:3400:600:69:9ab:1bb3:91ae:5856/128 is directly connected, ppp0, 4d02h43m
C>* 2406:3400:658:100::/64 is directly connected, br0, 5d00h02m
C>* 2406:3400:658:101::/64 is directly connected, br192, 5d00h02m
C>* 2406:3400:658:102::/64 is directly connected, br2, 5d00h02m
C>* 2406:3400:658:103::/64 is directly connected, br254, 5d00h02m
C>* 2406:3400:658:104::/64 is directly connected, br3, 5d00h02m
B>* 2406:3400:658:105::4:4/128 [200/100] via 2406:3400:658:102:be24:11ff:feda:1670, br2, weight 1, 2d11h43m
  *                                      via 2406:3400:658:104:be24:11ff:fef6:b89, br3, weight 1, 2d11h43m
C * fe80::/64 is directly connected, tun1, 4d02h55m
C * fe80::/64 is directly connected, eth4, 4d02h57m
C * fe80::/64 is directly connected, br64, 5d00h02m
C * fe80::/64 is directly connected, br3, 5d00h02m
C * fe80::/64 is directly connected, br254, 5d00h02m
C * fe80::/64 is directly connected, br2, 5d00h02m
C * fe80::/64 is directly connected, br192, 5d00h02m
C * fe80::/64 is directly connected, br0, 5d00h02m
C * fe80::/64 is directly connected, switch0.64, 5d00h02m
C * fe80::/64 is directly connected, switch0.3, 5d00h02m
C * fe80::/64 is directly connected, switch0.254, 5d00h02m
C * fe80::/64 is directly connected, switch0.2, 5d00h02m
C * fe80::/64 is directly connected, switch0.192, 5d00h02m
C * fe80::/64 is directly connected, switch0.1, 5d00h02m
C * fe80::/64 is directly connected, eth3, 5d00h02m
C * fe80::/64 is directly connected, eth2, 5d00h02m
C * fe80::/64 is directly connected, eth1, 5d00h02m
C * fe80::/64 is directly connected, eth0, 5d00h02m
C>* fe80::/64 is directly connected, switch0, 5d00h02m
C>* fe80::3e08:f6ff:fee5:0/128 is directly connected, ppp0, 4d02h43m
C>* fe80::9c3a:5edf:4d32:4bf9/128 is directly connected, ppp0, 4d02h43m

Add Port Forward and Firewall Rule for HAProxy

  • This was originally in my config.gateway.json so now I need to use the GUI to add a Port Forwarding fule for TCP/80 and TCP/443 to 192.168.4.4
  • As above, for the IPv6 access, use the GUI to add a firewall rule to allow Source Any, Dest 2406:3400:658:105::4:4/128 on TCP/80 and TCP/443.

MORE BGP Configuration (Proxmox SDN)

A little addendum to the BGP work. I also need to move the BGP config from the Unifi Security Gateway for the BGP Peering with Proxmox SDN so that the L2VPN / VXLAN zones are reachable to the rest of the network.

Proxmox SDN BGP

For this work, I am going to start by configuring the prefix lists so that they are ready when I setup the BGP neighbours. In this instance, the danger of a route leaking from the SDN network into my Prod network is very real and indeed did cause a “Denial of BBL” incident for a 90 minute period when I set this up (essentially the Proxmox SDN network was advertising a defaul route which the UCG was not setup to filter - oops!).

Proxmox SDN currently has two Zones configured which both live within the 10.100.0.0/16 IP range. So my prefix lists need simply to filter everything except that prefix. I assume this is best practise but I am also going to setup a prefix list to explicitly deny a default route 0.0.0.0/0 coming from the Proxmox SDN BGP Peers. Note the ge 16 below. This says that it will accept a prefix that is greater than 16 bits long. So any prexies with mask of /16 - /32 are acceptable.

Connect to your UCG via ssh ssh root@192.168.254.1 then enter the Virtual Router Shell vtysh:

debtestvm# conf t
debtestvm(config)# ip prefix-list PVE-IN seq 10 permit 10.100.0.0/16 ge 16
debtestvm(config)# ip prefix-list PVE-IN seq 20 deny 0.0.0.0/0
debtestvm(config)# do wr me

Now we can setup the BGP neighbours:

debtestvm(config)# router bgp 65002
debtestvm(config-router)# neighbor 192.168.254.21 remote-as 65005
debtestvm(config-router)# neighbor 192.168.254.167 remote-as 65005

…and configure the route propogation:

  • redistribute connected / redistribute static tells BGP to advertise any directly connected, or any static routed networks, to its Peers.
  • default-originate tells BGP to advertise itself as a default route to its BGP Peers. We want this so that our Proxmox SDN VM’s have a route to the internet and the rest of the network.
  • soft-reconfiguration inbound explained better than I understand here -> BGP Soft Reconfiguration
debtestvm(config-router)# address-family ipv4 unicaset
debtestvm(config-router-af)# network 10.100.0.0/16
debtestvm(config-router-af)# redistribute connected
debtestvm(config-router-af)# redistribute static
debtestvm(config-router-af)# neighbor 192.168.254.21 prefix-list PVE-IN in
debtestvm(config-router-af)# neighbor 192.168.254.167 prefix-list PVE-IN in
debtestvm(config-router-af)# neighbor 192.168.254.21 default-originate
debtestvm(config-router-af)# neighbor 192.168.254.167 default-originate
debtestvm(config-router-af)# neighbor 192.168.254.21 soft-reconfiguration inbound
debtestvm(config-router-af)# neighbor 192.168.254.167 soft-reconfiguration inbound
debtestvm(config-router-af)# do wr me

© 2021. All rights reserved.

Powered by Hydejack v9.1.6