def setup(self): """Raise errors if the definition doesn't make sense""" self.location = self.definition.get("location") self.description = self.definition.get("description") self.connection = self.amazon.kms_connection_for(self.location) if not self.description: raise BadPolicy("Please define a description", key=self.name) if "admin_users" in self.definition: policy = { "principal": self.definition["admin_users"], "action": "kms:*", "resource": { "kms": "__self__" }, "Sid": "" } for statement in self.statements.make_permission_statements( policy, allow=True): self.permission.append(statement) 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) for policy in listified(self.definition, "grant"): if not isinstance(policy, dict): raise BadPolicy( "Grant must be a dictionary of atleast {grantee, operations}", got=policy, key=self.name) if "grantee" not in policy and "operations" not in policy: raise BadPolicy( "Grant must be a dictionary of atleast {grantee, operations}", got=list(policy.keys()), key=self.name) policy['grantee'] = list( self.statements.iam_arns_from_specification(policy['grantee'])) if 'retiree' in policy: policy['retiree'] = list( self.statements.iam_arns_from_specification( policy['retiree'])) for thing in ('grantee', 'retiree'): if thing in policy: if len(policy[thing]) > 1: raise BadPolicy("Can only have one {0}".format(thing), got=len(policy[thing]), key=self.name) policy[thing] = policy[thing][0] self.grant.append(policy)
def make_permission_statements(self, policy, allow=None): """ Make zero or more permissions statements from a policy definition If allow is None and no allow or Effect is specified, an error is raised Otherwise we assume the truthiness of allow """ result = dict((key, val) for key, val in policy.items() if key[0].isupper()) if allow is None and "Effect" not in policy: if not isinstance(policy.get("allow"), bool): raise BadPolicy("Need to specify whether we allow this policy or not", policy=policy, **{self.self_type:self.name}) result["Effect"] = ["Deny", "Allow"][policy["allow"]] elif allow is not None: result["Effect"] = ["Deny", "Allow"][allow] for key, dest in (("action", "Action"), ("notaction", "NotAction")): for specified in listified(policy, key): listify(result, dest).append(specified) for key, dest in (("resource", "Resource"), ("notresource", "NotResource")): for specified in listified(policy, key): listify(result, dest).extend(self.fill_out_resources(specified)) self.expand_principal(policy, result) if "Resource" not in result and "NotResource" not in result: raise BadPolicy("No Resource or NotResource was defined for policy", policy=policy, **{self.self_type:self.name}) if "Action" not in result and "NotAction" not in result: raise BadPolicy("No Action or NotAction defined for this policy", policy=policy, **{self.self_type:self.name}) if "Sid" not in result and self.self_type == "bucket": result["Sid"] = "" # Amazon gets rid of the lists if only one item # And this mucks around with the diffing.... for thing in ("Action", "NotAction", "Resource", "NotResource"): if thing in result: if len(listify(result, thing)) == 1: result[thing] = result[thing][0] else: result[thing] = sorted(result[thing]) yield result
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 expand_principal(self, statement, result): """Expand out Principal and NotPrincipal""" for principal, capd in [("principal", "Principal"), ("notprincipal", "NotPrincipal")]: if principal in statement: if capd not in result: result[capd] = {} looking_at = statement[principal] if not isinstance(looking_at, list): looking_at = [looking_at] for instruction in looking_at: principal = result[capd] for specified in listified(instruction, "service"): if specified == "ec2": specified = "ec2.amazonaws.com" listify(principal, "Service").append(specified) for specified in listified(instruction, "federated"): listify(principal, "Federated").extend(self.iam_arns_from_specification(specified)) if "Action" not in result: result["Action"] = "sts:AssumeRoleWithSAML" if "iam" in instruction: listify(principal, "AWS").extend(self.iam_arns_from_specification(instruction)) # Amazon gets rid of the lists if only one item # And this mucks around with the diffing.... for princ in (result.get("Principal"), result.get("NotPrincipal")): if princ: for principal_type in ("AWS", "Federated", "Service"): if principal_type in princ: if len(listify(princ, principal_type)) == 1: princ[principal_type] = princ[principal_type][0] else: princ[principal_type] = sorted(princ[principal_type])
def setup(self): """Raise errors if the definition doesn't make sense""" self.location = self.definition.get("location") self.description = self.definition.get("description") self.connection = self.amazon.kms_connection_for(self.location) if not self.description: raise BadPolicy("Please define a description", key=self.name) if "admin_users" in self.definition: policy = {"principal": self.definition["admin_users"], "action": "kms:*", "resource": { "kms": "__self__" }, "Sid": ""} for statement in self.statements.make_permission_statements(policy, allow=True): self.permission.append(statement) 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) for policy in listified(self.definition, "grant"): if not isinstance(policy, dict): raise BadPolicy("Grant must be a dictionary of atleast {grantee, operations}", got=policy, key=self.name) if "grantee" not in policy and "operations" not in policy: raise BadPolicy("Grant must be a dictionary of atleast {grantee, operations}", got=list(policy.keys()), key=self.name) policy['grantee'] = list(self.statements.iam_arns_from_specification(policy['grantee'])) if 'retiree' in policy: policy['retiree'] = list(self.statements.iam_arns_from_specification(policy['retiree'])) for thing in ('grantee', 'retiree'): if thing in policy: if len(policy[thing]) > 1: raise BadPolicy("Can only have one {0}".format(thing), got=len(policy[thing]), key=self.name) policy[thing] = policy[thing][0] self.grant.append(policy)
def setup(self): """Raise errors if the definition doesn't make sense""" if "use" in self.definition: template = self.definition["use"] if not self.templates: raise NoTemplates(name=self.name, looking_for_template=template, available=self.templates.keys()) if template not in self.templates: raise CantFindTemplate(name=self.name, looking_for_template=template, available=self.templates.keys()) self.definition = MergedOptions.using(self.templates[template], self.definition) self.description = self.definition.get("description", "No description provided!") for statement in listified(self.definition, "allow_to_assume_me"): self.trust.extend(self.statements.expand_trust_statement(statement, allow=True)) for statement in listified(self.definition, "disallow_to_assume_me"): self.distrust.extend(self.statements.expand_trust_statement(statement, allow=False)) 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 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 iam_arns_from_specification(self, specification): """Get us an iam arn from this specification""" if not isinstance(specification, list): specification = [specification] for spec in specification: if isinstance(spec, six.string_types): yield spec else: provided_accounts = spec.get("account", "") if not isinstance(provided_accounts, list): provided_accounts = [provided_accounts] for provided_account in provided_accounts: if provided_account: if provided_account not in self.accounts: raise BadPolicy("Unknown account specified", account=provided_account, specification=spec) else: account_id = self.accounts[provided_account] else: account_id = self.account_id users = spec.get("users", []) for name in listified(spec, "iam"): if name == "__self__": if self.self_type == 'bucket': raise BadPolicy("Bucket policy has no __self__ iam role", bucket=self.name) account_id = self.account_id name = "role/{0}".format(self.name) service = "sts" if name.startswith("assumed-role") else "iam" arn = "arn:aws:{0}::{1}:{2}".format(service, account_id, name) if not users: yield arn else: for user in users: yield "{0}/{1}".format(arn, user)
it "returns the key as is if already a list": lst = [1, 2] dct = {"blah": lst} self.assertIs(listify(dct, "blah"), lst) self.assertEqual(dct, {"blah": lst}) it "makes the key a list and returns if in there but not a list already": for val in (0, 1, None, True, False, "", "adf", lambda: 1, mock.Mock(name="blah")): dct = {"blah": val} lst = listify(dct, "blah") self.assertEqual(lst, [val]) self.assertEqual(dct, {"blah": lst}) describe TestCase, "listified": it "yields nothing if the key isn't in the dict": self.assertEqual(list(listified({"meh": 1}, "blah")), []) it "yields the thing if the thing is not a list": for val in (0, 1, None, True, False, "", "adf", lambda: 1, mock.Mock(name="blah")): self.assertEqual(list(listified({"blah": val}, "blah")), [val]) it "yields the items in the thing if the thing is a list": item1 = 3 item2 = 1 item3 = 2 lst = [item1, item2, item3] self.assertEqual(list(listified({"blah": lst}, "blah")), [item1, item2, item3]) describe TestCase, "as_list": it "yields the things in the thing if it's a list": lst = [1, 2]