Используя утилиту Secmark можно организовать назначение в правилах iptables
SELinux-меток для сетевых пакетов, примерно также как осуществляется назначение
меток для локальных системных ресурсов. Подобное может использоваться для
предотвращения доступа сторонних процессов, не находящихся под контролем
SELinux, к определенному классу пакетов. Например, можно указать что запросы на
80 порт (метка http_packet_t) может отправлять только определенный web-браузер
(или процесс, имеющий SELinux-метку http_t) и никто иной.
По умолчанию все сетевые пакеты снабжаются меткой unlabeled_t, а для всех
подконтрольных процессов активируется правило, без ограничений разрешающее
отправку и прием пакетов:
allow MYDOMAIN unlabed_t:packet { send recv };
При назначении меток для трафика при помощи Secmark разрешительная политика по
отношению к unlabed_t может привести к тому, что в случае отключения пакетного
фильтра или в момент его перезапуска, правила блокирования будут временно проигнорированы.
Попытаемся отключить автоматическую установку метки unlabeled_t, которая
назначается в Fedora Linux через SELinux-модуль unlabelednet. Если отключить
данный набор SELinux-политик, то все подконтрольные SELinux приложения потеряют
возможность отправлять и принимать пакеты с меткой unlabeled_t. Чтобы вернуть
таким программам возможность работы в сети для них необходимо подготовить
соответствующие SELinux-правила и пометить пакеты.
Для усиления защиты ноутбука было решено подготовить простые SELinux-политики,
запрещающие обращаться к внешним сетевым ресурсам всем системным сервисам,
ограниченным при помощи SELinux. Всем программ, запущенные в рамках сессии
пользователя, разрешено обращаться как ко внутренним, так и к внешним сетевым ресурсам.
Подготовлено три политики доступа к сети:
internal_packet_t: Iptables помечает меткой internal_packet_t все пакеты,
отправленные в локальную сеть или приходящие на текущую машину из локальной сети;
dns_external_packet_t: Iptables помечает меткой dns_external_packet_t все
внешние обращения к DNS-серверам (udp/tcp порт 53);
external_packet_t: Iptables помечает меткой external_packet_t все остальные
пакеты, не подпадающие под первые два правила;
Для упрощения генерации iptables-правил для назначения SELinux-меток был создан скрипт
secmarkgen:
#!/bin/sh -e
init() {
# This just tells iptables to apply the same label to incoming packets as it did on outgoing
echo $IPTABLES -F -t security
echo $IPTABLES -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --restore
# Apply a label even if its on another port but is related
echo $IPTABLES -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --restore
echo
return
}
start() {
# Create a chain for each class of packets we have.
echo "$IPTABLES -t security -X $NAME 2> /dev/null"
echo "$IPTABLES -t security -N $NAME"
}
fini() {
# Label all other packets going internally to $TYPE:$MCS
echo $IPTABLES -t security -A $NAME -j SECMARK --selctx system_u:object_r:$TYPE:$MCS
echo $IPTABLES -t security -A $NAME -j CONNSECMARK --save
echo $IPTABLES -t security -A $NAME -j ACCEPT
echo
}
setup_network() {
if [ ! -z "$PORTS" ]; then
if [ ! -z "$NETWORK" ]; then
# Send packets going to an $NET httpd to the $NAME chain
echo $IPTABLES -A OUTPUT -t security -p $PROTOCOL -d $NETWORK --dport $PORTS -j $NAME
echo $IPTABLES -A INPUT -t security -p $PROTOCOL -d $NETWORK --sport $PORTS -j $NAME
else
# Send packets going to $PORTS httpd to the $NAME chain
echo $IPTABLES -A OUTPUT -t security -p $PROTOCOL --dport $PORTS -j $NAME
echo $IPTABLES -A INPUT -t security -p $PROTOCOL --sport $PORTS -j $NAME
fi
elif [ ! -z "$NETWORK" ]; then
# Send packets going to $PORT httpd to the $NAME chain
echo $IPTABLES -A OUTPUT -t security -d $NETWORK -j $NAME
echo $IPTABLES -A INPUT -t security -s $NETWORK -j $NAME
else
echo $IPTABLES -A OUTPUT -t security -j $NAME
echo $IPTABLES -A INPUT -t security -j $NAME
fi
}
usage() {
$"""
Usage: $0 -i
Usage: $0 -T iptablescmd -P protocol -p port[:...] -N network[,...] -t selinux_type -m MCS NAME
Usage: $0 -f NAME
"""
}
echo
echo "#---------------"
echo "# $0 $*"
echo "#---------------"
echo
IPTABLES=iptables
NAME=
PORTS=
MCS=s0
NETWORK=
TYPE=client_packet_t
PROTOCOL=tcp
FINISH=0
START=0
INIT=0
while getopts "sfin:p:m:t:T:P:" i; do
case "$i" in
i)
INIT=1
;;
s)
START=1
;;
f)
FINISH=1
;;
P)
PROTOCOL=$OPTARG
;;
T)
IPTABLES=$OPTARG
;;
n)
export NETWORK=$OPTARG
;;
t)
export TYPE=$OPTARG
;;
p)
export PORTS=$OPTARG
;;
m)
export MCS=$OPTARG
;;
*)
usage
exit 1
esac
done
# Init does not require a NAME
if [ $INIT == 1 ]; then
init
exit $?
fi
# Move out processed options from arguments
shift $(( OPTIND - 1 ))
NAME=$1
if [ -z "$NAME" -o -z "$MCS" -o -z "$NAME" ]; then
usage
exit 1
fi
if [ $START == 1 ]; then
start
exit $?
fi
if [ $FINISH == 1 ]; then
fini
exit $?
fi
setup_network
Скрипт можно запускать со следующими параметрами:
Инициализируем secmark-метки:
./secmarkgen -i
Определяем имя сети (имя Iptables-цепочки):
./secmarkgen -s INTERNAL
Привязываем к созданной цепочке набор правил. Синтаксис команды:
./secmarkgen -T iptablescmd -P protocol -p port[:...] -N network[,...] -t selinux_type -m MCS NAME
Например:
./secmarkgen -n 255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 INTERNAL
Для завершения формирования secmark-правил и их привязки к определенной
SELinux-метке используется команда:
./secmarkgen -f NAME
Например,
./secmarkgen -f -t internal_packet_t INTERNAL
в итоге будет сгенерирован примерно такой скрипт:
#--------------------
# ./secmarkgen -i
#--------------------
iptables -F -t security
iptables -t security -A INPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --restore
iptables -t security -A OUTPUT -m state --state ESTABLISHED,RELATED -j CONNSECMARK --restore
#--------------------
# ./secmarkgen -s INTERNAL
#--------------------
iptables -t security -X INTERNAL 2> /dev/null
iptables -t security -N INTERNAL
#--------------------
# ./secmarkgen -n 255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 INTERNAL
#--------------------
iptables -A OUTPUT -t security -d 255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 -j INTERNAL
iptables -A INPUT -t security -s 255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 -j INTERNAL
#--------------------
# ./secmarkgen -f -t internal_packet_t INTERNAL
#--------------------
iptables -t security -A INTERNAL -j SECMARK --selctx system_u:object_r:internal_packet_t:s0
iptables -t security -A INTERNAL -j CONNSECMARK --save
iptables -t security -A INTERNAL -j ACCEPT
Для генерации iptables-правил для локальных приложений используется примерно
такой скрипт (secmark_test.sh):
./secmarkgen -i
./secmarkgen -s INTERNAL
./secmarkgen -n 255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 INTERNAL
./secmarkgen -f -t internal_packet_t INTERNAL
./secmarkgen -s DNS
./secmarkgen -P udp -p 53 DNS
./secmarkgen -P tcp -p 53 DNS
./secmarkgen -f -t dns_external_packet_t DNS
./secmarkgen -s EXTERNAL
./secmarkgen EXTERNAL
./secmarkgen -f -t external_packet_t EXTERNAL
./secmarkgen -T ip6tables -i
./secmarkgen -T ip6tables -s INTERNAL
./secmarkgen -T ip6tables -n FEC0::/10,::1/128,FF::/8,FE80::/10FC00::/7 INTERNAL
./secmarkgen -T ip6tables -f -t internal_packet_t INTERNAL
./secmarkgen -T ip6tables -s EXTERNAL
./secmarkgen -T ip6tables EXTERNAL
./secmarkgen -T ip6tables -f -t external_packet_t EXTERNAL
Генерируем соответствующие iptables-правила:
./secmark_test.sh > /tmp/rules
Устанавливать данные iptables-правила пока рано, вначале нужно определить
соответствующие указанным меткам (*_packet_t) SELinux-политики, без которых
использование данных меток в iptables приведет к выводу ошибки.
Формируем файл с SELinux-политиками (secmark.te):
policy_module(secmark, 1.0)
gen_require('
attribute domain;
attribute sysadm_usertype;
# Domains that a staff user could transition to
attribute staff_usertype;
attribute telepathy_domain;
type ping_t;
type vpnc_t;
type ssh_t;
type nsplugin_t;
type mozilla_plugin_t;
# System domains that want to talk to the external network
type ntpd_t;
type sssd_t;
')
# Type Definitions
attribute external_packet;
type internal_packet_t;
corenet_packet(internal_packet_t)
type dns_external_packet_t, external_packet;
corenet_packet(dns_external_packet_t)
type external_packet_t, external_packet;
corenet_packet(external_packet_t)
# Allow Rules
allow domain internal_packet_t:packet { recv send };
allow sysadm_usertype external_packet:packet { recv send };
allow staff_usertype external_packet:packet { recv send };
allow vpnc_t external_packet:packet { recv send };
allow ssh_t external_packet:packet { recv send };
allow mozilla_plugin_t external_packet:packet { recv send };
allow nsplugin_t external_packet:packet { recv send };
allow telepathy_domain external_packet:packet { recv send };
allow ping_t external_packet:packet { recv send };
allow ntpd_t external_packet:packet { recv send };
dontaudit sssd_t dns_external_packet_t:packet { recv send };
Рассмотрим правила более подробно.
Строка
policy_module(secmark, 1.0)
определяет имя модуля с политиками.
Далее следует список требований
gen_require('
attribute domain;
...
type sssd_t;
')
При написании SELinux-политики необходимо сослаться на все типы и атрибуты,
чтобы их можно было использовать в правилах. Подобные ссылки указываются в
блоке gen_requires. Одновременно можно определить новые типы. Если один из
определенных в gen_requires атрибутов или типов будет не определен в других
частях правил, SELinux не активирует созданную политику. Например, атрибут
staff_usertype предоставляется всем обслуживающим пользовательским процессам,
sysadm_usertype присваивается всем процессам, используемым при
администрировании, домен telepathy_domain охватывает все приложения, связанные
с фреймворком telepathy.
Далее, в файле следуют правила определения типов и групп. Создаем атрибут
external_packet для группировки всех правил, связанных с внешним трафиком.
Также создаем интерфейс corenet_packet для ассоциации набора правил с пакетами.
attribute external_packet;
type internal_packet_t;
corenet_packet(internal_packet_t)
type dns_external_packet_t, external_packet;
corenet_packet(dns_external_packet_t)
type external_packet_t, external_packet;
corenet_packet(external_packet_t)
Далее указано правило, разрешающее всем процессам отправку и прием внутренних
пакетов из локальной сети:
allow domain internal_packet_t:packet { recv send };
Следующее правило позволяет запускаемым администраторами программам отправлять
и принимать пакеты из внешних сетей (вместо указания xternal_packet_t в
правиле фигурирует атрибут external_packet, который позволяет провести действие
сразу над группой - external_packet_t и dns_external_packet_t):
allow sysadm_usertype external_packet:packet { recv send };
allow staff_usertype external_packet:packet { recv send };
allow vpnc_t external_packet:packet { recv send };
allow ssh_t external_packet:packet { recv send };
allow mozilla_plugin_t external_packet:packet { recv send };
allow nsplugin_t external_packet:packet { recv send };
allow telepathy_domain external_packet:packet { recv send };
allow ping_t external_packet:packet { recv send };
Для сервиса ntpd заведен отдельный тип ntp_external_packet_t:
allow ntpd_t external_packet:packet { recv send };
Для программы sssd запрещаем общение с системами за пределами приватной сети:
dontaudit sssd_t dns_external_packet_t:packet { recv send };
Теперь приступим к компиляции, установке и применению созданной SELinux-политики:
Компилируем:
make -f /usr/share/selinux/devel/Makefile
Устанавливаем:
semodule -i secmark.pp
Активируем iptables-правила:
sh /tmp/rules
Сохраняем внесенные изменения:
service iptables save
service ip6tables save
С этого момента каждому сетевому пакету присваивается одна из трех созданных
SELinux-меток. Для отладки следует проследить за появлением avc-сообщений и при
необходимости добавить исключения с использованием правил allow/dontaudit или
расследовать причину появления непрошеного трафика.
|