How secure is duplicacy?

How did you create a key that can write but cannot delete?

I only see these options in B2:

key

And when I create a key with writeFiles permission it always comes with deleteFiles permission.

You have to use the B2 API to assign specific capabilities (Application Keys). The website doesn’t let you get that granular. The easiest way is to use their B2 command line tool (Get the Command-Line Tool).

Using the b2 cli tool:

b2 authorize-account
b2 create-key --bucket [bucket-id] [new-backup-key-name] listBuckets,listFiles,readFiles,writeFiles
b2 create-key --bucket [bucket-id] [new-prune-key-name] listBuckets,listFiles,readFiles,writeFiles,deleteFiles

Just be sure to save the Key ID and Key when the tool outputs those values.

3 Likes

Thanks! Time to regenerate all the keys … :roll_eyes: :laughing:

I think I found a problem with this approach.

If I use a key that is not allowed to delete (to perform the backups), and this key is stored in the keychain / keyring, the prune command will try to use this key as well, and it will obviously cause an error.

Possible workarounds:

  • Create a dummy entry in the preferences file with -no-save-password option, to run the prunes. Problem: the prune can only be run manually (as mentioned above by @tallgrass). How do you do to calling prune without it using the “backup key” that is already on the keyring?

  • Save the keys / passwords in the preferences file, with one entry for backup and another for prune. Problem: unsafe.

  • Use environment variables in the script that runs the prune, since “If an environment variable for a password is provided, Duplicacy will always take it.

I think the third is the way to go, right?

Any other options that I didn’t figure?

This is exactly what I do. Since the environment variable take precedence, I set it at runtime for the script which performs the prune. So that I don’t have a plaintext key sitting around, I keep the key GPG encrypted and the script is responsible for decrypting it (and using it to set the environment variable) at runtime.

1 Like

I had debated this approach early on. I had considered setting up the same B2 bucket as a different storage in Duplicacy. Then backup to “default” storage, and prune on the “B2-prune” storage ID. I believe in this case Duplicacy would not try to use the default storage credentials when accessing the B2-prune storage.

Ultimately, I didn’t like where it was headed and it sounded like too much to remember. So instead I settled on the environment variable route.

1 Like

Following up after 6+ months to say I’ve been using the same “two-key” B2 approach with a script to do a weekly prune and check. That script runs manually using my prune key. I have had absolutely NO issues and everything is working just fine. All my prunes and checks behave as expected and show no errors.

For background, this storage receives daily backups from 3 different machines all using the “backup-only” key. Once a week I prune the storage using my “prune key” and keep 1 snapshot a day for the past 30 days, and 1 snapshot a month for the past year beyond that.

I didn’t anticipate the massive increase in ransomware that we’ve seen, but I sleep even better at night now.

3 Likes

Hi,

curiosity, should the key also have the “shareFiles” capability in order to allow Duplicacy to download?

From B2:

Lets the client create authorization tokens for downloading files.

For application keys restricted to a bucket, only files in that bucket can be authorized.

For application keys restricted to a file name prefix, only files whose name starts with that prefix can be authorized.

Provides access to these APIs:

Also you think the capababilities: writeBucketEncryption and readBucketEncryption could be any harm?

No. You aren’t sharing them with third-parties. Your readFiles takes care of the download/restore.

1 Like

Not sure how this works. But since you can enable Duplicacy encryption, with keys you control, I’m not sure there is much gain.

1 Like

Hi,

would like to try this method.
How did you save the B2 “prune” key to disk?

So you run Duplicacy from another machine to prune, with the same storage init’ed on a dummy repository?

Here’s some of the snippets from my script:

# GPG encrypted file which holds the secrets
# Encrypt the file with "gpg -s -r <recipient> -e <file>"
# The intended use is to store the API keys which have delete permissions.
# We use environment variables because duplicacy will read and prefer those
# over any other storage (like gnome-keyring) which means we can override
# the "backup-only" API keys for the prune operation.
# This file should contain each environment variable on a
# separate line in the format with blank line at end:
# VARIABLE=value
SECRETS_FILE="${REPO_DIR}/.duplicacy/duplicacy-maint-secrets.gpg"

#########################################
# Get secrets
# This step will require user interaction to perform the decrypt

echo -e "Decrypting secrets from ${SECRETS_FILE}...\n"

# Exit the script if the decrypt fails
DECRYPTED_SECRETS=$(gpg --quiet --decrypt "${SECRETS_FILE}") || exit 1
echo -e "\nSecrets decrypted.  Pausing for 30 seconds for user to inspect signature...\n"
sleep 30

# Export each environment variable so duplicacy can access it
for LINE in ${DECRYPTED_SECRETS}
    do
    export ${LINE}
done

#...script continues, you now have the environment variables set from the GPG encrypted file but only after you manually inputted the password and confirmed the signature...

And finally, a sample duplicacy-maint-secrets.gpg file (decrypted of course):

DUPLICACY_B2_ID=12345
DUPLICACY_B2_KEY=key12355
2 Likes

Same machine. Same repository. Same storage.

Thank you!!

I will need to study this and try to apply to my case because i actually use Duplicacy Web Edition in a container and this seems a little tricky.

Ah, yeah. I couldn’t begin to tell you how you might do it there. I’m a CLI Linux user with a ton of custom wrapper scripts to accomplish my workflow.

This is my doubt. Iirc when initializing a storage with Duplicacy CLI or Web Edition the user needs to input the app key for the B2 bucket.

So i actually understand how you import and decrypt the key. But how you use the prune command with a B2 app key that is different from the one that was used to initiate the storage?

The next step in my script (which I didn’t show) was in essence to run the “duplicacy prune” command (with a bunch of parameters). Since the B2 ID and KEY are now stored in environment variables, those values take precedence over the values stored in the preferences or keyrings. So it just works.

1 Like

I could maybe write a script that asks to enter the keys manually (copy-pasting from a secure password vault) and stores it in the env variables and then export them?

I’ve been using this Python wrapper script with the Web UI on a QNAP NAS to log notifications and to ping healthchecks.io. I successfully experimented with using the following code to set the B2 key environment variables for the CLI:

#!/usr/bin/env python
'''
Decrypts and exports B2 encryption key, prune key ID, and prune key.

'''
from __future__ import print_function
import os
import os.path
from subprocess import *
import getpass
import re

pgp = """-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.7 (GNU/Linux)

<<< encrypted key deleted >>>
-----END PGP MESSAGE-----"""

passphrase = getpass.getpass(prompt='Passphrase: ')
p1 = Popen(['echo', pgp], stdout=PIPE)
p2 = Popen(['gpg', '--passphrase', passphrase, '--quiet', '--decrypt'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
creds = p2.communicate()[0]

for cred in creds.split():
	m = re.match(r'(\w+)=(\S+)', cred)
	if m:
		var, val = m.group(1, 2)
		os.environ[var] = val
		print('export {}={}'.format(var, os.environ[var]))
		
call('env')

I’ve not implemented this because I prefer fully automated backups, so I’d need to store the cleartext passphrase somewhere. There might still be some value in doing this, since generic ransomware would be less likely to target such a customized setup (“security by obscurity”).

1 Like

Maybe duplicacy can integrate with keyring to store the files in encrypted form and prompts for passwd for decryption to clear text?