Skip to main content

Raymii.org Logo (IEC resistor symbol)logo

Quis custodiet ipsos custodes?
Home | About | All pages | RSS Feed | Gopher

Encrypted Duplicity Backups to Openstack Swift Objectstore

Published: 19-05-2014 | Author: Remy van Elst | Text only version of this article


Table of Contents


openStack Logo

This is a guide on backing up your data to an Openstack Swift (Objectstore)instance using Duplicity. It provides encrypted backups using gpg so that youcan safely use any public cloud storage to store them. This tutorial is forUbuntu and CentOS and includes initial setup plus a script to automate it all.

If you like this article, consider sponsoring me by trying out a Digital OceanVPS. With this link you'll get $100 credit for 60 days). (referral link)

We will be using the Dutch provider CloudVPS, which is not bound to thePatriot Act, so your data is more safe than it is with a provider that isvulnerable to the Patriot Act. Although your data is already encrypted with GPG,you can never be to sure. CloudVPS provides 10GB free ObjectStore, if youhave VPS with them, the data is stored on at least 3 machines in 3 locations andthey have a boatload of certifications.

If you order a VPS or Objectstore at CloudVPS, please mention my name orthis article. I'll get a little referal bonus, which will be used to keep thisawesome website running.

Openstack is one of those cloudy cloud projects. Warning, keep your buzzwordbingo cards ready for the Wikipedia definition:

OpenStack is a free and open-source software cloud computing platform. It is primarily deployed as an infrastructure as a service (IaaS) solution. The technology consists of a series of interrelated projects that control pools of processing, storage, and networking resources throughout a data center, able to be managed or provisioned through a web-based dashboard, command-line tools, or a RESTful API. It is released under the terms of the Apache License.

Basically it is a very nice project which provides an easy and scalable way to:

  1. Virtualize (Compute / Nova) (KVM, VMWare, Xen)
  2. Provide scalable object access (Swift / Objectstore) (like s3)
  3. Manage it all using a nice dashboard (Horizon)
  4. Have a great API which lets people develop applications for it.
  5. Be open source. There is no vendor lock in, you can switch between any provider providing OpenStack.

My summary is, lets say, sparse. For the sake of this tutorial, we will be usingthe Swift service (Object Store) to store backups we make with Duplicity.

Duplicity is another wonderfull open source project which lets you easily make(encrypted) (remote) full or incremental backups. I've been using it for manyyears now, it is awesome and very easy to manage.

As we all know, your data is not backed up until it is at least backed up inthree places:

  1. Locally (homeserver)
  2. Off site (the cloud)
  3. Offline (DVD / Tape in a box at your bank)

Why would we want to use the Openstack Swift service to send our backups toinstead of your own ssh server? Duplicity supports that as well, right?

To be honest, you can use both to your preference. Objectstore provides a nicescalable way to acces data. Because it only needs to provide access to data, it(can be)/(mostly is) faster than one VPS or off site Rasberry Pi. It (dependingon the provider) can also be stored on more than one place, without to much userhassle.

An example can be a company providing managed services with their own (Openstackbased) "private cloud". They also provide backups, of course, and most of thetime they use Duplicity to make them. It is easier to scale up ObjectStore thenit is to scale up an SSH server. Both can be done of course, take a SAN or NFSbackend and it also scales.

Therefore, the choice is up to you. Both can complement each other, sometimesone is better and sometimes the other. Speaking like a lawyer, it depends.

CloudVPS

CloudVPS is the only Dutch company providing Openstack and Objectstore asfar as I know. It is not bound by the patriot act, because it has no Americanlocations and it has no American data centers. As far as I know, they only useDutch Data Centers.

CloudVPS has the following points listed on their website:

The latter can be very important for companies. I like the first and the secondmost, because it takes away hassle for me to set up multiple backup locations.

If you order a VPS or Objectstore at CloudVPS, please mention my name orthis article. I'll get a little referal bonus, which will be used to keep thisawesome website running.

Note that this article is not sponsored nor endorsed byCloudVPS, nor am Ispeaking for or as CloudVPS. They just happen to be the best DutchOpenstack provider.

Requirements

You will need the following for this tutorial:

You will need Duplicity version v0.6.22 or higher. v0.6.22 added supportfor Openstack Swift as a backend.

This tutorial was written for and tested on Ubuntu 12.04, 14.04 and CentOS 6. Italso works on any other distro where the above requirements are met.

Note that there are more Openstack providers, for example Rackspace. Donote, that they fall under the Patriot Act and thus the NSA probably can accessyour data.

I will be using an example data set containing photo's in this tutorial. Sincethe cost can sometimes be unclear with these Cloud providers, it is best tostart with a small data set.

Install packages

We will be using pip to install the required python modules. We also install gpgplus of course Duplicity itself. The following commands wil install them.

For debian/ubuntu:

apt-get install python-pip gnupg2 duplicity

For CentOS:

yum install python-pip gnupg2 duplicity

If the version of Duplicity in the repositories is to old, you can downloadoffcial RPM packages from the Duplicity Website. There is also an officialPPA for Ubuntu users. The duplicity versions in the Ubuntu 12.04 and CentOS6 repositories are to old, so those OS versions require manual install.

Use pip to install the packages Duplicity uses for the Openstackauthentication (keystone) and the actual storage (swift):

pip install python-swiftclient python-keystoneclient

Generate Keys

Because we trust nobody except ourselves with our backups, we will be encryptingthe backups using GPG.

We will be creating two different keys, one for signing and one for encrypting.

First generate the encryption key:

gpg --gen-key

Example output. I choose a 4096 RSA/RSA key whithout expiry date:

gpg (GnuPG) 2.0.14; Copyright (C) 2009 Free Software Foundation, Inc.This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.gpg: directory `/root/.gnupg' createdgpg: new configuration file `/root/.gnupg/gpg.conf' createdgpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this rungpg: keyring `/root/.gnupg/secring.gpg' createdgpg: keyring `/root/.gnupg/pubring.gpg' createdPlease select what kind of key you want:   (1) RSA and RSA (default)   (2) DSA and Elgamal   (3) DSA (sign only)   (4) RSA (sign only)Your selection? 1RSA keys may be between 1024 and 4096 bits long.What keysize do you want? (2048) 4096Requested keysize is 4096 bitsPlease specify how long the key should be valid.         0 = key does not expire      <n>  = key expires in n days      <n>w = key expires in n weeks      <n>m = key expires in n months      <n>y = key expires in n yearsKey is valid for? (0) 0Key does not expire at allIs this correct? (y/N) yGnuPG needs to construct a user ID to identify your key.Real name: Objectstore Backup EncryptionEmail address: user@example.comComment: You selected this USER-ID:    "Objectstore Backup Encryption <user@example.com>"Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? OYou need a Passphrase to protect your secret key.can't connect to `/root/.gnupg/S.gpg-agent': No such file or directorygpg-agent[25464]: directory `/root/.gnupg/private-keys-v1.d' createdWe need to generate a lot of random bytes. It is a good idea to performsome other action (type on the keyboard, move the mouse, utilize thedisks) during the prime generation; this gives the random numbergenerator a better chance to gain enough entropy.gpg: /root/.gnupg/trustdb.gpg: trustdb createdgpg: key 672FBC9E marked as ultimately trustedpublic and secret key created and signed.gpg: checking the trustdbgpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust modelgpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1upub   4096R/672FBC9E 2014-05-19      Key fingerprint = C3F3 8B08 7699 D9C9 9AE1  BFBF 1B01 60C5 672F BC9Euid                  Objectstore Backup Encryption <user@example.com>sub   4096R/7695ED36 2014-05-19

Remember your passphrase! Do the same thing again, now to create the Signingkey:

gpg --gen-key

Again, I choose a non-expiring 4096 bits RSA/RSA key, with a different name:

gpg (GnuPG) 2.0.14; Copyright (C) 2009 Free Software Foundation, Inc.This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.Please select what kind of key you want:   (1) RSA and RSA (default)   (2) DSA and Elgamal   (3) DSA (sign only)   (4) RSA (sign only)Your selection? 1RSA keys may be between 1024 and 4096 bits long.What keysize do you want? (2048) 4096Requested keysize is 4096 bitsPlease specify how long the key should be valid.         0 = key does not expire      <n>  = key expires in n days      <n>w = key expires in n weeks      <n>m = key expires in n months      <n>y = key expires in n yearsKey is valid for? (0) 0Key does not expire at allIs this correct? (y/N) yGnuPG needs to construct a user ID to identify your key.Real name: Objectstore Backup SigningEmail address: user@example.comComment: You selected this USER-ID:    "Objectstore Backup Signing <user@example.com>"Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? OYou need a Passphrase to protect your secret key.can't connect to `/root/.gnupg/S.gpg-agent': No such file or directoryWe need to generate a lot of random bytes. It is a good idea to performsome other action (type on the keyboard, move the mouse, utilize thedisks) during the prime generation; this gives the random numbergenerator a better chance to gain enough entropy.gpg: key C65A7536 marked as ultimately trustedpublic and secret key created and signed.gpg: checking the trustdbgpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust modelgpg: depth: 0  valid:   2  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 2upub   4096R/C65A7536 2014-05-19      Key fingerprint = 1FC8 49E2 9A81 2B0E 1BAC  952A 1BCF 6F51 C65A 7536uid                  Objectstore Backup Signing <user@example.com>sub   4096R/B569F653 2014-05-19

We now have two keys, B569F653 for backup signing, and 7695ED36 for backupencryption. You can check it with the command gpg --list-keys:

[root@vps2 ~]# gpg --list-keys/root/.gnupg/pubring.gpg------------------------pub   4096R/672FBC9E 2014-05-19uid                  Objectstore Backup Encryption <user@example.com>sub   4096R/7695ED36 2014-05-19pub   4096R/C65A7536 2014-05-19uid                  Objectstore Backup Signing <user@example.com>sub   4096R/B569F653 2014-05-19

Make a backup of these keys! Store it on a safe place. The key (hopefully) has apassword, but still should be kept as secret as possible.

Use the --export-secret-keys option to backup both keys (as ascii, hence the-a) to two files:

[root@vps2 ~]# gpg --export-secret-keys -a B569F653 > signing.asc[root@vps2 ~]# gpg --export-secret-keys -a 7695ED36 > encryption.asc

If you ever need to import those, use the gpg --import command:

root@vps5:~# gpg --import enc.asc gpg: directory `/root/.gnupg' createdgpg: new configuration file `/root/.gnupg/gpg.conf' createdgpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this rungpg: keyring `/root/.gnupg/secring.gpg' createdgpg: keyring `/root/.gnupg/pubring.gpg' createdgpg: key 672FBC9E: secret key importedgpg: /root/.gnupg/trustdb.gpg: trustdb createdgpg: key 672FBC9E: public key "Objectstore Backup Encryption <user@example.com>" importedgpg: Total number processed: 1gpg:               imported: 1  (RSA: 1)gpg:       secret keys read: 1gpg:   secret keys imported: 1

The key setup part is now complete. Let's continue on to making the actualbackups.

Duplicity

To use Duplicity with Swift we need to set 4 environment variables:

More information on CloudVPS Object Store can be found on their quickstartpage. Change this to fit your Cloud Providers settings.

You have to create a container/project at your Openstack Provider. I've createda project named Duplicity, that is what will be used in this example.

Set the variables in your shell:

export SWIFT_USERNAME="user@example.com"export SWIFT_PASSWORD="passw0rd"export SWIFT_AUTHURL="https://identity.stack.cloudvps.com/v2.0/"export SWIFT_AUTHVERSION="2"

Start a simple test. I have a folder with three photo's used as example.

duplicity ~/test-backup swift://duplicity

The whole credentials part was a bit confusing to me. Why do I have a tenant,project, bucket, user, password, url and what more? I got errors likeConnection failed: ClientException No tenant specified and Connection failed:ClientException Unauthorised. Check username, password and tenant name/id.

The format of SWIFT_USERNAME should be "tenant:username". I did not know mytenant name, so I used the Openstack API to find out. First get an AuthToken, using cURL:

curl -i 'https://identity.stack.cloudvps.com/v2.0/tokens' -X POST -H "Content-Type: application/json" -H "Accept: application/json"  -d '{"auth": {"tenantName": "", "passwordCredentials": {"username": "user@example.com", "password": "passw0rd"}}}'

Response:

HTTP/1.1 200 OKVary: X-Auth-TokenContent-Type: application/jsonContent-Length: 543Connection: close{    "access": {        "token": {            "issued_at": "2014-05-19T03:24:50.971373",            "expires": "2014-05-20T03:24:50Z",            "id": "8g2CeQ3kM0tkRAEiu6KmGaI6M8NLFDJ8WQ"        },        "serviceCatalog": [],        "user": {            "username": "user@example.com",            "roles_links": [],            "id": "J0XPUWipImRpkFXAVxJYELAXnXx26jPPj9w",            "roles": [],            "name": "user@example.com"        },        "metadata": {            "is_admin": 0,            "roles": []        }    }}

The token is the first id. In this case: 8g2CeQ3kM0tkRAEiu6KmGaI6M8NLFDJ8WQ.Use the token to get a list of tenants for that token:

curl -i -X GET 'https://identity.stack.cloudvps.com/v2.0/tenants' -H "User-Agent: python-keystoneclient" -H "X-Auth-Token: 8g2CeQ3kM0tkRAEiu6KmGaI6M8NLFDJ8WQ"

Response:

HTTP/1.1 200 OKVary: X-Auth-TokenContent-Type: application/jsonContent-Length: 523Connection: close{    "tenants_links": [],    "tenants": [        {            "handle": "HANDLE",            "description": "HANDLE Projectname",            "enabled": true,            "id": "zORIDFV4ybpbV9bRg1gwNi7NNnTiCw",            "name": "HANDLE Projectname"        },        {            "handle": "HANDLE",            "description": "Main Customer Tenant",            "enabled": true,            "id": "vnsdmwzPSl8dHm2RQQe",            "name": "HANDLE"        }    ]}

The part you want to have is the "name": "HANDLE Projectname" part. That isyour tenant.

In my case, the SWIFT_USERNAME should be:

SWIFT_USERNAME="HANDLE Projectname:user@example.com"

If you are wondering why you don't specify an URL like so:

duplicity ~/backup-test swift://https://zORIDFV4ybpbV9bRg1gwNi7NNnTiCw.objectstore.eu/duplicity

Well that is because Duplicity is smart enough to get that data from the API. Ifyou do try it, you will get an error like this:

Connection failed: ClientException Container PUT failed: https://zORIDFV4ybpbV9bRg1gwNi7NNnTiCw.objectstore.eu/zORIDFV4ybpbV9bRg1gwNi7NNnTiCw.objectstore.eu/duplicity 404 Not Found  [first 60 chars of response] <html> <head>  <title>404 Not Found</title> </head> <bod

If the authentication details are correct, Duplicity should ask for the passwordof your gpg keys and then do its magic:

Local and Remote metadata are synchronized, no sync needed.Last full backup date: noneGnuPG passphrase: Retype passphrase to confirm: No signatures found, switching to full backup.--------------[ Backup Statistics ]--------------StartTime 1400471008.22 (Mon May 19 05:43:28 2014)EndTime 1400471008.30 (Mon May 19 05:43:28 2014)ElapsedTime 0.08 (0.08 seconds)SourceFiles 10SourceFileSize 829395 (810 KB)NewFiles 10NewFileSize 829395 (810 KB)DeletedFiles 0ChangedFiles 0ChangedFileSize 0 (0 bytes)ChangedDeltaSize 0 (0 bytes)DeltaEntries 10RawDeltaSize 825299 (806 KB)TotalDestinationSizeChange 726604 (710 KB)Errors 0-------------------------------------------------

Now using list-current-files we can see what is in the backup:

duplicity list-current-files swift://duplicityLocal and Remote metadata are synchronized, no sync needed.Last full backup date: Mon May 19 05:43:17 2014Mon May 19 05:19:36 2014 .Mon May 19 05:19:36 2014 Metro-5110 Hdk-02.JPGMon May 19 05:19:36 2014 Metro-5110 brand bij Rhoon 02-06-1993 om 17.00 uur.jpgMon May 19 05:19:36 2014 Metro-5110-5124 brand bij Rho 2-06-1993.jpg

If we want to restore out backup, we can do it like this:

mkdir /tmp/backupduplicity restore swift://duplicity /tmp/backup

Output:

Local and Remote metadata are synchronized, no sync needed.Last full backup date: Mon May 19 05:43:17 2014GnuPG passphrase: 

And we check /tmp/backup to see it worked:

$ ls /tmp/backup/total 820Kdrwxr-xr-x  2 remy remy  220 May 19 05:19 .drwxrwxrwt 20 root root  440 May 19 05:49 ..-rwxr-xr-x  1 remy remy  45K May 19 05:19 Metro-5110 Hdk-02.JPG-rwxr-xr-x  1 remy remy 215K May 19 05:19 Metro-5110 brand bij Rhoon 02-06-1993 om 17.00 uur.jpg-rwxr-xr-x  1 remy remy  92K May 19 05:19 Metro-5110-5124 brand bij Rho 2-06-1993.jpg

And you know what the cloud provider/a three letter american agency has? Just abunch of encrypted blobs:

CloudVPS

Script

The below script automates the entire thing and lets you run a backup from acronjob. It requires that you put in your GPG passphrase to make unattendedbackups possible, so make sure you keep the script just as safe as the keysthemselves.

The below script takes a full backup every 7 days, the rest is incremental.

Also, edit the variables to fit your needs.

#!/bin/bashenc_key=7695ED36sign_key=B569F653src="/home/remy/backup-test"dest="swift://duplicity"# OpenStackexport SWIFT_USERNAME="HANDLE Projectname:user@example.com"export SWIFT_PASSWORD="passw0rd"export SWIFT_AUTHURL="https://identity.stack.cloudvps.com/v2.0/"export SWIFT_AUTHVERSION="2"# GnuPGexport PASSPHRASE="passw0rd"export SIGN_PASSPHRASE="passw0rd"duplicity --verbosity notice \        --encrypt-key "$enc_key" \        --sign-key "$sign_key" \        --full-if-older-than 7D \        --num-retries 3 \        --asynchronous-upload \        --volsize 10 \         "${src}" "${dest}"

That's all for today. Have fun using Openstack for your backups!

Tags: backup, backups, centos, cloud, debian, duplicity, gpg, keystone, objectstore, openstack, python, swift, tutorials, ubuntu