# Using NFS over TLS

This procedure shows how to mount an NFS share over a Transport Layer Security (TLS) channel on systems that run either **RHEL 9 / Rocky Linux 9** or **Ubuntu 24.04 LTS**.

## 1. Prerequisites

* A server that exports an NFS share and supports [RFC 9289 - Towards Remote Procedure Call Encryption by Default](https://datatracker.ietf.org/doc/rfc9289/).
* The kernel needs to be new enough to have been built with
`CONFIG_NET_HANDSHAKE=y`. Examples: RHEL 9.x or upstream kernel 6.7 and above.
* Access to certificates that the client will trust (either a private CA certificate or the server certificate itself)

## 2. Install the required packages

### RHEL 9 / Rocky Linux 9

```bash
sudo dnf install nfs-utils ktls-utils
```

The **ktls-utils** package delivers **`tlshd`**, the user‑space handshake daemon that enables kTLS.

### Ubuntu 24.04 LTS

```bash
sudo apt update
sudo apt install nfs-common ktls-utils (>= 0.11)
```

If your mirror does not yet carry version 0.11 or later, download the package manually:

```bash
wget -4 https://archive.ubuntu.com/ubuntu/pool/universe/k/ktls-utils/ktls-utils_0.11-1_amd64.deb
sudo dpkg -i ktls-utils_0.11-1_amd64.deb
```

## 3. Enable the **tlshd** handshake daemon

```bash
sudo systemctl enable --now tlshd.service
```

Verify that the service is active:

```bash
systemctl --no-pager status tlshd
```

## 4. Provide certificates

The client must present a certificate chain that it trusts. Use *one* of the following options:

### Option A — use an existing Enterprise CA

1. Copy the CA certificate that signed the NFS server’s certificate to the client.
2. Continue with [Section 5](#5-configure-tlshd).

### Option B — generate a private CA and a server certificate (lab use)

> **WARNING:** Self‑signed certificates are suitable only for testing. Use a trusted CA in production environments.

```bash
# Create a private CA (valid for 10 years)
openssl req \
  -x509 -nodes -new -sha256 -days 3650 \
  -newkey rsa:2048 \
  -keyout RootCA.key \
  -out   RootCA.crt \
  -subj  "/CN=Demo‑Root‑CA"

# Create a server key and CSR (replace with real FQDN / IP)
openssl req \
  -new -nodes -newkey rsa:2048 \
  -keyout server.key \
  -out   server.csr \
  -subj  "/CN=nfs.example.com"

cat > domains.ext <<'EOF'
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment
subjectAltName=DNS:nfs.example.com,IP:192.0.2.10
EOF

# Sign the CSR with the private CA (valid for ~3 years)
openssl x509 -req -in server.csr \
  -CA RootCA.crt -CAkey RootCA.key -CAcreateserial \
  -out server.crt -days 1024 -sha256 -extfile domains.ext
```

> **NOTE:** `subjectAltName` field must contain DNS names / IP addressees of server, used by client during connection establishing.


Copy **`RootCA.crt`** (or **`server.crt`** if you pinned only the server certificate) to the client.


## 5. Configure **tlshd**

Edit **`/etc/tlshd.conf`** and set the path to the certificate or trust store that you copied in the previous step. For example:

```ini
[authenticate.client]
x509.truststore=/etc/pki/ca-trust/source/anchors/RootCA.crt
```

> **NOTE:** On Ubuntu, place the file in `/usr/local/share/ca-certificates/` and run `sudo update-ca-certificates`.

Reload the daemon:

```bash
sudo systemctl restart tlshd.service
```

## 6. Mount the NFS share over TLS


1. Create a mount point:

   ```bash
   sudo mkdir -p /mnt/nfs_tls
   ```
2. Mount the share. Replace **`nfs.example.com:/export`** with your export path:

   ```bash
   sudo mount -o xprtsec=tls nfs.example.com:/export /mnt/nfs_tls
   ```

   The **`-o xprtsec=tls`** option tells the NFS client to negotiate a kTLS session with the server via *tlshd*.

To make the mount persistent, add an entry to **`/etc/fstab`**:

```
nfs.example.com:/export  /mnt/nfs_tls  nfs4  xprtsec=tls  0  0
```

---

## 7. Verify the TLS session

Run **`ss`** or **`nfsstat`** and check that the connection uses `tls`:

```bash
ss -tna | grep nfs
```

A line similar to the following confirms that the mount is encrypted:

```
ESTAB 0 0 192.0.2.100:915 192.0.2.10:2049 tls
```


## 8. Troubleshooting

| Symptom                                 | Possible cause                                   | Resolution                                                                               |
| --------------------------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------- |
| `mount` returns *permission denied*     | The client does not trust the server certificate | Verify that the correct CA / certificate is listed in `tlshd.conf` and restart **tlshd** |
| `mount` hangs                           | `tlshd` is not running                           | Start the service with `systemctl enable --now tlshd`                                    |


## 9. Additional resources

* `man nfs`
* `man tlshd`
