From e2ef1de8187e0f74c2b288090ce555f96699f72c Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Mon, 8 Oct 2018 00:53:40 +0000 Subject: [PATCH 1/4] Added fallback credentials option --- cmd.py | 2 +- cmd_backup.py | 14 +++++-- cmd_init.py | 1 + cmd_set_fallback.py | 95 +++++++++++++++++++++++++++++++++++++++++++++ registry.py | 11 +++++- 5 files changed, 118 insertions(+), 5 deletions(-) create mode 100755 cmd_set_fallback.py diff --git a/cmd.py b/cmd.py index 3badaec..af3d964 100755 --- a/cmd.py +++ b/cmd.py @@ -36,7 +36,7 @@ class CliWrapper(CliWrapper): PATH = [ dirname(realpath(__file__)) ] COMMANDS_USAGE_ORDER = ['init', '', - 'passphrase', 'escrow', + 'passphrase', 'escrow', 'set-fallback', '', 'backup', 'list', 'restore', 'restore-rollback', '', diff --git a/cmd_backup.py b/cmd_backup.py index 0b5fa36..81cffd2 100755 --- a/cmd_backup.py +++ b/cmd_backup.py @@ -342,13 +342,21 @@ def main(): except hb.Error, e: # asking for get_credentials() might fail if the hub is down. # But If we already have the credentials we can survive that. - if isinstance(e, hub.NotSubscribed) or \ not registry.credentials or \ registry.credentials.type == 'iamrole': - fatal(e) + # if we don't have cached credentials we might still be + # able to use the fallback credentials + if registry.fallback_access_key: + credentials = hub.Credentials.IAMUser( + registry.fallback_access_key, + registry.fallback_secret_key, + None) + else: + fatal(e) + elif registry.credentials: + warn("using cached backup credentials: " + e.description) - warn("using cached backup credentials: " + e.description) credentials = registry.credentials diff --git a/cmd_init.py b/cmd_init.py index dc69743..8da3015 100755 --- a/cmd_init.py +++ b/cmd_init.py @@ -166,6 +166,7 @@ def main(): registry.registry.sub_apikey = None registry.registry.credentials = None else: + if force or not registry.registry.sub_apikey: if not apikey: print "Copy paste the API-KEY from your Hub account's user profile" diff --git a/cmd_set_fallback.py b/cmd_set_fallback.py new file mode 100755 index 0000000..550451b --- /dev/null +++ b/cmd_set_fallback.py @@ -0,0 +1,95 @@ +#!/usr/bin/python +# Copyright (c) 2018 TurnKey GNU/Linux - https://www.turnkeylinux.org +# +# This file is part of TKLBAM (TurnKey GNU/Linux BAckup and Migration). +# +# TKLBAM is open source 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. +# +""" +Set Fallback + +This is used to setup fallback credentials used when access to the Hub is limited +or not possible. + +Arguments: + + FALLBACK-ACCESS-KEY Your IAMUser access key + + FALLBACK-SECRET-KEY Your IAMUser secret access key + +Security warning: + + Providing your AWS IAMUser credentials as a commandline argument is + potentially less secure than allowing tklbam-set-fallback to prompt + you for it interactively: + + * The shell may save the APIKEY to its history file (e.g., ~/.bash_history) + * The FALLBACK-ACCESS-KEY and FALLBACK-SECRET-KEY may briefly show up in the + process list. + + AWS IAMUser credentials must exist on your system in plaintext as they are + intended to work even when you can only access your AWS bucket and should + work automatically without interaction. + +""" + +import sys +import registry +import getopt + +def usage(e=None): + if e: + print >> sys.stderr, "error: " + str(e) + + print >> sys.stderr, "Usage: %s [ -options ]" % sys.argv[0] + print >> sys.stderr, __doc__.strip() + + sys.exit(1) + +def main(): + try: + opts, args = getopt.gnu_getopt(sys.argv[1:], "h", ["help"]) + except getopt.GetoptError, e: + usage(e) + + fallback_access_key = None + fallback_secret_key = None + + for opt, val in opts: + if opt in ('-h', '--help'): + usage() + + if args: + if len(args) > 2: + usage() + elif len(args) == 1: + fallback_access_key = args[0] + elif len(args) == 2: + fallback_access_key = args[0] + fallback_secret_key = args[1] + else: + usage() + + if not fallback_access_key: + print "Copy paste the AWS access key" + + while True: + fallback_access_key = raw_input("ACCESS-KEY: ").strip() + if fallback_access_key: + break + if not fallback_secret_key: + print "Copy paste the AWS secret access key" + + while True: + fallback_secret_key = raw_input("SECRET-KEY: ").strip() + if fallback_secret_key: + break + + registry.registry.fallback_access_key = fallback_access_key + registry.registry.fallback_secret_key = fallback_secret_key + +if __name__ == '__main__': + main() diff --git a/registry.py b/registry.py index 1ac7c2d..444fbfa 100644 --- a/registry.py +++ b/registry.py @@ -67,7 +67,8 @@ class ProfileNotFound(Exception): class Paths(_Paths): files = ['restore.log', 'backup.log', 'backup.pid', 'backup-resume', 'sub_apikey', 'secret', 'key', 'credentials', 'hbr', - 'profile', 'profile/stamp', 'profile/profile_id'] + 'profile', 'profile/stamp', 'profile/profile_id', 'fallback_access_key', + 'fallback_secret_key'] def __init__(self, path=None): if path is None: @@ -115,6 +116,14 @@ def _file_dict(cls, path, d=UNDEFINED): if retval: return AttrDict([ v.split("=", 1) for v in retval.split("\n") ]) + def fallback_access_key(self, val=UNDEFINED): + return self._file_str(self.path.fallback_access_key, val) + fallback_access_key = property(fallback_access_key, fallback_access_key) + + def fallback_secret_key(self, val=UNDEFINED): + return self._file_str(self.path.fallback_secret_key, val) + fallback_secret_key = property(fallback_secret_key, fallback_secret_key) + def sub_apikey(self, val=UNDEFINED): return self._file_str(self.path.sub_apikey, val) sub_apikey = property(sub_apikey, sub_apikey) From 11bc6160bdb0f2e372ef444add580c74fd60204a Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Mon, 8 Oct 2018 04:03:21 +0000 Subject: [PATCH 2/4] Fix cached credentials and use fallback when credentials have expired --- cmd_backup.py | 11 ++++++----- hub.py | 4 ++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cmd_backup.py b/cmd_backup.py index 81cffd2..7ce6619 100755 --- a/cmd_backup.py +++ b/cmd_backup.py @@ -344,6 +344,7 @@ def main(): # But If we already have the credentials we can survive that. if isinstance(e, hub.NotSubscribed) or \ not registry.credentials or \ + (registry.credentials and hub.credentials_expired(registry.credentials)) or \ registry.credentials.type == 'iamrole': # if we don't have cached credentials we might still be # able to use the fallback credentials @@ -351,14 +352,14 @@ def main(): credentials = hub.Credentials.IAMUser( registry.fallback_access_key, registry.fallback_secret_key, - None) + '') + warn("using fallback credentials: " + e.description) else: fatal(e) - elif registry.credentials: + + else: warn("using cached backup credentials: " + e.description) - - - credentials = registry.credentials + credentials = registry.credentials if registry.hbr: try: diff --git a/hub.py b/hub.py index c02790b..2a51f11 100644 --- a/hub.py +++ b/hub.py @@ -208,6 +208,10 @@ def from_dict(cls, d): return(creds_types[creds_type](**kwargs)) +def credentials_expired(credentials): + ''' Checks if credentials object has expired, expects credentials to be non None ''' + return datetime.strptime(credentials['expiration'], '%Y-%m-%dT%H:%M:%SZ') <= datetime.now() + class Backups: API_URL = os.getenv('TKLBAM_APIURL', 'https://hub.turnkeylinux.org/api/backup/') Error = Error From 47c67dfcdd02cd27a515f0e024b456c4635811ae Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Tue, 9 Oct 2018 01:40:41 +0000 Subject: [PATCH 3/4] Updated docs to include information about set-fallback --- docs/tklbam-faq.txt | 7 ++++++ docs/tklbam-set-fallback.txt | 47 ++++++++++++++++++++++++++++++++++++ docs/tklbam.txt | 1 + 3 files changed, 55 insertions(+) create mode 100644 docs/tklbam-set-fallback.txt diff --git a/docs/tklbam-faq.txt b/docs/tklbam-faq.txt index 717d417..cff1ef4 100644 --- a/docs/tklbam-faq.txt +++ b/docs/tklbam-faq.txt @@ -474,6 +474,10 @@ No, for a couple of reasons: 2) You can use TKLBAM without linking it to the Hub at all. See the tklbam-init --solo option. +3) You can setup fallback access keys to your Amazon S3. Even if the Hub goes + down AND your cached credentials become invalidated you're backups can still + function as normal. + If the Hub goes down, will my backup cron jobs still work? ---------------------------------------------------------- @@ -481,6 +485,9 @@ Yes. Backups which have already been configured will continue to work normally. If TKLBAM can't reach the Hub it just uses the locally cached profile and S3 address. +In the event that locally cached credentials become invalidated you can also +setup fallback keys to S3 as an additional protective measure. + If my connection to the Hub goes down, can I still restore? ----------------------------------------------------------- diff --git a/docs/tklbam-set-fallback.txt b/docs/tklbam-set-fallback.txt new file mode 100644 index 0000000..1cfcd83 --- /dev/null +++ b/docs/tklbam-set-fallback.txt @@ -0,0 +1,47 @@ +=================== +tklbam-set-fallback +=================== + +------------ +Set Fallback +------------ + +:Author: Stefan Davis +:Date: 2018-10-09 +:Manual section: 8 +:Manual group: backup + +SYNOPSIS +======== + +tklbam-set-fallback [ `FALLBACK-ACCESS-KEY` ] [ `FALLBACK-SECRET-KEY` ] + +This is used to setup fallback credentials used when access to the Hub is limited +or not possible. + +ARGUMENTS +========= + +`FALLBACK-ACCESS-KEY` Your IAMUser access key +`FALLBACK-SECRET-KEY` Your IAMUser secret access key + +If you do not provide FALLBACK-ACCESS-KEY and/or FALLBACK-SECRET-KEY you will be +prompted for it/them interactively. + +SECURITY WARNING +================ + +Providing your AWS IAMUser credentials as a commandline argument is potentially less secure +than allowing tklbam-set-fallback to prompt you for it interactively. + +* The shell may save the credentials in its history file (e.g. ~/.bash_history) +* The credentials may briefly show up in the process list. + +AWS IAMUser credentials must exist on your system in plaintext as they are intended to work +even when you can only access your AWS bucket and should work automatically without +interaction. + +SEE ALSO +======== + +``tklbam`` (8), ``tklbam-faq`` (7) diff --git a/docs/tklbam.txt b/docs/tklbam.txt index b92b729..7f12833 100644 --- a/docs/tklbam.txt +++ b/docs/tklbam.txt @@ -151,6 +151,7 @@ COMMANDS :list: List backup records :restore: Restore a backup :restore-rollback: Rollback last restore +:set-fallback: Sets additional fallback keys for S3 EXAMPLE USAGE SCENARIO ====================== From 0a6121d458cf4a15f5b20f5f6909c173694e8bf8 Mon Sep 17 00:00:00 2001 From: Stefan Davis Date: Tue, 9 Oct 2018 01:57:49 +0000 Subject: [PATCH 4/4] Rewording and typo fix --- docs/tklbam-faq.txt | 4 ++-- docs/tklbam-set-fallback.txt | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/tklbam-faq.txt b/docs/tklbam-faq.txt index cff1ef4..eebc2c0 100644 --- a/docs/tklbam-faq.txt +++ b/docs/tklbam-faq.txt @@ -474,8 +474,8 @@ No, for a couple of reasons: 2) You can use TKLBAM without linking it to the Hub at all. See the tklbam-init --solo option. -3) You can setup fallback access keys to your Amazon S3. Even if the Hub goes - down AND your cached credentials become invalidated you're backups can still +3) You can setup fallback credentials to your Amazon S3. Even if the Hub goes + down AND your cached credentials become invalidated your backups can still function as normal. If the Hub goes down, will my backup cron jobs still work? diff --git a/docs/tklbam-set-fallback.txt b/docs/tklbam-set-fallback.txt index 1cfcd83..112feab 100644 --- a/docs/tklbam-set-fallback.txt +++ b/docs/tklbam-set-fallback.txt @@ -22,8 +22,8 @@ or not possible. ARGUMENTS ========= -`FALLBACK-ACCESS-KEY` Your IAMUser access key -`FALLBACK-SECRET-KEY` Your IAMUser secret access key +`FALLBACK-ACCESS-KEY` Your IAMUser access key +`FALLBACK-SECRET-KEY` Your IAMUser secret access key If you do not provide FALLBACK-ACCESS-KEY and/or FALLBACK-SECRET-KEY you will be prompted for it/them interactively. @@ -37,9 +37,8 @@ than allowing tklbam-set-fallback to prompt you for it interactively. * The shell may save the credentials in its history file (e.g. ~/.bash_history) * The credentials may briefly show up in the process list. -AWS IAMUser credentials must exist on your system in plaintext as they are intended to work -even when you can only access your AWS bucket and should work automatically without -interaction. +AWS IAMUser credentials exist on your system in plaintext. This is to allow backups to work +seamlessly without interaction. SEE ALSO ========