Tech ONTAP Blogs
Tech ONTAP Blogs
NetApp Image
NetApp is the most secure storage on the planet. With that in mind, let's look at the available technology for encrypting NFS traffic over-the-wire with NetApp ONTAP. The options include using NFS with Kerberos, running NFS over IPsec connections, and a nascent approach using NFS over TLS. While the setup for NFS with Kerberos is well documented, examples of end-to-end configuration for IPsec and NFS over TLS with ONTAP are a bit harder to find, so we will cover those details in this article.
If you want a quick summary of these options, here are the key points:
If you are looking for details on how to configure over-the-wire encryption using these technologies with NetApp storage, read on!
We will start with a quick discussion of using NFS with Kerberos. This option has been available for many years and is well documented in TR-4616: NFS Kerberos in ONTAP. If you cannot trust who has root access on your NFS clients, then using NFS with Kerberos allows you to make sure that the users on your NFS client are who they say they are. NFS with Kerberos also provides for over-the-wire encryption, using the krb5p mount option. I won't go into the configuration steps for NFS with krb5p in this blog, since it is covered very well in TR-4616. While this is a great option for security, it also comes with the most complexity to configure and the largest performance hit of all the options for NFS over-the-wire encryption. In addition, there is no roadmap for improved performance of NFS with krb5p via hardware offload.
Next up is running NFS over IPsec connections. ONTAP has supported IPsec for years, since the 9.8 release! In addition to pre-shared keys being supported since ONTAP 9.8, we have supported certificate authentication since 9.10.1. More recently, we support IPsec hardware offload using ONTAP 9.16.1 with our newer platforms. See the Evolution of the ONTAP IPsec Implementation for more details.
For the remainder of the IPsec section of this blog, I give some end-to-end examples of configuring IPsec with ONTAP and on the NFS client. There are multiple approaches to configuring IPsec, and many configuration options with the popular IPsec client software strongSwan. All traffic can be encrypted, or only certain ports. Policies can be configured between specific IP addresses, or between entire subnets. The approach I document in this article tries to keep the IPsec client configuration as generic as possible while allowing for simultaneous connections to multiple storage LIFs.
When configuring NFS with Kerberos or using NFS over TLS, the NFS client can choose to mount an NFS export with the required options to enable these features or a standard mount can be performed with "sec=sys". This concept is different from IPsec in that once an IPsec security policy is defined and enabled for a LIF on the storage system, traffic is only allowed on that LIF via an IPsec connection.
Below are some storage side commands that are useful to be aware of for any type of IPsec configuration:
# Enable ipsec on your cluster
security ipsec config modify -is-enabled true
# Check for active IPsec connections
security ipsec show-ikesa -node <nodename>
# Check for IPsec related errors
event log show -event ipsec.*
To use IPSec with ONTAP we need IPsec client software that supports IKEv2. In the Linux world, two popular software packages that fill this requirement are strongSwan and Libreswan. For my examples, I will be using strongSwan. To install strongSwan, run the following commands on a Red Hat compatible Linux distribution:
dnf install epel-release
dnf install strongswan
systemctl enable strongswan
systemctl start strongswan
Here are some notes about strongSwan that will apply to all of the IPsec configurations we show in this article:
Configuration with a pre-shared key is straightforward. In the following example, we configure a storage system policy for each of two LIFs on the SVM and use a subnet definition for the IPsec clients:
::> security ipsec policy create -vserver svm1 -name lif1_psk -local-ip-subnets 192.168.0.201/32 -remote-ip-subnets 192.168.0.0/24
{Enter your passphrase - I used netapp123netapp123netapp123}
::> security ipsec policy create -vserver svm1 -name lif2_psk -local-ip-subnets 192.168.0.202/32 -remote-ip-subnets 192.168.0.0/24
{Enter your passphrase - I used netapp123netapp123netapp123}
On the client, we use the following swanctl.conf configuration with a connection definition for each storage LIF and the pre-shared key:
connections {
svm1_lif1 {
children {
svm1_lif1 {
esp_proposals = aes256gcm16
mode = transport
start_action = trap
# Connection from local subnet to lif1.
local_ts = 192.168.0.0/24
remote_ts = 192.168.0.201/32
}
}
# Connection from local subnet to lif2.
local_addrs = 192.168.0.0/24
remote_addrs = 192.168.0.201/32
proposals = aes256-sha384-ecp384
local {
auth = psk
}
remote {
auth = psk
}
}
svm1_lif2 {
children {
svm1_lif2 {
esp_proposals = aes256gcm16
mode = transport
start_action = trap
# Connection from local subnet to lif2.
local_ts = 192.168.0.0/24
remote_ts = 192.168.0.202/32
}
}
# Connection from local subnet to lif2.
local_addrs = 192.168.0.0/24
remote_addrs = 192.168.0.202/32
proposals = aes256-sha384-ecp384
local {
auth = psk
}
remote {
auth = psk
}
}
}
secrets {
ike-svm1 {
# This must match the pre-shared key entered for storage policy.
secret = netapp123netapp123netapp123
# The ike id must match the storage policy remote-ip-subnets.
id = 192.168.0.0/24
}
}
Now run "swanctl --load-all" and then "swanctl --list-conns" to make sure your connections are properly loaded. If all is well, you should be able to successfully ping the storage LIFs from the IPsec client,
Configuration with certificate authentication is a bit more involved due to the requirement for creating and configuring certificates both on the storage LIFs and the IPsec clients. If you are familiar with PKI, you can create and manage the certificates however you wish. In this example I use the certificate management tools built into ONTAP. Note that when copying a public key certificate or a private key, always include the "-----BEGIN ..." and "-----END ..." lines. First, we will create a certificate authority (CA), add that CA to the local ONTAP ipsec configuration, and copy the CA public key certificate to the IPsec client strongSwan configuration directory:
security certificate create -vserver svm1 -type root-ca -common-name svm1 -cert-name svm1_ipsec_ca
security ipsec ca-certificate add -vserver svm1 -ca-certs svm1_ipsec_ca
security certificate show -vserver svm1 -cert-name svm1_ipsec_ca -instance
{Copy the public key certificate to a file on the IPsec client at /etc/strongswan/swanctl/x509ca/svm1_ipsec_ca.pem}
Next, we will create the certificate to use for our storage LIF. Repeat the following steps for each storage LIF that is part of your IPsec policy, making sure to use the proper FQDN and IP address when generating the certificate signing request:
security certificate generate-csr -common-name svm1_lif1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.201 -dns-name svm1_lif1.demo.netapp.com
{Save each certificate request and private key}
security certificate sign -vserver svm1 -ca svm1 -ca-serial 1821A2A76A371FFC -expire-days 360
{Enter each certificate to sign and get signed certificate}
security certificate install -type server -vserver svm1
{Enter each signed certificate and private key}
We also need a certificate to use for the Linux IPsec client. We will again use the ONTAP certificate management functionality to create the certificate, and then place the public key certificate and private key in the correct location for strongSwan on the IPsec client:
security certificate generate-csr -common-name linux1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.61
{Save certificate request and private key}
security certificate sign -vserver svm1 -ca svm1 -ca-serial 1821A2A76A371FFC -expire-days 360
{Enter certificate to sign and get signed certificate}
{copy the signed public key certificate to /etc/strongswan/swanctl/x509/linux1.demo.netapp.com.pem}
{copy the private key to /etc/strongswan/swanctl/private/linux1.demo.netapp.com.key}
OK! With all the certificates in place, we use the following swantctl.conf on the IPsec client:
connections {
svm1_lif1 {
children {
svm1_lif1 {
esp_proposals = aes256gcm16
mode = transport
start_action = trap
local_ts = 192.168.0.0/24
remote_ts = 192.168.0.201/32
}
}
local_addrs = 192.168.0.0/24
remote_addrs = 192.168.0.201/32
proposals = aes256-sha384-ecp384
local {
auth = pubkey
id = "CN=linux1.demo.netapp.com"
certs = linux1.demo.netapp.com.pem
}
remote {
auth = pubkey
id = "CN=svm1_lif1.demo.netapp.com"
}
}
svm1_lif2 {
children {
svm1_lif2 {
esp_proposals = aes256gcm16
mode = transport
start_action = trap
local_ts = 192.168.0.0/24
remote_ts = 192.168.0.202/32
}
}
local_addrs = 192.168.0.0/24
remote_addrs = 192.168.0.202/32
proposals = aes256-sha384-ecp384
local {
auth = pubkey
id = "CN=linux1.demo.netapp.com"
certs = linux1.demo.netapp.com.pem
}
remote {
auth = pubkey
id = "CN=svm1_lif2.demo.netapp.com"
}
}
}
Now run "swanctl --load-all" and then "swanctl --list-conns" to make sure your connections are properly loaded. If all is well, you should be able to successfully ping the storage LIFs from the IPsec client.
I've also tested IPsec with IPv6, and ran into a couple of strongSwan configuration requirements to make this work. The first issue is that we need to bypass IPv6 NDP NS and NA traffic in the swanctl.conf as shown in this snippet of the configuration file:
{Add this at the start of the connections block}
# Bypass IPv6 NDP NS and NA traffic.
# As per https://docs.strongswan.org/docs/5.9/config/IPv6Ndp.html
ndp {
children {
ns {
mode = pass
start_action = trap
local_ts = ::/0[ipv6-icmp/135]
remote_ts = ::/0[ipv6-icmp/135]
}
na {
mode = pass
start_action = trap
local_ts = ::/0[ipv6-icmp/136]
remote_ts = ::/0[ipv6-icmp/136]
}
}
}
One more change that I found from my testing with IPv6 is that simple IP address endpoints (without subnet notation) must be given in the local_addrs and remote_addrs files of swanctl.conf, as shown in this snippet:
local_addrs = fd12:1234:5678:1::2
remote_addrs = fd12:1234:5678:1::4
Finally, we will showcase the use of NFS over TLS. The NFS over TLS feature was introduced in ONTAP 9.15.1 as a Tech Preview. This means that it is not yet ready for production, and full GA support for this feature in ONTAP will come in a future release. You should also be aware that this is a very new feature on the Linux NFS client side as well, as it first shows up in RHEL as a Technology Preview in RHEL 9.4.
Let's look at the configuration steps to get NFS over TLS running. NFS over TLS relies on certificates, and we will need to configure a unique certificate for each LIF in the SVM that will handle NFS over TLS traffic. If you are familiar with PKI, you can create and manage the certificates however you wish. In this example, I will simplify the setup by using the certificate management tools built into ONTAP. First, we will create a certificate authority (CA) in the SVM and display the public key certificate of the CA to be used later on our NFS client. Note that when copying a public key certificate or a private key, always include the "-----BEGIN ..." and "-----END ..." lines.
security certificate create -vserver svm1 -type root-ca -common-name svm1_ca
security certificate show -vserver svm1 -common-name svm1_ca -type root-ca -instance
Next, we will create a certificate for one of our SVM LIFs and configure the LIF to use this certificate for NFS over TLS:
security certificate generate-csr -common-name svm1_lif1.demo.netapp.com -algorithm RSA -hash-function SHA256 -ipaddr 192.168.0.61 -dns-name svm1_lif1.demo.netapp.com,svm1_lif1,svm1
{Save certificate request and private key}
security certificate sign -ca svm1_ca -vserver svm1 -ca-serial 181F8F545154B6BA -expire-days 364
{Enter certificate to sign and get signed certificate}
security certificate install -vserver svm1 -type server -cert-name svm1_lif1.demo.netapp.com
{Enter signed certificate and private key}
nfs tls interface enable -vserver svm1 -lif svm1_lif1 -certificate-name svm1_lif1.demo.netapp.com
The above commands will be required for each LIF on which you want to run NFS over TLS traffic. Also, a few notes are in order about the security certificate generate-csr command above:
Now, on the Linux NFS client, we have to first install the ktls package. In my example, I'm using a Red Hat 9.4 compatible client:
dnf install ktls-utils
systemctl enable tlshd
systemctl start tlshd
Next, remember that CA public key certificate I told you to make a copy of from the output of the "security certificate show -vserver svm1 -common-name svm1_ca -type root-ca -instance" command? We need to place it on the Linux client and run a command as follows:
vi /etc/pki/ca-trust/source/anchors/svm1_ca.pem
{Paste the CA public certificate that was used to sign LIF certificates on storage side}
update-ca-trust extract
Now we should be able to mount an NFS export using TLS! Here is the syntax to mount with NFSv3 over TLS:
mount -o nfsvers=3,xprtsec=tls svm1_lif1:/vol1 /vol1
That's it! If you are using IPv6, the procedure for NFS over TLS works the same way - substitute IPv6 IP addresses as required when creating your certificates.
I hope you found all of these details useful! Hit me in the comments if you have any questions on these technologies or how the configuration works.