Saturday, February 7, 2015

Encrypt your /home folder using LUKS encryption

Hi again,

welcome to a new post. This time I am going to talk about encryption.

As it may happen to you, when you are working for big company they might provide to you a laptop with the goal of improving your productivity and facilities, about to allow you keep working when, for work reasons, you have to do some business trips. As you guess that laptop will contain a huge amount of private information: private ssh-keys, databases, project codes, wireless pass....

Probably you all do agree that all that information mustn't be read by anyone who doesn't belong to the same company, especially from your company's competitors. Then, it is time to start thinking on encrypting your computer and every single private information which could become exposed.

Time to think on you alternatives:

1. BIOS Password: Useless if someone takes out your hard disk.
2. Software Encryption: Too weak, it could be encrypted easily.
3. Full disk encryption on boot level: Too hard and aggressive, not all your information may need to be protected, and it could decrease your computer performance.
4. Partition encryption:  As safe as full disk encryption and as slightly than Software encryption. That is the one I am going to explain below.


Once we have proceed with having a look into the topic and making a bit research about how to handle the problem I decided to use LUKS encryption. At this page it is not explained any technical, if you want to go further on it, go to wikipedia or any other of the other many article whose main topic trait about it.


At first you should have your disk split into several partitions. I tend to recommend to have at least four: /boot(ext2), /home(ext4) and /(ext4) (swap). So whatever you prefer but I you want to apply what I am going to illustrate in here, you will need to have your /home folder running on a separated partition.

Encrypting your home folder

Step1

Backup your home folder wherever you consider the safest and fastest way to do it, usb, sd, ssd, other disk partition....please, take in account that you must keep the permissions on all your files, so once you decide which device you will use to store your home data in meantime the process gets complete use one of the following commands to maintain permissions, personally I'd rather use scp. (COPY JUST HOME CONTENT)

cp -rp /home/* {to}
or 
scp -arxH /home/* {to}

Step2

Install Cryptsetup package which manages the creation, writing and reading of crypt-luks partitions. 

sudo apt-get install cryptsetup 

Step3

Check first which is the id of your home partition running command $df -h. Then, wipe out all the content of your current home partition (sdxy).

dd if=/dev/urandom of=/dev/sdxy bs=4096

This command may take a long while, so don't get hopeless, it might last several hours to complete.

Step4

Boot into recovery mode(root shell prompt) or switch into your root account. In case you have decided to take the way of recovery mode, notice you only have read access to the file system. You need write access too so remount the system partition. Then launch the following command:

mount -o remount,rw /

Step 5

Create your new home encrypted partition using the command bellow:

cryptsetup luksFormat --cipher aes-xts-plain64 --key-size 256 --hash sha256 /dev/sdxy

This command will ask you for a password to encrypt your partitions, so don't forget it. Once creation gets completed. Label you partitions using the next command and set a ext4 filesystem on it too. 


cryptsetup luksOpen /dev/sdxy home
mkfs.ext4 /dev/mapper/home

Step6

Use fstab(vim /etc/fstab) to mount your partition automatically:


As you can see on the screenshot you have to replace the UUID from you old home partition and replace it using the path of your new encrypted home partition. 

Step7

The crypttab file tells the system which are your encrypted volumes. First we need the devices' block identifiers.(search for your sdxy)

$ blkid

Then, edit your /etc/crypttab so it looks like:

Step8

Test everything went fine and copy back your home folder:


mount /dev/mapper/home

Go to /home/ and you will see only lost+found inside. Time to put back all your old home content into this new encrypted partition.

cp -rp {from} /home/
or 
scp {from} -arxH /home/

Don't forget to check that all the content you just copied into your home have the right permissions to your own user, anyway else fixed using the following command:


chown -R your_username /home/your_username 

chmod 750 /home/your_username 

Step 8

To finish up all this process, reboot your computer normally and you will see that during the boot it will ask you for the password you have set during this process. Then, you will see that your home folder is there and nothing have changed from the previous linux you had before the process started. 

*Possible problems(Apache and mysql running under an encrypted partition)

As we were talking at the beginning of all this process, the goal of this encryption consists on hiding from other all our private information. Inside that private information we want to protect there are, at least, in my case two things, web programming projects and mysql databases.

To protect both of them I'd rather create symbolic links from its original path into our home folder so all the information keeps protected, in case of MYSQL you could have a look here, in cases of other project of APACHE, via vhost you could manage it on several way, there are many blogs where you might find how to manage it. 

Are everything as good as looks like in first place? Of course THAT DON'T ! , most of services have its own user to manipulate certain files, folder, logs and so on. So, once you have moved part of its service structure out of its normal repositories you will need to maintain the permissions of every folder.It seems simple using the scp -raxH and the cp -r, but it is not as easy. Because in case, it seems like these two services have different behaviour in case they are running under a encrypted partition, even having every folder and file the right permissions you will see on the services logs errors like PERMISO DENIED, IMPOSSIBLE TO READ.....

After a long research I've found that if you want to run services running on two splitted partitions the user must have full read access to the whole partition which are going to be used, in our case just on the new partition we have created. 

Then there will be many ways to do it, but I did it on one simple way. I included mysql and apache users on my personal user groups, then I provided to my whole /home partition and to its mounted volume, group rw access by running:

chmod -R g+rw /home/ /dev/mapper/home

After that I've restart my two services and they were working fine.

I hope I helped you with all this information in the way it helped my in other ways.

Thanks for reading :)

Thursday, January 1, 2015

Simple example of a customized FileSystemStorage at Django 1.7

At this post it is published an example about how to implement your own FileSystemStorageClass and some extra methods which allow you to remove old images(files), once its value has changed and also when the instance is deleted, because these two behaviors seems like they should have been included at the normal workflow, of an ImageField (FileField), but they are not.

Setting out the initial approach

In first place you usually would like to develop a new model class whose goal is handling a type of file (in this case Images). I called my class Photo:

class Photo(models.Model):
    image = models.ImageField(location='Public/uploading')
    title = models.CharField(max_length=70, blank=False)
    alt = models.CharField(max_length=110, blank=True, null=True)
    description = models.TextField(null=True, blank=True)

As you see, at my first go I decided to store every file within the Public folder of the project itself because in my case I wanted to use these images a part of the html templating. Usually, glancing at  Django 1.7 manual it is recommend to you to use an absolute path to the media folder, out of project folder. You will see why ....

Problems showing up

Problem 1: Admin area

My first problem came after uploading the first file. It seems like everything is going to work "fine", apparently, till you click on the image link and it is loaded an url like that:
http://127.0.0.1:8000/admin/content/photo/6/Public/uploading/cartel_autoestima_Nuevo-1_l4w4IzB.png
And of course, nothing will load.

Problem 2: Rendering templates

Okay.... Problem 1 was annoying, we can carry on with this, deleting the removing the surplus from the url. Then the next challenge was using them in the templates. You have something like the following code.
<img src="/{{ photo.image }}"> 
As you have already realized, I have had to add and slash / before using the actual image url. It is another detail what tell you something is not done properly at the initial approach you implemented.

Problem 3: Endless amount of files

By now we have patched every "problem" we found in the way, and we don't feel happy how is done, because you know you are doing really dirty stuff to keep going ahead. Then once you try to face up to this one it forces you to change all done so far. Every file you have uploaded during all your testing process is still there, they never got deleted even after deleting the instance, and you have to clean it up manually because you are not going to fill up the server with useless files everywhere. 

Coding your customized FileSystemStorage

Due to all problem explained above we decide to redo everything and after some researches you find out that the best way to work them out is developing a customized FileSystemStorage class which will handle everything that were bothering you.
# Settings.py file
CUSTOM_STORAGE_FOLDER = '/Public/uploading'CUSTOM_STORAGE_FOLDER_ROOT = os.path.join(BASE_DIR, 'Public/uploading')
# models.py file
class MyStorage(FileSystemStorage):

        def url(self, name):
            if self.base_url is None:
                raise ValueError("This file is not accessible via a URL.")
            return os.path.join(self.base_url, filepath_to_uri(name))

fs = MyStorage(location=settings.CUSTOM_STORAGE_FOLDER_ROOT, base_url=settings.CUSTOM_STORAGE_FOLDER)


class Photo(models.Model):
    image = models.ImageField(storage=fs)
    title = models.CharField(max_length=70, blank=False)
    alt = models.CharField(max_length=110, blank=True, null=True)
    description = models.TextField(null=True, blank=True)

    def delete(self, *args, **kwargs):
        self.image.delete()
        super(Photo, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        if self.pk is not None:
            try:
                this = Photo.objects.get(id=self.id)
                if this.image != self.image:
                    this.image.delete(save=False)
            except OSError as e:
                pass
        super(Photo, self).save(*args, **kwargs)
Lets explain a bit what I do in here. 
  • Implement a new class called MyStorage which extends the FileSystemStorage, and we just override the def url method so you build up the image url you will need to use to render the files in the templates, and it is also automatically used at the admin panel too.
  • Instance of MyStorage using location and base_url parameters to define full storage folder path and rendering url respectively, and at the ImageField declaration we use it as storage object.
  • At last, we have overrided the methods delete and save to include the removing of old images, after changing the image value and after deleting the instanced object.

I hope this post makes your coding bit easier
Thanks for reading it ;)