Festplatten zu verschlüsseln um im Falle eines Diebstahles die Daten vor dem Zugriff zu schützen ist sinnvoll. Nur muss man dann eine Passwort eintippen oder ein Keyfile per USB-Stick bereitstellen. Ist der bootende Server mit LUKS-Verschlüsselung weit weg, kann zwar das Linux System hochfahren, aber die Dienste die auf die verschlüsselten Daten zu greifen müssen, können erst zu einem späteren Zeitpunkt gestartet werden. Zudem muss ja auch noch Alles manuell passieren.
Bedingungen / Voraussetzungen:
- Das Betriebssystem fährt ohne Verschlüsselung hoch.
- Die Systemplatten sind nicht verschlüsselt!
- LUKS verschlüsselte Partitionen
- Ein AD-Domänencontroller der stets verfügbar ist und sie haben Zugriffsrechte darauf.
- Zwei kleine Perl Scripte
- Systemd-Startscript
Ablauf-Prinzip:
Das System fährt hoch. Nachdem es Netzwerk-Zugriff hat, holt es sich per Perl-Script über LDAP die Keyfile-Daten aus dem LDAP-Attribute "extensionData" im AD. Dieses Attribut gehört zu jedem Computerkonto im AD.
Die Daten sind BASE64 kodiert und werden dann dekodiert in eine Datei geschrieben. Diese wiederum wird dem LUKS Command cryptsetup übergeben.
Über ein Systemd Startscript wird dieser Vorgang in den Boot- und Service-Startvorgänge eingebunden. Somit werden alle Dienste erst nach erfolgreichem mounten der LUKS-Partition(en) gestartet.
Prinzipiell kann natürlich auch ein beliebiger LDAP Server verwendet werden.
Umsetzung:
AD-Controller:
1. Ein AD Computerkonto erstellen
2. Ein AD User erstellen der NUR Leserecht auf das oder die Computerkonten hat
Linux-System:
3. Als root folgendes ausführen
# Installieren der Perl LDAP Pakete
zypper in perl-ldap-ssl perl-ldap perl-Authen-SASL perl-Digest-HMAC
# Generieren eines Zufalls-Schlüssels in der Datei keyfile
dd if=/dev/urandom of=/root/keyfile bs=1024 count=4
# Einfügen des Keyfiles Inhaltes in die LUKS Verschlüsselung
cryptsetup luksAddKey /dev/LUKS-Devie /root/keyfile
4. Anpassen des Perl Scriptes ldap-key-write.pl
Ersetzen aller FIRMA und COM Platzhalter in den LDAP-Pfaden durch die Ihrer Firma! (2-3 Mal)
5.Das erstellte und als LUKS-Keyfile zum entschlüsseln verwendete "keyfile" wird dann mit Hilfe des Perl Scriptes "ldap-key-write.pl" ins ADS Computerkonto geladen.
6. ldap-key-read.pl konfigurieren und testen
7. Erstellen einer crypttab.orig files (per Tab getrennt) im Format
cr_dev /dev/luks_device none noauto
8. Kopieren des Systemd-Startup-Scriptes nach /etc/systemd/system/multi-user.target.wants/cryptmount.service
9. Kopieren des SystemV-Startup-Scriptes nach /etc/init.d/cryptmount
10. systemctl --system daemon-reload
11. Testen / Rebooten / Testen
! Have al lot of Fun :) !
Files
-------- /etc/systemd/system/multi-user.target.wants/cryptmount.service ------------
[Unit]
Description=Mounted Crypt Volumes with Info from ADS / LDAP
Before=postgresql.service apache2.service nfsserver.service
After=syslog.target network.target
[Service]
ExecStart=/etc/init.d/cryptmount start
Type=forking
[Install]
WantedBy=multi-user.target
-------- /etc/systemd/system/multi-user.target.wants/cryptmount.service ------------
-------- /etc/crypttab.orig. ------------
cr_sdb1 /dev/sdb1 none noauto
-------- /etc/crypttab.orig. ------------
-------- /etc/init.d/cryptmount. ------------
#!/bin/sh
### BEGIN INIT INFO
# Provides: cryptmount
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: cryptmount provides mounting crypt partition with get the key from ADS
# Description: Start cryptmount to allow mounting encrypted partitions
# The key for unlock the partitions comming from ADS
### END INIT INFO
# Check for existence of needed config file and read it
cryptmount_CONFIG=/etc/sysconfig/cryptmount
# openSuse Specials!!!
. /etc/rc.status
# Reset status of this service
rc_reset
case "$1" in
start)
echo -n "Starting cryptmount "
echo
ping -c 4 dc.firma.com
echo "##################"
ping -c 4 dc.firma.com
echo "##################"
/root/ldap-key-read.pl "CRYPT.keyfile"
while read CDEV QDEV KEY PARAM;
do
echo "START: $CDEV - $QDEV - $KEY - $PARAM";
cryptsetup -d "/root/CRYPT.keyfile" luksOpen "$QDEV" "$CDEV"
rm "/root/CRYPT.keyfile"
mount /dev/mapper/$CDEV
done < /etc/crypttab.orig
# Remember status and be verbose
rc_status -v
;;
stop)
echo -n "Shutting down cryptmount "
## Stop daemon with killproc(8) and if this fails
## killproc sets the return value according to LSB.
echo
while read CDEV QDEV KEY PARAM;
do
echo "TEST: $CDEV - $QDEV - $KEY - $PARAM";
fgrep "$CDEV" /etc/fstab | while read AA MOUNTPOINT REST;
do
TREFFER=`lsof | grep "$MOUNTPOINT" | wc -l`
if [ "$TREFFER" -gt 0 ]; then
echo "WAITING FOR 5 sec";
sleep 5;
fi
done;
done < /etc/crypttab.orig
while read CDEV QDEV KEY PARAM;
do
echo "STOP: $CDEV - $QDEV - $KEY - $PARAM";
umount /dev/mapper/$CDEV || (echo "UNMOUNT ERROR"; mount; lsof | grep /srv; )
cryptsetup luksClose $CDEV
done < /etc/crypttab.orig
# Remember status and be verbose
rc_status -v
;;
restart)
## Stop the service and regardless of whether it was
## running or not, start it again.
$0 stop
$0 start
# Remember status and be quiet
rc_status
;;
status)
echo -n "Checking for service cryptmount "
echo
while read CDEV QDEV KEY PARAM;
do
echo "STATUS: $CDEV - $QDEV - $KEY - $PARAM";
cryptsetup status $CDEV
echo -n "MOUNTPOINT:"; mount | grep $CDEV
done < /etc/crypttab.orig
-------- /etc/init.d/cryptmount. ------------
#! /usr/bin/perl
use strict;
use Net::LDAP;
use Authen::SASL qw(Perl);
use MIME::Base64;
my $SERVERNAME = "Your Servername";
my $user="cn=ldap,dc=FIRMA,dc=COM";
my $passwd='secret password';
my $DEVICE = $ARGV[0];
my $ldap = Net::LDAP->new("dc.firma.com");
$ldap->bind($user, password=>$passwd);
# "(objectClass=computer)"
my $mesg = $ldap->search(filter=>"&(name=$SERVERNAME)(objectClass=computer)", base=>"dc=firma,dc=com");
my @entries = $mesg->entries;
my $entry = $mesg->entry(0); print "READ FROM DN: " . $entry->dn() . "\n";
my $content_base64 = $entry->get_value('extensionData');
my $content_binary = MIME::Base64::decode($content_base64);
open( KEY, '>/root/'.$DEVICE ) or die ("Cannot open KEY file!\n");
binmode( KEY );
print KEY $content_binary ;
close( KEY );
<-------- ldap-key-read.pl.< ------------
-------- ldap-key-write.pl. ------------>
#! /usr/bin/perl
use strict;
use Net::LDAP;
use Authen::SASL qw(Perl);
use MIME::Base64;
my $content_binary;
my $content_base64;
my $DC = "dc.firma.com";my $SERVERNAME = "Your Servername";
my $user="cn=$ARGV[0],dc=firma,dc=com";
print "PASSWORT eingeben:";
my $passwd;
$passwd = <STDIN>;
chomp( $passwd );
#print "USER: $user -- PW: $passwd\n";
my $ldap = Net::LDAP->new($DC);
$ldap->bind($user, password=>$passwd);
# "(objectClass=computer)"
my $mesg = $ldap->search(filter=>"&(name=$SERVERNAME)(objectClass=computer)", base=>"dc=firma,dc=com");
my @entries = $mesg->entries;
my $dn = 'CN=$SERVERNAME,CN=Computers,DC=firma,DC=com';
my $entry = $mesg->entry(0);
open( KEY, "<$ARGV[1]" ) or die ("Cannot open KEY file $ARGV[1] !\n");
binmode( KEY );
while(<KEY>)
{
#print KEY $content_binary ;
$content_binary .= $_;
}
close( KEY );
my $content_base64 = MIME::Base64::encode($content_binary);
print "BASE: $content_base64\n";;
$mesg = $ldap->modify($dn, replace => { "extensionData" => $content_base64 } );
$entry->update($ldap);
print "Message is ". $mesg->code ." (". $mesg->error .").\n";
<-------- ldap-key-write.pl. ENDE <------------