Access Control Lists

Explanation

Before configuring ACLs, you must test your configuration thoroughly. Once you implement an ACL, connectivity can be broken through physical failure, misconfiguration or the actions of the ACL. It is much more difficult to troubleshoot.

From the hotel case study scenario, the security requirements are as follows:

  1. Only communications initiated from within the HCGs network should be allowed to enter the hotel from the Internet.
  2. No direct traffic is allowed to flow between the guest subnets and the hotel systems and hotel users.
  3. No user should be able to access addresses in the range 1.2.3.4-10 as these are known phishing sites.
  4. All users should be able to ping any Internet address. You can test with the simulated Google.com (172.217.25.164).
  5. Guests are only allowed to browse the web. They are not allowed to use protocols other than HTTP, HTTPS (ping is OK).

There are a number of requirements here, but it can be helpful to think of the rules in terms of specific classes of users and rules that apply to all users. As a general principle, Internet rules that apply to the whole organisation are most easily position near the exit to the Internet as all traffic of interest will pass through this point, and you can limit the number of places you need to configure the ACL. Most organisations use a firewall between the ISP and their enterprise for this purpose. A natural place to impose such rules would be on the S1/1 interface on the Core routers. However, as a general rule, you should avoid ACLs on core devices as their role in the 3-layer hierarchy is to forward packets quickly and ACLs can impact performance. In this situation, I would advise the hotel to install another router between the Core and the ISP. The role of this router would be similar to a distribution-layer router where we implement policy. However, you can’t change the topology, so we will be forced to implement our security on the distribution layer device.

Let’s step through the requirements.

1

The hotel group use NAT, so unless an Internet access packet passes from inside the hotel group to the outside, no NAT translation exists, and no traffic can pass from the Internet to the hotel. In this way, NAT acts as an effective basic firewall. There is nothing to do for the first requirement as NAT delivers this functionality.

2

This rule says that hotel guests are not permitted to access anything else in the hotel: no internal systems or any class of users. You might be tempted to start creating an ACL that denies a list of floors and staff subnets etc. But that would be a very long list that needs to be updated every time the network grows. Instead, for guests, you can deny them from sending traffic to any address on the 10.0.0.0/8 network. In the absence of any other rules, we would permit traffic to any other address (the Internet).

 Router(config)#ip access-list extended PREVENT_GUEST_10_NET
 Router(config-std-nacl)#deny ip any 10.0.0.0 0.255.255.255
 Router(config-std-nacl)#permit ip any any             --> Until we are told otherwise, guests can do anything on the Internet.
  • Important: The source address is any. This is only possible if you place this ACL where only the guest traffic will flow. Such as a guest VLAN inbound on a DL router. If you place the ACL outbound on the DL interface to the Core, you would need to swap any for a specific address/wildcard that selected just the guest traffic.

3

The third rule states that no user should be able to access addresses in the range 1.2.3.4-10 as these are known phishing sites. As this is a site-wide rule, it makes sense to implement it as high as possible and catch traffic as it passes through bottlenecks. As we have a range of IP addresses, you may (will) need more than one deny statement to cover the range. You should carefully choose the wildcard mask to minimise the number of statements.

When determining wildcard masks it is important to look at the addresses in binary.

 1.2.3 . 0 0 0 0 0 1 0 0    (4)
 1.2.3 . 0 0 0 0 0 1 0 1    (5)
 1.2.3 . 0 0 0 0 0 1 1 0    (6)
 1.2.3 . 0 0 0 0 0 1 1 1    (7)
 1.2.3 . 0 0 0 0 1 0 0 0    (8)
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

We have to look at an ACL in terms of portions that must match and bits we don’t care about (wild): Clearly, each address needs to start with 1.2.3 so our wild card would start with 0.0.0, indicating that those bits must match. But the last octet is more difficult.

One approach is to look for the largest block of contiguous zeros on the right-hand side and see if that can be used to group a block of addresses into a single statement.

The largest group is the three zeros highlighted.

 1.2.3 . 0 0 0 0 0 1 0 0    (4)
 1.2.3 . 0 0 0 0 0 1 0 1    (5)
 1.2.3 . 0 0 0 0 0 1 1 0    (6)
 1.2.3 . 0 0 0 0 0 1 1 1    (7)
 1.2.3 . 0 0 0 0 1 0 0 0    (8) <--
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

If you look at the region to the left of the zeros, you can see that the next three entries all start with “0 0 0 0 1”. So we can create an ACL that matches this. But for anything that doesn’t match, we must be prepared to accept any value. If we count up in binary, we will go from “0 0 0” to “1 1 1”. In the example below, this is not possible. “0 0 0” is OK; “0 0 1” is OK; “0 1 0” is OK but “0 1 1” and on-wards is outside our range. It would be a group of 8 numbers, and we only want to include 3 in our ACL.

 1.2.3 . 0 0 0 0 0 1 0 0    (4)
 1.2.3 . 0 0 0 0 0 1 0 1    (5)
 1.2.3 . 0 0 0 0 0 1 1 0    (6)
 1.2.3 . 0 0 0 0 0 1 1 1    (7)
 1.2.3 . 0 0 0 0 1|0 0 0    (8)
 1.2.3 . 0 0 0 0 1|0 0 1    (9)
 1.2.3 . 0 0 0 0 1|0 1 0   (10)
 

This means that starting from three zeros is not possible at this point. So we go looking for smaller groupings (two zeros). Let’s start at the top.

 1.2.3 . 0 0 0 0 0 1 0 0    (4) <--
 1.2.3 . 0 0 0 0 0 1 0 1    (5)
 1.2.3 . 0 0 0 0 0 1 1 0    (6)
 1.2.3 . 0 0 0 0 0 1 1 1    (7)
 1.2.3 . 0 0 0 0 1 0 0 0    (8)
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

Again we draw a line dividing bits that must match from those that we don’t care about. We stop our line when the bits on the left are no longer the same (matching). If the bits on the right of the line cover all the possible values for two bits “0 0” through “1 1” then we can truly say “we don’t care” what those bit values are (they are wild).

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 1.2.3 . 0 0 0 0 1 0 0 0    (8)
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

Great, we have a block of bits that we can divide into a match and a wild portion. We can write a single ACL statement to represent that range. Draw a line under it so we know where we up to.

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0 0    (8)
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

Lets look to see if there is another pair of zeros on the right. There is. We are revisiting (8) but looking at just two zeros (not 3 because we know the block isn’t that big)

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0 0    (8) <--
 1.2.3 . 0 0 0 0 1 0 0 1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

If you look below you will see that on the right side we haven’t covered the full range “0 0” to “1 1”. So again we can’t cover this block of three addresses with a single statement. You should soon see that if we have two bits we define four addresses. So three addresses can never be matched.

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0|0 0    (8)
 1.2.3 . 0 0 0 0 1 0|0 1    (9)
 1.2.3 . 0 0 0 0 1 0|1 0   (10)

Now we have exhausted the consecutive two zero entries we step back to just one zero. Again, confirm the left all matches and the right covers both states of one bit “0” and “1”. It does. So we can represent those two addresses with just one ACL statement.

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0|0    (8) <--
 1.2.3 . 0 0 0 0 1 0 0|1    (9)
 1.2.3 . 0 0 0 0 1 0 1 0   (10)

Let’s rule that off and see what is left. Just one entry. In this case we care about every bit. Everything must match. This will become its own line in the ACL

 1.2.3 . 0 0 0 0 0 1|0 0    (4)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0|0    (8)
 1.2.3 . 0 0 0 0 1 0 0|1    (9)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 1 0   (10) <---

Let’s add the addresses we are comparing in each line of ACL so you can see where they come from:

 1.2.3 . 0 0 0 0 0 1|0 0    (4)     1.2.3.4
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0|0    (8)     1.2.3.8
 1.2.3 . 0 0 0 0 1 0 0|1    (9)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 1 0   (10)     1.2.3.10

And the wild card masks. Remember, a zero means we must match, and a one means it is wild (we don’t care). As we have said, the first three octets must match (1.2.3), so the first bytes in our wild card mask must match. Let’s do the last octet in the binary.

 1.2.3 . 0 0 0 0 0 1|0 0    (4)     1.2.3.4  0.0.0. 0 0 0 0 0 0 1 1 (last two bits are wild)
 1.2.3 . 0 0 0 0 0 1|0 1    (5)
 1.2.3 . 0 0 0 0 0 1|1 0    (6)
 1.2.3 . 0 0 0 0 0 1|1 1    (7)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 0|0    (8)     1.2.3.8  0.0.0. 0 0 0 0 0 0 0 1 (last single bit wild)
 1.2.3 . 0 0 0 0 1 0 0|1    (9)
 ------------------------------
 1.2.3 . 0 0 0 0 1 0 1 0   (10)     1.2.3.10 0.0.0. 0 0 0 0 0 0 0 0 (no wild bits, this is a single host)

Revisiting our requirements, remember we need to block (deny) traffic from these phishing sites. As we will block all of the IP protocol (which carries TCP/UDP/ICMP) from a source, we can use a standard access list.

 Router(config)#ip access-list standard BLOCK_PHISHING
 Router(config-std-nacl)#deny 1.2.3.4 0.0.0.3
 Router(config-std-nacl)#deny 1.2.3.8 0.0.0.1
 Router(config-std-nacl)#deny host 1.2.3.10
 Router(config-std-nacl)#permit any             --> We must have something permitted or nothing will pass the ACL.

4

Rule 4 says everyone can ping the Internet. We have two groups; staff and guests. So far, we don’t have any restrictions specifically for staff. So apart from not getting access to the phishing site, they appear to have unrestricted access to the Internet. So permitting ICMP (ping) for staff isn’t something we need to do if there is nothing that would (deny) them access. For guests, we prevent them from sending packets to other IP addresses in the 10.0.0.0/8 network but have a “permit any” allowing Internet access. So again, there is nothing to do at this stage. They can already ping the Internet. We need to keep it in mind if there is another rule that might otherwise take away their ability to ping an Internet site.

5

The final rule says that guests can only use HTTP (80) /HTTPS (443) and ping (ICMP echo) to the Internet. So our guests really have a black list. Unless we explicitly give them access, they cannot use particular protocols.

We already have a partial ACL for guests from step 1.

 Router(config)#ip access-list extended PREVENT_GUEST_10_NET
 Router(config-std-nacl)#deny ip any 10.0.0.0 0.255.255.255
 Router(config-std-nacl)#permit ip any any

Rule 5 says they can ONLY do HTTP/HTTPS and ping. That means everything else is denied. In isolation, the ACL would look like this:

 Router(config)#ip access-list extended GUEST_INTERNET_RULES
 Router(config-std-nacl)#permit tcp any any eq 80 443 
 Router(config-std-nacl)#permit icmp any any echo                  <-- A sent ping is actually an ICMP message "echo-request"
 Router(config-std-nacl)#deny ip any any                           <-- Block all IP packets because this a black list

Please pay attention that we are specific and permitting tcp ports for web and secure web browsing. You must specify TCP rather than IP in that line. Also, the source any assumes you place this ACL where no traffic sourced from the staff network will be present.

If you implement the ACLs on different interfaces, then you can keep these as separate ACLs and traffic passing through both ACLs must satisfy both rules. If you wish to combine the ACLs into a single guest policy, you must be careful in the sequencing.

 Router(config)#ip access-list extended GUEST_NETWORK_POLICY
 Router(config-std-nacl)#deny ip any 10.0.0.0 0.255.255.255              <-- No access to other hotel addresses.
 Router(config-std-nacl)#permit tcp any any eq 80 443              <-- Web access allowed.
 Router(config-std-nacl)#permit icmp any any echo                  <-- Ping is OK
 Router(config-std-nacl)#deny ip any any                           <-- Guests can do nothing else

If you put the deny 10.0.0.0 after the permits for http/https/icmp, the guests will be allowed to perform these operations on hotel 10.0.0.0 users and systems.

Unintended Consequences

Although the ACLs above are correct, this is what happens when the GUEST_NETWORK_POLICY is applied in-bound on the VLAN interface.

 SydDL2(config-if)#int vlan101
 SydDL2(config-if)#ip access-g GUEST_NETWORK_POLICY in
 SydDL2(config-if)#int vlan102
 SydDL2(config-if)#ip access-g GUEST_NETWORK_POLICY in
 *Oct 15 12:04:58.926: %HSRP-5-STATECHANGE: Vlan101 Grp 101 state Standby -> Active
 SydDL2(config-if)#
 *Oct 15 12:05:26.913: %OSPF-5-ADJCHG: Process 1, Nbr 10.2.255.1 on Vlan101 from FULL to DOWN, Neighbor Down: Dead timer expired
 SydDL2(config-if)#
  • HSRP on our router went from standby to active. Our router is not receiving HSRP hellos from the neighbour and thinks it has failed!
  • OSPF thinks a neighbouring router is dead because too much time (timer expired) passed since a hello was seen.

You need to be alert when things like this happen. We just applied some security rules (blocked packets), and two protocols, HSRP and OSPF, both experienced problems. What could we have done that caused them a problem?

Answer; “They both use hello packets, and we just created a rule forbidding anything but ping and web access.”

So we need to do some research and find out how to permit the OSPF and HSRP traffic. A Google search “ACL breaks HSRP” or “ACL breaks OSPF” very quickly leads to some clues as to how to fix the problem.

 ip access-list extended GUEST_NETWORK_POLICY
  deny ip any 10.0.0.0 0.255.255.255             
  permit tcp any any eq 80 443           
  permit icmp any any echo  
  permit udp any host 224.0.0.2 eq 1985  <-- From the lecture slides or Google you can find what protocol, port and address HSRP uses.
  permit ospf any any                    <-- OSPF is a protocol in its own right so you can just allow it totally.
  deny ip any any                       

What you need to do?

  • Create the appropriate ACLs on the distribution-layer devices.
    • As there is more than one distribution-layer device that a users traffic could flow through, you need to ensure you have an ACL on each device that could the traffic flow through it.
    • Apply an access-group command on an appropriate interface to activate the ACL.
    • Think carefully as to the direction it should operate in. Take care with the use of any as a source. Depending on where you apply the ACL, you may need to change this to match traffic from the appropriate address range.

How will you know it is configured correctly?

  • If you are blocking all access (IP) then ping gives you some clue as to whether the ACL is active.
  • show access-lists is very handy to get a quick overview as to what has been configured.
 PerDl1#sh access-lists 
 Standard IP access list BLOCK_PHISHING
     30 deny   1.2.3.10
     10 deny   1.2.3.4, wildcard bits 0.0.0.3
     20 deny   1.2.3.8, wildcard bits 0.0.0.1
     40 permit any (307 matches)
 Extended IP access list GUEST_NETWORK_POLICY
     10 deny ip any 10.0.0.0 0.255.255.255
     20 permit tcp any any eq www 443
     30 permit icmp any any echo
     40 permit udp any host 224.0.0.2 eq 1985 (8 matches)
     50 permit ospf any any (2 matches)
     60 deny ip any any

By testing communications (ping or other application), you can see the matches increment if the access-list statement is triggered.

Remember the host PCs support Telnet. You can use this for both the Staff and Guests to determine whether non ICMP or HTTP(s) will be permitted.

What questions could I see on the practical exam?

  • An ACL may not work properly.
    • It might have an incorrect statement.
    • It might be applied in the incorrect direction.
    • It might not be applied to an interface.
  • You may be given a range of addresses that need to be permitted/denied and asked to determine one or more lines to be added to an existing ACL.
  • You may be asked whether a particular user will be able to access a particular service (telnet/SSH/HTTP/HTPPS etc.) on a given IP address.