Everyone has different views on hardening IOS, and while I do not claim to be an expert, these are the practices that I commonly use when bringing up a new device. If you see something I missed, please leave a comment and I’ll add it to the list and send the credit your way. I’ve also included general best practices that I follow that fall outside of the security realm. This is in no way a complete list of best practices, or a complete steb-by-step guide to hardening an IOS device.
Base SSH and AAA
Before we get too far, we need to setup the basics. In order to enable SSH, we need to set a hostname, domain suffix, and generate an RSA key. Next we’re going to set some values that should be self explanatory.
The next section states that we’re going to lock out logins for 5 minutes if we have 4 unsuccessful attempts inside of 2 minutes. After an unsuccessful attempt, we’re delaying for 2 seconds, and on any failure or success we log.
The last 2 sections are a basic configuration for AAA. First we define a level 15 user named admin with a password of cisco. Then, we define our login and exec policies to use the local login methods. This is just a base line of the AAA configuration as once it’s moves to production you’ll add it to your TACACS/ACS server, right??? I also recommend changing your local admin/backup in case TACACS is down name from admin to something… more obscure. Captain? General? SquidBoy? Anything other than the normal admin, root, administrator, and etc.
! hostname Rooter ip domain-name routerjockey.com crypto key generate rsa modulus 2048 ip ssh time-out 120 ip ssh version 2 ip scp server enable ! login block-for 300 attempts 4 within 120 login delay 2 login on-failure log login on-success log ! username admin privilege 15 secret 0 cisco ! aaa new-model aaa authentication login default local-case aaa authorization exec default local if-authenticated !
Next we’re going to configure the lines used to gain console or VTY access. For the console line, I ensure logging synchronous is turned on to prevent mid-command interruption from logging messages. Transport preferred none disables the default behavior of attempting to open a telnet session to input that isn’t matched by the IOS command parser. Changing the escape-character to 3 allows us to use <ctrl>+C instead of <ctrl>+<shift>+6.
On our aux line, I’m always sure to disable exec, and as a fallback, set the exec-timeout to 1 second. I also like to disable output on the line using transport output none.
Now, probably the most important is securing your VTY lines. The ACL VTY-in is defined by only allowing devices that absolutely need access. This then applied via the access-class command to the vty lines. Again, logging synchronous, escape-character 3, and transport preferred none are used. I also disable telnet access by only allowing input via SSH.
! ip access-list extended VTY-in remark == Network Engineering VPNs permit ip 10.255.200.0 0.3.0.31 any remark == Network Management Servers permit ip 192.168.42.0 0.0.0.255 any ! line con 0 logging synchronous transport preferred none escape-character 3 line aux 0 exec-timeout 0 1 no exec transport output none line vty 0 15 access-class VTY-in in logging synchronous transport preferred none transport input ssh escape-character 3 !
As with any best practice, any unnecessary services should be disabled. Most of these are rarely used for any legitimate purpose, but can be used to launch attacks that are otherwise prevented by packet filtering. The following is a list of services that should be disabled unless in use.
- IP Source Route should be disabled to prevent implicit tunneling attacks.
- Packets that contains IP options must be punted, which can lead to high CPU utilization. IP options can also alter the path that traffic takes through the network, potentially allowing it to subvert security controls. Unless you have specific reasons, this traffic should be dropped. (This can break RSVP)
- HTTP and HTTPS servers – do I really need to explain what these are?
- TCP/UDP Small services such as echo, discard, daytime, chargen should be disabled. Although they can be protectd by an ACL, it would be best to just disable them. (The default since IOS 12.0)
- Password Encryption is just a best practice, the encryption used is a very simple Vigenère cipher and only protects from teh casual observer.
- The service tcp-keepalive-in and service tcp-keepalive-out global configuration commands enables the device to send TCP keepalives for TCP sessions, thus ensuring that the remote device is accessible and that half-open/orphaned connections are closed.
- DHCP, the Dynamic Host Configuration Protcol, best to leave this disabled if not in use.
- BootP, the Bootstrap Prototol used for auto configuration.
- Finger is a legacy protocol used for status and user information. Disabled by default since 12.1(5)
- The ip identd command returns accurate information about the host TCP port; however, no attempt is made to protect against unauthorized queries.
- Many engineers recommended disabling CDP. Although, I only do this in places where my network touches external networks. (The command to globally disabled CDP is not listed below. Therefore it is no cdp run – alternatively the interface command no cdp enable can be used to disabled it interface by interface.
- The Link Layer Discovery Protocol (LLDP) is an IEEE protocol similar to CDP. Except that LLDP allows interoperability between Cisco and non-Cisco devices that do not support CDP.
- Service Config should be disabled unless you’re loading configurations from the network.
- MOP or the Maintenance Operation Protocol is a legacy service used for utility services such as uploading and downloading system software, remote testing and problem diagnosis.
- Packet Assembler/Disassembler or PAD service is used on X.25 networks.
no ip source-route ip options drop no ip http server no ip http secure-server no service tcp-small-servers no service udp-small-servers service password-encryption service tcp-keepalives-in service tcp-keepalives-out no service dhcp no ip bootp server no ip finger no ip identd no service config no lldp run global no mop enabled no service pad
In some areas it can be impossible to prosecute and illegal to monitor malicious users unless they have been notified that they are not permitted to use the system. One method to provide this notification is to place this information into a banner message that is configured with the Cisco IOS software banner login command. The following is a slightly edited example from sans.org.
! banner login ^ ************************************************************************ You have logged on to a COMPANY proprietary device. This device may be used only for the authorized business purposes of COMPANY. Anyone found using this device or its information for any unauthorized purpose may be subject to disciplinary action and/or prosecution. Have a nice day! :) ************************************************************************ ^ !
SNMP, Logging, and NTP
Monitoring, monitoring, monitoring. One of the most important aspects of keeping your users happy that often gets pushed out of priority. When configuring SNMP, I’m sure your Network Management System (NMS) will appreciate you setting your SNMP location string, many use this to group systems. Whenever possible, please start using SNMPv3, an example for v2 and v3 is included (both of them use an ACL to provide additional security)
Syslog allows you to stream your logging messages to a remote server for aggregation, search ability and base line tracking. While I could’ve put the service timestamp command in with the rest of the service configuration, I thought it belonged here. This tells our router to use timestamps down to the millisecond in local time, and to also print the current timezone.
And last, but not least, please be good about setting up your time zones, and NTP destinations across your organization. Trying to dig through logs with different time zones, and unsynchronized time is a huge PITA.
! snmp-server location HQ ip access-list 60 remark == SNMP RO ip access-list 60 remark -ServerName ip access-list 60 permit 192.168.42.23 ip access-list 60 deny ip any any log ! ! SNMP v2 snmp-server community r0u73rj0ck3y RO 60 ! ! SNMP v3 <-- More Secure snmp-server user snmpv3user PRIVGROUP v3 auth md5 authpassword priv 3des privpassword access 60 ! logging host 192.168.42.42 service timestamps log datetime localtime msec show-timezone ! ntp server 10.1.1.10 preferred ntp server 10.2.1.10 !
The last couple of commands here are part best practices, and part convenience. The first command enables Cisco's Configuration Generation Performance Enhancement feature which greatly speeds up polling for current configuration data. Previous to this command NVGEN always had to query the entire system and could generate only a total configuration. This feature allows for caching of interface configuration information in system memory.
The second set of commands here configures your time zone, and sets up automagic DST based on the rules here in the states. For those of you outside the US, please use the following command. clock summer-time zone recurring [week day month hh:mm week day month hh:mm [offset]]
parser config cache interface ! clock timezone EST -5 0 clock summer-time EDT recurring
Network engineer turned management currently servicing the enterprise data center market. I started working on networks in the ’90s and still feel like that was just a few years ago. Jack of all trades, master of none; I love to learn about everything. Feel free to ask me about photography, woodworking, nhra, watches, or even networking! — For feedback, please leave a comment on the article in question, and I’ll respond as soon as I can. For everything else including fan mail or death threats, contact me via twitter.