Шифрование Linux (часть 4). Настройка удаленного доступа к полностью зашифрованной Centos системе

В предыдущей статьи я описал общий концепт для полного шифрования ОС Linux семейства rpm,deb (предыдущая инструкция тестировалась для Ubuntu, Debian, Centos Red Hat) при установке. Теперь, в продолжение статьи напишу инструкцию по удаленной разлочки зашифрованных luks томов под дистрибутивом Centos 6.4. Она так же подойдет и для Red Hat.

В отличие от настройки удаленной разлочки для deb-подобных систем, в Centos для обновления и создания initramfs используется – dracut . И для удаленной разлочки нам понадобиться писать специальный модуль под него.

Для начала нужно установить нужные пакеты. Так как пакета dropbear нету в стандартных репозиториях – нужно подключить свежий epel.

[root@slave ~]# wget http://mirror-fpt-telecom.fpt.net/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
[root@slave ~]# rpm -ivh epel-release-6-8.noarch.rpm
[root@slave ~]# yum -y update
[root@slave ~]# yum -y install dropbear cryptsetup busybox

Теперь нужно добавить dracut модуль. Если ваш сервер имеет статический IP, тогда установка и настройка модуля будет простой. Суть состоит в том, чтобы при начальной загрузке установить драйвер сети и статически вбить настройки интерфейса и добавить юзера для удаленной разлочки. Такая инструкция уже есть, можно почитать здесь . Я же хочу описать, как настроить раздачу адреса по dhcp. Для этого нам нужно писать скрипт, который будет имитировать dhcp клиент (в initramfs простой вызов команды dhclient не поднимет ваш интерфейс).
Приступаем.

[root@slave ~]# mkdir /usr/share/dracut/modules.d/30unlock
[root@slave ~]# cd /usr/share/dracut/modules.d/30unlock

Добавляем скрипт проверки и загрузку сетевого драйвера

[root@slave 30unlock]# cat check
#!/bin/sh
exit 0
[root@slave 30unlock]# cat installkernel
#!/bin/bash
instmods pcnet32

В данном случаи имя драйвера сети — pcnet32. Чтобы узнать который у вас драйвер, можно использовать утилиту ethtool.

[root@slave 30unlock]# ethtool -i eth0 | grep driver
driver: pcnet32

Далее добавляем пользователя, который будет делать разлочку и создаем ключ для подключения через dropbear.

[root@slave 30unlock]# echo 'root:x:0:0:root:/home/root:/bin/bash' > passwd
[root@slave 30unlock]# echo '/bin/bash' > shells
[root@slave 30unlock]# echo 'export PATH=/sbin:/usr/sbin:$PATH' >.profile
[root@slave 30unlock]# dropbearkey -t rsa -f dropbear_rsa_host_key
Will output 1024 bit rsa secret key to 'dropbear_rsa_host_key'
Generating key, this may take a while...
Public key portion is:
ssh-rsa AAAAB3NzaC1yc2EAASAADAQABAAAAgwC72SlhA7crmgxq+QJKxYa9NIxFiHFkw4VD65dOyeDAgQxW7LTlfc8JTMF3st+l2Kih/Z8Uyav8csG/Ti0YwaHyIbFG7MgO+WXehyFcuF+VGQFBjJSC2tuHFzJFtCDTVAeORM0aLMOWwBrVspXY/GtfQa0SiL/JkejS5z root@slave
Fingerprint: md5 4c:fa:6e:68:93:36:01:1a:2b:46:d7:7a:58:21:80:73
[root@slave 30unlock]# dropbearconvert dropbear openssh dropbear_rsa_host_key dropbear.key
Key is a RSA key
Wrote key to 'dropbear.key'
[root@slave 30unlock]# dropbearkey -y -f dropbear_rsa_host_key | grep "^ssh-rsa " > id_rsa.pub
[root@slave 30unlock]# cat id_rsa.pub >> authorized_keys

Добавляем файл служебной информации.

[root@slave 30unlock]# cat nsswitch.conf
passwd:  files
shadow:  files
group:  files
initgroups: files
hosts:  files dns
bootparams: files
ethers:  files
netmasks: files
networks: files
protocols: files
rpc:  files
services: files
automount: files
aliases: files

Добавляем скрипт разлочки

[root@slave 30unlock]# cat unlock
#!/bin/bash
if [ -f /etc/crypttab ] ; then
sed '/^$/d;/^#/d' /etc/crypttab > /tmp/crypttab
n=1
line="`sed -n "$n"p /tmp/crypttab`"
while [ -n "$line" ]; do
  name="`echo $line|awk '{ print $1 }'`"
  dev="`echo $line|awk '{ print $2 }'`"
  key="`echo $line|awk '{ print $3 }'`"
  if [ "$key" = "none" ]; then
    luksname="$name"
    if [ "${dev%%=*}" = "UUID" ]; then
      device="`blkid -t $dev|cut -d: -f1`"
    else
      device=$dev
    fi
    echo "Password [$device ($luksname)]:"
    while :;
    do
      cryptsetup luksOpen $device $luksname && break
    done
  fi
  n=$((n+1))
  line="`sed -n "$n"p /tmp/crypttab`"
done
sed -i /cryptsetup/c\ true /pre-pivot/*
[ "$1" = "-noexit" ] && exit 0
killall plymouth
killall cryptroot-ask
fi
exit 0

Скрипт для установки модуля сети и поднятия dropbear.

[root@slave 30unlock]# cat ssh.sh
#!/bin/sh
/sbin/modprobe pcnet32
/sbin/ifup eth0
/usr/sbin/dropbear -E -m -p 2222 -a -K 600
echo "dropbear is starting"
ping -c 4 8.8.8.8

Добавляем основной скрипт установки модуля

[root@slave 30unlock]# cat install
ARCH=$(uname -m)
for dir in /usr/$LIBDIR/tls/$ARCH/ /usr/$LIBDIR/tls/ /usr/$LIBDIR/$ARCH/ /usr/$LIBDIR/ /$LIBDIR/; do
    for i in $(ls $dir/libnss_dns.so.* $dir/libnss_mdns4_minimal.so.* 2>/dev/null); do
        dracut_install $i
    done
done

cat /etc/shadow|grep root > ${moddir}/shadow
inst_dir "/etc/dropbear"
inst "${moddir}/dropbear_rsa_host_key" "/etc/dropbear/dropbear_rsa_host_key"
inst_dir "/home"
inst_dir "/home/root"
inst_dir "/home/root/.ssh"
inst "${moddir}/.profile" "/home/root"
[ -s "${moddir}/authorized_keys" ] && inst "${moddir}/authorized_keys" "/home/root/.ssh/authorized_keys"
inst "/etc/localtime"
inst "${moddir}/nsswitch.conf" "/etc/nsswitch.conf"
inst "/etc/resolv.conf"
inst "/etc/host.conf"
inst "/etc/hosts"
inst "${moddir}/shadow" "/etc/shadow"
inst "${moddir}/passwd" "/etc/passwd"
inst "${moddir}/shells" "/etc/shells"
inst "${moddir}/unlock" "/bin/unlock"
inst "${moddir}/ifup" "/sbin/ifup"
inst "${moddir}/netroot" "/sbin/netroot"
inst "${moddir}/dhclient-script" "/sbin/dhclient-script"
inst "${moddir}/dhclient.conf" "/etc/dhclient.conf"
inst_hook pre-udev 01 "${moddir}/ssh.sh"
dracut_install ip dhclient brctl arping tr sed awk dropbear ifconfig route blkid cut killall true mkdir
dracut_install -o ps find grep less cat tac head tail false rmdir rm touch vi ping ssh scp lsmod

Добавляем настройки dhcp-клиента.

[root@slave 30unlock]# cat dhclient.conf
request subnet-mask, broadcast-address, time-offset, routers,
        domain-name, domain-name-servers, domain-search, host-name,
        root-path, interface-mtu;

Добавляем скрипт для поднятия и настройки dhcp

[root@slave 30unlock]# cat dhclient-script
#!/bin/sh

setup_interface() {
    ip=$new_ip_address
    mtu=$new_interface_mtu
    mask=$new_subnet_mask
    bcast=$new_broadcast_address
    gw=${new_routers%%,*}
    domain=$new_domain_name
    search=$(printf "$new_domain_search")
    namesrv=$new_domain_name_servers
    hostname=$new_host_name

    [ -f /tmp/net.$netif.override ] && . /tmp/net.$netif.override

    # Taken from debian dhclient-script:
    # The 576 MTU is only used for X.25 and dialup connections
    # where the admin wants low latency.  Such a low MTU can cause
    # problems with UDP traffic, among other things.  As such,
    # disallow MTUs from 576 and below by default, so that broken
    # MTUs are ignored, but higher stuff is allowed (1492, 1500, etc).
    if [ -n "$mtu" ] && [ $mtu -gt 576 ] ; then
        if ! ip link set $netif mtu $mtu ; then
            ip link set $netif down
            ip link set $netif mtu $mtu
            ip link set $netif up
            wait_for_if_up $netif
        fi
    fi

    ip addr add $ip${mask:+/$mask} ${bcast:+broadcast $bcast} dev $netif

    > /tmp/net.$netif.up
    ip addr add $ip${mask:+/$mask} ${bcast:+broadcast $bcast} dev $netif
    [ -n "$gw" ] && ip route add default via $gw dev $netif

    [ -n "$gw" ] && echo ip route add default via $gw dev $netif > /tmp/net.$netif.gw

    [ -n "${search}${domain}" ] && echo "search $search $domain" > /tmp/net.$netif.resolv.conf
    if  [ -n "$namesrv" ] ; then
        for s in $namesrv; do
            echo nameserver $s
        done
    fi >> /tmp/net.$netif.resolv.conf

    [ -n "$hostname" ] && echo "echo $hostname > /proc/sys/kernel/hostname" > /tmp/net.$netif.hostname
}

PATH=$PATH:/sbin:/usr/sbin

export PS4="dhclient.$interface.$$ + "
exec >>/dev/initlog.pipe 2>>/dev/initlog.pipe
. /lib/dracut-lib.sh

# We already need a set netif here
netif=$interface

case $reason in
    PREINIT)
        echo "dhcp: PREINIT $netif up"
        ip link set $netif up
        wait_for_if_up $netif
        ;;
    BOUND)
        echo "dhcp: BOND setting $netif"
        if ! arping -q -D -c 2 -I $netif $new_ip_address ; then
            warn "Duplicate address detected for $new_ip_address while doing dhcp. retrying"
            exit 1
        fi
        setup_interface
        set | while read line; do
            [ "${line#new_}" = "$line" ] && continue
            echo "$line"
        done >/tmp/dhclient.$netif.dhcpopts
        echo online > /sys/class/net/$netif/uevent
        /sbin/initqueue --onetime --name netroot-$netif  /sbin/netroot $netif
        ;;
    *) echo "dhcp: $reason";;
esac

exit 0

Добавляем скрипт для настройки параметров сетевого интерфейса

[root@slave 30unlock]# cat ifup
#!/bin/sh
#
# We don't need to check for ip= errors here, that is handled by the
# cmdline parser script
#
PATH=$PATH:/sbin:/usr/sbin

. /lib/dracut-lib.sh

# Run dhclient
do_dhcp() {
    # /sbin/dhclient-script will mark the netif up and generate the online
    # event for nfsroot
    # XXX add -V vendor class and option parsing per kernel
    #echo "Starting dhcp for interface $netif"
    dhclient "$@" -1 -q -cf /etc/dhclient.conf -pf /tmp/dhclient.$netif.pid -lf /tmp/dhclient.$netif.lease $netif

    # increase wait time for DHCP
    echo '[ $(($RDRETRY-$main_loop)) -lt 720 ] && RDRETRY=$(($main_loop+720)); rm -f "$job"' > /initqueue/rd_retry_inc_dhclient.$netif.sh

    #|| echo "dhcp failed"
}

load_ipv6() {
    modprobe ipv6
    i=0
    while [ ! -d /proc/sys/net/ipv6 ]; do
i=$(($i+1))
[ $i -gt 10 ] && break
sleep 0.1
    done
}

do_ipv6auto() {
    load_ipv6
    {
        echo 0 > /proc/sys/net/ipv6/conf/$netif/forwarding
        echo 1 > /proc/sys/net/ipv6/conf/$netif/accept_ra
        echo 1 > /proc/sys/net/ipv6/conf/$netif/accept_redirects
ip link set $netif up
wait_for_if_up $netif
    }
    > /tmp/net.$netif.up

    [ -n "$hostname" ] && echo "echo $hostname > /proc/sys/kernel/hostname" > /tmp/net.$netif.hostname

    namesrv=$(getargs nameserver)
    if  [ -n "$namesrv" ] ; then
for s in $namesrv; do
    echo nameserver $s
done
    fi >> /tmp/net.$netif.resolv.conf

    echo online > /sys/class/net/$netif/uevent
    /sbin/initqueue --onetime --name netroot-$netif  /sbin/netroot $netif
}

# Handle static ip configuration
do_static() {
    strstr $ip '*:*:*' && load_ipv6

    {
ip link set $netif up
wait_for_if_up $netif
# do not flush addr for ipv6
#strstr $ip '*:*:*' || \
#    ip addr flush dev $netif
ip addr add $ip/$mask brd + dev $netif
    }
    > /tmp/net.$netif.up

    [ -n "$gw" ] && echo ip route add default via $gw dev $netif > /tmp/net.$netif.gw
    [ -n "$hostname" ] && echo "echo $hostname > /proc/sys/kernel/hostname" > /tmp/net.$netif.hostname

    namesrv=$(getargs nameserver)
    if  [ -n "$namesrv" ] ; then
for s in $namesrv; do
    echo nameserver $s
done
    fi >> /tmp/net.$netif.resolv.conf

    echo online > /sys/class/net/$netif/uevent
    /sbin/initqueue --onetime --name netroot-$netif  /sbin/netroot $netif
}

PATH=$PATH:/sbin:/usr/sbin

export PS4="ifup.$1.$$ + "
exec >>/dev/initlog.pipe 2>>/dev/initlog.pipe
. /lib/dracut-lib.sh

# Huh? No $1?
[ -z "$1" ] && exit 1

# $netif reads easier than $1
netif=$1

# bridge this interface?
if [ -e /tmp/bridge.info ]; then
    . /tmp/bridge.info
    if [ "$netif" = "$ethname" ]; then
        netif="$bridgename"
    fi
fi

if [ -e /tmp/vlan.info ]; then
    . /tmp/vlan.info
    if [ "$netif" = "$phydevice" ]; then
        if [ "$netif" = "$bondname" ] && [ -n "$DO_BOND_SETUP" ] ; then
            : # We need to really setup bond (recursive call)
        else
            netif="$vlanname"
        fi
    fi
fi

# bail immediately if the interface is already up
# or we don't need the network
[ -f "/tmp/net.$netif.up" ] && exit 0
[ -f "/tmp/root.info" ] || exit 0
. /tmp/root.info
#[ -z "$netroot" ] && exit 0

# loopback is always handled the same way
if [ "$netif" = "lo" ] ; then
    ip link set lo up
    ip addr add 127.0.0.1/8 dev lo
    >/tmp/net.$netif.up
    exit 0
fi

# XXX need error handling like dhclient-script

# start bridge if necessary
if [ "$netif" = "$bridgename" ] && [ ! -e /tmp/net.$bridgename.up ]; then
    ip link set $ethname up
    wait_for_if_up $ethname
    # Create bridge and add eth to bridge
    brctl addbr $bridgename
    brctl setfd $bridgename 0
    brctl addif $bridgename $ethname
fi

get_vid() {
    case "$1" in
        vlan*)
            return ${1#vlan}
            ;;
        *.*)
            return ${1##*.}
            ;;
    esac
}

if [ "$netif" = "$vlanname" ] && [ ! -e /tmp/net.$vlanname.up ]; then
    modprobe 8021q
    ip link set "$phydevice" up
    wait_for_if_up "$phydevice"
    ip link add dev "$vlanname" link "$phydevice" type vlan id "$(get_vid $vlanname; echo $?)"
fi

# No ip lines default to dhcp
ip=$(getarg ip)

if [ -z "$ip" ]; then
    if [ "$netroot" = "dhcp6" ]; then
do_dhcp -6
    else
do_dhcp -4
    fi
fi

# Specific configuration, spin through the kernel command line
# looking for ip= lines
for p in $(getargs ip=); do
    ip_to_var $p
    # skip ibft
    [ "$autoconf" = "ibft" ] && continue

    # If this option isn't directed at our interface, skip it
    [ -n "$dev" ] && [ "$dev" != "$netif" ] && continue

    # Store config for later use
    for i in ip srv gw mask hostname; do
eval '[ "$'$i'" ] && echo '$i'="$'$i'"'
    done > /tmp/net.$netif.override

    OLDIFS="$IFS"
    IFS=,
    set -- $autoconf
    IFS="$OLDIFS"

    for autoconf in "$@"; do
case $autoconf in
    dhcp|on|any)
do_dhcp -4 ;;
    dhcp6)
do_dhcp -6 ;;
    auto6)
do_ipv6auto ;;
            *)
do_static ;;
esac
    done
    break
done

exit 0

Добавляем скрипт для завершения работы dhcp после разлочки.

[root@slave 30unlock]# cat kill-dhclient.sh
#!/bin/sh

for f in /tmp/dhclient.*.pid; do
    [ -e $f ] || continue
    read PID < $f;
    kill $PID;
done

Теперь делаем нужные скрипты – исполняемыми

[root@slave 30unlock]# chmod a+x check install installkernel ssh.sh unlock dhclient-script ifup
[root@slave 30unlock]# ls
authorized_keys  dhclient.conf    dropbear.key           id_rsa.pub  install        kill-dhclient.sh  passwd         shells check  dhclient-script  dropbear_rsa_host_key  ifup        installkernel  nsswitch.conf     ssh.sh  unlock

Теперь нужно обновить initramfs для добавления в него нашего модуля. И проверить, подхватился ли наш модуль

[root@slave 30unlock]# dracut -f
[root@slave 30unlock]# lsinitrd /boot/initramfs-2.6.32-279.el6.x86_64.img | grep ssh.sh
-rwxr-xr-x   1 root     root          140 Sep 30 20:57 pre-udev/01ssh.sh

Все действия идут по аналогии с удаленной разлочкой Ubuntu.

Теперь копируем ключ, перезагружаемся и проверяем.

root@ubuntu:~# ssh -o "UserKnownHostsFile=~/.ssh/known_hosts.initramfs" -i dropbear.key  root@192.168.1.108 -p 2222
[380] Oct 01 14:17:41 lastlog_perform_login: Couldn't stat /var/log/lastlog: No such file or directory
[380] Oct 01 14:17:41 lastlog_openseek: /var/log/lastlog is not a file or directory!
-bash-4.1# unlock
Password [/dev/sda2 (luks-2952e504-569b-438d-b43c-cdaa6ddcfd3a)]:
Enter passphrase for /dev/sda2:
-bash-4.1#

Если возникли проблемы – пишите, помогу чем смогу.

Автор: admin, 1 октября 2013
Рубрики: Безопасность
Метки: , , ,

Написать комментарий

Последние статьи

Яндекс.Метрика
?>