Tuesday 13 December 2011

Securing Netapp to a subset of snap-* commands


One of the disadvantages in the security model created by Netapp is the inability to lock the filer down to giving a user the ability to run a particular command against a subset of volumes, for example if you give a user access to the snap delete command this can be run against any volume on the filer.

Whilst it can be restricted by the use of virtual filers (vfilers) this requires the multistore licence which you may not have.

I needed a way to lock down the filer, so came up with the scripts below.

First we will create a role on the filer to limit the command set and create a user to have this role.  Here we are looking at the snap-* commands:

netapp> useradmin role add “snapshot_manager” -a cli-snap* -c “CLI Snapshots”
netapp> useradmin group add “snapshot_group” -r “snapshot_manager”
netapp> useradmin user add “netappconnector” -g “snapshot_group”

Now on our linux host, we create a group called netappconnector, followed by a user also called netappconnector.  This user should only be a member of the netappconnector group.

Now login to the netappconnector account on the linux host and setup ssh to the filer.

Generate the keys:

netappconnector $> ssh-keygen –t rsa –b 1024

Now copy the contents on /home/netappconnector/.ssh/id_dsa.pub to /vol/vol0/etc/sshd/netapconnector/.ssh/authorized_keys on the filer.

Next check that ssh is working as expected:

netappconnector $>  ssh <filer> snap list <volume name>

And that it is locked to the snap commands only, by testing against a command that is not-authorised:

netappconnector $> ssh <filer> version

We can now start the linux configuration.  First change the shell of the netappconnector account to /bin/false.  This locks the account down to the point that it is impossible to directly login to the account.

We then need to create scripts on the linux host.  Lets start with the script that will perform the connection to the filer and run the commands.  Place the following script into /home/netappconnector/bin/run_command_on_netapp.sh on the linux host:

#!/bin/bash -u
# Name:                     run_command_on_netapp.sh
# Purpose:            This script is an interface between the host and the netapp
#                      filer.  Parameters are passed to it, detailing which filer,
#                      command to run.  It then checks if this command is in the
#                      valid list, before running the command on the filer specified.
#
# Syntax:            run_command_on_netapp.sh [filer] [command] (command parameters)
#
# Error Codes:          
#                      1:            Incorrect arguments passed
#                      2:            Command not authorised on filer requested
#                      3:            User is attempting to run this script as a user other
#                                  than the netappconnector user
#
# NOTE: All parameters are mandatory except for the command parameters
#
# Author:            Matthew Harman
# Date:                       29/11/2011
#
# Updates:
# Who What            Why
#
#
# local configuration variables
AUTHORISED_NETAPP_COMMANDS=/usr/bin/authorised_netapp_commands
# Functions
function die { # ($1=errMsg)
            echo "ERROR: $1 - exiting." >&2
            exit 1
}

function usage {
cat << EOF
Usage:
            $0 [filer] [command] (command parameters)

This script is an interface to running commands on the netapp filer.
It can be used to run the passed command (subject to authority) on the filer

Examples:
            $0 ukocna04 "snap list ORACLE_DBF_FCHDT"
            $0 ukocna04 "snap create ORACLE_DBF_FCHDT" 201111291213

Notes:
            All parameters are mandatory except the command parameters element, an
            error will be returned if all required parameters have not been passed
EOF
}

function check_command_is_authorised { # ($1=CONCATENATED)
echo "we are looking for:$1"
            # We need to check if the string passed, is contained within the
            # authorised commands file
            COUNTER=`cat $AUTHORISED_NETAPP_COMMANDS|grep "$1"|wc -l`
            if [ $COUNTER == 0 ]; then
                        # command is not authorised, raise an error
                        exit 2
            fi
            # If we get here command is authorised
}

function remove_parameters_for_check { # ($1=NETAPP_COMMAND)
            # certain commands have parameters that are variables, so we need to
            # remove them to get a matched on authorised commands
            #
            # snap restore is a prime example, lets see if we have this
            SNAP_RESTORE_COUNT=`echo $1|grep "snap restore"|wc -l`
            if [ $SNAP_RESTORE_COUNT -eq 1 ]; then
                        # We have the snap restore command, lets strip it
                        STRIPPED_COMMAND=`echo $1|awk -F" " '{print $6}'`
                        OUR_NEW_COMMAND="snap restore $STRIPPED_COMMAND"
            else
                        OUR_NEW_COMMAND=$1
            fi
}

function check_correct_user {
            USER=`whoami`
            if [ $USER != "netappconnector" ]; then
                        # we are running as an incorrect user, flag as error
                        exit 3
            fi
}
# End Functions #############################################################

# Read arguments and set parameters
if [ "$#" == 1 ]; then
            # Not enough parameters have been passed
            usage
            exit 1
else
            # Correct number of parameters, lets pass them into variables
            NETAPP_FILER=$1
            NETAPP_COMMAND=$2
            CONCATENATED="$1:$2"
            if [ "$#" == 3 ]; then
                        COMMAND_OPTIONS=$3
            else
                        COMMAND_OPTIONS=""
            fi
fi

check_correct_user

remove_parameters_for_check "$NETAPP_COMMAND"
check_command_is_authorised "$OUR_NEW_COMMAND"

# If we get here command has been authorised, so we can run it
ssh $NETAPP_FILER $NETAPP_COMMAND $COMMAND_OPTIONS


Make sure the permissions on this file, for security are:

User: root
Group:  root
Permissions: 755

Next we will create a file that lists all the authorised commands, this is how we lock it down to a subset of volumes.  Place the following contents into a new file called /usr/bin/authorised_netapp_commands:

# This file contains a list of authorised commands that can be run against
# the netapp(s).
# The format of the lines is:
# filer:username:command
filer:<user not used>:snap list volume1
filer:<user not used>:snap list volume2

Here we are limiting the command list to just snap list on volume1 and volume2 against the filer named “filer”

To make things as secure as possible, make sure this file has the following permissions:

User: root
Group: root
Permissions: 644

Finally we need to configure sudo access to the netappconnector account, along with access to only the command above.  Create a filesystem group called netappaccess and add all the accounts you wish to grant access to this filesystem group.

Edit the /etc/sudoers file, and ensure it contains the following lines:

%netappaccess <hostname>=(netappconnector) NOPASSWD:/home/netappconnector/bin/run_command_on_netapp.sh

where <hostname> is replaced with the linux hostname.

We can now test it.  Login to an account that configured for sudo access and run the following command:

account $> sudo –u netappconnector /home/netappconnector/bin/run_command_on_netapp.sh <filer> “snap list volume1”

You can then check for errors codes, by echoing the value of $?:

account $> echo $?

The values are as follows:

0: successful
1: incorrect arguments passed to command
2: command is not authorised, add it to /usr/bin/authorised_netapp_commands

The /usr/bin/authorised_netapp_commands should only contain the high level command and the volume, should you wish to add additional parameters when running the command, for example to create a snapshot with a specific name on volume1, you would add filer:<user>:snap create volume1 to /usr/bin/authorised_netapp_commands and then run:

account $> sudo –u netappconnector /home/netappconnector/bin/run_command_on_netapp.sh <filer> “snap create volume1” “snapshot_name”

No comments:

Post a Comment