Monday, August 15, 2016

Dynamic Site-2-Site VPNs with Cisco ASA

So let's take a moment and assume your life is too easy, and you want to punish yourself. But how?! Here's a way, let's use the ASA for sites-2-site VPN. Even better, the spoke sites have be able to have dynamic IPs, and also need connectivity to other spokes. Also, IKEv2. Just because. Everyone ready?! I know I am.




Honestly, it's actually incredibly easy. If you're not familiar with the ASA's ability to form dynamic L2L tunnels this post might be an eye opener. The tricky part is getting spoke to spoke connectivity in a reasonable fashion. However, we'll cross that bridge when we come to it. Let's look at the amazingly complex and overwhelming topology we'll be working with today.


Give yourself a few minutes to study all the minute details. Alright, let's get the hub configured. Luckily this is actually really easy.

crypto ikev2 policy 10
 encryption aes-256
 integrity sha512
 group 2
 prf sha      
 lifetime seconds 28800
!
crypto ikev2 enable OUTSIDE
!
crypto ipsec ikev2 ipsec-proposal AES256
 protocol esp encryption aes-256
 protocol esp integrity sha-512
!
crypto ipsec security-association lifetime seconds 3600
!
crypto dynamic-map DYNAMIC-S2S 1 set pfs 
crypto dynamic-map DYNAMIC-S2S 1 set ikev2 ipsec-proposal AES256
crypto dynamic-map DYNAMIC-S2S 1 set reverse-route
crypto map VPNMAP 65535 ipsec-isakmp dynamic DYNAMIC-S2S
crypto map VPNMAP interface OUTSIDE
!
tunnel-group DefaultL2LGroup ipsec-attributes
 ikev2 remote-authentication pre-shared-key cisco123
 ikev2 local-authentication pre-shared-key cisco123

That's about it for the crypto. The tunnel-group name has to be DefaultL2LGroup. One thing of particular note that I do not care for, with this model any dynamic tunnel peers have to share the same PSK. You'll also take notice I didn't specify any interesting traffic, nor did I set any peers. I also really like using reverse-route to inject static routes into the RIB, if you're going to do that on the Hub just keep in mind you have to do this under the dynamic map.

Now on the Hub, let's setup our nat exempt which will look a little different than it does on spoke ASAs.


object-group network ALLSITES
 network-object 192.168.1.0 255.255.255.0
 network-object 192.168.2.0 255.255.255.0
 network-object 192.168.3.0 255.255.255.0
!
nat (any,OUTSIDE) source static ALLSITES ALLSITES destination static ALLSITES ALLSITES
!

So pretty basic, we're just using a single object-group with our subnets included. Then in the actual NAT configuration we're saying the internal nameif is "any". This is because as traffic transits the hub from spoke-2-spoke, we want this policy to pick that up along with traffic from the Hub's inside to Spokes. Alternatively, you could have separate NAT statements. One for (INSIDE,OUTSIDE) and another for (OUTSIDE,OUTSIDE). The later of which being for spoke-2-spoke communication. Alright! Moving along, the config on the spokes looks a little something like this.

crypto ikev2 policy 10
 encryption aes-256
 integrity sha512
 group 2
 prf sha      
 lifetime seconds 28800
!
crypto ikev2 enable OUTSIDE
!
crypto ipsec ikev2 ipsec-proposal AES256
 protocol esp encryption aes-256
 protocol esp integrity sha-512
!
crypto ipsec security-association lifetime seconds 3600
!
object-group network LAN

 network-object 192.168.2.0 255.255.255.0
!
access-list L2LVPN extended permit ip object-group S2 192.168.0.0 255.255.0.0 
!
crypto map VPNMAP 1 match address L2LVPN
crypto map VPNMAP 1 set pfs 
crypto map VPNMAP 1 set peer 200.1.1.1 
crypto map VPNMAP 1 set ikev2 ipsec-proposal AES256

crypto map VPNMAP interface OUTSIDE
!
tunnel-group 200.1.1.1 type ipsec-l2l
tunnel-group 200.1.1.1 ipsec-attributes
 ikev2 remote-authentication pre-shared-key cisco123

 ikev2 local-authentication pre-shared-key cisco123
!
nat (INSIDE,OUTSIDE) source static ALLSITES ALLSITES destination static ALLSITES ALLSITES
!


That's right, stock standard L2L VPN tunnel back to the hub. The above config is applied to ASAv2, however the only change in the configuration on ASAv3 is in "object-group network LAN", instead of 192.168.2.0, ASAv3 has 192.168.3.0. For our interesting traffic we're saying anything from our local subnet going to 192.168.0.0/16. This is pretty important, in order to have consistent and mostly reliable communication between spokes, we need the SA formed with the hub to also cover traffic to other spokes. I demonstrated why in my video below. The quick and dirty answer is, the Hub doesn't build tunnels outbound. Just by design, it's responder only within the DefaultL2LGroup tunnel. So while ASAv2 will build it's SA for S2>>S3 to the Hub, the Hub can't actually build the second half of that connection. Leaving you seeing a single SA for 192.168.2.0>>192.168.3.0 with the peer being ASAv2. The hub can receive that traffic, but will be unable to build the new SA out to S3 to actually forward it along. Again though, this is a non-issue if your Spokes are building tunnels where the destination covers all remote spoke subnets.


Well I could ramble on a bit longer, but that's the jist of it boys and girls. Linking the video below.


Sunday, July 31, 2016

How to Not Suck at Web Filtering: Cisco's Web Security Appliance Part (1)

So I'll start off by saying, configuring the WSA isn't too terribly hard. What seems to be tricky, is getting all the components working together in a way that provides a seamless experience for users, while providing accurate reporting and filtering. In this two parter, I'm going to attempt to get us from a based environment (Active Directory Domain, (1) DC, (1) Client PC, and an ASA Firewall) all the way to having the following requirements met: 

  • HTTP Filtering
  • HTTPS Filtering/Decrypting
  • Transparent Proxy 
  • AD Integration
  • Single Sign-on

Again, none of this is too difficult, there's just a lot of moving pieces. Sadly, many of those pieces are on the Systems side. So buckle up! In this first part, we're going to kick out all the server side stuff that makes web filtering as transparent and effective as possible. I know, I know "But JJoooooonnnnnnnn, this is a networking blog!! I don't like doing systems work!!"




I don't like it anymore than you. That said, it's important to know all these things so you can accurately make demands of your Server team! Also, if you want a working lab or POC, you'll have to do this stuff anyway. That said, I'm not a fan of text only guides for Windows. They just don't translate well, AND I loathe taking a million screen shots. So, I'll outline the general tasks below and then link to my YouTube video for this 1st part.


Prereqs:
  1. Windows Server 2008 (or newer) Domain Controller
  2. Windows 7 (or newer) client, joined to the domain
  3. Cisco ASA or IOS Router with WCCP support
  4. Cisco Web Security Appliance (using WSAv w/45 day demo license for this post)

Ingredients:
  • Active Directory Certificate Services (Enterprise Root)
    • Web Enrollment supported
  • Root CA certificate for WSA (or any cert with Subject Type=CA)
  • Server Certificate for WSA
  • URL to WSA in Window's "Trusted Sites"
    • Trusted Sites set to "Automatic Logon with Current Username and Password"
    • Can be done with GP, login script, or manually.
  • WSA joined to AD domain
  • Identification Policies for AD Users
    • And whatever access policies based on users/groups.
  • WCCP configured on router/firewall to redirect http/https traffic to WSA.

Video:



Monday, June 20, 2016

Using VXLAN to extend my home lab

So first off, I recently had a change of heart. While I still love Service Provider, I'm continually being pulled in for Security work. So, I've decided to stop resisting and follow the current. That said, CCIE Security (both v4 and v5) have some heavy demands. While my home server has plenty of RAM (96GB) and CPU... I ran out of disk space really fast. So naturally, I ordered some new 1TB drives to help out, but does that mean I should stop studying until the drives arrive?? No.




My workstation upstairs (server is in the garage) has 32GB of RAM, plenty of spare disk space... but how to get my VMs to appear on the same VLANs as VMs running downstairs in the garage. Let's look at the problem really quick.


So, essentially I need to get VM traffic from my host machine, over a wireless bridge, through my 5506, past my lab switch (c4948). There's a couple different ways to do this, but I kept gravitating towards VXLAN. My initial thought was to use a vswitch like vEOS to get the job done. After some light testing, I found that while it did pass traffic the performance was just absolutely awful. I need these VMs to be able to access web services, pull up GUIs from WSA, etc. So vEOS was out the window. Next up was CSR1000v. This guy would probably work... but I was out of demo licenses, and the unlicensed CSR1Kv is limited to 100kb/s. So that's a hard nope. Then it dawned on me... what about Open vSwitch? Granted, it's an openflow switch and without a controller would need some love, BUT the flows I'd need to get my lab working wouldn't be too complicated. So I gave it a go, here's the high level topology.



Essentially on the firewall I just needed to add a rule permitting the eth0 interface for ovs-vtep1 to send udp/4789 to ovs-vtep2's eth0 interface. Additionally, I only needed (2) segments, so instead of working with VLANs I just allocated 2 physically interfaces to each OVS server (Ubuntu 16.04 w/ 1GB of RAM). Then end result was very impressive. I won't go in depth for installing open vswitch in Ubuntu, since it's in the repositories. However, let's look at the config to get my OVS setup up and running. I have (2) VLANs I'm concerned about, VL37 and VL36. Again, OVS isn't doing any tagging (leaving that to vsphere) but I decided to use the VLAN numbers as my vxlan VNIs to keep things simple. So, I'll share the config below then we can break it down.

ovs-vtep1

jonmajor@ovs-vtep1:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0c:29:1d:cc:c3  
          inet addr:172.17.0.51  Bcast:172.17.0.255  Mask:255.255.255.0
{...}
!
sudo ifconfig eth1 up
sudo ifconfig eth2 up
!

sudo ovs-vsctl add-br BR1
sudo ovs-vsctl add-port BR1 eth1 -- set interface eth1 ofport_request=1
sudo ovs-vsctl add-port BR1 eth2 -- set interface eth2 ofport_request=2
sudo ovs-vsctl add-port BR1 vtep -- set interface vtep type=vxlan option:remote_ip=172.16.255.51 option:key=flow ofport_request=10
!
!

jonmajor@ovs-vtep1:~$ sudo ovs-vsctl show
e208bb8b-0adc-4d4e-b883-7819a8b63b35
    Bridge "BR1"
        Port "eth1"
            Interface "eth1"
        Port vtep
            Interface vtep
                type: vxlan
                options: {key=flow, remote_ip="172.16.255.51"}
        Port "eth2"
            Interface "eth2"
        Port "BR1"
            Interface "BR1"
                type: internal
     ovs_version: "2.5.0"



ovs-vtep2


jonmajor@ovs-vtep2:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:0c:29:a9:fb:41  
          inet addr:172.16.255.51  Bcast:172.16.255.255  Mask:255.255.255.0
{...}
!
sudo ifconfig eth1 up
sudo ifconfig eth2 up
!
sudo ovs-vsctl add-br BR1
sudo ovs-vsctl add-port BR1 eth1 -- set interface eth1 ofport_request=1
sudo ovs-vsctl add-port BR1 eth2 -- set interface eth2 ofport_request=2
sudo ovs-vsctl add-port BR1 vtep -- set interface vtep type=vxlan option:remote_ip=172.17.0.51 option:key=flow ofport_request=10
!
!

jonmajor@ovs-vtep2:~$ sudo ovs-vsctl show
c6a89e34-e0e8-41c7-b20d-fd38a262ecab
    Bridge "BR1"
        Port "eth1"
            Interface "eth1"
        Port "eth2"
            Interface "eth2"
        Port vtep
            Interface vtep
                type: vxlan
                options: {key=flow, remote_ip="172.17.0.51"}
        Port "BR1"
            Interface "BR1"
                type: internal

    ovs_version: "2.5.0"


Alright, so what just happened?! Fairly straight forward actually. The (1)st thing I did was bring up eth1 and eth2 interfaces, these are the ports facing my VMs on vtep2 and on vtep1 they're connecting to vsphere on two different port groups where they get their vlan tags. (2)nd,  I created my ovs bridge "BR1" with "ovs-vsctl add-br BR1". (3)rd, I added my ethernet interfaces and created/added a VXLAN interface called "vtep" to the bridge. Ofport_request,  I'm specifying the openflow port number. This will be handy in the next step when I define my flows. So I mapped Eth1 to ofport 1, Eth2 to ofport2, and the vxlan interface to ofport 10. Easy enough right?

So here's where you can get into trouble with OVS if you're not familiar with it. VXLAN doesn't define a control plane protocol, so each vendor does things a little differently. Cisco for example has largely been leveraging multicast for unknown unicast and broadcast traffic between vteps (there is support for BGP to exchange this information now). Open vSwitch, being a switch designed to work with openflow, doesn't have this functionality. You have to specifically tell it how to forward unicast frames, and ARP traffic. If you just let it forward anything, you'll quickly have a bridging loop. Especially if you try to add more than (2) VTEPs. So that said, we need a couple flows defined on each OVS. We need to tell OVS how to forward unicast traffic for local and remote devices, AND we need to tell it how to handle ARP traffic. So I have my flows defined in a text file on each server, and can load them in with a single command. Let's take a quick look then break it down.

ovs-vtep1

jonmajor@ovs-vtep1:~$ sudo su
!
root@ovs-vtep1:/home/jonmajor# cd ~
!
root@ovs-vtep1:~# cat wsa_lab.txt 
table=0,in_port=1,actions=set_field:37->tun_id,resubmit(,1)
table=0,in_port=2,actions=set_field:36->tun_id,resubmit(,1)
table=0,actions=resubmit(,1)
table=1,tun_id=37,dl_dst=00:0c:29:d9:5f:c4,actions=output:10
table=1,tun_id=37,dl_dst=00:1b:0c:0c:9b:bf,actions=output:1
table=1,tun_id=37,arp,nw_dst=136.1.37.100,actions=output:10
table=1,tun_id=37,arp,nw_dst=136.1.37.1,actions=output:1
table=1,tun_id=36,dl_dst=00:0c:29:db:bf:b5,actions=output:10
table=1,tun_id=36,dl_dst=00:1b:0c:0c:9b:bf,actions=output:2
table=1,tun_id=36,arp,nw_dst=172.16.20.100,actions=output:10
table=1,tun_id=36,arp,nw_dst=172.16.20.1,actions=output:2
table=1,priority=100,actions=drop
!
!

root@ovs-vtep1:~# ovs-ofctl dump-flows BR1
NXST_FLOW reply (xid=0x4):
!
root@ovs-vtep1:~# ovs-ofctl add-flows BR1 wsa_lab.txt 



ovs-vtep2

jonmajor@ovs-vtep2:~$ sudo su
!
root@ovs-vtep2:/home/jonmajor# cd ~
!
root@ovs-vtep2:~# cat wsa_lab.txt 
table=0,in_port=1,actions=set_field:37->tun_id,resubmit(,1)
table=0,in_port=2,actions=set_field:36->tun_id,resubmit(,1)
table=0,actions=resubmit(,1)
table=1,tun_id=37,dl_dst=00:0c:29:d9:5f:c4,actions=output:1
table=1,tun_id=37,dl_dst=00:1b:0c:0c:9b:bf,actions=output:10
table=1,tun_id=37,arp,nw_dst=136.1.37.100,actions=output:1
table=1,tun_id=37,arp,nw_dst=136.1.37.1,actions=output:10
table=1,tun_id=36,dl_dst=00:0c:29:db:bf:b5,actions=output:2
table=1,tun_id=36,dl_dst=00:1b:0c:0c:9b:bf,actions=output:10
table=1,tun_id=36,arp,nw_dst=172.16.20.100,actions=output:2
table=1,tun_id=36,arp,nw_dst=172.16.20.1,actions=output:10
table=1,priority=100,actions=drop
!
!
root@ovs-vtep2:~# ovs-ofctl dump-flows BR1
NXST_FLOW reply (xid=0x4):
!
root@ovs-vtep2:~# ovs-ofctl add-flows BR1 wsa_lab.txt 


First time I saw flow entries, I was hot in the face (angry). The above can look a little daunting at first, but if we take a minute to break it down it's not that bad. So, notice the first three lines of "wsa_lab.txt". Remember above where I specified which openflow ports Eth1 and Eth2 were mapped to? This is where that starts becoming important. The first line I'm saying "traffic coming in ofport 1 needs to get a tunnel id (vxlan vni) of 37. Then, after adding that id, please forward the traffic to table 1." The same logic applies for the second line, when traffic comes in ofport 2 (eth2), add tunnel id 36 and then continue processing traffic in table 1. The third rule is just a catch all for table 0, resubmitting to table 1. Now, in table 1 we're doing some interesting stuff. First I'm mapping where to forward traffic based on destination mac addresses. When the output is :1 or :2, those are my local ports eth1 and eth2. If the output is :10, remember from above that's the vxlan interface we named "vtep". In addition to mapping unicast traffic based on dest. mac address, we also need to map ARP traffic, which you'll see done above. If the arp req is for a node connected locally, forward out either port 1 or 2 depending on the dst IP. If for a remote node, forward out port 10. Notice also, for better segmentation, these flow entries are also matching on tun_id (vxlan vni). Lastly, if the traffic doesn't match any of my flow rules, drop it "table=1,priority=100,action=drop".

Finally, we actually load these flows into the vswitch with "ovs-ofctl add-flows BR1 wsa_lab.txt". I can verify that with "ovs-ofctl dump-flows BR1".

ovs-vtep1

root@ovs-vtep1:~# ovs-ofctl dump-flows BR1            
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=1.456s, table=0, n_packets=0, n_bytes=0, idle_age=1, in_port=1 actions=load:0x25->NXM_NX_TUN_ID[],resubmit(,1)
 cookie=0x0, duration=1.456s, table=0, n_packets=0, n_bytes=0, idle_age=1, in_port=2 actions=load:0x24->NXM_NX_TUN_ID[],resubmit(,1)
 cookie=0x0, duration=1.456s, table=0, n_packets=0, n_bytes=0, idle_age=1, actions=resubmit(,1)
 cookie=0x0, duration=1.456s, table=1, n_packets=0, n_bytes=0, idle_age=1, tun_id=0x25,dl_dst=00:0c:29:d9:5f:c4 actions=output:10
 cookie=0x0, duration=1.455s, table=1, n_packets=0, n_bytes=0, idle_age=1, tun_id=0x25,dl_dst=00:1b:0c:0c:9b:bf actions=output:1
 cookie=0x0, duration=1.454s, table=1, n_packets=0, n_bytes=0, idle_age=1, tun_id=0x24,dl_dst=00:0c:29:db:bf:b5 actions=output:10
 cookie=0x0, duration=1.454s, table=1, n_packets=0, n_bytes=0, idle_age=1, tun_id=0x24,dl_dst=00:1b:0c:0c:9b:bf actions=output:2
 cookie=0x0, duration=1.455s, table=1, n_packets=0, n_bytes=0, idle_age=1, arp,tun_id=0x25,arp_tpa=136.1.37.100 actions=output:10
 cookie=0x0, duration=1.455s, table=1, n_packets=0, n_bytes=0, idle_age=1, arp,tun_id=0x25,arp_tpa=136.1.37.1 actions=output:1
 cookie=0x0, duration=1.454s, table=1, n_packets=0, n_bytes=0, idle_age=1, arp,tun_id=0x24,arp_tpa=172.16.20.100 actions=output:10
 cookie=0x0, duration=1.454s, table=1, n_packets=0, n_bytes=0, idle_age=1, arp,tun_id=0x24,arp_tpa=172.16.20.1 actions=output:2

 cookie=0x0, duration=1.453s, table=1, n_packets=0, n_bytes=0, idle_age=1, priority=100 actions=drop

ovs-vtep2

root@ovs-vtep2:~# ovs-ofctl dump-flows BR1             
NXST_FLOW reply (xid=0x4):
 cookie=0x0, duration=2.056s, table=0, n_packets=3, n_bytes=180, idle_age=0, in_port=1 actions=load:0x25->NXM_NX_TUN_ID[],resubmit(,1)
 cookie=0x0, duration=2.056s, table=0, n_packets=1, n_bytes=161, idle_age=0, in_port=2 actions=load:0x24->NXM_NX_TUN_ID[],resubmit(,1)
 cookie=0x0, duration=2.056s, table=0, n_packets=0, n_bytes=0, idle_age=2, actions=resubmit(,1)
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, tun_id=0x25,dl_dst=00:0c:29:d9:5f:c4 actions=output:1
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, tun_id=0x25,dl_dst=00:1b:0c:0c:9b:bf actions=output:10
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, tun_id=0x24,dl_dst=00:0c:29:db:bf:b5 actions=output:2
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, tun_id=0x24,dl_dst=00:1b:0c:0c:9b:bf actions=output:10
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, arp,tun_id=0x25,arp_tpa=136.1.37.100 actions=output:1
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, arp,tun_id=0x25,arp_tpa=136.1.37.1 actions=output:10
 cookie=0x0, duration=2.055s, table=1, n_packets=0, n_bytes=0, idle_age=2, arp,tun_id=0x24,arp_tpa=172.16.20.100 actions=output:2
 cookie=0x0, duration=2.054s, table=1, n_packets=0, n_bytes=0, idle_age=2, arp,tun_id=0x24,arp_tpa=172.16.20.1 actions=output:10

 cookie=0x0, duration=2.054s, table=1, n_packets=4, n_bytes=341, idle_age=0, priority=100 actions=drop



From the above output, you can see each flow's number of packets matched/forwarded. Also note when you dump-flows, the tun_id is represented in hex format. A final note, MTU can be a killer if your network (like mine) can't accommodate the overhead. So, I lowered the MTU in my windows VM to 1200 bytes. I could probably get away with up to 1420 bytes, but I'm getting fantastic performance with 1200, so I'll probably just leave it as is. So what's the final result?






Works like a charm!

***Update***

So, as these things go, I found a way better way to do this. Basically, if I enable spanning-tree I can drastically decrease the amount of config needed to get this working.

ovs-vsctl set bridge BR1 stp_enable=true
!
root@ovs-vtep1:~# cat wsa_lab.txt 
table=0,in_port=1,actions=set_field:37->tun_id,resubmit(,1)
table=0,in_port=2,actions=set_field:36->tun_id,resubmit(,1)
table=0,actions=resubmit(,1)
table=1,priority=100,actions=NORMAL

So much simpler right? Now I'm running 802.1D over VXLAN thereby preventing loops. You can confirm that with the following:

root@openvswitch:~# ovs-ofctl show BR1
OFPT_FEATURES_REPLY (xid=0x2): dpid:0000080027d2f207
n_tables:254, n_buffers:256
capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
 1(eth1): addr:08:00:27:d2:f2:07
     config:     0
     state:      STP_FORWARD
     current:    1GB-FD COPPER AUTO_NEG
     advertised: 10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     supported:  10MB-HD 10MB-FD 100MB-HD 100MB-FD 1GB-FD COPPER AUTO_NEG
     speed: 1000 Mbps now, 1000 Mbps max
 12(vtep12): addr:0a:2d:a5:f8:a9:12
     config:     0
     state:      STP_BLOCK
     speed: 0 Mbps now, 0 Mbps max
 23(vtep23): addr:7e:2a:b3:f5:21:c2
     config:     0
     state:      STP_FORWARD
     speed: 0 Mbps now, 0 Mbps max
 LOCAL(BR1): addr:08:00:27:d2:f2:07
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0





Saturday, April 9, 2016

Routing authentication - Thinking outside the box.


So it's been awhile since my last post, and while I could just blame work, really I hit a bit of a dry spell. Then I saw a topic show up on CLN that sparked my imagination. The topic was simple enough, which authentication method is better (specifically for EIGRP) MD5 or SHA? Now I can feel your twitchy fingers from here. You want to comment in all caps, bold letters "SHA IS BETTER!!!!" Calm down. Deep breathes. I felt the exact same way, until I read the question a little more thoroughly. Well, while the short answer is yes 'SHA is better than MD5', however you can't use rotating keys (yet) with SHA. Yeah, SHA1 is 160-bit hash vs. MD5's 128-bit (EIGRP named mode actually supports sha256). And let's not forget, even with just SHA1, there's no example of a successful collision attack that I'm aware of.

So, definitely SHA is better right? If you want to use rotating keys with a keyring, as of this post you still need to use MD5. Bummer. This got me thinking though, why can't we do better than sha256. In a non-realistic, totally lab only scenario, how could we make EIGRP traffic basically bulletproof?





Don't read beyond this line, test your creative problem solving skills. If required by a task (real world or lab), how would you improve EIGRP security beyond sha256?






Before I go into how I tackled this hypothetical task, let me first say... there are a few different ways you could interpret that objective, and even more ways you could attempt to solve it. Seeing as I wrote the task, the way I interpret it is 'We need better encryption, and a higher degree of data integrity than what sha256 alone can provide.' Which is totally insane, I mean... protecting EIGRP traffic is important, but c'mon. Even still, this is what I came up with. IKEv2/IPsec to secure only EIGRP traffic. Think about the options you have here. Not only do we have the option of a secure hash with up to sha512, but we also can leverage PFS AND encrypt eigrp datagrams. Let's take a look at some config:

All Routers


crypto ikev2 proposal 100 
 encryption aes-cbc-256
 integrity sha512
 group 21
crypto ikev2 policy policy100 
 match fvrf any
 proposal 100
crypto ikev2 keyring EIGRP_RING
 peer EIGRP_PEERS
  address 10.0.123.0 255.255.255.0
  pre-shared-key cisco123
 !
crypto ikev2 profile profile100
 match fvrf any
 match identity remote address 10.0.123.0 255.255.255.0 
 authentication local pre-share
 authentication remote pre-share
 keyring local EIGRP_RING
crypto ipsec transform-set ESP-AES256 esp-aes 256 esp-sha512-hmac 
 mode transport


R1

ip access-list extended EIGRP_R2
 permit eigrp host 10.0.123.1 host 10.0.123.2
ip access-list extended EIGRP_R3

 permit eigrp host 10.0.123.1 host 10.0.123.3
!
crypto map EIGRP 1 ipsec-isakmp 
 set peer 10.0.123.2
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R2
!
crypto map EIGRP 2 ipsec-isakmp 
 set peer 10.0.123.3
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R3
!
interface GigabitEthernet2
 ip address 10.0.123.1 255.255.255.0
 negotiation auto
 crypto map EIGRP

R2

ip access-list extended EIGRP_R1
 permit eigrp host 10.0.123.2 host 10.0.123.1
ip access-list extended EIGRP_R3

 permit eigrp host 10.0.123.2 host 10.0.123.3
!
crypto map EIGRP 1 ipsec-isakmp 
 set peer 10.0.123.1
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R1
crypto map EIGRP 2 ipsec-isakmp 
 set peer 10.0.123.3
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R3
!
interface GigabitEthernet2
 ip address 10.0.123.2 255.255.255.0
 negotiation auto
 crypto map EIGRP


R3

ip access-list extended EIGRP_R1
 permit eigrp host 10.0.123.3 host 10.0.123.1
ip access-list extended EIGRP_R2

 permit eigrp host 10.0.123.3 host 10.0.123.2
!
crypto map EIGRP 1 ipsec-isakmp 
 set peer 10.0.123.1
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R1
crypto map EIGRP 2 ipsec-isakmp 
 set peer 10.0.123.2
 set transform-set ESP-AES256 
 set pfs group21
 set ikev2-profile profile100
 match address EIGRP_R2
!
interface GigabitEthernet2
 ip address 10.0.123.3 255.255.255.0
 negotiation auto
 crypto map EIGRP

So that's your basic IKEv2 IPsec configuration, using EIGRP as the only interesting traffic. The next thing we're going to need to make this happen is static EIGRP neighbors. I'm still tinkering around, trying to figure out how to make this a little more graceful (GETVPN would at least help with the crypto maps). For now, let's just add the following:

router eigrp IPSEC
 !
 address-family ipv4 unicast autonomous-system 47884
  !
  topology base
  exit-af-topology
  neighbor 10.0.123.1 GigabitEthernet2
  neighbor 10.0.123.2 GigabitEthernet2
  neighbor 10.0.123.3 GigabitEthernet2
  network 10.0.0.0

 exit-address-family


Now finally, some verification. I should note, loopback interfaces are 10.x.x.x where 'x' is the router number.

R1#show ip eigrp neighbors              
EIGRP-IPv4 VR(IPSEC) Address-Family Neighbors for AS(47884)
H   Address                 Interface              Hold Uptime   SRTT   RTO  Q  Seq
                                                   (sec)         (ms)       Cnt Num
0   10.0.123.2              Gi2                      14 07:57:58    5   100  0  14
1   10.0.123.3              Gi2                      10 21:16:19    5   100  0  11

R1#show ip route eigrp | b ^Gateway     
Gateway of last resort is not set

      10.0.0.0/8 is variably subnetted, 5 subnets, 2 masks
D        10.2.2.2/32 [90/10880] via 10.0.123.2, 07:58:37, GigabitEthernet2
D        10.3.3.3/32 [90/10880] via 10.0.123.3, 21:16:59, GigabitEthernet2

R1#show crypto ikev2 sa                 
 IPv4 Crypto IKEv2  SA 

Tunnel-id Local                 Remote                fvrf/ivrf            Status 
3         10.0.123.1/500        10.0.123.3/500        none/none            READY  
      Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:21, Auth sign: PSK, Auth verify: PSK
      Life/Active Time: 86400/76592 sec

Tunnel-id Local                 Remote                fvrf/ivrf            Status 
2         10.0.123.1/500        10.0.123.2/500        none/none            READY  
      Encr: AES-CBC, keysize: 256, PRF: SHA512, Hash: SHA512, DH Grp:21, Auth sign: PSK, Auth verify: PSK
      Life/Active Time: 86400/76641 sec

R1#show crypto ipsec sa | i remote|encap
   remote ident (addr/mask/prot/port): (10.0.123.3/255.255.255.255/88/0)
    #pkts encaps: 16566, #pkts encrypt: 16566, #pkts digest: 16566
     local crypto endpt.: 10.0.123.1, remote crypto endpt.: 10.0.123.3
   remote ident (addr/mask/prot/port): (10.0.123.2/255.255.255.255/88/0)
    #pkts encaps: 16579, #pkts encrypt: 16579, #pkts digest: 16579

     local crypto endpt.: 10.0.123.1, remote crypto endpt.: 10.0.123.2



So that's it gang! A different, albeit impractical, approach to securing your routing process. I'll probably do a short video on this configuration (if for no other reason than to demo a quick IKEv2 configuration). I'll update this post with that video when I do.

Wednesday, March 2, 2016

Quagga/Zebra - IOS like shell built in Linux



So today I'll be installing quagga in centos, and turning that centos vm into an IOS-like router.




After that, the goal is to test said faux Cisco router in GNS3 with some 7200 images. It's actually a pretty cool little concept, even if the source code looks like it hasn't been updated in a couple years. The concept? Take a Linux machine, slap a shell on it similar to Cisco IOS and use said Linux machine as a router. So, let's freaking do it!! I'll be using Centos 7, because I love Red Hat. First things first, let's install centos (minimal install here, you can have a GUI if you want one), and update it.


I used the basic settings for RHEL 64bit in Virtualbox, disabled the USB and audio controllers, and enabled Serial Port but left it disconnected for now. I bolded the 'enabled serial port' because, that will be important later. 





Now let's power this sucker on and boot from centos 7 minimal install. You can pretty much next->next->finish the install, however DO make sure you go into Network & Hostname section to enable your network adapter and set a hostname. 


Before install Quagga and getting into the configuration, let's update our system and enable console access over the Serial port.

Enable Serial Port


1) Add highlighted line to /etc/sysconfig/grub   (net.ifnames=0 gives you legacy interface names, ie eth0)

GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet net.ifnames=0 console=ttyS0"


2) Run the following

stty -F /dev/ttyS0 speed 9600
grub2-mkconfig -o /boot/grub2/grub.cfg
systemctl start getty@ttyS0
systemctl enable getty@ttyS0


Install Quagga, configure selinux, and get base settings in place

1) Install quagga

yum install quagga -y
cd /etc/quagga/

2) Copy basic conf files for OSPF and BGP into /etc/quagga/

cd /etc/quagga/
cp /usr/share/doc/quagga-0.99.22.4/ospfd.conf.sample .
cp /usr/share/doc/quagga-0.99.22.4/bgpd.conf.sample .
mv ospfd.conf.sample ospfd.conf
mv bgpd.conf.sample bgpd.conf  

3) Change owner and set proper permissions on ospfd.conf and bgp.conf

chown quagga:quagga bgpd.conf 
chown quagga:quagga ospfd.conf
chmod 640 bgpd.conf 
chmod 640 ospfd.conf 

4) Configure selinux to allow zebra to write to config files

setsebool -P zebra_write_config 1

5) Enable IP Forwarding (otherwise we'll just drop transit traffic)

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf

6) Make sure firewalld/iptables is disabled

[root@cent-router ~]# iptables -nvL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         


[root@cent-router ~]# systemctl status firewalld
* firewalld.service
   Loaded: not-found (Reason: No such file or directory)
   Active: inactive (dead)

We can explore enabling firewall features in the future, but for now... we just want to route. Luckily the minimal install doesn't include either firewalld or iptables. If firewalld is running issue the following:

systemctl stop firewalld
systemctl disable firewalld

7) Enable Zebra, OSPF, and BGP on boot and start services.

systemctl enable zebra.service
systemctl enable ospfd.service
systemctl enable bgpd.service 
systemctl start zebra.service 
systemctl start ospfd.service 
systemctl start bgpd.service 

8) Finally, test IOS-like shell.

[root@cent-router ~]# vtysh 

Hello, this is Quagga (version 0.99.22.4).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

cent-router# show run
Building configuration...

Current configuration:
!
hostname cent-router
hostname ospfd
log stdout
hostname bgpd
!
password zebra
!
interface enp0s3
 ipv6 nd suppress-ra
!
interface lo
!
router bgp 7675
 bgp router-id 172.16.255.110
!
line vty
!
end
cent-router# conf t
cent-router(config)# 

Beautiful!! Now we can shut this bad boy down, make (1) minor tweak and import it into virtualbox as a linked clone. This tweak is just marking network adapter 1 as "Not Attached", since we're relying on GNS3 to build these connections for us.




Last but not least, import this VM into GNS3.





Video Demo, Coming Soon...