F5 Best Practices Intro

I’ve spent a few years now working almost exclusively with F5 load balancers. Understanding how to securely manage an F5 Load Balancer, also commonly known as a BigIP, is very important.

I’ve seen a number of base configurations simply overlooked during security audits and even resulting in compromise. Many network engineers are intimidated by the BigIP load-balancer, because its really a linux box more so than the traditional Cisco router or switch. However, the base configurations are very similar and are not difficult.

I’ve come up with a list of the most critical configurations an F5 administrator must do to securely manage a F5 load balancer. Following these management practices will help prevent unauthorized access to your devices which could be devastating to your business and help when it comes time for compliance audits.


  1. Change the default passwords and rotate them every 3 months
  2. Limit Control Plane Access
  3. Use AAA for remote login and audit logging
  4. Setup DNS and NTP
  5. Setup SNMP Monitoring
  6. Harden the Control Plane Cryptography
  7. Harden Virtual Server SSL Profiles

I know this from experience as I just went through the process of working with compliance auditors. I was required to submit evidence regarding how my company securely manages our BigIP load-balancers. The auditors were mainly looking for the configurations I will be describing in this post along with change control procedures/adherence.

Also, keep in mind that the scope of this post is around best management practices. F5 offers many other security capabilities when using the AFM (network firewall), ASM (application firewall), and APM (web frontend/client vpn) modules.


1). Change the default passwords and rotate them every 3 months

To start, you should always change the default credentials on any device you manage. The default credentials for ssh are root/default and admin/admin for the Web UI.

I’m sure anyone reading this understands that not changing default passwords is one of the easiest ways to compromise your environment. Luckily, it is really easy to change the default username/passwords on an F5 load balancer.

When you first login through the Web UI and run through the initial setup utility, it will prompt you to change these accounts. Below is an example.

F5 setup utility screenshot
F5 Setup Utility Screenshot

If you license your F5 load balancer through the command line interface, then you can use the following tmsh commands to change the passwords.

tmsh modify auth password root 
tmsh modify auth password admin

I would recommend that you set a strong password of at least 12 random characters including numbers, letters, and special characters. Also, make sure that you document the password in a secure manner and its usually recommended to store in a password manager.

However, do not store the password in your personal password manager if the load balancer is owned by the company you work for. Always follow company policy/procedures for password storage for corporate devices.

If you want to read the official F5 documentation on this topic then click the link here.


2). Limit Control Plane Access

SSH/HTTPS Allowed Lists

I find that limiting control plane access is commonly missed when a F5 load balancer is placed behind a network firewall. F5 makes this easy by allowing you to configure a sshd and httpd allowed list.

Using these allowed list, you can restrict what source ip addresses can ssh and access the web UI/Rest API via https. This is typically for restricting access to the management interface since you can use packet-filters to restrict access to the self ip’s. However, I try to avoid using packet-filters whenever possible for performance reasons.

Below are a couple of example commands that will only allow 192.168.0.0/24 to manage a BigIP over ssh and https. All other ip addresses will not be allowed to login.

tmsh modify sys sshd allow replace-all-with { 192.168.0.0/255.255.255.0 } 
tmsh modify sys httpd allow replace-all-with { 192.168.0.0/255.255.255.0 }

If you want to read the official F5 documentation on this then click the links below.

SSHD Allowed list: https://support.f5.com/csp/article/K5380

HTTPD Allowed list: https://support.f5.com/csp/article/K13309

Click below to expand an example of me executing the changes above on a lab device.

Click to expand

First, I tested ssh and https access to my lab BipIP before making changes.

zachsmacbookpro:~ zach.brooks$ curl -Ik https://192.168.10.5
 HTTP/1.1 200 OK
 Date: Thu, 17 Jan 2019 05:37:18 GMT
 Server: Apache
 X-Frame-Options: SAMEORIGIN
 Strict-Transport-Security: max-age=16070400; includeSubDomains
 Last-Modified: Thu, 17 Jan 2019 05:36:22 GMT
 ETag: "2afd2-f97-57fa0c64df148"
 Accept-Ranges: bytes
 Content-Length: 3991
 X-Content-Type-Options: nosniff
 X-XSS-Protection: 1; mode=block
 Content-Security-Policy: default-src 'self'  'unsafe-inline' 'unsafe-eval' data: blob:; img-src 'self' data:  http://127.4.1.1 http://127.4.2.1
 Content-Type: text/html; charset=ISO-8859-1

zachsmacbookpro:~ zach.brooks$ ssh [email protected]
 The authenticity of host '192.168.10.5 (192.168.10.5)' can't be established.
 ECDSA key fingerprint is SHA256:xXYCVnvSCR1FpohQYpqhBXRYqfcMSD9EIoNc5t16jRw.
 Are you sure you want to continue connecting (yes/no)? ^C

Next, I executed the tmsh commands to restrict control plane access.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify sys sshd allow replace-all-with { 192.168.56.0/255.255.255.0 }
 [email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify sys httpd allow replace-all-with { 192.168.56.0/255.255.255.0 }
 [email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)#

Finally, I ran the same test after and observed a 403 when attempting to connect on https and a tcp reset when trying to ssh.

zachsmacbookpro:~ zach.brooks$ curl -Ik https://192.168.10.5
 HTTP/1.1 403 Forbidden
 Date: Thu, 17 Jan 2019 05:37:45 GMT
 Server: Apache
 X-Frame-Options: SAMEORIGIN
 Strict-Transport-Security: max-age=16070400; includeSubDomains
 Accept-Ranges: bytes
 X-Content-Type-Options: nosniff
 X-XSS-Protection: 1; mode=block
 Content-Security-Policy: default-src 'self'  'unsafe-inline' 'unsafe-eval' data: blob:; img-src 'self' data:  http://127.4.1.1 http://127.4.2.1
 Content-Length: 1296
 Content-Type: text/html; charset=ISO-8859-1
 
zachsmacbookpro:~ zach.brooks$ ssh [email protected]
 ssh_exchange_identification: read: Connection reset by peer

Self IP Allowed Services

The second item is the allowed services attribute under the self ip addresses. Typically, management of an F5 load balancer is done by using an Out of Band (OOB) network connecting to the management interface on the BigIP.

However, you can also use any of the network interfaces to manage as well. When you create network self ip addresses, there is an allowed services attribute that limits what ports the self ip will listen on. In many cases, this is set to allow default, which allows many of the default services. This includes ssh, https, the F5 config sync ports, iQuery, and others from any source if there is not another filter configured.

In my opinion, this is only acceptable when used on a connection directly between two BigIPs for HA purposes.

For any other configuration, I recommend that you start with an allowed services of none and only allow the services you need. For example, if your leveraging the LTM and GTM modules but on different BigIPs (typical deployment), then your GTMs will need to monitor your LTMs using the iQuery protocol.

Additionally, you will need to allow tcp 4353 and a couple of other services between the GTM and LTM. This allows the GTM to properly monitor the health of the LTM.

For example, you can use the following command to only allow ssh and snmp-polling on a self ip.

tmsh modify net self <Self-IP> allow-service replace-all-with { tcp:22, udp:161 }

I’ve also included a screenshot from the GUI of my F5 load balancer. The allowed-service list shows up under the port-lockdown portion of the self ip configuration. This self ip is not configured to listen for any service.

Self IP Screenshot
F5 Self IP Example

3). Use AAA for remote login and audit logging

Next, we will move on to using AAA with an F5 load balancer. F5 supports multiple methods of authentication. I’ve typically seen Tacacs+ and Ldap as the most common. Unfortunately, once you configure remote authentication, the local username db can no longer be used for login to the gui or cli (accounts created using tmsh create auth user). There is a workaround to manually add these users to the /config/bigip/auth/localusers file on the BigIP but F5 doesn’t officially support or recommend this method.

If your using tacacs then you can configure your audit logs to also be sent to your tacacs server using the tacacs protocol. Alternatively, you can ship the audit logs to a syslog server. I have found audit logs to be extremely useful when troubleshooting down devices.

This is overlooked all the time by network engineers when troubleshooting. Many times a network engineer will trace an issue down to a specific device but have difficulty determining what is wrong with the configuration. If you have access to your devices change logs, you can quickly identify what changed and roll it back without fully understanding each part of the configuration.

I’ve included some links below for each of the mentioned configurations on a F5 load balancer.

Auth: https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/bigip-user-account-administration-11-6-0/5.html

Tacacs: https://support.f5.com/csp/article/K8811

Audit Log: https://support.f5.com/kb/en-us/products/big-iq-security/manuals/product/bigiq-web-application-security-administration-4-3-0/7.html

Syslog Configuration: https://support.f5.com/csp/article/K13080


4). Setup DNS and NTP

DNS Setup

DNS is useful for a number of configurations on a F5 load balancer. An example is below where I configured my lab F5 to use 0.us.pool.ntp.org has it’s ntp server. Keep in mind this is just an example. I’ve listed the specific tmsh commands below and an expand if you would like to see the changes and verification done on my lab device.

Below is a DNS example command that will configure the F5 load balancer to use Google’s name-servers for dns resolution.

modify sys dns name-servers replace-all-with { 8.8.8.8 8.8.4.4 }

NTP Setup

NTP is critical for security and troubleshooting. Accurate time stamps are crucial when performing a root cause analysis or forensic investigation. It can be extremely challenging to correlate logs between multiple systems if the clock is not synchronized with an ntp server.

The ntp example command below sets 0.us.pool.ntp.org as the ntp server for the load balancer. DNS must be configured before you can use a hostname as the ntp server. If DNS is not configured, then you can only configure a specific ip address.

modify sys ntp servers replace-all-with { 0.us.pool.ntp.org } timezone America/Chicago

Click the links to be redirected to F5 knowledge articles for DNS and NTP configuration on the BigIP.

Click below to view a full example of me adding ntp and dns configurations to a lab device.

Click to expand

First, I added the dns name-servers my F5 load balancer will use to resolve hostnames.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify sys dns name-servers replace-all-with { 8.8.8.8 8.8.4.4 }

! Resulting configuration

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# list sys dns {
     name-servers { 8.8.8.8 8.8.4.4 }
 }

Next, I will configure my ntp server. I’m using 0.us.pool.ntp.org from the pool.ntp.org project as my ntp server.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify sys ntp servers replace-all-with { 0.us.pool.ntp.org } timezone America/Chicago

! Resulting configuration

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# list sys ntp {
     servers { 0.us.pool.ntp.org }
     timezone America/Chicago
 }

Finally, I validated that my F5 load balancer was able to synchronize it’s time with the NTP server using ntpq. I recommend doing this so your absolutely sure that your BigIP’s clock is correct.

! Executed from the bash shell
[[email protected]:Active:Standalone] config # ntpq -np
      remote           refid      st t when poll reach   delay   offset  jitter
 *45.79.11.217    200.98.196.212   2 u    7   64    1   64.619   -3.252   9.004
 [[email protected]:Active:Standalone] config #

Below are screenshots from the GUI showing how to change this configuration.

System > Configuration > Device > DNS

DNS Setup Screenshot
F5 DNS Screenshot

System > Configuration > Device > NTP

F5 NTP Screenshot

5). Setup SNMP Monitoring

Monitoring your F5 load balancer via snmp allows you to identify network issues by changes in traffic patterns. I’ve used snmp based monitor to help troubleshoot a number of issues like Denial of Service attacks, sizing issues, and application troubleshooting. It also allows you to configure your monitoring server to alert you based on specific events like high cpu/memory utilization or high network interface utilization.

There are three different versions of snmp. I’ve only seen snmpv2c and snmpv3 configured. However, snmpv3 is the only secure version and you must ensure that priv and auth are configured. Refer to the F5 knowledge articles below for additional detail.

MIB Info: https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/bigip-external-monitoring-implementations-11-5-0/10.html

Configuration: https://support.f5.com/kb/en-us/products/big-ip_ltm/manuals/product/tmos-implementations-11-2-1/25.html

NewRelic also has a F5 agent that you can install that is really nice. If you already use NewRelic, then it is worth looking into. The customers that I’ve worked with that use it love it.


6). Harden the Control Plane Cryptography

This is key to passing compliance audits. Auditors want to see that devices are managed in a secure way. You have to make sure secure encryption is being used. Researchers are continually discovering vulnerabilities in older cryptography that is commonly used on the internet that was previously considered secure. Examples of this are the usage of the triple DES cipher which is vulnerable to the sweet32 vulnerability and the RC4 cipher which is also considered insecure.

It is very easy to modify the cipher suites used by the control plane with the exception of the ssl configuration for iQuery. The following commands can be used to change the ciphers used by the sshd and httpd processes.

tmsh edit /sys sshd all-properties 
include "Ciphers aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc  
Macs hmac-sha2-256,hmac-sha2-512" 
restart sys service sshd tmsh 

modify sys httpd ssl-ciphersuite ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1 

! Or disable any Non-PFS Cipher 

tmsh modify sys httpd ssl-ciphersuite ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE+AES:SSLv3:!TLSv1

Nmap and openssl are very useful in auditing ssl and ssh ciphers. I’ve listed the commands that I use to validate ssl and ssh cipher changes below.

nmap --script ssl-enum-ciphers target-ip -p 443 
nmap --script ssh2-enum-algos target-ip -p 22

Click the links to be redirected to F5 knowledge articles for sshd and httpd.

If you click below you can view an example of the configuration changes along with verification done in my lab environment.

Click to expand

To start, I did a cipher scan for ssh and https to view the current cipher-suites used by both protocols. Note the insecure protocols used by sshd and https (particularly 3des which is vulnerably to sweet32).

! Testing SSHD Ciphers

zachsmacbookpro:~ zach.brooks$ nmap --script ssh2-enum-algos 192.168.56.102 -p 22
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-16 23:56 CST
 Nmap scan report for 192.168.56.102
 Host is up (0.00082s latency).
 PORT   STATE SERVICE
 22/tcp open  ssh
 | ssh2-enum-algos:
 |   kex_algorithms: (5)
 |       ecdh-sha2-nistp256
 |       ecdh-sha2-nistp384
 |       diffie-hellman-group-exchange-sha1
 |       diffie-hellman-group14-sha1
 |       diffie-hellman-group1-sha1
 |   server_host_key_algorithms: (4)
 |       ssh-rsa
 |       ssh-dss
 |       ecdsa-sha2-nistp256
 |       ssh-ed25519
 |   encryption_algorithms: (7)
 |       aes128-cbc
 |       aes256-cbc
 |       aes128-ctr
 |       aes192-ctr
 |       aes256-ctr
 |       aes192-cbc
 |       3des-cbc
 |   mac_algorithms: (1)
 |       hmac-sha1
 |   compression_algorithms: (2)
 |       none
 |_      [email protected]
 Nmap done: 1 IP address (1 host up) scanned in 0.70 seconds

! Testing HTTPD Ciphers

zachsmacbookpro:~ zach.brooks$ nmap --script ssl-enum-ciphers 192.168.56.102 -p 443
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-16 23:56 CST
 Nmap scan report for 192.168.56.102
 Host is up (0.00061s latency).
 PORT    STATE SERVICE
 443/tcp open  https
 | ssl-enum-ciphers:
 |   TLSv1.0:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
 |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       64-bit block cipher 3DES vulnerable to SWEET32 attack
 |   TLSv1.1:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
 |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       64-bit block cipher 3DES vulnerable to SWEET32 attack
 |   TLSv1.2:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
 |       TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA (secp256r1) - C
 |       TLS_RSA_WITH_3DES_EDE_CBC_SHA (rsa 2048) - C
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       64-bit block cipher 3DES vulnerable to SWEET32 attack
 |_  least strength: C
 Nmap done: 1 IP address (1 host up) scanned in 0.75 seconds

Next, I added the changes to harden the ssh cipher-suites. By default, the sshd configuration with have includes line set to none. You need to change none to the list of specific ciphers you want to be used and then add the Macs line with the desired hashing algorithms.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# edit /sys sshd all-properties
 ! will open VI
 modify sshd {
     allow replace-all-with { ALL }
     banner disabled
     banner-text none
     description none
     inactivity-timeout 0
     log-level info
     login enabled
     port 22
     include "Ciphers aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc
     Macs hmac-sha2-256,hmac-sha2-512"
 }
 Save changes? (y/n/e) y
 [email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# restart sys service sshd
 Stopping sshd:[  OK  ]
 Starting sshd:[  OK  ]

This change was successful and verified using the nmap script.

zachsmacbookpro:~ zach.brooks$ nmap --script ssh2-enum-algos 192.168.56.102 -p 22
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-16 23:59 CST
 Nmap scan report for 192.168.56.102
 Host is up (0.00062s latency).
 PORT   STATE SERVICE
 22/tcp open  ssh
 | ssh2-enum-algos:
 |   kex_algorithms: (5)
 |       ecdh-sha2-nistp256
 |       ecdh-sha2-nistp384
 |       diffie-hellman-group-exchange-sha1
 |       diffie-hellman-group14-sha1
 |       diffie-hellman-group1-sha1
 |   server_host_key_algorithms: (4)
 |       ssh-rsa
 |       ssh-dss
 |       ecdsa-sha2-nistp256
 |       ssh-ed25519
 |   encryption_algorithms: (4)
 |       aes256-ctr
 |       aes192-ctr
 |       aes128-ctr
 |       aes256-cbc
 |   mac_algorithms: (2)
 |       hmac-sha2-256
 |       hmac-sha2-512
 |   compression_algorithms: (2)
 |       none
 |_      [email protected]

Below is the httpd cipher lock-down changes which are very similar to changing the cipher suite in an ssl profile. Refer to section on Hardening Virtual Server SSL for a command that will show you which ciphers are allowed for a specific cipher string.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify sys httpd ssl-ciphersuite ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1
 [email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# restart sys service httpd
 Stopping httpd: [  OK  ]
 Starting httpd: [  OK  ]

Lastly, I verified the change with the nmap script. Make sure to always do this when your changing ssl configurations.

zachsmacbookpro:~ zach.brooks$ nmap --script ssl-enum-ciphers 192.168.56.102 -p 443
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-17 00:00 CST
 Nmap scan report for 192.168.56.102
 Host is up (0.00065s latency).
 PORT    STATE SERVICE
 443/tcp open  https
 | ssl-enum-ciphers:
 |   TLSv1.2:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
 |     compressors:
 |       NULL
 |     cipher preference: server
 |_  least strength: A
 Nmap done: 1 IP address (1 host up) scanned in 0.49 seconds

7). Harden Virtual Server SSL Profiles

The BigIP is typically used to offload ssl in many configurations. Similar to the control plane, its best to harden the ssl configuration in the ssl profiles to protect web application traffic or any other application encrypted with ssl.

Typically, the only non-default settings that will need to be changed are the ciphers string and the cert, key, and chain files. The cipher string can be modified directly in the ssl profile but its recommended to set the string in a parent profile and let the ssl profile applied to the virtual server inherit this attribute from the parent.

! how to modify the specific clientssl profile 

modify ltm profile client-ssl CLIENTSSL_EXAMPLE_PROF ciphers ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1:!TLSv1_1 

! using a parent profile, can be used on multiple end clientssl profiles and allows you to update ciphers on multiple vips with one configuration change 

create ltm profile client-ssl CLIENTSSL_SECURE_PARENT ciphers ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1:!TLSv1_1 defaults-from clientssl 

modify ltm profile client-ssl CLIENTSSL_EXAMPLE_PROF defaults-from CLIENTSSL_SECURE_PARENT

Please note, any attribute not specifically configured will default the setting from the parent profile. The default ssl parent profile will be clientssl which contains all default ciphers. Many of these ciphers are considered insecure.

I recommend that you also run the following command to list out all of the ciphers in the proposed cipher string before updating an ssl profile. This command is executed from the bash shell.

tmm --clientciphers '<cipher-string>'

I would recommend reading the following knowledge article to better understand ssl cipher strings. Also, I ran through these changes on a lab device. Click the expand below to view those changes.

Click to expand

I ran the nmap cipher scan ran before any changes were made. Allow of the ciphers are the ones allowed in the default client-ssl profile for the code version my lab load balancer is running.

zachsmacbookpro:~ zach.brooks$ nmap --script ssl-enum-ciphers 192.168.10.50 -p 443
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-17 00:01 CST
 Nmap scan report for 192.168.10.50
 Host is up (0.0015s latency).
 PORT    STATE SERVICE
 443/tcp open  https
 | ssl-enum-ciphers:
 |   TLSv1.0:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
 |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 1024) - A
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       Key exchange (dh 1024) of lower strength than certificate key
 |   TLSv1.1:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
 |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 1024) - A
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       Key exchange (dh 1024) of lower strength than certificate key
 |   TLSv1.2:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (rsa 2048) - A
 |       TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (dh 1024) - A
 |       TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (dh 1024) - A
 |     compressors:
 |       NULL
 |     cipher preference: server
 |     warnings:
 |       Key exchange (dh 1024) of lower strength than certificate key
 |_  least strength: A
 Nmap done: 1 IP address (1 host up) scanned in 0.60 seconds

I then validated the cipher string I was about to use, using the tmm –clientciphers command from bash.

[[email protected]:Active:Standalone] config # tmm --clientciphers 'ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1:!TLSv1_1'
        ID  SUITE                            BITS PROT    METHOD  CIPHER    MAC     KEYX
  0: 49199  ECDHE-RSA-AES128-GCM-SHA256      128  TLS1.2  Native  AES-GCM   SHA256  ECDHE_RSA
  1: 49200  ECDHE-RSA-AES256-GCM-SHA384      256  TLS1.2  Native  AES-GCM   SHA384  ECDHE_RSA
  2: 49192  ECDHE-RSA-AES256-SHA384          256  TLS1.2  Native  AES       SHA384  ECDHE_RSA
  3: 49191  ECDHE-RSA-AES128-SHA256          128  TLS1.2  Native  AES       SHA256  ECDHE_RSA
  4: 49171  ECDHE-RSA-AES128-CBC-SHA         128  TLS1.2  Native  AES       SHA     ECDHE_RSA
  5: 49172  ECDHE-RSA-AES256-CBC-SHA         256  TLS1.2  Native  AES       SHA     ECDHE_RSA
  6:   156  AES128-GCM-SHA256                128  TLS1.2  Native  AES-GCM   SHA256  RSA
  7:   157  AES256-GCM-SHA384                256  TLS1.2  Native  AES-GCM   SHA384  RSA
  8:    60  AES128-SHA256                    128  TLS1.2  Native  AES       SHA256  RSA
  9:    61  AES256-SHA256                    256  TLS1.2  Native  AES       SHA256  RSA
 10:    47  AES128-SHA                       128  TLS1.2  Native  AES       SHA     RSA
 11:    47  AES128-SHA                       128  DTLS1   Native  AES       SHA     RSA
 12:    53  AES256-SHA                       256  TLS1.2  Native  AES       SHA     RSA
 13:    53  AES256-SHA                       256  DTLS1   Native  AES       SHA     RSA

Next, I added a parent ssl profile with the desired cipher string. Then I applied the parent profile to the end profile applied to the virtual server.

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# create ltm profile client-ssl CLIENTSSL_SECURE_PARENT ciphers ECDHE+AES-GCM:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE+AES:RSA+AES-GCM:RSA+AES+SHA256:RSA+AES:!SSLv3:!TLSv1:!TLSv1_1 defaults-from clientssl

[email protected](labve1)(cfg-sync Standalone)(Active)(/Common)(tmos)# modify ltm profile client-ssl clientssl_testvip defaults-from CLIENTSSL_SECURE_PARENT

Lastly, I ran nmap again to validate the change was successful. You can compare the output with the tmm –clientciphers output. Keep in mind that certain options in a client-ssl profile can limit additional ciphers that show up in the tmm –clientciphers output.

zachsmacbookpro:~ zach.brooks$ nmap --script ssl-enum-ciphers 192.168.10.50 -p 443
 Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-17 00:02 CST
 Nmap scan report for 192.168.10.50
 Host is up (0.00083s latency).
 PORT    STATE SERVICE
 443/tcp open  https
 | ssl-enum-ciphers:
 |   TLSv1.2:
 |     ciphers:
 |       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
 |       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
 |       TLS_RSA_WITH_AES_128_GCM_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_GCM_SHA384 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 2048) - A
 |       TLS_RSA_WITH_AES_128_CBC_SHA (rsa 2048) - A
 |       TLS_RSA_WITH_AES_256_CBC_SHA (rsa 2048) - A
 |     compressors:
 |       NULL
 |     cipher preference: server
 |_  least strength: A
 Nmap done: 1 IP address (1 host up) scanned in 0.52 seconds

Be Careful!

This can be a very impactful change if not all clients are browsers. Many times there are services that are calling vips configured and these services could be using older versions of ssl.

For example, older versions of python did not support ssl handshake protocol tls1.2. I ran into a problem where I updated a cipher string on a virtual server to only allow tls1.2 and an api written in an old python version was also calling the same virtual server.

This change caused a good portion of our network automation to fail until I rolled back the change.

Using the show profile command to see SSL Stats

Luckily, there are ways to determine what ssl handshake protocol and ciphers clients are using that are connecting to the virtual server. To start, if you run the following command, you will get all statistics for a client-ssl profile.

tmsh show ltm profile client-ssl <profile_name>

The stats will indicate how many handshakes were completed for each handshake protocol along with errors. You can see how many clients are making requests using older handshake protocols and monitor this statistic for counter increments. However, this does not give you any detail about those clients or their source ip addresses.

Using an iRule to Log SSL

Alternatively, another method is to create an iRule on your F5 load balancer to log specific details about the client when older ssl handshake protocols are used. I created a simple iRule that logs the clients source ip, url, cipher suite, and handshake protocol when the handshake protocol used is tls1.0. The iRule then forwards this log to the clients syslog server using HSL. This allowed the client to have more visibility on which users are actually using tls1.0 before we disabled it.

Please note, in order to apply this iRule on a virtual server, the virtual server must have a client-ssl and http profile applied.

ltm rule RULE_HSL_LOG_TLSv1 { 
when CLIENTSSL_HANDSHAKE {     
    if { [SSL::cipher version] == "TLSv1" } {         
        set hslpool [HSL::open -proto UDP -pool POOL_HSL]
    } 
} 
when HTTP_REQUEST {     
    if {[info exists hslpool]} { 
        HSL::send $hslpool "Client_IP=[IP::client_addr], SSL_Version=[SSL::cipher version], SSL_Cipher=[SSL::cipher name], URL=[HTTP::host][HTTP::uri], VIP=[virtual name]"     
    } 
}

Alternatively, you can configure the iRule to log to the local ltm file.

ltm rule RULE_LOG_TLSv1 { 
when HTTP_REQUEST {
    if { [SSL::cipher version] == "TLSv1" } {
        log local0. "Client_IP=[IP::client_addr], SSL_Version=[SSL::cipher version], SSL_Cipher=[SSL::cipher name], URL=[HTTP::host][HTTP::uri], VIP=[virtual name]"     
    } 
}
}

Conclusion

In conclusion, following these recommendations is a good first step in securing your F5 load balancer environment. In addition, you may also want to incorporate these configurations into any F5 load balancer deployment templates. Lastly, you can also use this article as a starting point for a security audit on current F5 deployments. I hope find this article help and provide feedback in the comments below.

If your interested in F5 then read more posts here!