<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://wiki.lustre.org/index.php?action=history&amp;feed=atom&amp;title=Lustre_Multi_Tenancy</id>
	<title>Lustre Multi Tenancy - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.lustre.org/index.php?action=history&amp;feed=atom&amp;title=Lustre_Multi_Tenancy"/>
	<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Multi_Tenancy&amp;action=history"/>
	<updated>2026-10-28T04:07:20Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>http://wiki.lustre.org/index.php?title=Lustre_Multi_Tenancy&amp;diff=5761&amp;oldid=prev</id>
		<title>Elliswilson: Created page with &quot;__TOC__  == Overview ==  Multi-tenancy lets separate groups of users share one Lustre filesystem without being able to see or reach each other&#039;s data, even when they have root on their own clients. It is built from three pieces:  * &#039;&#039;&#039;Nodemaps&#039;&#039;&#039; group clients by NID. Each group gets its own identity mapping (UID/GID/PROJID), root squash, and policy (read-only mounts, encryption, which admin operations are allowed, and more). * &#039;&#039;&#039;Filesets&#039;&#039;&#039; confine a nodemap&#039;s clients...&quot;</title>
		<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Multi_Tenancy&amp;diff=5761&amp;oldid=prev"/>
		<updated>2026-10-12T15:11:03Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;__TOC__  == Overview ==  Multi-tenancy lets separate groups of users share one Lustre filesystem without being able to see or reach each other&amp;#039;s data, even when they have root on their own clients. It is built from three pieces:  * &amp;#039;&amp;#039;&amp;#039;Nodemaps&amp;#039;&amp;#039;&amp;#039; group clients by NID. Each group gets its own identity mapping (UID/GID/PROJID), root squash, and policy (read-only mounts, encryption, which admin operations are allowed, and more). * &amp;#039;&amp;#039;&amp;#039;Filesets&amp;#039;&amp;#039;&amp;#039; confine a nodemap&amp;#039;s clients...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Multi-tenancy lets separate groups of users share one Lustre filesystem without being able to see or reach each other&amp;#039;s data, even when they have root on their own clients. It is built from three pieces:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Nodemaps&amp;#039;&amp;#039;&amp;#039; group clients by NID. Each group gets its own identity mapping (UID/GID/PROJID), root squash, and policy (read-only mounts, encryption, which admin operations are allowed, and more).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Filesets&amp;#039;&amp;#039;&amp;#039; confine a nodemap&amp;#039;s clients to one or more subdirectories, which those clients see as the filesystem root.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Client identification&amp;#039;&amp;#039;&amp;#039; ensures a client really is the node it claims to be. Nodemaps trust NIDs, so isolation is only as strong as your guarantee that one tenant cannot use another tenant&amp;#039;s NID. Use a trusted network design, or strong authentication with [[Lustre Kerberos SSK Authentication|Kerberos or Shared-Secret Key]]. SSK keys can be bound to a specific nodemap.&lt;br /&gt;
&lt;br /&gt;
For the full nodemap reference, see [[UID/GID_Mapping|UID/GID Mapping]] and the &amp;#039;&amp;#039;Mapping UIDs and GIDs with Nodemap&amp;#039;&amp;#039; chapter of the [https://doc.lustre.org/lustre_manual.xhtml Lustre Operations Manual]. For the broader security picture, see [[Setting up Lustre Security]].&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Run all &amp;lt;code&amp;gt;lctl nodemap_*&amp;lt;/code&amp;gt; commands on the MGS.&amp;#039;&amp;#039;&amp;#039; Since Lustre 2.9 the configuration is stored on the MGS and propagated to all servers automatically, usually within about ten seconds. During that window, clients may be served under either the old or the new settings, so make changes in a maintenance window, or while the affected clients are not writing.&lt;br /&gt;
&lt;br /&gt;
== Before You Start: A Nodemap for the Servers ==&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Do this first.&amp;#039;&amp;#039;&amp;#039; Once nodemaps are active, any node that matches no nodemap falls into the &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; nodemap, which squashes root and maps every user to &amp;lt;code&amp;gt;nobody&amp;lt;/code&amp;gt;. That includes Lustre servers, which act as clients when they talk to each other. The manual requires a nodemap that covers &amp;#039;&amp;#039;&amp;#039;all Lustre server nodes&amp;#039;&amp;#039;&amp;#039;, with both &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;trusted&amp;lt;/code&amp;gt; set:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_add TrustedSystems&lt;br /&gt;
 mgs# lctl nodemap_add_range --name TrustedSystems --range 10.0.0.[1-20]@tcp&lt;br /&gt;
 mgs# lctl nodemap_modify --name TrustedSystems --property admin --value 1&lt;br /&gt;
 mgs# lctl nodemap_modify --name TrustedSystems --property trusted --value 1&lt;br /&gt;
&lt;br /&gt;
Put administrative clients (backup nodes, data movers, and the nodes you run &amp;lt;code&amp;gt;chown&amp;lt;/code&amp;gt; from) in this nodemap or a similar one. You need at least one group with full access for maintenance.&lt;br /&gt;
&lt;br /&gt;
== Nodemaps ==&lt;br /&gt;
&lt;br /&gt;
=== Creating a Nodemap and Assigning Clients ===&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_add tenantA&lt;br /&gt;
 mgs# lctl nodemap_add_range --name tenantA --range 10.0.1.[0-255]@tcp&lt;br /&gt;
 mgs# lctl nodemap_add_range --name tenantA --range 10.0.2.[0-255]@tcp&lt;br /&gt;
&lt;br /&gt;
Clients whose NIDs fall in these ranges belong to &amp;lt;code&amp;gt;tenantA&amp;lt;/code&amp;gt;. To remove a range with &amp;lt;code&amp;gt;nodemap_del_range&amp;lt;/code&amp;gt;, give exactly the range you added. You cannot remove a sub-range or a partly overlapping range.&lt;br /&gt;
&lt;br /&gt;
=== The default Nodemap ===&lt;br /&gt;
&lt;br /&gt;
Clients that match no nodemap belong to the built-in &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; nodemap, which cannot be deleted. Only some properties can be set on it (&amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trusted&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;squash_uid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;squash_gid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fileset&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;audit_mode&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;rbac&amp;lt;/code&amp;gt;), and &amp;#039;&amp;#039;&amp;#039;no ID mappings&amp;#039;&amp;#039;&amp;#039; can be defined on it. With its default values (&amp;lt;code&amp;gt;admin=0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;trusted=0&amp;lt;/code&amp;gt;), clients that match no other nodemap have root squashed and every other user squashed to &amp;lt;code&amp;gt;nobody&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Be careful changing &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;trusted&amp;lt;/code&amp;gt; on &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt;. Every unlisted node inherits the change, possibly including your servers.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
Set properties with &amp;lt;code&amp;gt;lctl nodemap_modify --name NAME --property PROPERTY --value VALUE&amp;lt;/code&amp;gt;. The ones that matter most for tenancy:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Property !! Default !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt; || 0 || 1 = do &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; squash root. 0 = map root to &amp;lt;code&amp;gt;squash_uid&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;squash_gid&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;trusted&amp;lt;/code&amp;gt; || 0 || 1 = use client IDs as-is (no mapping) for non-root users. 0 = map users through the nodemap&amp;#039;s idmaps or offset, and &amp;#039;&amp;#039;&amp;#039;squash unmapped users&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;squash_uid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;squash_gid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;squash_projid&amp;lt;/code&amp;gt; || 65534 (&amp;lt;code&amp;gt;nobody&amp;lt;/code&amp;gt;) || The ID that root (when &amp;lt;code&amp;gt;admin=0&amp;lt;/code&amp;gt;) and unmapped IDs (when &amp;lt;code&amp;gt;trusted=0&amp;lt;/code&amp;gt;) are mapped to. Cannot be 0. &amp;lt;code&amp;gt;squash_projid&amp;lt;/code&amp;gt; exists since 2.15.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;deny_unknown&amp;lt;/code&amp;gt; || 0 || 1 = deny unmapped users entirely instead of squashing them. This includes root, when &amp;lt;code&amp;gt;admin=0&amp;lt;/code&amp;gt; and root is not mapped.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;map_mode&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;all&amp;lt;/code&amp;gt; || Which ID types are mapped: one or more of &amp;lt;code&amp;gt;uid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;gid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;projid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;both&amp;lt;/code&amp;gt; (UIDs and GIDs), or &amp;lt;code&amp;gt;all&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;readonly_mount&amp;lt;/code&amp;gt; || 0 || 1 = clients are forced to a read-only mount unless they explicitly specify otherwise.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;deny_mount&amp;lt;/code&amp;gt; || 0 || 1 = refuse new client mounts from this nodemap. Existing mounts keep working until a remount is attempted.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;forbid_encryption&amp;lt;/code&amp;gt; || 0 || 1 = prevent clients from using [[Lustre Client Encryption|client-side encryption]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;audit_mode&amp;lt;/code&amp;gt; || 1 || 0 = do not record this nodemap&amp;#039;s access events in Changelogs. Useful for backup or HSM agent nodes that would otherwise flood them.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;rbac&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;all&amp;lt;/code&amp;gt; || Admin operations the nodemap&amp;#039;s clients may perform, such as &amp;lt;code&amp;gt;quota_ops&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;chlg_ops&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;dne_ops&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;file_perms&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;fscrypt_admin&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;hsm_ops&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;byfid_ops&amp;lt;/code&amp;gt;. Roles not listed are forbidden. Accepts &amp;lt;code&amp;gt;+role&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;-role&amp;lt;/code&amp;gt; to add or remove a single role.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;gssonly_identification&amp;lt;/code&amp;gt; || 0 || 1 = identify clients by the GSS token they authenticate with instead of by NID. Such a nodemap cannot have NID ranges.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Not every property exists in every release. Check &amp;lt;code&amp;gt;lctl-nodemap-modify(8)&amp;lt;/code&amp;gt; on your version, or run &amp;lt;code&amp;gt;lctl nodemap_info --list&amp;lt;/code&amp;gt; (2.16.52 and later).&lt;br /&gt;
&lt;br /&gt;
How &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;trusted&amp;lt;/code&amp;gt; combine:&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Both 0&amp;#039;&amp;#039;&amp;#039; (the defaults): root is squashed, mapped users get their mapped IDs, and everyone else is squashed. This is the normal setting for a tenant.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;admin=1, trusted=0&amp;#039;&amp;#039;&amp;#039;: root stays root, explicit idmaps are honored, and everyone else is squashed.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;admin=0, trusted=1&amp;#039;&amp;#039;&amp;#039;: full access to canonical IDs, but root is squashed.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Both 1&amp;#039;&amp;#039;&amp;#039;: unrestricted, as if nodemaps were off. Use this only for servers and administrative nodes.&lt;br /&gt;
&lt;br /&gt;
=== Mapping IDs ===&lt;br /&gt;
&lt;br /&gt;
With &amp;lt;code&amp;gt;trusted=0&amp;lt;/code&amp;gt;, only mapped IDs keep a distinct identity. Everything else is squashed, or denied if &amp;lt;code&amp;gt;deny_unknown=1&amp;lt;/code&amp;gt;. There are two mapping mechanisms.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Explicit idmaps&amp;#039;&amp;#039;&amp;#039; map a client ID to a filesystem ID:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_add_idmap --name tenantA --idtype uid --idmap 500:10500&lt;br /&gt;
 mgs# lctl nodemap_add_idmap --name tenantA --idtype gid --idmap 500:10500&lt;br /&gt;
 mgs# lctl nodemap_add_idmap --name tenantA --idtype projid --idmap 33:1&lt;br /&gt;
&lt;br /&gt;
UID and GID maps are independent of each other. Lustre 2.16 and later also accept a range:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_add_idmap --name tenantA --idtype uid --idmap 1000-1999:11000-11999&lt;br /&gt;
&lt;br /&gt;
On earlier releases, each ID must be mapped one at a time. To remove a mapping, run &amp;lt;code&amp;gt;lctl nodemap_del_idmap&amp;lt;/code&amp;gt; with the same arguments.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Offsets&amp;#039;&amp;#039;&amp;#039; (Lustre 2.16 and later) shift a tenant&amp;#039;s whole ID space for UIDs, GIDs, and PROJIDs at once: &amp;lt;code&amp;gt;fs_id = client_id + offset&amp;lt;/code&amp;gt;, for client IDs &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; through &amp;lt;code&amp;gt;limit-1&amp;lt;/code&amp;gt;. This is the simplest way to give each tenant a non-overlapping ID range:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_add_offset --name tenantA --offset 100000 --limit 100000&lt;br /&gt;
 mgs# lctl nodemap_add_offset --name tenantB --offset 200000 --limit 100000&lt;br /&gt;
&lt;br /&gt;
Offset rules:&lt;br /&gt;
&lt;br /&gt;
* Offset ranges of different nodemaps cannot overlap, and a nodemap can have only one offset.&lt;br /&gt;
* The offset is applied &amp;#039;&amp;#039;&amp;#039;last&amp;#039;&amp;#039;&amp;#039;, after any explicit idmap. Keep idmap targets and &amp;lt;code&amp;gt;squash_*&amp;lt;/code&amp;gt; values within &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;limit-1&amp;lt;/code&amp;gt;, or the resulting IDs fall outside the tenant&amp;#039;s range.&lt;br /&gt;
* Choose a &amp;lt;code&amp;gt;limit&amp;lt;/code&amp;gt; large enough to include &amp;lt;code&amp;gt;nobody&amp;lt;/code&amp;gt; (65534).&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Choose the offset once.&amp;#039;&amp;#039;&amp;#039; Changing or deleting it does not remap existing files; they must be fixed with &amp;lt;code&amp;gt;chown&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;lfs project&amp;lt;/code&amp;gt; from a trusted client.&lt;br /&gt;
&lt;br /&gt;
Make sure the resulting filesystem IDs resolve on the MDS (through LDAP or another identity source), or set the MDS &amp;lt;code&amp;gt;identity_upcall&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;NONE&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Activating Nodemaps ===&lt;br /&gt;
&lt;br /&gt;
Nodemaps have no effect until the feature is activated, globally, on the MGS:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_activate 1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;lctl nodemap_activate 0&amp;lt;/code&amp;gt; turns it off again. Check the current state with &amp;lt;code&amp;gt;lctl get_param nodemap.active&amp;lt;/code&amp;gt;. After activating, check that the mappings are correct before letting tenants mount.&lt;br /&gt;
&lt;br /&gt;
=== Viewing the Configuration ===&lt;br /&gt;
&lt;br /&gt;
 # Lustre 2.16.52 and later&lt;br /&gt;
 mgs# lctl nodemap_info --list             # global state, nodemap names, property names&lt;br /&gt;
 mgs# lctl nodemap_info --name tenantA     # every property of one nodemap&lt;br /&gt;
 mgs# lctl nodemap_info --property ranges  # one property across all nodemaps&lt;br /&gt;
&lt;br /&gt;
 # Any version&lt;br /&gt;
 mgs# lctl get_param nodemap.tenantA.*&lt;br /&gt;
&lt;br /&gt;
== Filesets ==&lt;br /&gt;
&lt;br /&gt;
A fileset confines a nodemap&amp;#039;s clients to a subdirectory. They mount it as their filesystem root and cannot see or reach anything outside it, including through &amp;lt;code&amp;gt;..&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Create the directory first&amp;#039;&amp;#039;&amp;#039;, from a client in a trusted nodemap. If a nodemap&amp;#039;s primary fileset does not exist, no client in that nodemap can mount at all.&lt;br /&gt;
&lt;br /&gt;
 trusted-client# mkdir /mnt/lustre/tenantA&lt;br /&gt;
&lt;br /&gt;
Then set its owner and permissions to match the tenant&amp;#039;s &amp;#039;&amp;#039;&amp;#039;mapped&amp;#039;&amp;#039;&amp;#039; filesystem IDs.&lt;br /&gt;
&lt;br /&gt;
=== Lustre 2.17 and Later: nodemap_fileset_add ===&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_fileset_add --name tenantA --fileset /tenantA&lt;br /&gt;
&lt;br /&gt;
Each nodemap can have:&lt;br /&gt;
&lt;br /&gt;
* One &amp;#039;&amp;#039;&amp;#039;primary&amp;#039;&amp;#039;&amp;#039; fileset, used as the root when a client mounts without naming a subdirectory.&lt;br /&gt;
* Up to 255 &amp;#039;&amp;#039;&amp;#039;alternate&amp;#039;&amp;#039;&amp;#039; filesets (&amp;lt;code&amp;gt;--alt&amp;lt;/code&amp;gt;). Clients mount these by naming them explicitly; an alternate never becomes the default.&lt;br /&gt;
* A &amp;#039;&amp;#039;&amp;#039;read-only&amp;#039;&amp;#039;&amp;#039; flag on any fileset (&amp;lt;code&amp;gt;--ro&amp;lt;/code&amp;gt;). Mounts that resolve to that fileset are forced read-only.&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_fileset_add --name tenantA --fileset /tenantA_scratch --alt&lt;br /&gt;
 mgs# lctl nodemap_fileset_add --name tenantA --fileset /reference --alt --ro&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;lctl nodemap_fileset_modify&amp;lt;/code&amp;gt; to change a fileset (rename it, switch it between primary and alternate, or toggle &amp;lt;code&amp;gt;--ro&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;--rw&amp;lt;/code&amp;gt;), and &amp;lt;code&amp;gt;lctl nodemap_fileset_del&amp;lt;/code&amp;gt; to remove one (&amp;lt;code&amp;gt;--fileset PATH&amp;lt;/code&amp;gt;) or all of them (&amp;lt;code&amp;gt;--all&amp;lt;/code&amp;gt;). The nodemap&amp;#039;s &amp;lt;code&amp;gt;readonly_mount&amp;lt;/code&amp;gt; property overrides a read-write fileset.&lt;br /&gt;
&lt;br /&gt;
=== Before Lustre 2.17: nodemap_set_fileset ===&lt;br /&gt;
&lt;br /&gt;
Earlier releases support only one fileset per nodemap:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_set_fileset --name tenantA --fileset /tenantA&lt;br /&gt;
 mgs# lctl nodemap_set_fileset --name tenantA --fileset &amp;quot;&amp;quot;     # remove it&lt;br /&gt;
&lt;br /&gt;
Running &amp;lt;code&amp;gt;nodemap_set_fileset&amp;lt;/code&amp;gt; again &amp;#039;&amp;#039;&amp;#039;replaces&amp;#039;&amp;#039;&amp;#039; the fileset; it does not add a second one. Before 2.17, also store the fileset persistently, so that servers still enforce it after a restart:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl set_param -P nodemap.tenantA.fileset=/tenantA&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;nodemap_set_fileset&amp;lt;/code&amp;gt; is deprecated in newer releases and affects only the primary fileset. Use &amp;lt;code&amp;gt;nodemap_fileset_add&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nodemap_fileset_del&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;nodemap_fileset_modify&amp;lt;/code&amp;gt; where they are available.&lt;br /&gt;
&lt;br /&gt;
=== How Clients Mount ===&lt;br /&gt;
&lt;br /&gt;
With a primary fileset of &amp;lt;code&amp;gt;/tenantA&amp;lt;/code&amp;gt;, a tenantA client&amp;#039;s ordinary mount is silently redirected:&lt;br /&gt;
&lt;br /&gt;
 tenantA-client# mount -t lustre mgs@tcp:/testfs /mnt/lustre&lt;br /&gt;
 # /mnt/lustre now shows /tenantA&lt;br /&gt;
&lt;br /&gt;
Clients can also mount an explicit subdirectory that matches one of their filesets. The full precedence rules, including how a requested path combines with the primary fileset, are in &amp;lt;code&amp;gt;lctl-nodemap-fileset-add(8)&amp;lt;/code&amp;gt;. Test the exact mounts your tenants will use before going live.&lt;br /&gt;
&lt;br /&gt;
== Complete Example: Two Tenants ==&lt;br /&gt;
&lt;br /&gt;
This sets up two isolated tenants on Lustre 2.17 or later. On older releases, use &amp;lt;code&amp;gt;nodemap_set_fileset&amp;lt;/code&amp;gt; plus &amp;lt;code&amp;gt;set_param -P&amp;lt;/code&amp;gt; instead of &amp;lt;code&amp;gt;nodemap_fileset_add&amp;lt;/code&amp;gt;; before 2.16, use explicit idmaps instead of offsets.&lt;br /&gt;
&lt;br /&gt;
 # 0. Servers and admin nodes get full access (see &amp;quot;Before You Start&amp;quot;)&lt;br /&gt;
 mgs# lctl nodemap_add TrustedSystems&lt;br /&gt;
 mgs# lctl nodemap_add_range --name TrustedSystems --range 10.0.0.[1-20]@tcp&lt;br /&gt;
 mgs# lctl nodemap_modify --name TrustedSystems --property admin --value 1&lt;br /&gt;
 mgs# lctl nodemap_modify --name TrustedSystems --property trusted --value 1&lt;br /&gt;
&lt;br /&gt;
 # 1. Tenant nodemaps and their client NIDs&lt;br /&gt;
 mgs# lctl nodemap_add tenantA&lt;br /&gt;
 mgs# lctl nodemap_add tenantB&lt;br /&gt;
 mgs# lctl nodemap_add_range --name tenantA --range 10.0.1.[0-255]@tcp&lt;br /&gt;
 mgs# lctl nodemap_add_range --name tenantB --range 10.0.2.[0-255]@tcp&lt;br /&gt;
&lt;br /&gt;
 # 2. Non-overlapping ID spaces&lt;br /&gt;
 mgs# lctl nodemap_add_offset --name tenantA --offset 100000 --limit 100000&lt;br /&gt;
 mgs# lctl nodemap_add_offset --name tenantB --offset 200000 --limit 100000&lt;br /&gt;
&lt;br /&gt;
 # 3. Nothing to do: admin=0 and trusted=0 are the defaults, so root is squashed and IDs are mapped&lt;br /&gt;
&lt;br /&gt;
 # 4. Tenant directories, owned by each tenant&amp;#039;s mapped ID (client UID/GID 1000 here)&lt;br /&gt;
 trusted-client# mkdir /mnt/lustre/tenantA /mnt/lustre/tenantB&lt;br /&gt;
 trusted-client# chown 101000:101000 /mnt/lustre/tenantA&lt;br /&gt;
 trusted-client# chown 201000:201000 /mnt/lustre/tenantB&lt;br /&gt;
&lt;br /&gt;
 # 5. Filesets&lt;br /&gt;
 mgs# lctl nodemap_fileset_add --name tenantA --fileset /tenantA&lt;br /&gt;
 mgs# lctl nodemap_fileset_add --name tenantB --fileset /tenantB&lt;br /&gt;
&lt;br /&gt;
 # 6. Activate, then check before tenants mount&lt;br /&gt;
 mgs# lctl nodemap_activate 1&lt;br /&gt;
 mgs# lctl nodemap_info&lt;br /&gt;
&lt;br /&gt;
Result:&lt;br /&gt;
&lt;br /&gt;
* tenantA clients see only &amp;lt;code&amp;gt;/tenantA&amp;lt;/code&amp;gt;. Their UID 1000 is stored on disk as 101000, and their root is squashed.&lt;br /&gt;
* tenantB clients see only &amp;lt;code&amp;gt;/tenantB&amp;lt;/code&amp;gt;. Their UID 1000 is stored as 201000.&lt;br /&gt;
* The two tenants can use the same client UIDs without colliding on disk.&lt;br /&gt;
* Nodes in none of the three nodemaps fall into &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt;: root squashed, every user mapped to &amp;lt;code&amp;gt;nobody&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
To stop a tenant from impersonating another by spoofing a NID, also issue each tenant an SSK key bound to its nodemap. See [[Lustre Kerberos SSK Authentication#Binding Keys to Nodemaps|Binding Keys to Nodemaps]].&lt;br /&gt;
&lt;br /&gt;
== Removing a Tenant ==&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl nodemap_del tenantA&lt;br /&gt;
&lt;br /&gt;
Deleting a nodemap removes its ranges, mappings, and properties, and its clients fall back to the &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; nodemap. Files keep the filesystem IDs they were written with.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[UID/GID_Mapping|UID/GID Mapping]]&lt;br /&gt;
* [[Lustre Kerberos SSK Authentication]] — strong client identification, including SSK keys bound to nodemaps&lt;br /&gt;
* [[Lustre Client Encryption]]&lt;br /&gt;
* [[Setting up Lustre Security]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Administration]]&lt;br /&gt;
[[Category:Security]]&lt;/div&gt;</summary>
		<author><name>Elliswilson</name></author>
	</entry>
</feed>