Exemple #1
0
    def main(self, cmd_args):
        """change what IAM group an IAM user is a part of"""
        iam_client = aws.iam_client()
        path_prefix = f"/{consts.NAMESPACE}/"
        user_name = aws.validate_user_exists(path_prefix, cmd_args.name)
        group_name = aws.validate_group_exists(path_prefix, cmd_args.group)

        old_group_names = [old_group['GroupName'] for old_group
            in iam_client.list_groups_for_user(UserName=user_name)['Groups']]
        if group_name in old_group_names and len(old_group_names) == 1:
            halt.err(f"{user_name} is already in the {group_name} IAM group.")

        if group_name not in old_group_names:
            iam_client.add_user_to_group(
                GroupName=group_name,
                UserName=user_name
            )
        for old_group_name in old_group_names:
            if old_group_name != group_name:
                iam_client.remove_user_from_group(
                    GroupName=old_group_name,
                    UserName=user_name
                )

        print("")
        print(f"{user_name}'s group set to the {group_name} IAM group.")
def _validate_user(config_dict):
    """validate config's IAM user access key and minimal permissions

    iam:GetUser, iam:SimulatePrincipalPolicy, iam:GetAccessKeyLastUsed, and
    ec2:DescribeRegions permissions required for successful validation.

    Args:
        config_dict (dict): Should contain config's IAM user access key.
            'access_key' (dict): IAM user's access key.
                Access key ID (str): Secret access key.
    """
    consts.KEY_ID = next(iter(config_dict['access_key']))
    consts.KEY_SECRET = config_dict['access_key'][consts.KEY_ID]

    # IAM User access key must be validated before validate_perms can be used.
    try:
        iam_user = aws.iam_client().get_user()['User']
    except ClientError as e:
        # TODO: Use client exceptions instead once they're documented
        if e.response['Error']['Code'] == "InvalidClientTokenId":
            halt.err("Access key ID is invalid.")
        elif e.response['Error']['Code'] == "SignatureDoesNotMatch":
            halt.err("Access key ID is valid, but its secret is invalid.")
        elif e.response['Error']['Code'] == "AccessDenied":
            halt.assert_empty(["iam:GetUser"])
        halt.err(str(e))

    # This ARN is needed for iam:SimulatePrincipalPolicy action.
    consts.IAM_ARN = iam_user['Arn']
    consts.IAM_NAME = iam_user['UserName']

    # Validate IAM user can use iam:SimulatePrincipalPolicy action.
    try:
        validate_perms.blocked(actions=["iam:GetUser"])
    except ClientError as e:
        if e.response['Error']['Code'] == "AccessDenied":
            halt.assert_empty(["iam:SimulatePrincipalPolicy"])
        halt.err(str(e))

    # Validate IAM user can use other basic permissions needed for the script
    halt.assert_empty(
        validate_perms.blocked(
            actions=["iam:GetAccessKeyLastUsed", "ec2:DescribeRegions"]))
Exemple #3
0
    def main(self, cmd_args):
        """create a new IAM user under an IAM group"""
        iam_client = aws.iam_client()
        path_prefix = f"/{consts.NAMESPACE}/"
        aws.validate_group_exists(path_prefix, cmd_args.group)

        # IAM user created and added to group (given the name is unique)
        try:
            iam_client.create_user(Path=path_prefix, UserName=cmd_args.name)
        except ClientError as e:
            if e.response['Error']['Code'] == "EntityAlreadyExists":
                halt.err(f"IAM user \"{cmd_args.name}\" already exists.")
            halt.err(str(e))
        iam_client.add_user_to_group(GroupName=cmd_args.group,
                                     UserName=cmd_args.name)

        print("")
        print(f"IAM user \"{cmd_args.name}\" created on AWS.")

        # IAM user access key generated and saved to dictionary
        new_key = iam_client.create_access_key(
            UserName=cmd_args.name)['AccessKey']
        new_key = {new_key['AccessKeyId']: new_key['SecretAccessKey']}
        self._access_key_usable_waiter(new_key)

        config_dict = os2.parse_json(consts.CONFIG_JSON)
        if 'backup_keys' not in config_dict:
            config_dict['backup_keys'] = {}

        if cmd_args.default:
            # Modify existing config instead of creating new one
            config_dict['backup_keys'].update(config_dict['access_key'])
            config_dict['access_key'] = new_key
            os2.save_json(config_dict, consts.CONFIG_JSON)
            print("  User's access key set as default in config.")
        else:
            # Back up new IAM user's access key in config file
            config_dict['backup_keys'].update(new_key)
            os2.save_json(config_dict, consts.CONFIG_JSON)

            os2.create_configuration_zip(cmd_args.name, new_key,
                                         cmd_args.ssh_key)
            print("  User's zipped configuration created in config.")
def blocked(actions: List[str],
            resources: Optional[List[str]] = None,
            context: Optional[Dict[str, List]] = None) -> List[str]:
    """test whether IAM user is able to use specified AWS action(s)

    Args:
        actions (list): AWS action(s) to validate IAM user can use.
        resources (list): Check if action(s) can be used on resource(s).
            If None, action(s) must be usable on all resources ("*").
        context (dict): Check if action(s) can be used with context(s).
            If None, it is expected that no context restrictions were set.

    Returns:
        list: Actions denied by IAM due to insufficient permissions.
    """
    if not actions:
        return []
    actions = list(set(actions))

    if resources is None:
        resources = ["*"]

    _context: List[Dict] = [{}]
    if context is not None:
        # Convert context dict to list[dict] expected by ContextEntries.
        _context = [{
            'ContextKeyName': context_key,
            'ContextKeyValues': [str(val) for val in context_values],
            'ContextKeyType': "string"
        } for context_key, context_values in context.items()]

    results = aws.iam_client().simulate_principal_policy(
        PolicySourceArn=consts.IAM_ARN,
        ActionNames=actions,
        ResourceArns=resources,
        ContextEntries=_context)['EvaluationResults']

    return sorted([
        result['EvalActionName'] for result in results
        if result['EvalDecision'] != "allowed"
    ])
Exemple #5
0
    def main(self, cmd_args):
        """list IAM groups and their IAM users"""
        iam_client = aws.iam_client()
        path_prefix = f"/{consts.NAMESPACE}/"

        iam_group_names = [iam_group['GroupName'] for iam_group
            in iam_client.list_groups(PathPrefix=path_prefix)['Groups']]
        if not iam_group_names:
            halt.err("No namespace IAM groups found from AWS.",
                "  Have you uploaded the AWS setup?")

        print("")
        print(f"{len(iam_group_names)} IAM group(s) found from AWS:")
        for group_name in iam_group_names:
            group_users = iam_client.get_group(GroupName=group_name)['Users']
            if group_users:
                print(f"{group_name}: {len(group_users)} user(s) in group:")
                for group_user in group_users:
                    print(f"  {group_user['UserName']}")
            else:
                print(f"{group_name}: 0 users in group.")
Exemple #6
0
 def __init__(self, config_aws_setup):
     self._iam_client = aws.iam_client()
     self._path_prefix = f"/{consts.NAMESPACE}/"
     # Local IAM group setup information (names and attached policies)
     self._iam_group_setup = config_aws_setup['IAM']['Groups']
Exemple #7
0
 def __init__(self, cmd_args):
     self._iam_client = aws.iam_client()
Exemple #8
0
 def __init__(self, config_aws_setup):
     self._iam_client = aws.iam_client()
     self._policy_dir = consts.AWS_SETUP_DIR / "iam_policies"
     self._path_prefix = f"/{consts.NAMESPACE}/"
     # Local IAM policy setup information (names and descriptions)
     self._iam_policy_setup = config_aws_setup['IAM']['Policies']