This is a text-only version of the following page on https://raymii.org: --- Title : Encrypted Duplicity Backups to Openstack Swift Objectstore Author : Remy van Elst Date : 19-05-2014 URL : https://raymii.org/s/tutorials/Encrypted_Duplicity_Backups_to_Openstack_Swift_Objectstore.html Format : Markdown/HTML --- ![openStack Logo][1] 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 you can safely use any public cloud storage to store them. This tutorial is for Ubuntu and CentOS and includes initial setup plus a script to automate it all. <p class="ad"> <b>Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:</b><br><br> <a href="https://leafnode.nl">I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!</a><br><br> <a href="https://github.com/sponsors/RaymiiOrg/">Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.</a><br><br> <a href="https://www.digitalocean.com/?refcode=7435ae6b8212">You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days. </a><br><br> </p> We will be using the Dutch provider [CloudVPS][3], which is not bound to the Patriot Act, so your data is more safe than it is with a provider that is vulnerable to the Patriot Act. Although your data is already encrypted with GPG, you can never be to sure. [CloudVPS][3] provides 10GB free ObjectStore, if you have VPS with them, the data is stored on at least 3 machines in 3 locations and they have a boatload of certifications. If you order a VPS or Objectstore at [CloudVPS][3], please mention my name or this article. I'll get a little referal bonus, which will be used to keep this awesome website running. Openstack is one of those cloudy cloud projects. Warning, keep your buzzword bingo cards ready for the [Wikipedia][4] 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 using the 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 many years 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 in three 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 to instead of your own ssh server? Duplicity supports that as well, right? To be honest, you can use both to your preference. Objectstore provides a nice scalable 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 (depending on the provider) can also be stored on more than one place, without to much user hassle. An example can be a company providing managed services with their own (Openstack based) "private cloud". They also provide backups, of course, and most of the time they use Duplicity to make them. It is easier to scale up ObjectStore then it is to scale up an SSH server. Both can be done of course, take a SAN or NFS backend and it also scales. Therefore, the choice is up to you. Both can complement each other, sometimes one is better and sometimes the other. Speaking like a lawyer, it depends. ### CloudVPS [CloudVPS][3] is the only Dutch company providing Openstack and Objectstore as far as I know. It is not bound by the patriot act, because it has no American locations and it has no American data centers. As far as I know, they only use Dutch Data Centers. [CloudVPS][3] has the following points listed on [their website][5]: * Durable: Your data is stored 3 times on 3 different machines in at least two different datacenters. This means you do not have to worry about data loss. You are getting the security of a datacenter redundant file cluster at a fraction of the cost. * Privacy concious: We are not subject to the Patriot Act like Amazon and others. This means our cloud storage can be used to store privacy sensitive data. * Certification: The [CloudVPS][3] Object Store is covered by our strict certification. This platform is covered by the ISO 27002, NEN 7510 and the CloudControls that we developed together with KPMG. The latter can be very important for companies. I like the first and the second most, because it takes away hassle for me to set up multiple backup locations. If you order a VPS or Objectstore at [CloudVPS][3], please mention my name or this article. I'll get a little referal bonus, which will be used to keep this awesome website running. **Note that this article is not sponsored nor endorsed by[CloudVPS][3], nor am I speaking for or as [CloudVPS][3]. They just happen to be the best Dutch Openstack provider.** ### Requirements You will need the following for this tutorial: * Data to back up * [Duplicity][6] * Openstack Swift/Objectstore access You will need Duplicity version v0.6.22 or higher. [v0.6.22][7] added support for Openstack Swift as a backend. This tutorial was written for and tested on Ubuntu 12.04, 14.04 and CentOS 6. It also works on any other distro where the above requirements are met. Note that there are more Openstack providers, for example [Rackspace][8]. Do note, that they fall under the Patriot Act and thus the NSA probably can access your data. I will be using an example data set containing photo's in this tutorial. Since the cost can sometimes be unclear with these Cloud providers, it is best to start with a small data set. ### Install packages We will be using pip to install the required python modules. We also install gpg plus 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 download offcial RPM packages from the [Duplicity Website][9]. There is also an [official PPA][10] for Ubuntu users. The duplicity versions in the Ubuntu 12.04 and CentOS 6 repositories are to old, so those OS versions require manual install. Use `pip` to install the packages Duplicity uses for the Openstack authentication (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 encrypting the 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' created gpg: new configuration file `/root/.gnupg/gpg.conf' created gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run gpg: keyring `/root/.gnupg/secring.gpg' created gpg: keyring `/root/.gnupg/pubring.gpg' created 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? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) 4096 Requested keysize is 4096 bits Please 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 years Key is valid for? (0) 0 Key does not expire at all Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: Objectstore Backup Encryption Email address: user@example.com Comment: You selected this USER-ID: "Objectstore Backup Encryption <user@example.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O You need a Passphrase to protect your secret key. can't connect to `/root/.gnupg/S.gpg-agent': No such file or directory gpg-agent[25464]: directory `/root/.gnupg/private-keys-v1.d' created We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. gpg: /root/.gnupg/trustdb.gpg: trustdb created gpg: key 672FBC9E marked as ultimately trusted public and secret key created and signed. gpg: checking the trustdb gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u pub 4096R/672FBC9E 2014-05-19 Key fingerprint = C3F3 8B08 7699 D9C9 9AE1 BFBF 1B01 60C5 672F BC9E uid Objectstore Backup Encryption <user@example.com> sub 4096R/7695ED36 2014-05-19 Remember your passphrase! Do the same thing again, now to create the Signing key: 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? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) 4096 Requested keysize is 4096 bits Please 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 years Key is valid for? (0) 0 Key does not expire at all Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: Objectstore Backup Signing Email address: user@example.com Comment: You selected this USER-ID: "Objectstore Backup Signing <user@example.com>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O You need a Passphrase to protect your secret key. can't connect to `/root/.gnupg/S.gpg-agent': No such file or directory We need to generate a lot of random bytes. It is a good idea to perform some other action (type on the keyboard, move the mouse, utilize the disks) during the prime generation; this gives the random number generator a better chance to gain enough entropy. gpg: key C65A7536 marked as ultimately trusted public and secret key created and signed. gpg: checking the trustdb gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model gpg: depth: 0 valid: 2 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 2u pub 4096R/C65A7536 2014-05-19 Key fingerprint = 1FC8 49E2 9A81 2B0E 1BAC 952A 1BCF 6F51 C65A 7536 uid Objectstore Backup Signing <user@example.com> sub 4096R/B569F653 2014-05-19 We now have two keys, `B569F653` for backup signing, and `7695ED36` for backup encryption. You can check it with the command `gpg --list-keys`: [root@vps2 ~]# gpg --list-keys /root/.gnupg/pubring.gpg ------------------------ pub 4096R/672FBC9E 2014-05-19 uid Objectstore Backup Encryption <user@example.com> sub 4096R/7695ED36 2014-05-19 pub 4096R/C65A7536 2014-05-19 uid 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 a password, 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' created gpg: new configuration file `/root/.gnupg/gpg.conf' created gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run gpg: keyring `/root/.gnupg/secring.gpg' created gpg: keyring `/root/.gnupg/pubring.gpg' created gpg: key 672FBC9E: secret key imported gpg: /root/.gnupg/trustdb.gpg: trustdb created gpg: key 672FBC9E: public key "Objectstore Backup Encryption <user@example.com>" imported gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) gpg: secret keys read: 1 gpg: secret keys imported: 1 The key setup part is now complete. Let's continue on to making the actual backups. ### Duplicity To use Duplicity with Swift we need to set 4 environment variables: * SWIFT_USERNAME: your username, in the form tenant:user * SWIFT_PASSWORD: your password * SWIFT_AUTHURL: URL to the Keystone service. For CloudVPS, it would be [https://identity.stack.cloudvps.com/v2.0/][11] * SWIFT_AUTHVERSION: for keystone authentication, set it to 2. More information on CloudVPS Object Store can be found on their [quickstart][11] page. Change this to fit your Cloud Providers settings. You have to create a container/project at your Openstack Provider. I've created a 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 like `Connection 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 my tenant name, so I used the [Openstack API][12] to find out. First get an Auth Token, 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 OK Vary: X-Auth-Token Content-Type: application/json Content-Length: 543 Connection: 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 OK Vary: X-Auth-Token Content-Type: application/json Content-Length: 523 Connection: 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 is your 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. If you 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 password of your gpg keys and then do its magic: Local and Remote metadata are synchronized, no sync needed. Last full backup date: none GnuPG 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 10 SourceFileSize 829395 (810 KB) NewFiles 10 NewFileSize 829395 (810 KB) DeletedFiles 0 ChangedFiles 0 ChangedFileSize 0 (0 bytes) ChangedDeltaSize 0 (0 bytes) DeltaEntries 10 RawDeltaSize 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://duplicity Local and Remote metadata are synchronized, no sync needed. Last full backup date: Mon May 19 05:43:17 2014 Mon May 19 05:19:36 2014 . Mon May 19 05:19:36 2014 Metro-5110 Hdk-02.JPG Mon May 19 05:19:36 2014 Metro-5110 brand bij Rhoon 02-06-1993 om 17.00 uur.jpg Mon 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/backup duplicity 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 2014 GnuPG passphrase: And we check `/tmp/backup` to see it worked: $ ls /tmp/backup/ total 820K drwxr-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 a bunch of encrypted blobs: ![CloudVPS][13] ### Script The below script automates the entire thing and lets you run a backup from a cronjob. It requires that you put in your GPG passphrase to make unattended backups possible, so make sure you keep the script just as safe as the keys themselves. The below script takes a full backup every 7 days, the rest is incremental. Also, edit the variables to fit your needs. #!/bin/bash enc_key=7695ED36 sign_key=B569F653 src="/home/remy/backup-test" dest="swift://duplicity" # OpenStack export 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" # GnuPG export 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! [1]: https://raymii.org/s/inc/img/openstack.jpg [2]: https://www.digitalocean.com/?refcode=7435ae6b8212 [3]: http://www.cloudvps.com [4]: https://en.wikipedia.org/wiki/OpenStack [5]: http://www.cloudvps.com/openstack/object-store/ [6]: http://duplicity.nongnu.org [7]: http://duplicity.nongnu.org/CHANGELOG [8]: http://www.rackspace.com/cloud/files/ [9]: http://duplicity.nongnu.org/ [10]: https://launchpad.net/%7Eduplicity-team/+archive/ppa [11]: http://www.cloudvps.com/community/knowledge-base/cloudvps-object-store-quickstart/ [12]: http://docs.openstack.org/api/quick-start/content/ [13]: https://raymii.org/s/inc/img/haha-nsa2.png --- License: All the text on this website is free as in freedom unless stated otherwise. This means you can use it in any way you want, you can copy it, change it the way you like and republish it, as long as you release the (modified) content under the same license to give others the same freedoms you've got and place my name and a link to this site with the article as source. This site uses Google Analytics for statistics and Google Adwords for advertisements. You are tracked and Google knows everything about you. Use an adblocker like ublock-origin if you don't want it. All the code on this website is licensed under the GNU GPL v3 license unless already licensed under a license which does not allows this form of licensing or if another license is stated on that page / in that software: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. Just to be clear, the information on this website is for meant for educational purposes and you use it at your own risk. I do not take responsibility if you screw something up. Use common sense, do not 'rm -rf /' as root for example. If you have any questions then do not hesitate to contact me. See https://raymii.org/s/static/About.html for details.