217 lines
8.7 KiB
ReStructuredText
217 lines
8.7 KiB
ReStructuredText
|
.. SPDX-License-Identifier: GPL-2.0
|
||
|
|
||
|
=======================
|
||
|
NFSv4 client identifier
|
||
|
=======================
|
||
|
|
||
|
This document explains how the NFSv4 protocol identifies client
|
||
|
instances in order to maintain file open and lock state during
|
||
|
system restarts. A special identifier and principal are maintained
|
||
|
on each client. These can be set by administrators, scripts
|
||
|
provided by site administrators, or tools provided by Linux
|
||
|
distributors.
|
||
|
|
||
|
There are risks if a client's NFSv4 identifier and its principal
|
||
|
are not chosen carefully.
|
||
|
|
||
|
|
||
|
Introduction
|
||
|
------------
|
||
|
|
||
|
The NFSv4 protocol uses "lease-based file locking". Leases help
|
||
|
NFSv4 servers provide file lock guarantees and manage their
|
||
|
resources.
|
||
|
|
||
|
Simply put, an NFSv4 server creates a lease for each NFSv4 client.
|
||
|
The server collects each client's file open and lock state under
|
||
|
the lease for that client.
|
||
|
|
||
|
The client is responsible for periodically renewing its leases.
|
||
|
While a lease remains valid, the server holding that lease
|
||
|
guarantees the file locks the client has created remain in place.
|
||
|
|
||
|
If a client stops renewing its lease (for example, if it crashes),
|
||
|
the NFSv4 protocol allows the server to remove the client's open
|
||
|
and lock state after a certain period of time. When a client
|
||
|
restarts, it indicates to servers that open and lock state
|
||
|
associated with its previous leases is no longer valid and can be
|
||
|
destroyed immediately.
|
||
|
|
||
|
In addition, each NFSv4 server manages a persistent list of client
|
||
|
leases. When the server restarts and clients attempt to recover
|
||
|
their state, the server uses this list to distinguish amongst
|
||
|
clients that held state before the server restarted and clients
|
||
|
sending fresh OPEN and LOCK requests. This enables file locks to
|
||
|
persist safely across server restarts.
|
||
|
|
||
|
NFSv4 client identifiers
|
||
|
------------------------
|
||
|
|
||
|
Each NFSv4 client presents an identifier to NFSv4 servers so that
|
||
|
they can associate the client with its lease. Each client's
|
||
|
identifier consists of two elements:
|
||
|
|
||
|
- co_ownerid: An arbitrary but fixed string.
|
||
|
|
||
|
- boot verifier: A 64-bit incarnation verifier that enables a
|
||
|
server to distinguish successive boot epochs of the same client.
|
||
|
|
||
|
The NFSv4.0 specification refers to these two items as an
|
||
|
"nfs_client_id4". The NFSv4.1 specification refers to these two
|
||
|
items as a "client_owner4".
|
||
|
|
||
|
NFSv4 servers tie this identifier to the principal and security
|
||
|
flavor that the client used when presenting it. Servers use this
|
||
|
principal to authorize subsequent lease modification operations
|
||
|
sent by the client. Effectively this principal is a third element of
|
||
|
the identifier.
|
||
|
|
||
|
As part of the identity presented to servers, a good
|
||
|
"co_ownerid" string has several important properties:
|
||
|
|
||
|
- The "co_ownerid" string identifies the client during reboot
|
||
|
recovery, therefore the string is persistent across client
|
||
|
reboots.
|
||
|
- The "co_ownerid" string helps servers distinguish the client
|
||
|
from others, therefore the string is globally unique. Note
|
||
|
that there is no central authority that assigns "co_ownerid"
|
||
|
strings.
|
||
|
- Because it often appears on the network in the clear, the
|
||
|
"co_ownerid" string does not reveal private information about
|
||
|
the client itself.
|
||
|
- The content of the "co_ownerid" string is set and unchanging
|
||
|
before the client attempts NFSv4 mounts after a restart.
|
||
|
- The NFSv4 protocol places a 1024-byte limit on the size of the
|
||
|
"co_ownerid" string.
|
||
|
|
||
|
Protecting NFSv4 lease state
|
||
|
----------------------------
|
||
|
|
||
|
NFSv4 servers utilize the "client_owner4" as described above to
|
||
|
assign a unique lease to each client. Under this scheme, there are
|
||
|
circumstances where clients can interfere with each other. This is
|
||
|
referred to as "lease stealing".
|
||
|
|
||
|
If distinct clients present the same "co_ownerid" string and use
|
||
|
the same principal (for example, AUTH_SYS and UID 0), a server is
|
||
|
unable to tell that the clients are not the same. Each distinct
|
||
|
client presents a different boot verifier, so it appears to the
|
||
|
server as if there is one client that is rebooting frequently.
|
||
|
Neither client can maintain open or lock state in this scenario.
|
||
|
|
||
|
If distinct clients present the same "co_ownerid" string and use
|
||
|
distinct principals, the server is likely to allow the first client
|
||
|
to operate normally but reject subsequent clients with the same
|
||
|
"co_ownerid" string.
|
||
|
|
||
|
If a client's "co_ownerid" string or principal are not stable,
|
||
|
state recovery after a server or client reboot is not guaranteed.
|
||
|
If a client unexpectedly restarts but presents a different
|
||
|
"co_ownerid" string or principal to the server, the server orphans
|
||
|
the client's previous open and lock state. This blocks access to
|
||
|
locked files until the server removes the orphaned state.
|
||
|
|
||
|
If the server restarts and a client presents a changed "co_ownerid"
|
||
|
string or principal to the server, the server will not allow the
|
||
|
client to reclaim its open and lock state, and may give those locks
|
||
|
to other clients in the meantime. This is referred to as "lock
|
||
|
stealing".
|
||
|
|
||
|
Lease stealing and lock stealing increase the potential for denial
|
||
|
of service and in rare cases even data corruption.
|
||
|
|
||
|
Selecting an appropriate client identifier
|
||
|
------------------------------------------
|
||
|
|
||
|
By default, the Linux NFSv4 client implementation constructs its
|
||
|
"co_ownerid" string starting with the words "Linux NFS" followed by
|
||
|
the client's UTS node name (the same node name, incidentally, that
|
||
|
is used as the "machine name" in an AUTH_SYS credential). In small
|
||
|
deployments, this construction is usually adequate. Often, however,
|
||
|
the node name by itself is not adequately unique, and can change
|
||
|
unexpectedly. Problematic situations include:
|
||
|
|
||
|
- NFS-root (diskless) clients, where the local DCHP server (or
|
||
|
equivalent) does not provide a unique host name.
|
||
|
|
||
|
- "Containers" within a single Linux host. If each container has
|
||
|
a separate network namespace, but does not use the UTS namespace
|
||
|
to provide a unique host name, then there can be multiple NFS
|
||
|
client instances with the same host name.
|
||
|
|
||
|
- Clients across multiple administrative domains that access a
|
||
|
common NFS server. If hostnames are not assigned centrally
|
||
|
then uniqueness cannot be guaranteed unless a domain name is
|
||
|
included in the hostname.
|
||
|
|
||
|
Linux provides two mechanisms to add uniqueness to its "co_ownerid"
|
||
|
string:
|
||
|
|
||
|
nfs.nfs4_unique_id
|
||
|
This module parameter can set an arbitrary uniquifier string
|
||
|
via the kernel command line, or when the "nfs" module is
|
||
|
loaded.
|
||
|
|
||
|
/sys/fs/nfs/net/nfs_client/identifier
|
||
|
This virtual file, available since Linux 5.3, is local to the
|
||
|
network namespace in which it is accessed and so can provide
|
||
|
distinction between network namespaces (containers) when the
|
||
|
hostname remains uniform.
|
||
|
|
||
|
Note that this file is empty on name-space creation. If the
|
||
|
container system has access to some sort of per-container identity
|
||
|
then that uniquifier can be used. For example, a uniquifier might
|
||
|
be formed at boot using the container's internal identifier:
|
||
|
|
||
|
sha256sum /etc/machine-id | awk '{print $1}' \\
|
||
|
> /sys/fs/nfs/net/nfs_client/identifier
|
||
|
|
||
|
Security considerations
|
||
|
-----------------------
|
||
|
|
||
|
The use of cryptographic security for lease management operations
|
||
|
is strongly encouraged.
|
||
|
|
||
|
If NFS with Kerberos is not configured, a Linux NFSv4 client uses
|
||
|
AUTH_SYS and UID 0 as the principal part of its client identity.
|
||
|
This configuration is not only insecure, it increases the risk of
|
||
|
lease and lock stealing. However, it might be the only choice for
|
||
|
client configurations that have no local persistent storage.
|
||
|
"co_ownerid" string uniqueness and persistence is critical in this
|
||
|
case.
|
||
|
|
||
|
When a Kerberos keytab is present on a Linux NFS client, the client
|
||
|
attempts to use one of the principals in that keytab when
|
||
|
identifying itself to servers. The "sec=" mount option does not
|
||
|
control this behavior. Alternately, a single-user client with a
|
||
|
Kerberos principal can use that principal in place of the client's
|
||
|
host principal.
|
||
|
|
||
|
Using Kerberos for this purpose enables the client and server to
|
||
|
use the same lease for operations covered by all "sec=" settings.
|
||
|
Additionally, the Linux NFS client uses the RPCSEC_GSS security
|
||
|
flavor with Kerberos and the integrity QOS to prevent in-transit
|
||
|
modification of lease modification requests.
|
||
|
|
||
|
Additional notes
|
||
|
----------------
|
||
|
The Linux NFSv4 client establishes a single lease on each NFSv4
|
||
|
server it accesses. NFSv4 mounts from a Linux NFSv4 client of a
|
||
|
particular server then share that lease.
|
||
|
|
||
|
Once a client establishes open and lock state, the NFSv4 protocol
|
||
|
enables lease state to transition to other servers, following data
|
||
|
that has been migrated. This hides data migration completely from
|
||
|
running applications. The Linux NFSv4 client facilitates state
|
||
|
migration by presenting the same "client_owner4" to all servers it
|
||
|
encounters.
|
||
|
|
||
|
========
|
||
|
See Also
|
||
|
========
|
||
|
|
||
|
- nfs(5)
|
||
|
- kerberos(7)
|
||
|
- RFC 7530 for the NFSv4.0 specification
|
||
|
- RFC 8881 for the NFSv4.1 specification.
|