home of the madduck/ blog/ ocat/
madduck's droppings - blogs previously filed under the debian category

This page exists to ease the transition since I migrated my blog to a new software. You are interested in the posts previously filed in the “debian” category, which are listed below.

My new blog can be found at http://madduck.net/blog. Future articles, which would have been filed as “debian”, are going to show up here as well. However, please watch this space as these transitional pages may disappear at some point.

Ubuntu giving back

OpenExpo ended last night with a lovely dinner at Roter Turm, and I ought to thank Matthias Stürmer and his team for their efforts.

I especially would like to thank Myriam Schweingruber of the Ubuntu team! Debian.ch could not assemble enough manpower for a booth, and so Myriam took care of selling our new t-shirts at the Ubuntu booth — 29 of them.

That’s Ubuntu giving back to Debian! :)

NP: AC/DC: Stiff Upper Lip

Posted Fri 26 Sep 2008 14:44:34 CEST Tags: ?ch ?openexpo ?t-shirts ?ubuntu
Auto-subscribing to Debian bugs I file

It happens from time to time that bug reports I file receive attention, but I don’t notice because our bug tracking system still does not auto-subscribe bug submitters to their own bugs (see bug #37078 and bug #351856). I thus decided to take the matter into my own hands.

Just in time, before I started hacking this up myself, I found Justin Pryzby’s procmail recipies, which are installed to /usr/share/doc/devscripts/examples/bts_autosubscription.procmail by the devscripts package. The result is available in my mailfilter git repository. So far, I only auto-subscribe in response to bugs I file; Justin also auto-subscribes to bugs he manipulates via the control bot.

For completeness, I also wanted to subscribe to all bugs that I have submitted. This turned out to be easier than I thought, thanks to bts in the devscripts package; note the sleep instruction in the loop to prevent hammering the system:

bts select submitter:madduck@debian.org \
  | while read bugno; do
      echo X-debbugs-autosubscribe: madduck \
        | sendmail -f madduck@debian.org ${bugno}-subscribe@bugs.debian.org
      echo subscription to \#${bugno} sent
      sleep 30
    done

NP: The Dukes of Leisure: The Dukes of Leisure

Posted Fri 20 Jun 2008 12:17:37 CEST Tags: ?debbugs ?devscripts
IPv6 with Debian

Debian seems to be ready for IPv6 (although there are still some problems). In less than a day, I put a few of my machines online and joined the Internet of the future. In the following, I’d like to share with you how I did it.

Configuring the packet filter

The first thing I did was to configure the packet filter on each host appropriately. Unfortunately, this is harder than it should be, because — to quote one of the netfilter developers — “when ip6tables was conceived, someone had a big bad brainfart”: rather than adding IPv6 rules to your existing iptables ruleset, you have to create a new ruleset, duplicate all chains, networks, hosts, and individual rules, and maintain the two in parallel. Even though there are efforts of unification on the way, I speculate it’ll take another couple of years until PF_INET6 will be fused into PF_INET and one will be able to do sensible cross-address-family packet filtering with Linux. Since I’ve recently started to look (again) at pyroman, maybe the most logical way forward would be to extend it to write both, IPv4 and IPv6 rulesets from its knowledge about the hosts and networks you configured.

Anyway, we want to get stuff working now! Thus, let’s configure ourselves a packet filter. (Almost) all IPv6-related filtering must be configured via ip6tables (read on further down about IPv6 in IPv4 tunneling, the reason I said “almost”). The following is a simple default ruleset to start with, which I put into /etc/network/ip6tables to load with ip6tables-restore:

*filter
:INPUT REJECT [0:0]
:FORWARD REJECT [0:0]
:OUTPUT ACCEPT [0:0]
:in-new - [0:0]

### INPUT chain

# allow all loopback traffic
-A INPUT -i lo -j ACCEPT

# RT0 processing is disabled since 2.6.20.9
#-A INPUT -m rt --rt-type 0 -j REJECT

# allow all ICMP traffic
-A INPUT -p icmpv6 -j ACCEPT

# packets belonging to an establish connection or related to one can pass
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# packets that are out-of-sequence are silently dropped
-A INPUT -m state --state INVALID -j DROP
# new connections unknown to the kernel are handled in a separate chain
-A INPUT -m state --state NEW -j in-new

# pass SYN packets for SSH
-A in-new -p tcp -m tcp --dport 22 --syn -j ACCEPT

# log everything else
-A INPUT -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[INPUT6]: "

### OUTPUT chain

# RT0 processing is disabled since 2.6.20.9
#-A OUTPUT -m rt --rt-type 0 -j REJECT

# allow outgoing traffic, explicitly (despite chain policy)
-A OUTPUT -j ACCEPT

### FORWARD chain

# RT0 processing is disabled since 2.6.20.9
#-A FORWARD -m rt --rt-type 0 -j REJECT

# disallow forwarded traffic, explicitly (despite chain policy)
-A FORWARD -j REJECT

COMMIT

Note that this recipe is pretty much unusable on pre-2.6.20 kernels due to their broken implementation of stateful connection tracking.

The ruleset should be fairly obvious, but you might wonder about my use of REJECT and allowing all ICMP — after all, you’ve heard for the past 30 years that ICMP is a “bad hacker protocol”, and Internet security is no domain for being nice to people, so to prevent any information disclosure, you should DROP connections, not let people know that they’re simply not allowed.

Well, to hell with all that! I don’t see a single reason or attack vector that is foiled by DROP or disallowing ICMP. In fact, it’s just security by obscurity, and might inconvenient at the same time. ICMP is also much more important with IPv6 than with IPv4 (it replaces ARP, for instance), and it’s actually useful to be able to ping hosts, or get back informational messages on why something failed. Finally, rejecting traffic rather than dropping it doesn’t suggest to a hacker that something’s hidden here.

Then there is RFC 4890, which almost made me puke. This document is part of the reason why I say: let’s fix problems in the kernel, rather than shielding them with unreadable and unmanageable rulesets!

Setting system parameters

The /proc/sys/net/ipv6 filesystem exports a number of parameters that you might want to set. The Linux IPv6 HOWTO explains all available parameters, so let me just show you the ones I set in /etc/sysctl.conf and load with a call to sysctl:

net.ipv6.conf.default.autoconf = 0
net.ipv6.conf.default.accept_ra = 0
net.ipv6.conf.default.accept_ra_defrtr = 0
net.ipv6.conf.default.accept_ra_pinfo = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv6.conf.default.forwarding = 0
net.ipv6.conf.all.autoconf = 0
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.all.accept_ra_defrtr = 0
net.ipv6.conf.all.accept_ra_pinfo = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.all.forwarding = 0

Obviously, for gateways, you want to enable forwarding, and on machines where you want to use autoconfiguration, those accept_ra* entries ought to be 1 accordingly.

If you’re curious, the default values (the first seven lines) set the defaults for new interfaces, while the all values override the values for all interfaces. I am not sure whether this is a permanent overwrite, or just overwrites all existing interfaces, which is why I simply set the parameters for both.

Getting connected

If you already have an IPv6 address, you’re basically ready to go, but may want to read further down on how to connect your local network to the IPv6 Internet as well. If you are searching for a provider, have a look at the list of providers with native IPv6 connectivity over at sixxs.net.

If you are reading up to here, I assume you are connected to the ‘Net with IPv4. There are two ways for you to move towards IPv6: 6to4 or by way of a tunnel provider. A Kiwi website explains how to setting up 6to4 connectivity, and thus I will concentrate only on the tunnel approach. Even though everyone can set up 6to4 in a breeze without any accounts or waiting, there are a number of security considerations, it’s pretty ugly to debug (due in part to asymmetric routing), and makes your life unnecessarily difficult when all you have is a dynamic IP that changes from time to time. If you are stuck behind a NAT gateway, you cannot use 6to4 either. Thus, I prefer the tunnel approach.

With the tunnel approach, IPv6 packets are wrapped up in IPv4 packets on your host, and sent to the IPv4 address of your tunnel provider, who has native IPv6 connectivity. The tunnel provider unwraps your packet and shoves the contained IPv6 packet onto the backbone. The IPv6 address you used as source address is routed to the tunnel provider, so any replies arrive at their machines, where they’re again wrapped into IPv4 packets and sent to your (publicly-accessible) IPv4 address. Those IPv4 packets specify payload type 41 (“ipv6”), which is why we need those -p ipv6 -j ACCEPT rules in the iptables ruleset.

There are a few tunnel providers out there. I chose SixXS and have not regretted my choice. I shall thus assume that you do the same: sign up for an account right now, so that you have it by the time you finished reading this document! SixXS works on a credit system: tunnels and subnets cost credits, which you can accumulate by maintaining your tunnels properly. This ensures that everyone can play around, but to do more advanced stuff, you need to first display competence with the basic concepts.

Tunnel types

Your first step with SixXS will be to request a tunnel. SixXS offers three types of tunnels:

Each of these tunnels have advantages and disadvantages, as everything does: the first two types of tunnels use IP protocol 41 packets to encapsulate the IPv6 packets. As such, there are security considerations involving the impersonation by spoofing, and all upstream firewalls must let protocol 41 pass. AYIYA addresses these problems by using signed packets, but that solution comes with extra computation overhead and smaller MTUs.

I suggest to use the first type of tunnel that fits your situation. Debian’s aiccu package can take care of heartbeat and AYIYA tunnels for you, and it can even set up static ones.

During registration, you will also need to choose a “PoP”, which stands for “Point of Presence”. If your country only has a single PoP, that’s the one you will end up using (unless you have a good reason for another one), but if there are more options, I strongly suggest that you go through the list of PoPs and select the one with the best roundtrip time and lowest latency from your location! Note that you must answer ping requests (ICMP echo-request) from the PoP you chose, or else the tunnel will not be created.

Other tunnel brokers include HE, which give you up to four tunnels and subnets within minutes, but they only support proto-41 tunnels (“static tunnels”), which do not work everywhere.

Setting up the tunnel

Once your tunnel request gets approved, you’ll get a /64 prefix, in which you only use two addresses: the PoP will configure the :1 address and you need to configure your host to use the :2 address on the tunnel interface. You’ll also be told the IPv4 address of your PoP “endpoint”.

Joey Hess taught me that aiccu can set up the interface for you, using the data it queries from the SixXS registration (TIC) server. I tried it, and it works. However, I prefer the pure ifupdown approach, as it makes things explicit and allows me to use the hooks for stuff like loading the packet filter. So in my /etc/network/interfaces, you can find:

auto sixxs
iface sixxs inet6 v4tunnel
  endpoint 194.1.163.40
  address 2001:41e0:ff00:3b::2
  netmask 64
  gateway 2001:41e0:ff00:3b::1
  ttl 64
  pre-up ip6tables-restore < /etc/network/ip6tables
  up ip link set mtu 1480 dev $IFACE
  up invoke-rc.d aiccu start
  down invoke-rc.d aiccu stop

Make sure to read about MTU values of the tunnel and adjust the 1480 value in the above to your tunnel settings and ISP connectivity.

The last two lines are only needed for heartbeat tunnels and assume that you have configured aiccu appropriately.

Also, when using /etc/network/interfaces, make sure to set noconfigure true in /etc/aiccu.conf, or else aiccu will bring up a duplicate/additional interface. If your version of aiccu does not honour this configuration option, you can set ipv6_interface sixxs instead: if you tell it to configure the same interface as specified in /etc/network/interfaces, it will actually execute all the same commands (which will fail), but won’t report any errors.

For AYIYA tunnels, the following can be used, if you prefer to be able to bring up the interface with the usual ifup command, rather than having it appear when the daemon starts.

auto sixxs
iface sixxs inet manual
  pre-up invoke-rc.d aiccu start
  up sleep 1
  up ip link set mtu 1480 dev $IFACE
  post-down invoke-rc.d aiccu stop

It is also a good idea to prevent aiccu from starting at boot when using this method:

update-rc.d -f aiccu remove
update-rc.d aiccu stop 0 0 1 6 .

Allowing proto-41 traffic

Unfortunately, these methods are likely to fail, because your regular IP packet filter (iptables, without the 6) doesn’t let those encapsulating IPv4 packets pass, unless you tell it to; you probably want to do this early on in the chain, and also limit it to the tunnel peer, so in my case, I use the following rule:

iptables -I INPUT -p ipv6 -s 194.1.163.40/32 -j ACCEPT

For AYIYA, you need to open port 5072, either for UDP, TCP, or SCTP, depending on how you configured it. Also have a look at this FAQ entry on what a firewall needs to pass. If it still doesn’t work, you have an upstream packet filter that needs some of those holes poked. Good luck.

In most situations, the FORWARD chain does not get such a rule, since the tunnel terminates at the gateway, which routes to a native IPv6 network, or another tunnel. Allowing tunnels through a gateway is almost always a bad thing, as it would allow undetected and untraceable traffic from compromised boxes in the local network. The OUTPUT chain also does not need such a rule, if you have configured stateful filtering properly.

Now bring up the interface and verify the connection:

# ifup sixxs
# ping6 -nc1 2001:41e0:ff00:3b::1
PING 2001:41e0:ff00:3b::1(2001:41e0:ff00:3b::1) 56 data bytes
64 bytes from 2001:41e0:ff00:3b::1: icmp_seq=1 ttl=64 time=74.0 ms
[...]
# ping6 -nc1 ipv6.aerasec.de
PING ipv6.aerasec.de(2001:a60:9002:1::184:1) 56 data bytes
64 bytes from 2001:a60:9002:1::184:1: icmp_seq=1 ttl=55 time=91.5 ms
[...]

Welcome to the Internet of the future!

Setting up an IPv6-capable gateway

Your IPv6 connection works, but it’s limited to a single address, and you do not get to specify the reverse DNS PTR record for it. Since the concept of NAT is mostly absent from IPv6 (thanks! thanks! thanks!), you will not be able to connect any other hosts to the IPv6 network. If your local network has a few hosts behind a gateway, you will need to request a subnet from SixXS and configure your gateway (which has the tunnel connection) appropriately. Don’t worry, this is not really very difficult.

First, request a subnet for your tunnel from your PoP via your SixXS homepage. Once approved, you will get a /48 prefix for your own use: 2^80 — 1.2 heptillion addresses which are yours to assign to every dust particle in your office or home, if you so desire.

The way I set it up is to add the first of these addresses to your internal interface on the gateway, by adding the following two lines to the interface’s stanza in /etc/network/interfaces; you will need the iproute package installed (which you should be using for everything network-related anyway):

up ip -6 addr add 2001:41e0:ff12::1/64 dev $IFACE
down ip -6 addr del 2001:41e0:ff12::1/64 dev $IFACE

Instead of bringing the interface down and up, just run ip -6 addr add 2001:41e0:ff12::1/64 dev eth0. Note the use of the /64 prefix instead of the /48 that got assigned, leaving only 20 pentillion addresses. Oh no! The reason for this is buried in the specs: basically, /48 is a site prefix, but individual networks should not be larger than /64, which is the prefix length of links in the IPv6 domain.

The /64 prefix is only one of 65536 different /64 prefixes you can use from your /48 prefix. Since it’s unlikely that you’ll use them all, it’s a good idea to route unused ones to an unreachable destination, such as the loopback interface, which conveniently causes packets to any addresses outside the used /64 networks to be answered with ICMP destination network unreachable. You could route them to the special unreachable target instead, which would cause host unreachable messages, but the following is more explicit:

up ip -6 route add 2001:41e0:ff12::/48 dev lo
down ip -6 route del 2001:41e0:ff12::/48 dev lo

Enabling forwarding

Now is also a good time to enable IPv6 forwarding, e.g. like so:

# echo net.ipv6.conf.all.forwarding = 1 >> /etc/sysctl.conf
# sysctl

Obviously, you will also need to change the policy on the ip6tables FORWARD chain. For now, let’s just set it to accept all traffic between the local network behind eth0 and the Internet behind eth1. You should later create a proper ruleset, though!

# ip6tables -I FORWARD -i eth0 -o eth1 -s 2001:41e0:ff12::/64 -j ACCEPT
# ip6tables -I FORWARD -i eth1 -o eth0 -d 2001:41e0:ff12::/64 -j ACCEPT

Advertising addresses on your local network

The final step is to spread the love to your local network. Refrain from selecting addresses from your subnet and assigning them to the local hosts, or wondering how to configure the DHCP server, because IPv6 does it differently: your gateway will advertise its routes (which includes a default route) to your network, and each host will pick an address based on its MAC address (unless it already has an EUI-64 address assigned. This all happens automagically, at least with current Debian and Windows machines.

On the gateway, you need to install radvd and simply tell it which prefix to use on which interface. My /etc/radvd.conf looks like this, and I won’t explain it:

interface eth0
{
  AdvSendAdvert on;
  prefix 2001:41e0:ff12::/64
  {
  };
};

Note again how we advertise a /64 network rather than the /48 we “own”. You cannot advertise smaller networks if you want automatic configuration to work, and you should not use networks larger than /64 in any case. If 2^64 addresses are not enough for you, I trust you’ll be able to figure out how to advertise another of your 65536 /64 prefixes in the /48 subnet to appropriate hosts.

Restart radvd and run over to another host to witness how it automagically gets connected to the IPv6 network by scanning /var/log/kern.log and watching the output of ip -6 addr and ip -6 route. Try ping6ing from there! Find the dancing turtle! It should all work.

If you don’t like the automagic aspect of this, look into stateful configuration, using DHCPv6, as provided by dibbler-server and wide-dhcpv6-server.

Choosing source addresses

Even though you have obtained a /48 network and configured the gateway appropriately, connections originating from the gateway itself will have the tunnel endpoint IP as source address. This is because Linux picks the address of the outgoing interface when it sends packets, and we only slapped the address from our own subnet onto the LAN interface. However, if the firewall answers to 2001:41e0:ff12::1, it ought to use that address for sending, too.

Unfortunately, there’s no guaranteed way to achieve this, due to RFC 3484, which is explained nicely on this page.

The best solution is to add 2001:41e0:ff12::1/128 as last address to the external interface, which will cause Linux to use it in most cases. When it doesn’t, you ought to just ignore it:

iface sixxs inet6 v4tunnel
  […]
  up ip -6 addr add 2001:41e0:ff12::1/128 dev $IFACE
  down ip -6 addr del 2001:41e0:ff12::1/128 dev $IFACE

Here is a thread on the issue on the SixXS forum.

Resolving names

Take note of the IPv6 address of each host. There’s a way to determine it given the host’s MAC address, but this is easier (ipv6calc is also useful). You might want to let your local DNS server know by adding AAAA records in parallel to the existing A records, and possibly even adding PTR entries.

If you’re serious about IPv6, you can tell SixXS to delegate reverse lookups for the IPv6 addresses to your DNS servers, but you ought to refrain from polluting the DNS namespace. The dig tool and its +trace option are awesome to debug and analyse reverse delegations:

dig +trace -x 2001:41e0:ff12::1

Note that bind9-host provides an improved host tool, which fetches all kinds of information about names, not just the one single information configured as default:

% host pulse.madduck.net
pulse.madduck.net has address 130.60.75.74
pulse.madduck.net has IPv6 address 2001:41e0:ff1a::1
pulse.madduck.net mail is handled by 99 b.mx.madduck.net.
pulse.madduck.net mail is handled by 10 a.mx.madduck.net.

% host 2001:41e0:ff1a::1
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.a.1.f.f.0.e.1.4.1.0.0.2.ip6.arpa
domain name pointer pulse.madduck.net.

Oh, and if you’re really that curious about how IPv6 addresses are computed from MAC addresses, read RFC 2464. Basically, given a prefix 2001:41e0:ff1a:: and a MAC address aa:bb:cc:dd:ee:ff, the resulting IPv6 address is obtained by:

  1. inserting ff:fe into the middle of the MAC address to yield aa:bb:cc:ff:fe:dd:ee:ff;
  2. removing the odd colons to yield aabb:ccff:fedd:eeff, the EUI-64;
  3. flipping the second lowest bit of the first octet to yield a8bb:ccff:fedd:eeff; this marks the EUI-64 globally unique.
  4. concatenating the prefix and this result to get 2001:41e0:ff1a::a8bb:ccff:fedd:eeff.

Other (easier) ways to determine the local component of an IPv6 address are:

If you find your (Windows) IPv6 addresses changing all the time, you might be faced by “privacy features”.

Remaining issues

Even though my IPv6 connectivity works, I have two remaining issues.

Sending larger amounts of data to the network

I am experiencing a curious issue where outgoing ssh IPv6 connections time out and outgoing data transfers hiccup. I have yet to find out what’s going on, but it’s most likely an MTU problem.

Mapping names to laptops

Laptops generally have two interfaces, one with a cable, and the other wireless. Both of these interfaces will have separate MAC addresses, and by extension, the laptop will have different IPv6 addresses depending on how it is connected to the local network.

I want to be able to connect to laptops without knowing the medium they use to connect to the network. Unfortunately, there seems to be no feasible way. The solutions I see are:

The second solution works for me for now, but I am interested in the third.

In response to this document, Andreas Henriksson has suggested the replace the stateless configuration (radvd) with stateful configuration, using DHCPv6. I have yet to investigate this option.

Jeroen Massar suggests to unite cable and wireless into a bridged interface, which seems like a very good idea.

Kernel versions and stateful connection tracking

Even though the default kernel of Debian etch, our current stable release, speaks IPv6, I cannot recommend it for deployment, as the 2.6.18 kernel does not support proper stateful connection tracking for IPv6, and thus makes it impossible to firewall hosts in a sensible manner (I always add local packet filters to all my hosts, and if only to guard against the situation when a user installs a malicious programme to listen on a high port). Of course, it is possible to configure a packet filter statelessly in an acceptable manner once you know the use case, so do with this information what you wish; I prefer to stay general for now.

A remedy exists, however: Debian “etch” 4.0r4 adds the so-called etch-and-a-half kernels, e.g. linux-image-2.6.24-etchnhalf.1-686. The 2.6.24 kernel seems to support stateful connection tracking for IPv6. Alternatively, you could use the 2.6.24 linux kernel packages on backports.org.

Xen and IPv6

One drawback of switching to 2.6.24 is that you cannot run a dom0 on that machine any longer, so by practical extension, you cannot connect it to the IPv6 network with a packet filter in place. Supposedly, running 2.6.24 instances on a 2.6.18 dom0 is reported to work, however.

Credits

Thanks to Bernhard Schmidt, William Boughton, and Jeroen Massar, and everyone on #ipv6/irc.freenode.org for their help over the past few weeks, and all those who fed back comments in response to this document!

Posted Thu 19 Jun 2008 19:24:39 CEST Tags: ?documentation ?howto ?ipv6 ?networking
Setting up an encrypted Debian system

Even though the Debian installer can set up encrypted partitions, it is optimised for systems with a single data partition, unless you want to enter multiple passphrases when the system boots. The installer configures a LUKS volume using cryptsetup, but it provides no mechanism for the use of key files, only interactive passphrases.

I like partitioning my disks and use different filesystems for /tmp, /home, /var, and /usr/local for a number of reasons. I don’t like entering more passphrases than necessary. If you can identify with that, the following is for you.

Several people have pointed out to me that one can simply create a single encrypted “physical volume” with the Debian installer and place “logical volumes” for the various filesystems in there. You still need a separate /boot partition, in any case. Kapil Hari Paranjape has described the approach, as well as Simon McVittie.

This method is much cleaner and to be preferred. It’s quite likely that it also improves the speed since only a single kcryptd process takes care of all of the decryption and encryption needs.

Nevertheless, the following is still useful with that approach, although it’ll be less complicated.

Installing the system

The first step to setting up an encrypted Debian system is to perform a normal Debian system installation. When you are asked to partition your harddrive and create filesystems, set up all partitions as encrypted volumes (I suggest to go with the installer defaults and use dm-crypt and AES with the default settings, simply because I have no reason to doubt the installer dveeloper team’s choices). Make sure to erase the disks in the process — the installer has an option for that.

Set up the swap partition as an encrypted volume too, but don’t worry too much about the settings at this point; we will recreate the swap partition later.

Unless you want to boot off an external medium, such as a USB stick, you will need to create an unencrypted partition for /boot. I will return to this topic, which has security implications, further down.

The installer will ask you for passphrases for each of the volumes you create. I suggest you pick a secure passphrase for the root volume (/), but simple passphrases for all the other ones (such as “a”), since we will reconfigure them to use key files instead.

Using key files

A key file is like a passphrase stored in a file on disk; as opposed to “what you know”, it’s a “what you have” security asset. Thus, you need to store the file somewhere. When I boot up my system, I unlock the root partition with a passphrase entered interactively, which makes the root filesystem available. I store key files for all other volumes in /etc/keys. Obviously, I need to tell cryptsetup to use those.

The first step is to create a key file for each partition and to add it as a decryption key to the LUKS volume. You can do all of the following without unmounting the filesystems. See the following example for hda6, which will prompt for the simple passphrase we entered above to unlock the key ring when adding the key file:

umask 077
mkdir /etc/keys
dd if=/dev/urandom of=/etc/keys/hda6.luks bs=4k count=1
cryptsetup luksAddKey /dev/hda6 /etc/keys/hda6.luks
cryptsetup luksKillSlot /dev/hda6 0 --key-file /etc/keys/hda6.luks

The last command wipes the simple passphrase from the key ring and thus makes it unusable.

Now we need to tell cryptsetup to use the key file by editing /etc/crypttab and ensuring a line such as the following exists:

hda6_crypt /dev/hda6 /etc/keys/hda6.luks luks

This tells cryptsetup to create the cryptographic volume hda6_crypt from the base device /dev/hda6, using the key file we created above, and letting it know that it’s dealing with a LUKS volume.

Repeat this for every partition except your root and swap partitions.

Encrypting the swap partition

If you are using an encrypted Debian system, you likely have some security requirements to meet. If that’s the case, you must also use an encrypted swap partition.

The swap partition can be encrypted in two ways:

If you want to use suspend-to-disk, you cannot use the first approach as it would overwrite your memory footprint stored in the swap partition. Furthermore, you cannot use a key file like the other partitions, since the root filesystem is not (and must not) be mounted by the time the resume process starts and needs to read the decrypted swap partition.

The way I solved this is by telling cryptsetup to compute the passphrase of the swap partition from the decryption key of the volume holding the root filesystem; the cryptsetup package implements this with /lib/cryptsetup/scripts/decrypt_derived. Thus, to set up the swap partition, I do the following, assuming hda2 is the partition holding the encrypted swap and the root filesystem is in hda5_crypt:

swapoff /dev/mapper/hda2_crypt
cryptsetup luksClose hda2_crypt
dd if=/dev/urandom of=/dev/hda2
/lib/cryptsetup/scripts/decrypt_derived hda5_crypt \
  | cryptsetup luksFormat /dev/hda2 --key-file -
/lib/cryptsetup/scripts/decrypt_derived hda5_crypt \
  | cryptsetup luksOpen /dev/hda2 hda2_crypt --key-file -
mkswap /dev/mapper/hda2_crypt

To tell the system about this swap partition, we need to add it to /etc/crypttab and /etc/fstab; make sure, those files contain lines like the following:

/etc/crypttab:
  hda2_crypt /dev/hda2 hda5_crypt luks,keyscript=/lib/cryptsetup/scripts/decrypt_derived

/etc/fstab:
  /dev/mapper/hda2_crypt swap swap sw 0 0

With this in place, as soon as you configure the system for suspend-to-disk, the swap partition will be automatically set up alongside the root filesystem very early during the boot sequence. To figure out which swap partition to make available at that point, cryptsetup checks the following:

You can inspect /usr/share/initramfs-tools/hooks/cryptroot if you want to know more about this.

Using UUIDs

Even though the above is all you have to do, you might want to consider replacing the device paths in /etc/crypttab with persistent ones. One motivation might be the ability to boot off your drive via a USB adapter, which might cause it to appear as /dev/sda instead of /dev/hda.

udev is installed by default on Debian systems and it makes persistent links to partitions available under /dev/disk/by-uuid, using the UUID of the content structure (e.g. the LUKS header). It uses /lib/udev/vol_id to determine those link names.

If you replace the entries in /etc/crypttab, make sure to update the initramfs (update-initramfs -u -k all) and consider to use the same approach for the /boot filesystem in /etc/fstab; you’ll note that all other filesystems use persistent device paths thanks to the dm-crypt layer.

If you ever end up booting off the disk through a USB adapter, you might face the problem where the usb_storage subsystem takes too long to activate, so that the cryptsetup script does not find the devices in time. You can either solve this by adding the rootdelay=x parameter or break=mount to the kernel command line. The first will cause the scripts to wait x seconds before trying to configure and mount the root filesystem; the second would give you a shell that you can exit as soon as the kernel spouted its device initialisation messages at you.

If you got this far, you might even want to take it further and replace hda5_crypt with cr_root or the like to abstract those silly partition numbers away even further. This is easier than it sounds, but does require several steps. Do not do this if you’re not comfortable reviving your system in case it fails to come back up!

  1. replace the old names with the new names in /etc/crypttab for all volumes except the root volume. If you are using a derived passphrase for the swap partition, make sure to put the new name for the root volume into the third column of the swap partition’s configuration line.
  2. modify /etc/fstab accordingly, leave the root filesystem’s device path alone.
  3. call update-initramfs -u
  4. modify your bootloader to ask the kernel to boot off the new root volume.
  5. replace the root volume’s old name with the new one in /etc/fstab.
  6. reboot, and add break=mount to the kernel command line.
  7. at the busybox prompt, edit (vi) /conf/conf.d/cryptroot and change the first field of the root volume’s line to the new name.
  8. exit the shell and watch the boot process complete.
  9. finally, replace the root volume’s old name with the new one in /etc/crypttab.

If the system fails to boot up again, you can use the backup initial ramdisk, which update-initramfs left in /boot.

Security implications

Apart from the usual security implications related to cryptosystems, passphrases, mathematics, user stupidity, and so on, the approach I outlined will leave you with a pretty well-secured system. Obviously, you should make sure to lock your screen whenever you leave the system unattended or the entire encryption is basically useless.

There are two attack vectors on your system, both involving physical access to the machine:

Other than that, you should be careful when travelling to totalitarian countries, like the Excited States of America, China, and probably the UK. First off, encryption arouses suspicion, and second, border agents might ask you to decrypt the partitions for them to copy or scan, and refusal to do so might get your turned away at the border. When travelling to those countries, make sure to hide your data properly.

Speed implications

Obviously, having your entire system encrypted (including swap) will slow it down. I don’t have any quantitative information on that, but after several years of using full-disk encryption on my laptop (an X40, which isn’t very powerful), I can say that it remains usable, if you don’t rely on disk-intensive operations, such as compiling kernels and the like.

Alternative approaches

Several alternative approaches exist, all involving an additional device:

I have chosen neither of these approaches, because the extra security does not make up for the inconvenience, and the danger of an unbootable system in case of loss of forgetting of the additional device.

Posted Mon 16 Jun 2008 11:43:40 CEST Tags: ?cryptsetup ?dm-crypt ?documentation ?encryption ?howto ?privacy ?s2disk ?security
RRR Interview on Debian and cross-distro collaboration

During LCA2008, Ed Borland of Melbourne-based Triple R FM Byte Into It show took me aside for an interview and asked some good questions about Debian and my work on cross-distro collaboration. The interview was recorded and is now available as Ogg Vorbis file from the 14 May 2008 issue of Byte Into It.

I am looking forward to any feedback.

Thanks to Ed and Phil Wales for their time and help.

NP: Mono: You Are There

Posted Tue 20 May 2008 18:31:28 CEST Tags: ?cross-distro ?interview
vcs-pkg work session in Extremadura, 2nd try

We were given another chance to meet in Extremadura to discuss vcs-pkg issues, after the first opportunity was too short notice.

Currently, the tentatively scheduled dates are 2-7 September 2008. You can get the details from the wiki page. If you’re interested, please reserve those dates and add yourself to the list of participants.

NP: Hooverphonic: The Magnificent Tree

Posted Sun 18 May 2008 15:16:57 CEST Tags: ?extremadura ?vcs
netconf and the GSoC

I am very excited to announce that Jonathan Roes has successfully applied to the Google Summer of Code 2008 and will be working on netconf over this summer. With his help, I am confident that netconf 1.0 in Debian “lenny” is no longer a dream.

Jonathan is a soon-to-be computer science graduate from the University of North Carolina at Charlotte, and his application was (by far) the most convincing of the ten I received. He has several years of programming and Linux experience and it’s quite obvious that he has understood the philosophy of netconf.

I am looking forward to working with Jonathan!

NP: Underworld: Second Toughest of the Infants

Posted Tue 22 Apr 2008 14:24:00 CEST Tags: ?gsoc ?gsoc2008 ?netconf
vcs-pkg meeting in Extremadura?

If you are interested in using version control for distro packaging, you

If you read the mailing list, you know about the upcoming Extremadura meeting 2-6 April 2008.

If this is news to you, well, it isn’t anymore.

If you think you should be in Extremadura when this party takes place, don’t hesitate and reply. The message ID is 20080311193428.GA25745@piper.oerlikon.madduck.net.

Update: mostly due to the short notice, I had to call off the meeting. I will make a run for the next slot and hopefully announce it a lot earlier.

Posted Wed 12 Mar 2008 00:27:57 CET Tags: ?extremadura ?vcs
Asterisk on Debian: piece of cake!

Yesterday, my phone had a temporary fit, yet I had a bunch of important calls left to make. Since I have an account with a VoIP provider and a Swiss number associated with it, I decided to use it as a fallback. That worked.

The next thing I found out was that a meeting had been cancelled, and since I was in a VoIP-related mindset anyway, I did what I’ve been meaning to do for years: check out Asterisk.

An excellent article by Stefan Wintermeyer in the 01/2008 issue of the German Linux Magazin helped me understand the basics of the Asterisk configuration paradigms in a single read.

With 40 minutes left, I installed the Debian Asterisk packages on a test machine and by the time of my next meeting, I had the server register with two VoIP providers (one of them being the university) and routed outgoing calls accordingly: calls to university numbers went there, all others would be routed via Insphone. I also hooked up three softphones and routed incoming calls to them.

I shall post my configuration once I spent a little more time with it, configured e.g. voice mail and a simple voice- or DMTF-activated menu system to distinguish work from private calls, and cleaned it up. If you care before then, ask.

Asterisk is said to have a steep learning curve. Thanks to the article and the excellent work by the Debian maintainers, I climbed that curve to the point where I can make and receive phone calls in about an hour.

Thanks!

NP: Age Pryor: Shanks’ Pony

Posted Wed 27 Feb 2008 16:27:24 CET Tags: ?asterisk ?kudos ?voip
Consolidating packaging workflows across distros

I speculate that most of what we do for Debian squares with what others do for their respective distro. Thus, it should be possible to identify a conceptual workflow applicable to all distros, consolidate individual workflows on a per-package basis, and profit from each other. Jonathan let me have the after-afternoon-coffee slot of the Distro Summit for an impromptu discussion on the various workflows used by distros for packaging.

The discussion round was very short-notice and despite the announcement sent to the conference mailing list, only ten people showed up: two people familiar with Fedora, and (“versus”) eight Debianites.

Regardless, I think the discussion was success- and fruitful. We were able to identify a one-to-one mapping between the Fedora and Debian workflows, even though we use different techniques:

Many Debian package maintainers use version control systems to maintain the ./debian directory, and if patch files are stored in ./debian/patches/, then Debian and Fedora both store patch files in a version control repository, which seems awful.

Just as I am only one of many who are experimenting with VCS-based workflows for Debian packaging, the Fedora people are also considering the use of version control for packaging. Unlike Fedora, who seem to try to standardise on bzr, I try to cater for the plethora of version control systems in use in Debian, anticipating the impossibility of standardising/converging on a single tool across the entire project.

Update: Toshio Kuratomi wrote in to tell that Fedora has not settled on bzr: “the things that have been tried have spanned most of the current major vcs’s (darcs being the one exception due to it’s not meeting our requirements for keeping history intact.)”

It seems that our two projects are both at the start of a new phase in packaging, a “paradigm shift”. What better time could there be for us to listen to each other and come up with a workflow that works for both projects?

My suggestion currently centres around a common repository for each package across all (participating) distros, and feature branches. Specifically, given an upstream source tree, modifications made during packaging for a given distro fall into four categories:

Given a version control system with sufficient branching support, I imagine having different namespaces for branches: upstream-patches/*, distro/*, rpm/* or debian/*. Now, when building the Debian package, I’d apply upstream-patches/*, distro/*, deb/* and debian/* in order, while my colleague from the Fedora project would apply upstream-patches/*, distro/*, rpm/* and fedora/*, before calling the build tools and uploading the package.

There are surely problems to be overcome. Pascal Hakim mentioned patch dependencies, and I can’t necessarily say with a clear conscience that my workflow isn’t too complicated to be unleashed into the public… yet. But if we find a conceptual workflow applicable to more than one distro, it should be possible to implement a higher-level tool to implement it.

Also, the above is basically patch maintenance, not the entire workflow. Bug tracking system integration is going to play a role, as well as other aspects of daily distro packaging. I’ll leave those for future time.

For me, this is the start of a potentially fruitful cooperation and I hope that interested parties from other distros jump on. For now, I suggest my mailing list for discussion. You can also find some links on the Debian wiki.

Posted Tue 29 Jan 2008 07:30:14 CET Tags: ?fedora ?vcs ?workflow