def kms_connection_for(self, location): if KMSConnection is None: raise SyncrError("Sorry, need python3 to do anything related to kms") if getattr(self, "_kms_connections", None) is None: self._kms_connections = {} if location not in self._kms_connections: try: self._kms_connections[location] = boto.kms.connect_to_region(location) except boto.exception.NoAuthHandlerFound: raise SyncrError("Export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY before running this script (your aws credentials)") return self._kms_connections[location]
def s3_connection(self): if getattr(self, "_s3_connection", None) is None: try: self._s3_connection = S3Connection() except boto.exception.NoAuthHandlerFound: raise SyncrError("Export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY before running this script (your aws credentials)") return self._s3_connection
def add(self, configuration, location, only_consider=None): """Add a new configuration""" if not self.types: raise SyncrError("Syncr doesn't know about anything, try syncr.register_default_types() first") if not isinstance(configuration, dict): raise InvalidConfiguration("Configuration needs to be a dict", found=type(configuration)) for name in self.types: if not only_consider or name in only_consider: if name in configuration: self.configurations[name].append((location, configuration[name]))
def accounts_from(location): """Get the accounts dictionary""" if not os.path.exists(location): raise SyncrError("Could not find an accounts.yaml", location=location) if not os.access(location, os.R_OK): raise SyncrError("Could not read the accounts.yaml", location=location) try: accounts = yaml.load(open(location)) except yaml.parser.ParserError as error: raise SyncrError("Failed to parse the accounts yaml file", location=location, error_typ=error.__class__.__name__, error=error) for account_id in list(accounts.values()): if account_id not in accounts: accounts[account_id] = account_id return accounts
def setup(self): """Make sure our current credentials are for this account and set self.connection""" try: connection = IAMConnection() except boto.exception.NoAuthHandlerFound: raise SyncrError("Export AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY before running this script (your aws credentials)") # Need roles to make sure we have the correct account log.info("Finding roles in your account") try: result = connection.list_roles() except boto.exception.BotoServerError as error: if error.status == 403: raise SyncrError("Your credentials aren't allowed to look at iam roles :(") else: raise roles = self.all_roles = result["list_roles_response"]["list_roles_result"]["roles"] if not roles: raise SyncrError("There are no roles in your account, I can't figure out the account id") # Need users for kms to be able to grant to users log.info("Finding users in your account") try: result = connection.get_all_users() except boto.exception.BotoServerError as error: if error.status == 403: raise SyncrError("Your credentials aren't allowed to look at iam users :(") else: raise self.all_users = result["list_users_response"]["list_users_result"]["users"] amazon_account_id = roles[0]['arn'].split(":")[4] if str(self.account_id) != str(amazon_account_id): raise SyncrError("Please use credentials for the right account", expect=self.account_id, got=amazon_account_id) # If reached this far, the credentials belong to the correct account :) self.connection = connection return connection
def make_amazon(folder, accounts_location=None, dry_run=False): """Find the account we're using and return a setup Amazon object""" if not accounts_location: accounts_location = os.path.join(folder, '..', 'accounts.yaml') accounts = accounts_from(accounts_location) account_name = os.path.basename(folder) if account_name not in accounts: raise SyncrError("Please add this account to accounts.yaml", accounts_yaml_location=accounts_location, account_name=account_name) account_id = accounts[account_name] amazon = Amazon(account_id, account_name, accounts, dry_run=dry_run) amazon.setup() return amazon
def setup(self): """Raise errors if the definition doesn't make sense""" self.tags = self.definition.get("tags", {}) if type(self.tags) != dict or any( not isinstance(tag_name, six.string_types) or not isinstance(tag_val, six.string_types) for tag_name, tag_val in self.tags.items()): raise SyncrError( "Bucket tags should be a dictionary of {<string> : <string>}", got=self.tags) self.location = self.definition.get("location", "ap-southeast-2") for key, default_allow in (("permission", None), ("allow_permission", True), ("deny_permission", False)): for policy in listified(self.definition, key): for statement in self.statements.make_permission_statements( policy, allow=default_allow): self.permission.append(statement)
def do_sync(amazon, found, only_consider=None): """Sync the configuration from this folder""" try: parsed = parse_configurations(found) except BadConfiguration as err: log.error("Failed to parse all the yaml specifications") for _, error in sorted(err.kwargs["parse_errors"].items()): log.error(error) raise BadConfiguration() sync = Sync(amazon) sync.register_default_types() if only_consider: dont_consider = [ considering for considering in only_consider if considering not in sync.types ] if dont_consider: raise SyncrError("Told to sync unknown types", only_sync=list(sync.types.keys()), unknown_types=dont_consider) for location, configuration in sorted(parsed.items()): sync.add(configuration, location, only_consider) try: log.info("Combining configuration") combined = sync.combine_configurations() except BadConfiguration as err: log.error("Your configuration didn't make sense") for error in err.kwargs["errors"]: log.error(error) raise BadConfiguration() log.info("Starting sync") sync.sync(combined)