<?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_Kerberos_SSK_Authentication</id>
	<title>Lustre Kerberos SSK Authentication - 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_Kerberos_SSK_Authentication"/>
	<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Kerberos_SSK_Authentication&amp;action=history"/>
	<updated>2026-10-28T14:52:00Z</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_Kerberos_SSK_Authentication&amp;diff=5760&amp;oldid=prev</id>
		<title>Elliswilson: Created page with &quot;__TOC__  == Overview ==  Lustre can authenticate nodes and protect PtlRPC traffic through GSSAPI, using one of two mechanisms:  {| class=&quot;wikitable&quot; ! !! Kerberos (krb5) !! Shared-Secret Key (SSK) |- | Infrastructure || MIT Kerberos 5 KDC || None; the administrator distributes key files |- | Authenticates || Nodes, &#039;&#039;&#039;and&#039;&#039;&#039; individual users via &lt;code&gt;kinit&lt;/code&gt; || Nodes only (a single root context per connection) |- | Binds a client to its identity by || A per-host pr...&quot;</title>
		<link rel="alternate" type="text/html" href="http://wiki.lustre.org/index.php?title=Lustre_Kerberos_SSK_Authentication&amp;diff=5760&amp;oldid=prev"/>
		<updated>2026-10-12T15:09:29Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;__TOC__  == Overview ==  Lustre can authenticate nodes and protect PtlRPC traffic through GSSAPI, using one of two mechanisms:  {| class=&amp;quot;wikitable&amp;quot; ! !! Kerberos (krb5) !! Shared-Secret Key (SSK) |- | Infrastructure || MIT Kerberos 5 KDC || None; the administrator distributes key files |- | Authenticates || Nodes, &amp;#039;&amp;#039;&amp;#039;and&amp;#039;&amp;#039;&amp;#039; individual users via &amp;lt;code&amp;gt;kinit&amp;lt;/code&amp;gt; || Nodes only (a single root context per connection) |- | Binds a client to its identity by || A per-host pr...&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;
Lustre can authenticate nodes and protect PtlRPC traffic through GSSAPI, using one of two mechanisms:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! !! Kerberos (krb5) !! Shared-Secret Key (SSK)&lt;br /&gt;
|-&lt;br /&gt;
| Infrastructure || MIT Kerberos 5 KDC || None; the administrator distributes key files&lt;br /&gt;
|-&lt;br /&gt;
| Authenticates || Nodes, &amp;#039;&amp;#039;&amp;#039;and&amp;#039;&amp;#039;&amp;#039; individual users via &amp;lt;code&amp;gt;kinit&amp;lt;/code&amp;gt; || Nodes only (a single root context per connection)&lt;br /&gt;
|-&lt;br /&gt;
| Binds a client to its identity by || A per-host principal and keytab || A key file bound to a [[Lustre Multi Tenancy|nodemap]]&lt;br /&gt;
|-&lt;br /&gt;
| Can encrypt traffic || Yes (&amp;lt;code&amp;gt;krb5p&amp;lt;/code&amp;gt;) || Yes (&amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
SSK was added in Lustre 2.9 ([https://jira.whamcloud.com/browse/LU-3289 LU-3289]). It suits sites that want node authentication and wire encryption without running a KDC.&lt;br /&gt;
&lt;br /&gt;
Both mechanisms need Lustre built with GSS support, the &amp;lt;code&amp;gt;lsvcgssd&amp;lt;/code&amp;gt; daemon on servers, and the &amp;lt;code&amp;gt;lgss_keyring&amp;lt;/code&amp;gt; request-key upcall on every node. The authoritative references are the &amp;#039;&amp;#039;Configuring Shared-Secret Key (SSK) Security&amp;#039;&amp;#039; and &amp;#039;&amp;#039;Managing Security&amp;#039;&amp;#039; chapters of the [https://doc.lustre.org/lustre_manual.xhtml Lustre Operations Manual].&lt;br /&gt;
&lt;br /&gt;
This page covers &amp;#039;&amp;#039;&amp;#039;transport&amp;#039;&amp;#039;&amp;#039; security. It does not encrypt data at rest; for that, see [[Lustre Client Encryption]].&lt;br /&gt;
&lt;br /&gt;
== Security Flavors ==&lt;br /&gt;
&lt;br /&gt;
A &amp;#039;&amp;#039;security flavor&amp;#039;&amp;#039; sets the authentication and protection applied to a connection, covering both RPC messages and bulk data.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Flavor !! Mechanism !! RPC message !! Bulk data !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; || — || None || None || &amp;#039;&amp;#039;&amp;#039;Default&amp;#039;&amp;#039;&amp;#039; for all connections&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;plain&amp;lt;/code&amp;gt; || — || colspan=&amp;quot;2&amp;quot; | Plaintext with a hash on each RPC || No authentication&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;krb5n&amp;lt;/code&amp;gt; || Kerberos || None || Checksum || Lightest Kerberos flavor&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;krb5a&amp;lt;/code&amp;gt; || Kerberos || Header integrity only || Checksum ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;krb5i&amp;lt;/code&amp;gt; || Kerberos || Integrity || Integrity || Heavy overhead&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;krb5p&amp;lt;/code&amp;gt; || Kerberos || &amp;#039;&amp;#039;&amp;#039;Privacy&amp;#039;&amp;#039;&amp;#039; || &amp;#039;&amp;#039;&amp;#039;Privacy&amp;#039;&amp;#039;&amp;#039; || Heaviest overhead&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;skn&amp;lt;/code&amp;gt; || SSK || None || None || Authentication only: a valid key is required to mount&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ska&amp;lt;/code&amp;gt; || SSK || Integrity || None || Integrity for non-bulk RPCs only&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ski&amp;lt;/code&amp;gt; || SSK || Integrity || Integrity ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt; || SSK || &amp;#039;&amp;#039;&amp;#039;Privacy&amp;#039;&amp;#039;&amp;#039; and integrity || &amp;#039;&amp;#039;&amp;#039;Privacy&amp;#039;&amp;#039;&amp;#039; and integrity || The only SSK flavor that encrypts&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;gssnull&amp;lt;/code&amp;gt; || GSS || None || None || Testing only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Only &amp;lt;code&amp;gt;krb5p&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt; encrypt traffic.&amp;#039;&amp;#039;&amp;#039; The other flavors authenticate nodes and/or detect tampering, but send data in the clear. Every SSK flavor requires a valid key to mount.&lt;br /&gt;
&lt;br /&gt;
== Setting Flavors with sptlrpc Rules ==&lt;br /&gt;
&lt;br /&gt;
Flavors are set by persistent rules defined on the MGS with &amp;lt;code&amp;gt;lctl conf_param&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;target&amp;gt;.srpc.flavor.&amp;lt;network&amp;gt;[.&amp;lt;direction&amp;gt;]=&amp;lt;flavor&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;target&amp;gt;&amp;lt;/code&amp;gt; is a filesystem name (&amp;lt;code&amp;gt;testfs&amp;lt;/code&amp;gt;) or a specific target (&amp;lt;code&amp;gt;testfs-MDT0000&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;testfs-OST0001&amp;lt;/code&amp;gt;).&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;network&amp;gt;&amp;lt;/code&amp;gt; is the LNet network of the RPC &amp;#039;&amp;#039;&amp;#039;initiator&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;tcp0&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;o2ib0&amp;lt;/code&amp;gt;), or &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt; for any network without a more specific rule.&lt;br /&gt;
* &amp;lt;code&amp;gt;&amp;lt;direction&amp;gt;&amp;lt;/code&amp;gt; is optional: &amp;lt;code&amp;gt;cli2mdt&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;cli2ost&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;mdt2mdt&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;mdt2ost&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The most specific matching rule wins. Examples:&lt;br /&gt;
&lt;br /&gt;
 # Authenticate and encrypt everything by default&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.default=skpi&lt;br /&gt;
&lt;br /&gt;
 # ...but on physically secure, high-performance networks, authenticate and check integrity only&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.tcp1=ska&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.o2ib0=ska&lt;br /&gt;
&lt;br /&gt;
 # List the rules&lt;br /&gt;
 mgs# lctl get_param mgs.*.live.testfs | grep srpc.flavor&lt;br /&gt;
&lt;br /&gt;
 # Delete a rule&lt;br /&gt;
 mgs# lctl conf_param -d testfs.srpc.flavor.o2ib0&lt;br /&gt;
&lt;br /&gt;
Important behavior:&lt;br /&gt;
&lt;br /&gt;
* Rule changes reach &amp;#039;&amp;#039;&amp;#039;existing as well as new&amp;#039;&amp;#039;&amp;#039; connections, typically within seconds to a few minutes depending on system load.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Make sure every affected node is ready before you change a rule.&amp;#039;&amp;#039;&amp;#039; A node that cannot negotiate the new flavor (missing key, daemon not running, Kerberos misconfigured) can be evicted.&lt;br /&gt;
* &amp;lt;code&amp;gt;lctl set_param -P&amp;lt;/code&amp;gt; does &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; work for sptlrpc rules. Use &amp;lt;code&amp;gt;lctl conf_param&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Rules do not cover the MGS connection itself, because a node only learns the rules after it connects to the MGS. See [[#Securing the MGS Connection|Securing the MGS Connection]].&lt;br /&gt;
&lt;br /&gt;
== SSK Setup ==&lt;br /&gt;
&lt;br /&gt;
This walkthrough follows the example in the Operations Manual: filesystem &amp;lt;code&amp;gt;testfs&amp;lt;/code&amp;gt;, a combined MGS/MDS at &amp;lt;code&amp;gt;172.16.0.1@tcp&amp;lt;/code&amp;gt;, one OSS, and two clients. It protects client-to-server traffic with &amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Step 1: Confirm the GSS Components Are Installed ===&lt;br /&gt;
&lt;br /&gt;
When Lustre is built with GSS keyring support, its packages install:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;/etc/request-key.d/lgssc.conf&amp;lt;/code&amp;gt; on every node, containing this single line:&lt;br /&gt;
 create lgssc * * /usr/sbin/lgss_keyring %o %k %t %d %c %u %g %T %P %S&lt;br /&gt;
* &amp;lt;code&amp;gt;lsvcgss.service&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/etc/sysconfig/lsvcgss&amp;lt;/code&amp;gt; on servers.&lt;br /&gt;
&lt;br /&gt;
Check that the request-key file exists on &amp;#039;&amp;#039;&amp;#039;every&amp;#039;&amp;#039;&amp;#039; node, clients included. Without it, nodes cannot establish security contexts.&lt;br /&gt;
&lt;br /&gt;
=== Step 2: Create a Key Directory on Every Node ===&lt;br /&gt;
&lt;br /&gt;
 # mkdir /secure_directory&lt;br /&gt;
 # chmod 600 /secure_directory&lt;br /&gt;
&lt;br /&gt;
=== Step 3: Generate the Server Key ===&lt;br /&gt;
&lt;br /&gt;
 mds# lgss_sk -t server -f testfs -w /secure_directory/testfs.server.key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;lgss_sk&amp;lt;/code&amp;gt; reads &amp;lt;code&amp;gt;/dev/random&amp;lt;/code&amp;gt; by default. On a system without a hardware random number generator, it can block until enough entropy is available.&lt;br /&gt;
&lt;br /&gt;
=== Step 4: Distribute the Key ===&lt;br /&gt;
&lt;br /&gt;
Copy the key to every other server, and to every client under a client filename, over a secure channel:&lt;br /&gt;
&lt;br /&gt;
 mds# scp /secure_directory/testfs.server.key oss:/secure_directory/&lt;br /&gt;
 mds# scp /secure_directory/testfs.server.key client1:/secure_directory/testfs.client.key&lt;br /&gt;
&lt;br /&gt;
Never put key files on a shared filesystem.&lt;br /&gt;
&lt;br /&gt;
=== Step 5: Convert Each Client Copy to a Client Key ===&lt;br /&gt;
&lt;br /&gt;
On &amp;#039;&amp;#039;&amp;#039;each client&amp;#039;&amp;#039;&amp;#039;:&lt;br /&gt;
&lt;br /&gt;
 client1# lgss_sk -t client -m /secure_directory/testfs.client.key&lt;br /&gt;
&lt;br /&gt;
This sets the key type to &amp;lt;code&amp;gt;client&amp;lt;/code&amp;gt; and generates the Diffie-Hellman prime that only client keys carry. Generating the prime can take a while.&lt;br /&gt;
&lt;br /&gt;
=== Step 6: Start lsvcgssd on the Servers ===&lt;br /&gt;
&lt;br /&gt;
Set &amp;lt;code&amp;gt;LSVCGSSDARGS&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;/etc/sysconfig/lsvcgss&amp;lt;/code&amp;gt;. &amp;lt;code&amp;gt;-s&amp;lt;/code&amp;gt; enables SSK; &amp;lt;code&amp;gt;-m&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-o&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; select the MDS, OSS, and MGS services the daemon handles.&lt;br /&gt;
&lt;br /&gt;
 # /etc/sysconfig/lsvcgss on the MDS&lt;br /&gt;
 LSVCGSSDARGS=&amp;quot;-s -m&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 # /etc/sysconfig/lsvcgss on the OSS&lt;br /&gt;
 LSVCGSSDARGS=&amp;quot;-s -o&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 mds# systemctl start lsvcgss.service&lt;br /&gt;
 oss# systemctl start lsvcgss.service&lt;br /&gt;
&lt;br /&gt;
=== Step 7: Mount the Targets with skpath ===&lt;br /&gt;
&lt;br /&gt;
 mds# mount -t lustre -o skpath=/secure_directory /dev/mdt_device /mnt/mdt&lt;br /&gt;
 oss# mount -t lustre -o skpath=/secure_directory /dev/ost_device /mnt/ost0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;skpath&amp;lt;/code&amp;gt; loads &amp;#039;&amp;#039;&amp;#039;every&amp;#039;&amp;#039;&amp;#039; key file in the directory into the kernel keyring. A world-writable key file fails to load.&lt;br /&gt;
&lt;br /&gt;
=== Step 8: Set the Flavor ===&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.tcp.cli2mdt=skpi&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.tcp.cli2ost=skpi&lt;br /&gt;
&lt;br /&gt;
Server-to-server connections keep the default &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; flavor. See [[#Securing Server-to-Server Traffic|Securing Server-to-Server Traffic]].&lt;br /&gt;
&lt;br /&gt;
=== Step 9: Mount the Clients ===&lt;br /&gt;
&lt;br /&gt;
 client1# mount -t lustre -o skpath=/secure_directory 172.16.0.1@tcp:/testfs /mnt/testfs&lt;br /&gt;
&lt;br /&gt;
A client without a valid key is refused:&lt;br /&gt;
&lt;br /&gt;
 mount.lustre: mount 172.16.0.1@tcp:/testfs at /mnt/testfs failed: Connection refused&lt;br /&gt;
&lt;br /&gt;
Then [[#Verifying Security Contexts|verify the contexts]].&lt;br /&gt;
&lt;br /&gt;
=== lgss_sk Reference ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Option !! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-w, --write &amp;#039;&amp;#039;FILE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Generate a new key file. Will not overwrite an existing file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-m, --modify &amp;#039;&amp;#039;FILE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Change only the attributes given on the command line&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-r, --read &amp;#039;&amp;#039;FILE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Show a key file&amp;#039;s attributes (&amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt; reads standard input)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-l, --load &amp;#039;&amp;#039;FILE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Load one key file into the session keyring. Must be run as root.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-t, --type &amp;#039;&amp;#039;TYPE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;mgs&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;server&amp;lt;/code&amp;gt;, or &amp;lt;code&amp;gt;client&amp;lt;/code&amp;gt;; combine with a comma (e.g. &amp;lt;code&amp;gt;mgs,server&amp;lt;/code&amp;gt;). Required when writing.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-f, --fsname &amp;#039;&amp;#039;NAME&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Filesystem the key is for. Writing requires &amp;lt;code&amp;gt;-f&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-g, --mgsnids &amp;#039;&amp;#039;NIDS&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Comma-separated MGS NIDs. Needed only when &amp;lt;code&amp;gt;mgssec&amp;lt;/code&amp;gt; is used.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-n, --nodemap &amp;#039;&amp;#039;NAME&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Nodemap the key is bound to (default: &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt;)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-e, --expire &amp;#039;&amp;#039;SECONDS&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || How long session contexts created from this key last before they are renegotiated (default 604800, 7 days). This is &amp;#039;&amp;#039;&amp;#039;not&amp;#039;&amp;#039;&amp;#039; an expiry date for the key file.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-i, --hmac &amp;#039;&amp;#039;ALG&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Integrity hash: &amp;lt;code&amp;gt;SHA256&amp;lt;/code&amp;gt; (default) or &amp;lt;code&amp;gt;SHA512&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-c, --crypt &amp;#039;&amp;#039;ALG&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Cipher for privacy: &amp;lt;code&amp;gt;AES-256-CTR&amp;lt;/code&amp;gt; (the default and only choice)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-p, --prime-bits &amp;#039;&amp;#039;BITS&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Diffie-Hellman prime length (default 2048). On server and MGS keys, this is also the minimum prime length accepted from clients.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-k, --key-bits &amp;#039;&amp;#039;BITS&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Shared key length (default 256)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-d, --data &amp;#039;&amp;#039;FILE&amp;#039;&amp;#039;&amp;lt;/code&amp;gt; || Entropy source for the shared key (default &amp;lt;code&amp;gt;/dev/random&amp;lt;/code&amp;gt;). Use &amp;lt;code&amp;gt;/dev/urandom&amp;lt;/code&amp;gt; for testing only.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;-v, --verbose&amp;lt;/code&amp;gt; || More detailed error messages&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Binding Keys to Nodemaps ===&lt;br /&gt;
&lt;br /&gt;
Every SSK key names a nodemap (&amp;lt;code&amp;gt;-n&amp;lt;/code&amp;gt;, default &amp;lt;code&amp;gt;default&amp;lt;/code&amp;gt;). When a client connects, it sends a hash of the nodemap name from its key. The server looks up which nodemap the client&amp;#039;s NID belongs to, and &amp;lt;code&amp;gt;lsvcgssd&amp;lt;/code&amp;gt; checks that the two match. A key used from a NID outside that nodemap&amp;#039;s ranges is therefore rejected.&lt;br /&gt;
&lt;br /&gt;
This is what stops one tenant from impersonating another with a copied key. Issue a separate key for each nodemap:&lt;br /&gt;
&lt;br /&gt;
 mgs# lgss_sk -t server -f testfs -n biology -w /secure_directory/testfs.server.biology.key&lt;br /&gt;
&lt;br /&gt;
The NID-to-nodemap lookup works whether or not nodemaps have been activated with &amp;lt;code&amp;gt;lctl nodemap_activate&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Alternatively, the nodemap property &amp;lt;code&amp;gt;gssonly_identification=1&amp;lt;/code&amp;gt; identifies clients by the GSS token they authenticate with, rather than by NID; such a nodemap cannot have NID ranges. See [[Lustre Multi Tenancy]].&lt;br /&gt;
&lt;br /&gt;
=== Securing the MGS Connection ===&lt;br /&gt;
&lt;br /&gt;
Each node chooses the flavor for its MGS connection with the &amp;lt;code&amp;gt;mgssec&amp;lt;/code&amp;gt; mount option. A node has only one MGS connection, so every target and client on that node uses the flavor set when the first connection was made, and it cannot change until remount.&lt;br /&gt;
&lt;br /&gt;
# On the MGS, add &amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;LSVCGSSDARGS&amp;lt;/code&amp;gt; and restart &amp;lt;code&amp;gt;lsvcgss.service&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Add the &amp;lt;code&amp;gt;mgs&amp;lt;/code&amp;gt; type and the MGS NIDs to the server key, and load it:&lt;br /&gt;
#: &amp;lt;code&amp;gt;mgs# lgss_sk -t mgs,server -g 172.16.0.1@tcp,172.16.0.2@tcp -m /secure_directory/testfs.server.key&amp;lt;/code&amp;gt;&lt;br /&gt;
#: &amp;lt;code&amp;gt;mgs# lgss_sk -l /secure_directory/testfs.server.key&amp;lt;/code&amp;gt;&lt;br /&gt;
# Add the MGS NIDs to each client key:&lt;br /&gt;
#: &amp;lt;code&amp;gt;client1# lgss_sk -g 172.16.0.1@tcp,172.16.0.2@tcp -m /secure_directory/testfs.client.key&amp;lt;/code&amp;gt;&lt;br /&gt;
# Remount each client with &amp;lt;code&amp;gt;mgssec&amp;lt;/code&amp;gt;:&lt;br /&gt;
#: &amp;lt;code&amp;gt;client1# mount -t lustre -o mgssec=skpi,skpath=/secure_directory 172.16.0.1@tcp:/testfs /mnt/testfs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
By default the MGS accepts any flavor. To require a particular one, add a rule on the special target &amp;lt;code&amp;gt;_mgs&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl conf_param _mgs.srpc.flavor.tcp=skpi&lt;br /&gt;
&lt;br /&gt;
=== Securing Server-to-Server Traffic ===&lt;br /&gt;
&lt;br /&gt;
When servers talk to each other (for example, MDT to OST), they act as clients, so they need a &amp;#039;&amp;#039;&amp;#039;client&amp;#039;&amp;#039;&amp;#039;-type key too. To apply &amp;lt;code&amp;gt;ski&amp;lt;/code&amp;gt; to MDT-to-OST traffic:&lt;br /&gt;
&lt;br /&gt;
# Put the servers in their own nodemap:&lt;br /&gt;
#: &amp;lt;code&amp;gt;mgs# lctl nodemap_add LustreServers&amp;lt;/code&amp;gt;&lt;br /&gt;
#: &amp;lt;code&amp;gt;mgs# lctl nodemap_add_range --name LustreServers --range 172.16.0.[1-3]@tcp&amp;lt;/code&amp;gt;&lt;br /&gt;
# Create an &amp;lt;code&amp;gt;mgs,server&amp;lt;/code&amp;gt; key for that nodemap and copy it to every server:&lt;br /&gt;
#: &amp;lt;code&amp;gt;mds# lgss_sk -t mgs,server -f testfs -g 172.16.0.1@tcp,172.16.0.2@tcp -n LustreServers -w /secure_directory/testfs.LustreServers.key&amp;lt;/code&amp;gt;&lt;br /&gt;
# On each server, copy that key to &amp;lt;code&amp;gt;testfs.LustreServers.client.key&amp;lt;/code&amp;gt; and convert the copy with &amp;lt;code&amp;gt;lgss_sk -t client -m&amp;lt;/code&amp;gt;.&lt;br /&gt;
# On each server, load both keys with &amp;lt;code&amp;gt;lgss_sk -l&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Set the rule:&lt;br /&gt;
#: &amp;lt;code&amp;gt;mgs# lctl conf_param testfs.srpc.flavor.tcp.mdt2ost=ski&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If nodemaps are active, the servers&amp;#039; nodemap must also have &amp;lt;code&amp;gt;admin=1&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;trusted=1&amp;lt;/code&amp;gt;. See [[Lustre Multi Tenancy]].&lt;br /&gt;
&lt;br /&gt;
=== Revoking and Rotating Keys ===&lt;br /&gt;
&lt;br /&gt;
SSK keys cannot be revoked as such, and Lustre has no way to flush established contexts. To lock out a compromised key, do one of the following:&lt;br /&gt;
&lt;br /&gt;
* Unload the key from the keyring on the servers (with &amp;lt;code&amp;gt;keyctl&amp;lt;/code&amp;gt;). New connections that use it then fail.&lt;br /&gt;
* Move the affected NIDs to a nodemap with a different name. Keys that name the old nodemap can no longer establish contexts.&lt;br /&gt;
&lt;br /&gt;
Contexts that already exist last until they expire (&amp;lt;code&amp;gt;-e&amp;lt;/code&amp;gt;, 7 days by default) or the targets are unmounted. If you need revocation to take effect quickly, create keys with a shorter expiry; the manual suggests 3600 seconds as reasonable for some sites.&lt;br /&gt;
&lt;br /&gt;
To rotate keys: generate new key files, distribute and load them, and remove the old files from every &amp;lt;code&amp;gt;skpath&amp;lt;/code&amp;gt; directory so they are not reloaded at the next mount.&lt;br /&gt;
&lt;br /&gt;
== Kerberos Setup ==&lt;br /&gt;
&lt;br /&gt;
Lustre supports MIT Kerberos 5, version 1.3 or later, with the &amp;lt;code&amp;gt;aes128-cts&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;aes256-cts&amp;lt;/code&amp;gt; enctypes. Clocks must be synchronized across all nodes and the KDC.&lt;br /&gt;
&lt;br /&gt;
=== Packages and Build ===&lt;br /&gt;
&lt;br /&gt;
Install on every node:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;krb5-workstation&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;krb5-libs&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;keyutils&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;keyutils-libs&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lustre must be built with GSS support. On the build host, install &amp;lt;code&amp;gt;krb5-devel&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;keyutils-libs-devel&amp;lt;/code&amp;gt;, then configure with:&lt;br /&gt;
&lt;br /&gt;
 ./configure --enable-gss&lt;br /&gt;
&lt;br /&gt;
=== Principals and Keytabs ===&lt;br /&gt;
&lt;br /&gt;
Create a principal for each node, using that node&amp;#039;s &amp;#039;&amp;#039;&amp;#039;fully qualified&amp;#039;&amp;#039;&amp;#039; hostname, and install its keytab on that node:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Node role !! Principal&lt;br /&gt;
|-&lt;br /&gt;
| Client || &amp;lt;code&amp;gt;lustre_root/client_host.domain@REALM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| MGS || &amp;lt;code&amp;gt;lustre_mgs/mgs_host.domain@REALM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| MDS || &amp;lt;code&amp;gt;lustre_mds/mds_host.domain@REALM&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| OSS || &amp;lt;code&amp;gt;lustre_oss/oss_host.domain@REALM&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 kadmin&amp;gt; addprinc -randkey lustre_mds/mds_host.domain@REALM&lt;br /&gt;
 kadmin&amp;gt; ktadd lustre_mds/mds_host.domain@REALM&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* The hostname in each principal must be the one that resolves to the IP address in that node&amp;#039;s Lustre NID. Otherwise the servers do not recognize its GSS requests.&lt;br /&gt;
* To avoid a keytab per client, you can create a single &amp;lt;code&amp;gt;lustre_root@REALM&amp;lt;/code&amp;gt; principal and install its keytab on every client. The cost is that &amp;#039;&amp;#039;&amp;#039;one compromised client compromises them all&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
* On networks without hostname resolution (anything other than TCP or InfiniBand), each node needs an executable &amp;lt;code&amp;gt;/etc/lustre/nid2hostname&amp;lt;/code&amp;gt; script that translates a NID into a hostname. The &amp;#039;&amp;#039;Configuring Kerberos (KRB) Security&amp;#039;&amp;#039; section of the manual includes an example.&lt;br /&gt;
&lt;br /&gt;
=== Start lsvcgssd ===&lt;br /&gt;
&lt;br /&gt;
On each server, run &amp;lt;code&amp;gt;lsvcgssd&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;-k&amp;lt;/code&amp;gt;, plus the services that node runs (&amp;lt;code&amp;gt;-g&amp;lt;/code&amp;gt; MGS, &amp;lt;code&amp;gt;-m&amp;lt;/code&amp;gt; MDS, &amp;lt;code&amp;gt;-o&amp;lt;/code&amp;gt; OSS), &amp;#039;&amp;#039;&amp;#039;before&amp;#039;&amp;#039;&amp;#039; starting Lustre:&lt;br /&gt;
&lt;br /&gt;
 # /etc/sysconfig/lsvcgss on a combined MGS/MDS&lt;br /&gt;
 LSVCGSSDARGS=&amp;quot;-k -g -m&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 # systemctl start lsvcgss.service&lt;br /&gt;
&lt;br /&gt;
Clients use the same request-key upcall as SSK; check that &amp;lt;code&amp;gt;/etc/request-key.d/lgssc.conf&amp;lt;/code&amp;gt; exists on every client.&lt;br /&gt;
&lt;br /&gt;
=== Set the Flavor ===&lt;br /&gt;
&lt;br /&gt;
Use [[#Setting Flavors with sptlrpc Rules|sptlrpc rules]] with a &amp;lt;code&amp;gt;krb5&amp;lt;/code&amp;gt; flavor, for example:&lt;br /&gt;
&lt;br /&gt;
 mgs# lctl conf_param testfs.srpc.flavor.default=krb5i&lt;br /&gt;
&lt;br /&gt;
=== User Authentication ===&lt;br /&gt;
&lt;br /&gt;
With Kerberos, &amp;#039;&amp;#039;&amp;#039;users&amp;#039;&amp;#039;&amp;#039; authenticate as well as nodes. Non-root users must run &amp;lt;code&amp;gt;kinit&amp;lt;/code&amp;gt; before accessing Lustre, as with any Kerberized application.&lt;br /&gt;
&lt;br /&gt;
* Each user&amp;#039;s principal (&amp;lt;code&amp;gt;username@REALM&amp;lt;/code&amp;gt;) must exist in the KDC.&lt;br /&gt;
* Clients and MDS nodes must share the same user database for name and UID/GID translation.&lt;br /&gt;
&lt;br /&gt;
Users can destroy their security contexts before logging out:&lt;br /&gt;
&lt;br /&gt;
 $ lfs flushctx -k -r /mnt/testfs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;-k&amp;lt;/code&amp;gt; also destroys the on-disk Kerberos credential cache (like &amp;lt;code&amp;gt;kdestroy&amp;lt;/code&amp;gt;), and &amp;lt;code&amp;gt;-r&amp;lt;/code&amp;gt; reaps revoked keys from the keyring.&lt;br /&gt;
&lt;br /&gt;
== Verifying Security Contexts ==&lt;br /&gt;
&lt;br /&gt;
On a client (or on a server, for its own outgoing connections), check the flavor each import is using:&lt;br /&gt;
&lt;br /&gt;
 client1# lctl get_param *.*.srpc_info&lt;br /&gt;
 mdc.testfs-MDT0000-mdc-ffff8800da9f0800.srpc_info=&lt;br /&gt;
 rpc flavor:     skpi&lt;br /&gt;
 bulk flavor:    skpi&lt;br /&gt;
 ...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;srpc_contexts&amp;lt;/code&amp;gt; shows each established context and its mechanism (&amp;lt;code&amp;gt;mech: sk&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;krb5&amp;lt;/code&amp;gt;). SSK supports only a single root context per import, so there should be exactly one.&lt;br /&gt;
&lt;br /&gt;
 client1# lctl get_param *.*.srpc_contexts&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;mgc&amp;lt;/code&amp;gt; import without a secure context means the MGS connection is not protected; see [[#Securing the MGS Connection|Securing the MGS Connection]].&lt;br /&gt;
&lt;br /&gt;
== Troubleshooting ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Mount fails with &amp;quot;Connection refused&amp;quot;&amp;#039;&amp;#039;&amp;#039;: the client has no valid key for this filesystem and nodemap, or the key did not load. Check the &amp;lt;code&amp;gt;skpath&amp;lt;/code&amp;gt; directory, and use &amp;lt;code&amp;gt;lgss_sk -r&amp;lt;/code&amp;gt; to confirm the key&amp;#039;s type (&amp;lt;code&amp;gt;client&amp;lt;/code&amp;gt;), filesystem name, and nodemap.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;A key file fails to load&amp;#039;&amp;#039;&amp;#039;: the file is world-writable.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Nodes are evicted after a rule change&amp;#039;&amp;#039;&amp;#039;: a node could not negotiate the new flavor. Check that &amp;lt;code&amp;gt;lsvcgssd&amp;lt;/code&amp;gt; is running with the right options, that the request-key file exists, and that the keys or keytabs are in place.&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Client-side logging.&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;lgss_keyring&amp;lt;/code&amp;gt; runs from the request-key upcall, which has no standard output, so it logs to syslog. Raise its level (0 error, 1 warn, 2 info, 3 debug, 4 trace):&lt;br /&gt;
&lt;br /&gt;
 client# lctl set_param sptlrpc.gss.lgss_keyring.debug_level=4&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Server-side logging.&amp;#039;&amp;#039;&amp;#039; Run the daemon in the foreground with extra &amp;lt;code&amp;gt;-v&amp;lt;/code&amp;gt; flags. It logs to standard output in the foreground and to syslog as a daemon:&lt;br /&gt;
&lt;br /&gt;
 server# lsvcgssd -f -vvv -s&lt;br /&gt;
&lt;br /&gt;
To inspect the keys in a keyring:&lt;br /&gt;
&lt;br /&gt;
 # keyctl show&lt;br /&gt;
 # keyctl pipe &amp;lt;key_id&amp;gt; | lgss_sk -r -&lt;br /&gt;
&lt;br /&gt;
== Performance ==&lt;br /&gt;
&lt;br /&gt;
Overhead grows with the level of protection. Authentication-only flavors (&amp;lt;code&amp;gt;skn&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;krb5n&amp;lt;/code&amp;gt;) are light, integrity flavors cost more, and the privacy flavors (&amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;krb5p&amp;lt;/code&amp;gt;) cost the most, because they encrypt bulk data. CPUs with hardware AES acceleration reduce the cost of &amp;lt;code&amp;gt;skpi&amp;lt;/code&amp;gt;. Benchmark your workload before enabling privacy system-wide, and consider rules that apply privacy only on untrusted networks.&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;SSK authenticates nodes, not users.&amp;#039;&amp;#039;&amp;#039; For multi-tenant isolation, combine it with nodemaps (UID/GID mapping and root squash). Use Kerberos if you need per-user authentication.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;A key file is a shared secret.&amp;#039;&amp;#039;&amp;#039; Anyone who obtains it can authenticate as a member of its nodemap, from a NID in that nodemap. Use separate keys per nodemap, keep them off shared filesystems, and protect them like passwords.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Each connection uses one flavor&amp;#039;&amp;#039;&amp;#039;, so Kerberos and SSK cannot both apply to the same connection. Rules can still give different networks, directions, or targets different mechanisms.&lt;br /&gt;
* Transport security does not protect data at rest. See [[Lustre Client Encryption]].&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[Setting up Lustre Security]] — overview of Lustre security features&lt;br /&gt;
* [[Lustre Multi Tenancy]] — nodemaps, filesets, and tenant isolation&lt;br /&gt;
* [[Shared Secret Key Authentication And Encryption]] — background and original design references for SSK&lt;br /&gt;
* [[Lustre Client Encryption]] — encryption of data at rest&lt;br /&gt;
&lt;br /&gt;
[[Category:Security]]&lt;/div&gt;</summary>
		<author><name>Elliswilson</name></author>
	</entry>
</feed>