First we need to setup RSBAC User Management modules. In /etc/nsswitch.conf we may have ‘[passwd|shadow|group]: compat rsbac’, and in /etc/pam.d/system-auth ‘[auth|account|password|session] sufficient pam_rsbac.so’ before any pam_unix.so lines. Then :
secoff$ rsbac_useradd -O && rsbac_groupadd -O secoff$ rsbac_passwd -n secoff
Sshd must be allow to change his identity during key exchange
secoff$ for user in 0 22; do for param in "" "-e" "-f"; do auth_set_cap $param FD add /usr/sbin/sshd $user done done
Now we want sshd to be allow to change his identity only to an user who have been properly authenticated (by entering his password).
secoff$ attr_set_fd AUTH FD auth_may_setuid 3 /usr/sbin/sshd
Note: if you use CONFIG_RSBAC_AUTH_DAC_*, CONFIG_RSBAC_DAC_* you must add caps for allowed user, because they don’t use the special auth_may_setuid value : ‘Last Auth...’
secoff$ for user in 400 "1000 3000"; do for param in "-e" "-f"; do auth_set_cap $param FD add /usr/sbin/sshd $user done done
Add the following parameter to sshd init script:
-o "HostbasedAuthentication no" -o "PasswordAuthentication yes" -o "ChallengeResponseAuthentication no" -o "UsePAM yes" -o "UsePrivilegeSeparation yes" -o "PermitRootLogin no"
ssh secoff@your_server
If you use the unix password, then you’ll get : ‘rsbac_adf_request(): request CHANGE_OWNER, ..., prog_name sshd, prog_file /usr/sbin/sshd, uid 0, remote ip ..., target_type PROCESS, ...., attr owner, value 400, result NOT_GRANTED by AUTH’. Now you have to use the rsbac password, like that the kernel will know that secoff have been authenticate, then he’ll allow sshd to change his identity.
This is a pretty good security measure, because even if sshd get’s cracked, it won’t be able to gain secoff credential without his passw ord.
RES allows to enforce user limits (ulimit). Here are somes examples:
secoff$ for user in -4 root; do attr_set_user RES $user res_max fsize 250000 # user won t create file more than 1G (block size = 4096) attr_set_user RES $user res_max stack 100000 # user stack won t get bigger than 100 KB attr_set_user RES $user res_max nofile 1024 # user won t open more than 1024 fds at a time attr_set_user RES $user res_min core -1 # user will coredump by default attr_set_user RES $user res_max nproc 200 # user won t start more than 200 process attr_set_user RES $user res_max as 100000000 # user s process won t get bigger than 100MB done secoff$ attr_set_user RES root res_role 0
And that’s it !
user$ ulimit -a core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited file size (blocks, -f) 976 max locked memory (kbytes, -l) unlimited max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 97 cpu time (seconds, -t) unlimited max user processes (-u) 200 virtual memory (kbytes, -v) 97656 file locks (-x) unlimited user$ ulimit -u 1024 -sh: ulimit: max user processes: cannot modify limit: Operation not permitted user$ for i in `seq 0 250`; do sleep 5& done .... [195] 12759 -sh: fork: Resource temporarily unavailable
In this example, we don’t want anyone, except secoff, to be able to update kernel in /boot.
First, let’s protect /boot directory with RC
# We create a new FD rc_type rc_set_item TYPE `rc_get_item list_unused_fd_type_nr` type_fd_name BOOT_FD # We allow secoff to access this type rc_set_item ROLE 1 type_comp_fd $BOOT_FD A # We set /boot rc_type_fd attr_set_fd RC FD rc_type_fd $BOOT_FD /boot # Repeat this last one after mounting the device: When a directory get s mounted, #its attributes are replaced by the ones of the new device's root.
This is good, but root can still access boot data directly through /dev/sda1.
# We create a new DEV rc_type rc_set_item TYPE `rc_get_item list_unused_dev_type_nr` type_dev_name BOOT_Device # We allow secoff to access this type rc_set_item ROLE 1 type_comp_dev $BOOT_Device A # We set /dev/sda1 rc_type attr_set_file_dir -d DEV b8:1 rc_type $BOOT_Device
Finally we wan’t secoff to be able to mount the device:
# Let s fool mount attr_set_fd GEN FD fake_root_uid 3 /bin/mount # And allow secoff to changes files in /boot, the GEN way: attr_set_fd GEN FD linux_dac_disable 1 /boot # do that when /boot is mounted ! # or the CAP way: attr_set_user -a CAP secoff min_caps FS_MASK
RSBAC transactions works pretty much the same as SQL databases transactions... It ease policies development, for example you can do without loads of NOT_GRANTED:
There are four commands to use :
To monitor what’s going on, read the ‘/proc/rsbac-info/gen_lists’ file
finally, there are two way to change attributes in a transaction, you can either
attr_set_fd -N ta_number RC FD rc_type 2 /whatever`rsbac_list_ta -b -t 900 begin`
rsbac_menu ...export RSBAC_TA=ta_number
Here is a small script which show how to use transaction for user creation purposes.
#!/bin/sh function abord { echo -e "\n\e[1;33m*\e[1;32m $1\e[0;37m"; rsbac_list_ta -N $RSBAC_TA forget; exit 1 } export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin if [ -z "$1" ]; then echo "usage: $0 username"; exit 1; fi; export RSBAC_TA="`rsbac_list_ta -t 10 begin`" rsbac_useradd -x 60 -w 30 -g users -p '' $1 || myabord "Could not create user" rsbac_usermod -l 0 $1 || myabord "Could not usermod" attr_set_user RC $1 rc_def_role `rc_get_item list_roles | grep ' Remote_Users$' | awk '{print $1}'` || myabord "Could not set def role" attr_set_user CAP $1 min_caps IPC_LOCK || myabord "attr_set_user" attr_set_user CAP $1 cap_ld_env 1 || myabord "attr_set_user" rsbac_list_ta -N $RSBAC_TA commit || myabord "rsbac_list_ta" mkdir -m 700 /home/$1 chown $1 /home/$1
First some documentation. For each network access, the adf will try to match the object with a network template from lowest to highest ordering number until it matches one. So general purpose templates should have high numbers, and more detailed templates should have low numbers.
Let’s try to enforce network access of a web server First, we create network template, with rsbac_nettemp_def_menu, and for each template we create a new rc_netobj_type with the name + _NETOBJ
| Name | Nr | Family | Type | Address | Protocol | Ports |
|---|---|---|---|---|---|---|
| DNS_SRV | 53 | INET | DGRAM | nameserver/32 | UDP | 53:53 |
| TCP | 300000 | INET | STREAM | 0.0.0.0/0 | TCP | |
| UDP | 300001 | INET | DGRAM | 0.0.0.0/0 | UDP | |
| NETLINK | 300002 | NETLINK | RAW | ANY | ||
| HTTPS | 200443 | INET | STREAM | 0.0.0.0/0 | TCP | 443:443 |
| LAN_TCP | 100000 | INET | STREAM | 192.168.0.0/16 | TCP |
The NETLINK socket is a special socket family for asking network configuration to the kernel. So first, we must allow apache to access this template.
Then apache will create a TCP socket. At this point the netobj is defined as follow : ‘INET STREAM proto TCP local 0.0.0.0:0 remote 0.0.0.0:0’. So the TCP template will match.
Then apache will bind this socket. The netobj is defined as follow: ‘INET STREAM proto TCP local 0.0.0.0:443 remote 0.0.0.0:0, attr sock_type, value STREAM’, aka HTTPS
Finally, when a browser connects to the server, the netobj is defined as follow : ‘INET STREAM proto TCP local eth0:SRV_ADDR:443 remote CLIENT_ADDR:35967’ aka LAN_TCP
So here is the list of necessary type_comp apache needs to be available for lan clients:
| Netobj | Access |
|---|---|
| NETLINK_NETOBJ | CREATE GET_STATUS_DATA BIND RECEIVE SEND |
| TCP_NETOBJ | CREATE GET_STATUS_DATA MODIFY_SYSTEM_DATA |
| HTTPS_NETOBJ | BIND LISTEN MODIFY_SYSTEM_DATA NET_SHUTDOWN |
| LAN_TCP | ACCEPT GET_STATUS_DATA READ RECEIVE WRITE SEND NET_SHUTDOWN |
| UDP_NETOBJ | CREATE GET_STATUS_DATA MODIFY_SYSTEM_DATA IOCTL NET_SHUTDOWN |
| DNS_SRV_NETOBJ | CONNECT SEND RECEIVE |
And here you go !