{"id":1102,"date":"2013-10-19T22:30:01","date_gmt":"2013-10-19T20:30:01","guid":{"rendered":"https:\/\/brakkee.org\/site\/?p=1102"},"modified":"2013-10-19T22:30:01","modified_gmt":"2013-10-19T20:30:01","slug":"encrypting-an-existing-centos-install","status":"publish","type":"post","link":"https:\/\/brakkee.org\/site\/2013\/10\/19\/encrypting-an-existing-centos-install\/","title":{"rendered":"Encrypting an existing Centos install"},"content":{"rendered":"<p>Edit: Meanwhile I have found a better way to migrate an existing centos unencrypted install to a fully encrypted install with \/boot as the only unencrypted disk space. This solution is much preferred over the one described in this post. The new approach is <a href=\"https:\/\/brakkee.org\/site\/2013\/10\/19\/encrypting-an-existing-centos-install\/\">here<\/a>.<\/p>\n<p>Inspired by yet another incident in the news of a laptop with sensitive information getting stolen, you start imagining what would happen if someone would get hold of your laptop. How much sensitive data would be on it and what would the consequences be. A small investigation revealed that the consequences could be quite big. There are various personal document stored, version control systems and IDEs with insecure password storage and of course various browser history files and cookies. That made me a bit nervous.<\/p>\n<p>Therefore, I set out the investigate how to make this laptop more secure. The setup is an extension of setups I found on the internet where typically LUKS over LVM or LVM over LUKS is used. The current setup will in effect be LVM over LUKS over LVM.<br \/>\n<!--more--><br \/>\nFrom the looks of it there is no personal data on the root file system (as it should because the user has all its files under \/home). Therefore encrypting the home and data partitions would be sufficient. That at least would save me from a lot of hassle trying to have an encrypted root volume.<\/p>\n<p>The laptop is running centos 6.4 and uses a typical logical volume setup. There is a physical disk (<code>\/dev\/sda<\/code>) with a <code>\/boot<\/code> partition on a physical disk partition and the other partitions are added to a volume group from which home and data volumes are allocated. This setup is shown below.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/brakkee.org\/site\/wp-content\/uploads\/2013\/10\/cryptlvm1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-1106 aligncenter\" alt=\"cryptlvm1\" src=\"https:\/\/brakkee.org\/site\/wp-content\/uploads\/2013\/10\/cryptlvm1-300x100.png\" width=\"300\" height=\"100\" \/><\/a><\/p>\n<p>The idea is to use <a href=\"http:\/\/code.google.com\/p\/cryptsetup\/\">LUKS<\/a>\u00a0for encryption and to use a single logical volume called encrypted \u00a0instead of home and data. Then using LUKS, a decrypted block device (called estorage) is created that provides encryption and decryption of data on the fly to\/from the encrypted logical volume. Then in the next step, this estorage block device is used as a physical volume of a new volume group vg_estorage. Then from the vg_estorage volume group, the home and data logical volumes can be created as before.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/brakkee.org\/site\/wp-content\/uploads\/2013\/10\/cryptlvm2.png\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1107 aligncenter\" alt=\"cryptlvm2\" src=\"https:\/\/brakkee.org\/site\/wp-content\/uploads\/2013\/10\/cryptlvm2-300x207.png\" width=\"300\" height=\"207\" \/><\/a><\/p>\n<p>This is a very interesting setup that shows the power of the device mapper on linux. Both Logical Volume Management and encryption make use of this device mapper. Basically, the device mapper allows block devices to be combined in various ways. For instance, in design pattern terminology, logical volume management is more or less a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Composite_pattern\">composite design pattern<\/a> where multiple block devices are combined into a big storage pool (volume group) from which individual logical block devices (logical volumes) are allocated. In the case of the disk encryption it is in effect an application of the <a href=\"http:\/\/nl.wikipedia.org\/wiki\/Decorator\">decorator design pattern<\/a>. Other powerful features in linux are the ability to treat a file as if it were a disk (using losetup) and the way to use a physical disk partition or logical volume as a disk (using kpartx).\u00a0 But I digress, below I will discuss how to get from the initial setup to the final setup while keeping a working system all the time.<\/p>\n<p><strong>Disk space<\/strong><\/p>\n<p>The first thing to consider is disk space. The migration will involve copying of data and you should at least have the amount of disk space free on the <code>vg_root<\/code> volume group for a copy of the biggest logical volume. So, if home has 10GB and data has 15GB, you should make sure you have 15GB free on vg_estorage. If this is not possible, then the safest option is to go to runlevel 1 (init 1) and copy the data on the involved logical volumes to a separate disk. It is also possible to extend the volume group vg_root with storage on an external disk but you should be very careful there since then your system will not startup without the external disk and there are some additional steps involved in moving data from the external disk back to the system (using the &#8216;dangerous&#8217; pvmove command).<\/p>\n<p><strong>Backups<\/strong><\/p>\n<p>If you are wise, create a backup of your entire disk first so you can always go back to a working system. I always boot up a linux rescue system, and then mount a filesystem on an external disk and backup all data using dd:<\/p>\n<pre>dd if=\/dev\/sda bs=32M | gzip -c &gt; sda.img.gz<\/pre>\n<p>Of course, replace <code>sda<\/code> by the physical disk name of your disk. The gzip is optional and makes the backup smaller but also much slower. While executing the process I also used the same procedure to create intermediate backups. It is also time for a <strong>disclaimer<\/strong> now. I have done my best to make these instructions as complete as possible but these executing these instructions is at your own risk.<\/p>\n<p><strong>Creating encrypted storage<\/strong><\/p>\n<p>With disk space out of the way, a logical volume encrypted can be created using:<\/p>\n<pre>lvcreate -L&lt;size&gt;G -n encrypted \/dev\/vg_root<\/pre>\n<p>then setup encryption on the device:<\/p>\n<pre>cryptsetup --verbose --verify-passphrase luksFormat \/dev\/vg_root\/encrypted<\/pre>\n<p>This step asks for a password and uses default encryption options.<\/p>\n<p>Open the encrypted logical volume<\/p>\n<pre>cryptsetup luksOpen \/dev\/vg_root\/encrypted estorage<\/pre>\n<p>The above step asks for the password to decrypt the logical volume and creates a new device <code>\/dev\/mapper\/estorage<\/code> that provides the decrypted view of the data.<\/p>\n<p>Now, it is time to backup the LUKS header of the encrypted disk so in case of disk problems you might still be able to recover data.<\/p>\n<pre>cryptsetup luksHeaderBackup --header-backup-file header.estorage \/dev\/vg_root\/encrypted<\/pre>\n<p>Keep the backup file in a safe place. There is no security risk if someone else gets hold of this file. It is only used to attempt a restore when you \u00a0have a disk problem.<\/p>\n<p>Now add the following entry to <code>\/etc\/crypttab<\/code> to make sure the system will ask for a password after booting and make the decrypted device <code>\/dev\/mapper\/estorage<\/code> available:<\/p>\n<pre>estorage \/dev\/vg_root\/encrypted none<\/pre>\n<p>Now create the physical volume and volume group based on estorage<\/p>\n<pre>pvcreate \/dev\/mapper\/estorage\nvgcreate vg_estorage \/dev\/mapper\/estorage<\/pre>\n<p>Also, create a small logical volume for testing.<\/p>\n<pre>lvcreate -L 100m -n test vg_estorage<\/pre>\n<p>At this point it is good to attempt a reboot and to verify that the system still boots.<\/p>\n<p>After booting you can inspect the logical volumes and volume groups using the lvs and vgs commands. What you should notice there is that the volume group test is seen but that it is inactive. You can tell from the output of <code>lvs<\/code> since it will show <code>-wi------<\/code> without the <code>a<\/code> flag for active as in <code>-wi-a----<\/code>.<\/p>\n<p>What is happening here is that at boot, the system sets up the logical volumes from the <code>vg_root<\/code> volume and creates the decrypted device <code>estorage<\/code>. \u00a0The system then will see the volume group <code>vg_estorage<\/code> which is on the <code>estorage<\/code> device but will not have activated the logical volumes for it.<\/p>\n<p>Luckily there is a simple fix for this which is a feature (on Centos at least) to activate logical volumes at a later stage. This is done using the <code>netfs<\/code> service. First make sure the <code>netfs<\/code> service is enabled and if not enable it using<\/p>\n<pre>chkconfig netfs on<\/pre>\n<p>Then, to test the setup for the test logical volume, activate the <code>vg_estorage<\/code> volume group and create a file system on the test logical volume:<\/p>\n<pre>vgchange -ay # activates all logical volumes\nmkfs.ext4 \/dev\/vg_estorage\/test\nmkdir \/mnt\/tmp # create temporary mount point for checking<\/pre>\n<p>Now add an entry to the <code>\/etc\/fstab<\/code> file for test similar to other entries for for example \/home, but add one additional flag <code>_netdev<\/code>. The entry could like like this:<\/p>\n<pre>\/dev\/vg_estorage\/test \u00a0\/mnt\/tmp \u00a0ext4 \u00a0_netdev,noatime,acl,user_xattr 1 2<\/pre>\n<p>Then issue <code>mount -a<\/code> to verify that the test logical volume is mounted.<\/p>\n<p>Because of the special flag <code>_netdev<\/code>, the <code>netfs<\/code> service will activate logical volumes after the estorage device is made available but before the filesystems are mounted from <code>\/etc\/fstab<\/code>.<\/p>\n<p>It is time for another reboot now. This time you should see the test logical volume being mounted at <code>\/mnt\/tmp<\/code> after boot.<\/p>\n<p>This is the basic setup for LUKS which is in effect LVM over LUKS over LVM. If this works, then we can start copying data from the unencrypted logical volumes on vg_root to the encrypted storage on the vg_estorage volume group.<\/p>\n<p><strong>Copying data and resizing the vg_estorage volume group<\/strong><\/p>\n<p>I recommend to use the step by step method of extending the encrypted logical volume, copying a volume from <code>vg_root<\/code> to <code>vg_estorage<\/code>, testing (using a reboot), and then deleting the old logical volume on <code>vg_root<\/code>. In particular, the reboot is a good verification that everything still works. Only delete data if you are really sure that it works and make intermediate backups if you think it is needed. Also, use runlevel 1 in all following instructions.<\/p>\n<p>First check the disk space required:<\/p>\n<pre>lvs # find out the size of the logical volume you want to copy on vg_root\nvgs # find out the available free space on storage, and make sure it is enough<\/pre>\n<p>If there is not enough disk space, you can use disk space that was freed up by logical volumes that you copied earlier. To extend the vg_estorage volume group, proceed as follows:<\/p>\n<pre>lvremove \/dev\/vg_root\/&lt;oldlvname&gt; # remove an unused logical volume from vg_root\nlvextend -L +&lt;extra&gt;G \/dev\/vg_root\/encrypted # extend the logical volume for encrypted data\ncryptsetup resize estorage # inform the encryption of the change in size\npvresize \/dev\/mapper\/estorage # inform LVM on the vg_estorage volume group about the change<\/pre>\n<p>This is more or less a \u00a0Russian doll and shows why it is important to understand the layering. Resizing can be done without any down time and also at runlevel 3 and 5.<\/p>\n<p>Now that sufficient disk space is available there are two ways to copy. Either create a copy on the <code>vg_estorage<\/code> volume group with the same size and use dd to copy data like<\/p>\n<pre>dd if=\/dev\/vg_root\/&lt;lvname&gt; bs=32M of=\/dev\/vg_estorage\/&lt;lvname&gt;<\/pre>\n<p>or create a new logical volume with possibly different size and copy at file system level<\/p>\n<pre>mkfs.ext4 \/dev\/vg_estorage\/&lt;lvname&gt; # create filesystem\ntune2fs -m0 \/dev\/vg_estorage\/&lt;lvname&gt; # remove reserved blocks for non-root fs\nmount \/dev\/vg_estorage\/&lt;lvname&gt; \/mnt\/tmp # mount it\nrsync -av --delete \/path\/to\/old\/&lt;lvname&gt;\/mountpoint \/mnt\/tmp # copy data<\/pre>\n<p>With the second approach it is also possible to copy data while in a higher runlevel doing the expensive full data sync while still using the system and then in runlevel 1 repeat the <code>rsync<\/code> one more time to quickly make the copy completely identical.<\/p>\n<p>After copying, edit <code>\/etc\/fstab<\/code> to replace <code>\/dev\/vg_root\/&lt;lvname&gt;<\/code> by <code>\/dev\/vg_estorage\/&lt;lvname&gt;<\/code> and add the <code>_netdev<\/code> option. Reboot the system to verify that everything is still working.<\/p>\n<p><strong>Suspend\/resume<\/strong><\/p>\n<p>I found a small issue with suspend\/resume where the filesystems were not mounted again after suspending to RAM and resuming (I do not have suspend to disk configured).<\/p>\n<p>This issue was fixed by adding the following script \u00a0\/etc\/pm\/sleep.d\/99-cryptsetup-custom<\/p>\n<pre>#!\/bin\/bash\necho \"Custom hook called: $0 $*\"\n\nif [[ \"$1\" = \"resume\" ]]\nthen\n  df\n  echo \"$0: Remounting all devices from \/etc\/fstab...\"\n  \/etc\/init.d\/netfs start\n  df\nfi<\/pre>\n<p>Edit: it appears that this trick does not really work and I still lose some of the mounts when the system resumes.<\/p>\n<p><strong>\/tmp and swap<\/strong><\/p>\n<p>If \/tmp is located on your root logical volume then it is a good idea to encrypt that as well. Also, encrypting swap is a good idea because confidential data could leak there as well. See the <a href=\"http:\/\/wiki.centos.org\/HowTos\/EncryptTmpSwapHome\">Centos wiki<\/a> for instructions on how to do this. For \/tmp an alternative is to use tmpfs, thereby also ensuring that no trace is left of data in \/tmp when the system is shutdown. Another alternative would be to add tmp as a regular volume in the vg_estorage volume group, but I could not get that approach to work.<\/p>\n<p><strong>Cavaets<\/strong><\/p>\n<p>There can be more sensitive information on your system. In particular, the root home directory could contain sensitive data as well as \/var\/tmp. It is probably best to install your system straight away with disk encryption. I will most likely do this myself as well at some point in the near future.<\/p>\n<p><strong>Performance<\/strong><\/p>\n<p>I have found the performance impacts of encryption to be negligible. The reason is probably that my system has ample memory and is usually never blocked (noticeably) to the user because of IO. Also, it has a quad-core processor which is mostly idle (it is used for mail, web, and also for Java Enterprise software development). In some cases I see 1-2% of CPU use of kcryptd and when doing large sequential writes (typically using dd), kcryptd sometimes has 100 % CPU. I have not noticed any performance degredation in my daily work, including timing of expensive operations involving database and Java application server.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Edit: Meanwhile I have found a better way to migrate an existing centos unencrypted install to a fully encrypted install with \/boot as the only unencrypted disk space. This solution is much preferred over the one described in this post. &hellip; <a href=\"https:\/\/brakkee.org\/site\/2013\/10\/19\/encrypting-an-existing-centos-install\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"inline_featured_image":false,"footnotes":""},"categories":[10,7,4],"tags":[],"_links":{"self":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts\/1102"}],"collection":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/comments?post=1102"}],"version-history":[{"count":0,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/posts\/1102\/revisions"}],"wp:attachment":[{"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/media?parent=1102"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/categories?post=1102"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/brakkee.org\/site\/wp-json\/wp\/v2\/tags?post=1102"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}