Skip to content

simp/pupmod-simp-nfs

Repository files navigation

License CII Best Practices Puppet Forge Puppet Forge Downloads Build Status

Table of Contents

Description

The is a module for managing the exporting and mounting of NFS devices. It provides all the infrastructure needed to share folders over the network.

The module is broken into two parts: the server and the client. It supports security with either krb5 or stunnel, but not both, as these security services conflict at a system level. It also manages firewall and TCP wrapper settings, when enabled.

This is a SIMP module

This module is a component of the System Integrity Management Platform, a compliance-management framework built on Puppet.

If you find any issues, they may be submitted to our bug tracker.

This module is optimally designed for use within a larger SIMP ecosystem, but it can be used independently:

  • When included within the SIMP ecosystem, security compliance settings will be managed from the Puppet server.
  • If used independently, all SIMP-managed security subsystems are disabled by default and must be explicitly opted into by administrators. See the SIMP simp_options module for more detail.

Setup

What nfs affects

The nfs module installs NFS packages, configures services for the NFS server and/or client and manages most NFS configuration files.

Setup Requirements

The only requirement is to include the nfs module and its dependencies in your modulepath.

  • If you are using any of the nfs module's optional dependencies, e.g. autofs, please also include those modules in the module path as well. The list of optional dependencies can be found in the nfs module's metadata.json file under simp/optional_dependencies.

Beginning with nfs

You can use the nfs module to manage NFS settings for a node that is a NFS client, a NFS server or both.

NFS client

Including one or more nfs::client::mount defines in a node's manifest will automatically include the nfs::client class, which, in turn, will ensure the appropriate packages are installed and appropriate services are configured and started.

NFS server

Including one or more nfs::server::export defines in a node's manifest and setting the hiera below will automatically include the nfs::server class, which, in turn, will ensure the appropriate packages are installed and appropriate services are configured.

nfs::is_server: true
nfs::is_client: false

NFS server and client

Including one or more nfs::server::export or nfs::client::mount defines in a node's manifest and setting the hiera below will automatically include the nfs::server and nfs::client classes. This will, in turn, ensure the appropriate packages are installed and appropriate services are configured for both roles.

nfs::is_server: true

Usage

Basic Usage

Exporting a filesystem

To export /srv/nfs_share, add the following to the NFS server's manifest:

  nfs::server::export { 'nfs4_root':
    client      => [ <trusted networks> ]
    export_path => '/srv/nfs_share',
    require     => File['/srv/nfs_share']
  }

  file { '/srv/nfs_share':
    ensure => 'directory',
    owner  => 'root',
    group  => 'root',
    mode   => '0644'
  }

Be sure to set the following in hiera, as well:

nfs::is_server: true

Mounting

Static mount

To mount /srv/nfs_share statically to /mnt/nfs on the NFS client using NFSv4, add the following to the NFS client's manifest:

$mount_dir = '/mnt/nfs'

nfs::client::mount { $mount_dir:
  nfs_server  => '<NFS server IP>',
  remote_path => '/srv/nfs_share',
  autofs      => false
}

# mount directory must exist if not using autofs
file { $mount_dir:
  ensure => 'directory',
  owner  => 'root',
  group  => 'root',
  mode   => '0644'
}

File[$mount_dir] -> Nfs::Client::Mount[$mount_dir]
Automatic direct mount

To automount /exports/data as /data using an direct mount, add the following to the NFS client's manifest:

nfs::client::mount { '/data':
  nfs_server  => '<NFS server IP>',
  remote_path => '/exports/data'
}
Automatic indirect mount

To automount /exports/apps as /apps using an indirect mount with key substitution, add the following to the NFS client's manifest:

nfs::client::mount { '/apps':
  nfs_server              => '<NFS server IP>',
  remote_path             => '/exports/apps',
  autofs_indirect_map_key => '*',
  autofs_add_key_subst    => true
}
Automatic mount of home directories for LDAP users

Please reference the SIMP documentation for details on how to implement this feature.

Usage with krb5


WARNING

This functionality requires some manual configuration and when keys change may require manual purging of the gssproxy cache.


This module, used with the SIMP krb5 module, can automatically use kerberos to secure the exported filesystem. The module can create and manage the entire kerberos configuration automatically, but check the krb5 module itself if you want more control.

Modify the examples provided above to include the following hieradata on all nodes:

simp_options::kerberos: true
nfs::secure_nfs: true

krb5::config::dns_lookup_kdc: false
krb5::kdc::auto_keytabs::global_services:
  - 'nfs'

On the node intended to be the KDC, include the following class:

include 'krb5::kdc'

On the NFS server and client nodes, add the following to each node's manifest:

# If your realm is not your domain name then change this
# to the string that is your realm
$myrealm = upcase($facts['domain'])

krb5::setting::realm { $myrealm:
  admin_server   => <KDC fqnd>,
  default_domain => $myrealm
}

SIMP does not have kerberos set up to work automatically with LDAP yet. You must add a principal for each user you want to give access to the krb5 protected directories. To do this log onto the KDC and run:

kadmin.local
# Note the prompt is now kadmin.local!
kadmin.local:  add_principal -pw <password> <username>
...
kadmin.local:  exit

When the user logs on after kerberos has been configured they must run:

kinit

It will ask them for their password. Once the have done this they should be able to access any shares from that realm.

Usage with stunnel

When use of kerberos is not viable, but you want to encrypt NFS traffic, you can configure the NFS server and client to use stunnel automatically on NFSv4 connections.

This module uses the SIMP stunnel module for stunnel management.

NFSv4 stunnel, one NFS server

In this scenario, we will consider a site with one NFS server.

Export with stunnel

To enable use of stunnel at the NFS server, set the following in hieradata:

nfs::is_server: true
nfs::stunnel: true

To export /srv/nfs_share, add the following to the NFS server's manifest:

nfs::server::export { 'nfs4_root':
  client      => [ <trusted networks> ]
  export_path => '/srv/nfs_share',
  # This MUST be set to true due to a NFS exports processing bug.
  # See description in nfs::server::export.
  insecure    => true,
  require     => File['/srv/nfs_share']
}

file { '/srv/nfs_share':
  ensure => 'directory',
  owner  => 'root',
  group  => 'root',
  mode   => '0644'
}
Mount with stunnel

To enable use of stunnel at the NFS client, set the following in hieradata:

nfs::stunnel: true

To mount /srv/nfs_share statically to /mnt/nfs on the NFS client, add the following to the NFS client's manifest:

$mount_dir = '/mnt/nfs'

nfs::client::mount { $mount_dir:
  nfs_server  => '<NFS server IP>',
  remote_path => '/srv/nfs_share',
  autofs      => false
}

# mount directory must exist if not using autofs
file { $mount_dir:
 ensure => 'directory',
 owner  => 'root',
 group  => 'root',
 mode   => '0644'
}

File[$mount_dir] -> Nfs::Client::Mount[$mount_dir]

In this simple case, the mount manifest looks exactly the same as in the unencrypted case. Only the hieradata has changed.

NFSv4 stunnel, multiple NFS servers

In this scenario, we will consider a site with two NFS servers. The example shown can be extrapolated to any number of NFS servers.

Server 1 export with stunnel

The first NFS server will be configured exactly as is done with the single server example above.

Server 1 hieradata:

nfs::is_server: true
nfs::stunnel: true

Server 1 manifest:

nfs::server::export { 'nfs4_root':
  client      => [ <trusted networks> ]
  export_path => '/srv/nfs_share',
  # This MUST be set to true due to a NFS exports processing bug
  insecure    => true,
  require     => File['/srv/nfs_share']
}

file { '/srv/nfs_share':
  ensure => 'directory',
  owner  => 'root',
  group  => 'root',
  mode   => '0644'
}
Server 2 export with stunnel

The second NFS server requires a little more configuration.

To enable use of stunnel at this NFS server and prevent port conflicts with Server 1 on any client that wants to mount from both servers over stunnel, set the following in hieradata:

nfs::is_server: true
nfs::stunnel: true

# The nfsd port must be unique among all NFS servers at the site.
# The stunnel nfsd port is configured here for consistency, but
# could be left at the default.
nfs::nfsd_port: 2050
nfs::stunnel_nfsd_port: 20500

To export /srv/nfs_share2, add the following to Server 2's manifest:

nfs::server::export { 'nfs4_root':
  client      => [ <trusted networks> ]
  export_path => '/srv/nfs_share2',
  # This MUST be set to true due to a NFS exports processing bug
  insecure    => true,
  require     => File['/srv/nfs_share2']
}

file { '/srv/nfs_share2':
  ensure => 'directory',
  owner  => 'root',
  group  => 'root',
  mode   => '0644'
}
Mounts to servers with stunnel

To enable use of stunnel at the NFS client, set the following in hieradata:

nfs::stunnel: true

To mount /srv/nfs_share from Server 1 statically to /mnt/nfs and /srv/nfs_share2 from Server 2 statically to /mnt/nfs2, add the following to the NFS client's manifest:

# this mount uses the defaults, because Server 1 uses nfs
# module defaults
$mount_dir = '/mnt/nfs'
nfs::client::mount { $mount_dir:
  nfs_server  => '<NFS Server 1 IP>',
  remote_path => '/srv/nfs_share',
  autofs      => false
}

# this mount sets ports to match those of Server 2
$mount_dir2 = '/mnt/nfs2'
nfs::client::mount { $mount_dir2:
  nfs_server        => '<NFS Server 2 IP>',
  remote_path       => '/srv/nfs_share2',
  autofs            => false,
  nfsd_port         => 2050,
  stunnel_nfsd_port => 20500
}

# mount directories must exist if not using autofs
file { [ $mount_dir, $mount_dir2 ]:
 ensure => 'directory',
 owner  => 'root',
 group  => 'root',
 mode   => '0644'
}

File[$mount_dir] -> Nfs::Client::Mount[$mount_dir]
File[$mount_dir2] -> Nfs::Client::Mount[$mount_dir2]

NFSv3 considerations

NFSv3 traffic cannot be encrypted with stunnel because of two key reasons:

  • The NFS client sends the NFS server Network Status Manager (NSM) notifications via UDP, exclusively.

    • stunnel only handles TCP traffic.
    • Loss of these notification may affect NFS performance.
  • In multi-NFS-server environments, there is no mechanism to configure rpcbind to use a non-standard port.

    • NFSv3 heavily relies upon rpcbind to determine the side-band channel ports in use on the NFS nodes. This includes the statd and lockd ports used in NSM and NLM, respectively.
    • A unique rpcbind port per server is required in order for a NFS client to be able tunnel its server-specific RPC requests to the appropriate server.

Despite this limitation, this module still fully supports unencrypted NFSv3 and allows the NFS server and client to use unencrypted NFSv3 concurrently with stunneled NFSv4.

  • If a NFS server is configured to both allow NFSv3 and to use stunnel, it will accept unencrypted NFSv3 connections, unencrypted NFSv4 connections and stunneled NFSv4 connections.

    The hieradata for this configuration is:

    nfs::is_server: true
    nfs::nfsv3: true
    nfs::stunnel: true
  • If a NFS client is configured to both allow NFSv3 and to use stunnel, it can use unencrypted NFSv3 mounts and stunneled NFSv4 mounts.

    The hieradata for this configuration is:

    nfs::nfsv3: true
    nfs::stunnel: true

Other security features

This module can be configured to automatically add firewall rules and allow NFS services in TCP wrappers using the SIMP iptables module and the SIMP tcpwrappers module, respectively.

To enable these features on the NFS server and NFS client nodes, add the following to their hieradata:

simp_options::firewall: true
simp_options::tcpwrappers: true

Reference

Please refer to the REFERENCE.md.

Limitations

This module does not yet manage the following:

  • /etc/nfsmounts.conf

  • gssproxy configuration

    • If you are using a custom keytab location, you must fix the cred_store entries in /etc/gssproxy/24-nfs-server.conf and /etc/gssproxy/99-nfs-client.conf.
    • If a node's keytab has changed content and the old keytab entries are no longer valid, you will have to manually clear the gssproxy credential cache using kdestroy -c <gssproxy cache>. Simply restarting the gssproxy service does not clear the cache and re-read the keytab!
  • RDMA packages or its service

  • idmapd configuration for the umich_ldap translation method

    • If you need to configure this, consider using nfs::idmapd::config::content to specify full contents of the /etc/idmapd.conf file.

This module does not address an intermittent systemd issue in which the rpc.statd NFSv3 daemon is not always stopped when the rpc-statd service is stopped. When this occurs,

  • systemd no longer has a record of that daemon's PID and cannot fix the problem.

  • The rpc-statd service cannot be subsequently started.

    • When the service tries to start another instance of rpc.statd, the new instance detects the running instance and then immediately exits with a failed exit code.
  • You must manually kill the running rpc.statd daemon to recover.

SIMP Puppet modules are generally intended for use on Red Hat Enterprise Linux and compatible distributions, such as CentOS. Please see the metadata.json file for the most up-to-date list of supported operating systems, Puppet versions, and module dependencies.

Development

Please read our Contribution Guide.

Acceptance tests

This module includes Beaker acceptance tests using the SIMP Beaker Helpers. By default the tests use Vagrant with VirtualBox as a back-end; Vagrant and VirtualBox must both be installed to run these tests without modification. To execute the tests run the following:

bundle install
bundle exec rake beaker:suites

Please refer to the SIMP Beaker Helpers documentation for more information.