Today the fun starts, as I will start by building up the MPLS core, which will serve as the connecting element between the three/four sites in the topology.
R1 will be the provider router, R2, R3, and Prov1 will be the PE routers. So I'll quickly go through the basic IP connectivity, IGP (OSPF), MPLS and BGP configuration, before looking at the best way to secure the individual components.
If you are not familiar with MPLS, then please go and buy my book; MPLS for Cisco Networks. It is a good place to start learning MPLS and covers, in much more depth, the stuff I will whizz through.
Just to re-iterate previous post, I won't be dwelling on MPLS security. It's not explicitly stated on the blueprint, and it does not feature on the INE workbook either. Which means its a pretty good bet that it won't feature in the exam.
Let's start with the basic IP configuration:
R1(config)#int gi 0/0 R1(config-if)#desc Connection to R2 R1(config-if)#ip add 134.20.1.1 255.255.255.252 R1(config-if)#no shu R1(config-if)#do ping 134.20.1.2 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 134.20.1.2 .!!!! Success rate is 80 percent (4/5) R1(config-if)#int gi 0/1 R1(config-if)#desc Link to R3 R1(config-if)#ip add 134.20.1.5 255.255.255.252 R1(config-if)#no shu R1(config-if)#int gi 0/2 R1(config-if)#desc Link to Prov1 R1(config-if)#ip add 134.20.1.9 255.255.255.252 R1(config-if)#no shu R1(config-if)#int lo0 R1(config-if)#ip add 1.1.1.1 255.255.255.255 R1(config-if)#int lo8 R1(config-if)#ip add 8.8.8.8 255.255.255.255 R1(config-if)#do ping 134.20.1.6 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 134.20.1.6 .!!!! Success rate is 80 percent (4/5) R1(config-if)#do ping 134.20.1.10 Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 134.20.1.10 .!!!! Success rate is 80 percent (4/5) R1(config-if)# R2(config)#int gi 0/0 R2(config-if)#desc Connection to R1 R2(config-if)#ip add 134.20.1.2 255.255.255.252 R2(config-if)#no shut R2(config-if)# R2(config-if)#int lo0 R2(config-if)#ip add 2.2.2.2 255.255.255.255 R2(config-if)# R4(config)#int gi 0/1 R4(config-if)#desc Link to R1 R4(config-if)#ip add 134.20.1.6 255.255.255.252 R4(config-if)#no shu R4(config-if)# R4(config-if)#int lo0 R4(config-if)#ip add 4.4.4.4 255.255.255.255 R4(config-if)# Prov1(config)#int gi 0/0 Prov1(config-if)#desc Link to R1 Prov1(config-if)#ip add 134.20.1.10 255.255.255.252 Prov1(config-if)#no shu Prov1(config-if)# Prov1(config-if)#int lo0 Prov1(config-if)#ip add 10.10.10.10 255.255.255.255 Prov1(config-if)#I am going to use OSPF as my IGP, so let's configure that...
R1(config-if)#exi R1(config)#router ospf 1 R1(config-router)#router-id 1.1.1.1 R1(config-router)#network 0.0.0.0 0.0.0.0 area 0 R1(config-router)# R2(config-if)#router ospf 1 R2(config-router)#router-id 2.2.2.2 R2(config-router)#network 134.20.1.0 0.0.0.3 area 0 R2(config-router)#net 2.2.2.2 0.0.0.0 area 0 R2(config-router)# R4(config-if)#router ospf 1 R4(config-router)#router-id 4.4.4.4 R4(config-router)#net 134.20.1.4 0.0.0.3 ar 0 R4(config-router)#net 4.4.4.4 0.0.0.0 a 0 R4(config-router)# Prov1(config-if)#router ospf 1 Prov1(config-router)#router-id 10.10.10.10 Prov1(config-router)#net 134.20.1.10 0.0.0.0 a 0 Prov1(config-router)#net 10.10.10.10 0.0.0.0 a 0 Prov1(config-router)# R1(config-router)#do sh ip ospf neigh Neighbor ID Pri State Dead Time Address Interface 10.10.10.10 1 FULL/BDR 00:00:34 134.20.1.10 GigabitEthernet0/2 4.4.4.4 1 FULL/BDR 00:00:33 134.20.1.6 GigabitEthernet0/1 2.2.2.2 1 FULL/DR 00:00:37 134.20.1.2 GigabitEthernet0/0 R1(config-router)#Because we are running OSPF, we can use the command "mpls ldp autoconfig":
R1(config-router)#mpls ldp autoconfig R1(config-router)# R2(config-router)#mpls ldp autoconfig R2(config-router)# R4(config-router)#mpls ldp autoconfig R4(config-router)# Prov1(config-router)#mpls ldp autoconfig Prov1(config-router)# R1(config-router)# %LDP-5-NBRCHG: LDP Neighbor 2.2.2.2:0 (1) is UP %LDP-5-NBRCHG: LDP Neighbor 4.4.4.4:0 (2) is UP %LDP-5-NBRCHG: LDP Neighbor 10.10.10.10:0 (3) is UP R1(config-router)#Following a couple of best practices, we really should hard-code our label switching method, and our LDP router-id. At the moment the R1 will be using 8.8.8.8 as it's router ID, whereas I want to use 1.1.1.1:
R1(config-router)#exi R1(config)#mpls label protocol ldp R1(config)#mpls ldp router-id lo0 force R1(config)# R2(config-router)#mpls label protocol ldp R2(config)#mpls ldp router-id lo0 force R2(config)# R4(config)#mpls label protocol ldp R4(config)#mpls ldp router-id lo0 force R4(config)# Prov1(config-router)#mpls label protocol ldp Prov1(config)#mpls ldp router-id lo0 force Prov1(config)#Now we can configure MP-BGP:
R2(config)#router bgp 1 R2(config-router)#bgp router-id 2.2.2.2 R2(config-router)#no bgp def ipv4-unicast R2(config-router)#neigh 4.4.4.4 remote 1 R2(config-router)#neigh 10.10.10.10 remote 1 R2(config-router)#neigh 4.4.4.4 update lo0 R2(config-router)#neigh 10.10.10.10 update lo0 R2(config-router)#address-family vpnv4 R2(config-router-af)#neigh 4.4.4.4 activate R2(config-router-af)#neigh 10.10.10.10 activ R2(config-router-af)#neigh 4.4.4.4 send-community extended R2(config-router-af)#neigh 10.10.10.10 send-community extended R2(config-router-af)# R4(config)#router bgp 1 R4(config-router)#bgp router-id 4.4.4.4 R4(config-router)#no bgp def ipv4 R4(config-router)#neigh 2.2.2.2 remote 1 R4(config-router)#neigh 10.10.10.10 remote 1 R4(config-router)#neigh 2.2.2.2 update lo0 R4(config-router)#neigh 10.10.10.10 update lo0 R4(config-router)#add vpnv4 R4(config-router-af)#neigh 2.2.2.2 activ R4(config-router-af)#neigh 10.10.10.10 activ R4(config-router-af)#neigh 2.2.2.2 send-community extended R4(config-router-af)#neigh 10.10.10.10 send-community extended R4(config-router-af)# Prov1(config)#router bgp 1 Prov1(config-router)#bgp router-id 10.10.10.10 Prov1(config-router)#no bgp def ipv4 Prov1(config-router)#neigh 2.2.2.2 remote 1 Prov1(config-router)#neigh 4.4.4.4 remote 1 Prov1(config-router)#neigh 2.2.2.2 update lo0 Prov1(config-router)#neigh 4.4.4.4 update lo0 Prov1(config-router)#add vpnv4 Prov1(config-router-af)#neigh 2.2.2.2 activ Prov1(config-router-af)#neigh 4.4.4.4 activ Prov1(config-router-af)#neigh 2.2.2.2 send-comm ext Prov1(config-router-af)#neigh 4.4.4.4 send-comm ext Prov1(config-router-af)# R2#sh bgp vpnv4 uni all sum BGP router identifier 2.2.2.2, local AS number 1 BGP table version is 1, main routing table version 1 Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 4.4.4.4 4 1 4 4 1 0 0 00:02:25 0 10.10.10.10 4 1 13 14 1 0 0 00:10:30 0 R2# Prov1#sh bgp vpnv4 uni all sum BGP router identifier 10.10.10.10, local AS number 1 BGP table version is 1, main routing table version 1 Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd 2.2.2.2 4 1 14 13 1 0 0 00:10:52 0 4.4.4.4 4 1 7 6 1 0 0 00:04:15 0 Prov1#So far so good, now we need to set up our VRF. I will only be using one (at least for the moment):
R2(config)#ip vrf 802101 R2(config-vrf)#rd 1:1 R2(config-vrf)#route-target bo 1:1 R2(config-vrf)# R4(config-router-af)#ip vrf 802101 R4(config-vrf)# rd 1:1 R4(config-vrf)# route-target export 1:1 R4(config-vrf)# route-target import 1:1 R4(config-vrf)# Prov1(config)#ip vrf 802101 Prov1(config-vrf)# rd 1:1 Prov1(config-vrf)# route-target export 1:1 Prov1(config-vrf)# route-target import 1:1 Prov1(config-vrf)#Next we need to assign the relevant interfaces to the VRF:
R2(config-vrf)#int gi 0/1 R2(config-if)#ip vrf for 802101 R2(config-if)#ip add 128.2.2.2 255.255.255.252 R2(config-if)#desc Link to R3 R2(config-if)#no shu R2(config-if)# R4(config-vrf)#int gi 0/0 R4(config-if)#ip vrf for 802101 R4(config-if)#ip add 198.240.5.1 255.255.255.252 R4(config-if)#desc Link to CUSTFW01 R4(config-if)#no shu R4(config-if)# Prov1(config-vrf)#int gi 0/1 Prov1(config-if)#ip vrf for 802101 Prov1(config-if)#ip add 10.1.1.1 255.255.255.0 Prov1(config-if)#desc Link to ProvSW Prov1(config-if)#no shu Prov1(config-if)#And finally we add the VRF to BGP:
R2(config-if)#router bgp 1 R2(config-router)#add ipv4 vrf 802101 R2(config-router-af)# R4(config-if)#router bgp 1 R4(config-router)#add ipv4 vrf 802101 R4(config-router-af)# Prov1(config)#router bgp 1 Prov1(config-router)#add ipv4 vrf 802101 Prov1(config-router-af)#When we look at adding the sites together, we'll need to do redistribution between R3 and R2, CUSTFW01 and R4, and our HQ ASAs and the provider (Prov1), but it is not the intention to go that far just yet. Instead we'll now look at how we can secure the MPLS environment.
So, what can we, or should we secure? Our biggest danger, as it currently stands, is that someone could plug a router into the network, and it would not take them long to form an adjacency with us on OSPF or LDP. To gain access to BGP then they would have to perform some kind of man-in-the-middle attack and place themselves on the connecting wire - i.e. between R1 and R2, and then they would have to impersonate R2. This could easily be done through packet sniffing initially.
The simplest way in which we can protect ourselves is to implement some passwords. We will do this first on R2, below, and we can see that adding a password on it's own is good, but clearly not foolproof - if you gain access to the router, or to the configuration backups, then you can see that the password is stored in cleartext, unless you enable "service password-encryption":
R2(config)#router bgp 1 R2(config-router)#neigh 4.4.4.4 password 0 802101-Secrets R2(config-router)#do sh run | i password no service password-encryption neighbor 4.4.4.4 password 802101-Secrets R2(config-router)#service password-encryption R2(config)#do sh run | i password service password-encryption neighbor 4.4.4.4 password 7 135D47405A5C556718212B21303600 R2(config)#router bgp 1 R2(config-router)#neigh 10.10.10.10 password 0 802101-Secrets R2(config-router)#do sh run | i password service password-encryption neighbor 4.4.4.4 password 7 135D47405A5C556718212B21303600 neighbor 10.10.10.10 password 7 154A5B5E557A7A691B363630161305 R2(config-router)# R4(config)#router bgp 1 R4(config-router)#neigh 2.2.2.2 password 802101-Secrets R4(config-router)#neigh 10.10.10.10 password 802101-Secrets R4(config-router)#service password-encryption R4(config)# Prov1(config)#router bgp 1 Prov1(config-router)#neigh 2.2.2.2 password 802101-Secrets Prov1(config-router)#neigh 4.4.4.4 password 802101-Secrets Prov1(config-router)#service password-encryption Prov1(config)#Let's turn our attention to our MPLS configuration. We are not done with BGP security completely, we'll revisit it in a later post, where we'll look at ttl-security, which can only be done through eBGP peers.
We can do a number of things to secure our MPLS configuration from prying eyes. We can set a restriction on the route target values that we will import (and export):
R2(config)#ip extcommunity-list 101 permit RT:1:1 R2(config)#route-map ImportMap perm 10 R2(config-route-map)#match extcommunity 101 R2(config-route-map)#exit R2(config)#route-map ExportMap perm 10 R2(config-route-map)#match extcommunity 101 R2(config-route-map)#ip vrf 802101 R2(config-vrf)#export map ExportMap R2(config-vrf)#import map ImportMap R2(config-vrf)# R4(config)#ip extcommunity-list 101 permit RT:1:1 R4(config)#route-map ImportMap perm 10 R4(config-route-map)#match extcommunity 101 R4(config-route-map)#route-map ExportMap perm 10 R4(config-route-map)#match extcommunity 101 R4(config-route-map)#ip vrf 802101 R4(config-vrf)#export map ExportMap R4(config-vrf)#import map ImportMap R4(config-vrf)# Prov1(config)#ip extcommunity-list 101 permit RT:1:1 Prov1(config)#route-map ImportMap perm 10 Prov1(config-route-map)#match extcommunity 101 Prov1(config-route-map)#route-map ExportMap perm 10 Prov1(config-route-map)#match extcommunity 101 Prov1(config-route-map)#ip vrf 802101 Prov1(config-vrf)#export map ExportMap Prov1(config-vrf)#import map ImportMap Prov1(config-vrf)#The extended community list will match our route target (1:1), and permit it. The default deny rule will catch anything else, and this is then applied inbound and outbound to our VRF.
We can also set an LDP neighbor password. This is done below, and password encryption is turned on:
R1(config)#mpls ldp neigh 4.4.4.4 password 0 80201-Secret R1(config)#mpls ldp neigh 2.2.2.2 password 0 80201-Secret R1(config)#mpls ldp neigh 10.10.10.10 password 0 80201-Secret R1(config)#do sh run | i password no service password-encryption mpls ldp neighbor 4.4.4.4 password 80201-Secret mpls ldp neighbor 2.2.2.2 password 80201-Secret mpls ldp neighbor 10.10.10.10 password 80201-Secret R1(config)#service password-encryption R1(config)#do sh run | i password service password-encryption mpls ldp neighbor 4.4.4.4 password 7 135D47405B5D49192E273A3621 mpls ldp neighbor 2.2.2.2 password 7 025E54095B574212494D1B1C11 mpls ldp neighbor 10.10.10.10 password 7 04035B545F70017D0C1A171206 R1(config)# R2(config)#mpls ldp neighbor 1.1.1.1 password 0 802101-Secret R2(config)# R4(config-vrf)#mpls ldp neighbor 1.1.1.1 password 0 802101-Secret R4(config)# Prov1(config-vrf)#mpls ldp neighbor 1.1.1.1 password 0 802101-Secret Prov1(config)#Another best practice is to "hide" our MPLS network from our CE devices (should they do a trace route), the below command will do this:
R1(config)#no mpls ip propagate-ttl R1(config)#OSPF, similarly, can be password protected using MD5, this will have the immediate effect of the OSPF speakers losing their adjacencies, but I have omitted those messages:
R1(config)#router ospf 1 R1(config-router)#area 0 authentication message-digest R1(config-router)#int gi 0/0 R1(config-if)#ip ospf authentication message-digest R1(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret R1(config-if)#int g0/1 R1(config-if)#ip ospf authentication message-digest R1(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret R1(config-if)#int gi 0/2 R1(config-if)#ip ospf authentication message-digest R1(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret R1(config-if)# R2(config)#router ospf 1 R2(config-router)#area 0 authentication message-digest R2(config-router)#int gi 0/0 R2(config-if)#ip ospf authentication message-digest R2(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret R2(config-if)# %OSPF-5-ADJCHG: Process 1, Nbr 1.1.1.1 on GigabitEthernet0/0 from LOADING to FULL, Loading Done R2(config-if)# R4(config)#router ospf 1 R4(config-router)#area 0 authentication message-digest R4(config-router)#int gi 0/1 R4(config-if)#ip ospf authentication message-digest R4(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret R4(config-if)# %OSPF-5-ADJCHG: Process 1, Nbr 1.1.1.1 on GigabitEthernet0/1 from LOADING to FULL, Loading Done R4(config-if)# Prov1(config)#router ospf 1 Prov1(config-router)#area 0 authentication message-digest Prov1(config-router)#int gi 0/0 Prov1(config-if)#ip ospf authentication message-digest Prov1(config-if)#ip ospf message-digest-key 1 md5 0 802101-Secret Prov1(config-if)# %OSPF-5-ADJCHG: Process 1, Nbr 1.1.1.1 on GigabitEthernet0/0 from LOADING to FULL, Loading Done %BGP-5-NBR_RESET: Neighbor 4.4.4.4 active reset (BGP Notification sent) %BGP-5-ADJCHANGE: neighbor 4.4.4.4 Up %BGP-5-NBR_RESET: Neighbor 2.2.2.2 active reset (BGP Notification sent) %BGP-5-ADJCHANGE: neighbor 2.2.2.2 Up Prov1(config-if)#OK, all looks fine so far. But what happened after OSPF got torn down and the neighborships reestablished? LDP wouldn't come up. The passwords were there, but the message (Invalid MD5 digest) indicates that the password is wrong.
R1(config-router)#do sh run | i password service password-encryption mpls ldp neighbor 4.4.4.4 password 7 135D47405B5D49192E273A3621 mpls ldp neighbor 2.2.2.2 password 7 025E54095B574212494D1B1C11 mpls ldp neighbor 10.10.10.10 password 7 04035B545F70017D0C1A171206 R1(config-router)#do sh ip ospf neigh Neighbor ID Pri State Dead Time Address Interface 10.10.10.10 1 FULL/DR 00:00:39 134.20.1.10 GigabitEthernet0/2 4.4.4.4 1 FULL/DR 00:00:33 134.20.1.6 GigabitEthernet0/1 2.2.2.2 1 FULL/DR 00:00:38 134.20.1.2 GigabitEthernet0/0 R1(config-router)#exit R1(config)#logging con R1(config)# %TCP-6-BADAUTH: Invalid MD5 digest from 2.2.2.2(13861) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 4.4.4.4(19675) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(16183) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 2.2.2.2(13861) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 4.4.4.4(39459) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(16183) to 1.1.1.1(646) tableid - 0So what is happening here?
Well, in one of those "can't see the wood for the trees" moments, I fat-fingered the configuration on R1. It took me running the password through a password cracker to see the difference. Just goes to prove you should pick a password that makes spotting mistakes easy to do. Alternatively, a much better approach is to do it all on one router, and then copy the encrypted password from the "master" to the other routers - using "mpls ldp neigh <neighbor> password 7 <encrypted password>". Below you can see that once thew password was copied from R1 onto R2, the error cleared and LDP came up.
The full compare, replace and contrast sequence is below:
%LDP-5-NBRCHG: LDP Neighbor 2.2.2.2:0 (1) is UP %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(16183) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 4.4.4.4(39459) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(49475) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(49475) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 4.4.4.4(60395) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 4.4.4.4(60395) to 1.1.1.1(646) tableid - 0 %TCP-6-BADAUTH: Invalid MD5 digest from 10.10.10.10(49475) to 1.1.1.1(646) tableid - 0 R1(config)#no logging con R1(config)# R2(config-if)#do sh run | i password service password-encryption mpls ldp neighbor 1.1.1.1 password 7 09141E5B4855465F380907382E30 neighbor 4.4.4.4 password 7 135D47405A5C556718212B21303600 neighbor 10.10.10.10 password 7 154A5B5E557A7A691B363630161305 R2(config-if)#mpls ldp neighbor 1.1.1.1 password 7 025E54095B574212494D1B1C11 R2(config)# %LDP-5-PWDCFG: Password configuration changed for 1.1.1.1:0 %LDP-5-NBRCHG: LDP Neighbor 1.1.1.1:0 (1) is UP R4(config)#do sh run | i password service password-encryption mpls ldp neighbor 1.1.1.1 password 7 1016594B544743463F012939213C neighbor 2.2.2.2 password 7 0757711E1F5948482417081E013E38 neighbor 10.10.10.10 password 7 065E5F731D1E585436121119091039 R4(config)#mpls ldp neighbor 1.1.1.1 password 7 135D47405B5D49192E273A3621 R4(config)# %LDP-5-PWDCFG: Password configuration changed for 1.1.1.1:0 R4(config)# %LDP-5-NBRCHG: LDP Neighbor 1.1.1.1:0 (1) is UP Prov1(config)#do sh run | i password service password-encryption mpls ldp neighbor 1.1.1.1 password 7 135D47405A5C556718212B213036 neighbor 2.2.2.2 password 7 09141E5B4855465F380907382E303B neighbor 4.4.4.4 password 7 1016594B544743463F012939213C20 Prov1(config)#neighbor 1.1.1.1 password 7 04035B545F70017D0C1A171206 Prov1(config)# %LDP-5-PWDCFG: Password configuration changed for 1.1.1.1:0 Prov1(config)# %LDP-5-NBRCHG: LDP Neighbor 1.1.1.1:0 (1) is UP Prov1(config)# R1#sh mpls ldp neigh | i Ident Peer LDP Ident: 2.2.2.2:0; Local LDP Ident 1.1.1.1:0 Addresses bound to peer LDP Ident: Peer LDP Ident: 4.4.4.4:0; Local LDP Ident 1.1.1.1:0 Addresses bound to peer LDP Ident: Peer LDP Ident: 10.10.10.10:0; Local LDP Ident 1.1.1.1:0 Addresses bound to peer LDP Ident: R1#Not a bad start. I learnt something (about properly using password encryption), and I have a basis for the network to start to evolve.
I am currently reading "MPLS VPN Security", which is pretty good, lot's of theory and explanation, but a little light on configuration. Still, definitely a good purchase so far.
There is a good inclusion on access-lists, below is one with would permit BGP, OSPF, and LDP:
access-list 110 permit tcp host x.x.x.x host loopback eq bgp access-list 110 permit ospf host x.x.x.x host 224.0.0.5 access-list 110 permit ospf host x.x.x.x host 224.0.0.6 access-list 110 permit ospf host x.x.x.x host local_ip access-list 110 permit tcp address mask any eq 646 access-list 110 permit udp address mask any eq 646I think I will save this for later on though, when all the tunnels are in place. The next post will either be about transparent firewalls, or Multiple-context firewalls.