Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback key #4

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
'',
Expand Down
21 changes: 15 additions & 6 deletions cmd_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,15 +342,24 @@ 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 and hub.credentials_expired(registry.credentials)) or \
registry.credentials.type == 'iamrole':
fatal(e)

warn("using cached backup credentials: " + e.description)

credentials = registry.credentials
# 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,
'')
warn("using fallback credentials: " + e.description)
else:
fatal(e)

else:
warn("using cached backup credentials: " + e.description)
credentials = registry.credentials

if registry.hbr:
try:
Expand Down
1 change: 1 addition & 0 deletions cmd_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
95 changes: 95 additions & 0 deletions cmd_set_fallback.py
Original file line number Diff line number Diff line change
@@ -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()
7 changes: 7 additions & 0 deletions docs/tklbam-faq.txt
Original file line number Diff line number Diff line change
Expand Up @@ -474,13 +474,20 @@ 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 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?
----------------------------------------------------------

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?
-----------------------------------------------------------

Expand Down
46 changes: 46 additions & 0 deletions docs/tklbam-set-fallback.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
===================
tklbam-set-fallback
===================

------------
Set Fallback
------------

:Author: Stefan Davis <[email protected]>
: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 exist on your system in plaintext. This is to allow backups to work
seamlessly without interaction.

SEE ALSO
========

``tklbam`` (8), ``tklbam-faq`` (7)
1 change: 1 addition & 0 deletions docs/tklbam.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
======================
Expand Down
4 changes: 4 additions & 0 deletions hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 10 additions & 1 deletion registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down