Thursday, November 27, 2014

Encrypt Everything: Encrypt data using GPG and save passwords

Data security is an important concern these days and encryption is a very powerful tool to secure the data. In my previous post I talked about how to encrypt a disk. Now we are going to talk about how to encrypt files using GNU Privacy Guard (GPG).

GPG uses public key cryptography. This means that instead of having one key to encrypt and decrypt, there are two keys. One of these keys can be publicly shared and hence is known as public key. The other key is to be kept secret and is known as private key. Anything encrypted with public key can only be decrypted with private key.

How to encrypt files?
Assuming a scenario that user "test" wants to send an encrypted file to me, the user just has to find my public key, encrypt the data and send it to me where I will be able to decrypt the file using my private key and obtain the data. Note that user "test" doesn't need to have GPG keys generated in order to encrypt and send data to me.

Step1: Let us create a text file which we'll encypt:
test$ echo "This is a secret message." > secret.txt

Step2: User "test" needs to find my keys. There are many public servers where one can share their public key in case someone else wants to encrypt the data. One such server is run by MIT at http://pgp.mit.edu.
test$ gpg --keyserver pgp.mit.edu --search-keys aditya@adityapatawari.com

Step3: Once the user obtains my public key, then encrypting data is really easy.
test$ gpg --output secret.txt.gpg --encrypt --recipient aditya@adityapatawari.com secret.txt

The command above will create an encrypted file named secret.txt.gpg which can be shared via email or any other means. Once I get the encrypted file, I can decrypt it using my private key
aditya$ gpg --output secret.txt --decrypt secret.txt.gpg

How to create GPG keys to receive data?
Now assume a scenario where "test" user wants to create a set of GPG keys in order to share the public key and receive encrypted data.

Step1: Generate a key pair. The command will present you some options (stick to defaults if you are not sure) and ask for some data like your name and email address etc.
test$ gpg --gen-key

Step2: Check the keys.

test$ gpg --list-secret-keys
/home/test/.gnupg/secring.gpg
-----------------------------
sec   2048R/E46749BB 2014-11-23
uid                  Aditya TestKeys (This is not a valid key) <adimania+test@gmail.com>
ssb   2048R/C5E57FF2 2014-11-23


Step3: Upload the key to a public server using the id from the above.
test$ gpg --keyserver pgp.mit.edu --send-key E46749BB

Now others can search for the key, use it to encrypt the data and send it to the "test" user. 

To use GPG for saving password, have a look at pass utility. It uses GPG to encrypt passwords and other data and store it in a hierarchical format. 

Saturday, November 22, 2014

Encrypt Everything: How to encrypt the disk to protect the data

Recently, at BrowserStack.com, some of our services got compromised. We use Amazon Web Services extensively. The person (or group) who attacked us mounted one of our backups and managed to steal some of the data. We could have prevented this simply by ensuring that we use encrypted disks which would have made this attack useless. Learning from our mistakes, we have recently started encrypting everything and I am going to show you how to do that. One point worth noting here is that Amazon AWS does provide encryption support for the EBS volumes but that is transparent and would not help in case of the account getting compromised. I am going to use dm-crypt which is supported by Linux kernel so the steps are quite generic and would work on any kind of disk, on any kind of environment, including Amazon AWS, Google Compute Engine, physical disks in your datacenter.

Our goal is to encrypt /home. To achieve this, we'll attach a disk, encrypt it, move the entire /home data to this disk and create a symbolic link to /home.

Step1: We are going to use Linux Unified Key Setup. For that we need to install cryptsetup package.
# yum install cryptsetup

Step2: While using AWS, never attach the volume to be encrypted while launching the instance. If we do so, the instance will fail to boot up next time because it'll ask for decryption password while booting up which is not possible to supply in AWS. Still if it is absolutely mandatory to do this then I suggest trying to remove entries from fstab and crypttab but it is much easier to just attach the disk after the launching of the instance is done. Assuming that the attached disk is available at /dev/xvdf, we'll setup the encryption now.
# cryptsetup -y -v luksFormat /dev/xvdf
WARNING!
========
This will overwrite data on /dev/xvdf irrevocably.

Are you sure? (Type uppercase yes): YES
Enter LUKS passphrase:
Verify passphrase:

Command successful.


We can verify the encryption parameters as well. Default is AES 256 bit.
# cryptsetup luksDump /dev/xvdf

Step3: We'll open the device and map it to /dev/mapper/home so that we can use it.
# cryptsetup luksOpen /dev/xvdf home
Enter passphrase for /dev/xvdf:


Step4: This step is optional. To further protect our data, we can zero out the entire disk before even creating the filesystem.
# dd if=/dev/zero of=/dev/mapper/home

Step5: Now we'll create a filesytem
# mkfs.ext4 /dev/mapper/home

Step6: Let us mount and copy the data from /home
# mkdir /myhome
# mount /dev/mapper/home /myhome
# cp -a /home/* /myhome/
# rm -rf /home
# ln -s /myhome /home

Great! Our /home directory is encrypted. But wait a minute.. this approach has a short coming. We have deliberately designed it so that the disk won't auto-mount during the boot because there is no way to give it a password in cloud environment during the boot. Since the disk won't mount, we won't be able to ssh into the machine because the authorized_keys file is kept inside the home directory of the user. To address this problem, either change the "AuthorizedKeysFile" in sshd_config or create a user with home directory in /var/lib or /opt and grant sudo for cryptsetup and mount commands. So after reboot, if we take the first approach, we would be able to ssh without any problem or we'll ssh via other user, mount the encrypted drive and then use it normally.

$ ssh mountuser@<ip>
$ sudo /sbin/cryptsetup luksOpen /dev/xvdf home
$ sudo /bin/mount /dev/mapper/home /myhome/


Couple of points to remember:
  • Do not forget the LUKS password. It cannot be retrieved, if lost.
  • Try it a couple of times on staging machines before doing it on the machines that matter.