Example #1
0
def display_provisioned_ou(org_client,
                           log,
                           deployed_ou,
                           parent_name,
                           indent=0):
    """
    Recursive function to display the deployed AWS Organization structure.
    """
    # query aws for child orgs
    parent_id = lookup(deployed_ou, 'Name', parent_name, 'Id')
    child_ou_list = lookup(deployed_ou, 'Name', parent_name, 'Child_OU')
    child_accounts = lookup(deployed_ou, 'Name', parent_name, 'Accounts')
    # display parent ou name
    tab = '  '
    log.info(tab * indent + parent_name + ':')
    # look for policies
    policy_names = list_policies_in_ou(org_client, parent_id)
    if len(policy_names) > 0:
        log.info(tab * indent + tab + 'Policies: ' + ', '.join(policy_names))
    # look for accounts
    account_list = sorted(child_accounts)
    if len(account_list) > 0:
        log.info(tab * indent + tab + 'Accounts: ' + ', '.join(account_list))
    # look for child OUs
    if child_ou_list:
        log.info(tab * indent + tab + 'Child_OU:')
        indent += 2
        for ou_name in child_ou_list:
            # recurse
            display_provisioned_ou(org_client, log, deployed_ou, ou_name,
                                   indent)
Example #2
0
def manage_ou(org_client, args, log, deployed, ou_spec_list, parent_name):
    """
    Recursive function to manage OrganizationalUnits in the AWS
    Organization.
    """
    for ou_spec in ou_spec_list:

        # ou exists
        ou = lookup(deployed['ou'], 'Name', ou_spec['Name'])
        if ou:

            # check for child_ou. recurse before other tasks.
            if 'Child_OU' in ou_spec:
                manage_ou(org_client, args, log, deployed, ou_spec['Child_OU'],
                          ou_spec['Name'])

            # check if ou 'absent'
            if ensure_absent(ou_spec):
                # error if ou contains anything
                for key in ['Accounts', 'Policies', 'Child_OU']:
                    if key in ou and ou[key]:
                        msg = (
                            "Can not delete OU '%s'. deployed '%s' exists." %
                            (ou_spec['Name'], key))
                        raise RuntimeError(msg)

                # delete ou
                log.info("Deleting OU %s" % ou_spec['Name'])
                if args['--exec']:
                    org_client.delete_organizational_unit(
                        OrganizationalUnitId=ou['Id'])

            else:
                manage_policy_attachments(org_client, args, log,
                                          deployed['policies'], ou_spec,
                                          ou['Id'])
                manage_account_moves(org_client, args, log,
                                     deployed['accounts'], ou_spec, ou['Id'])

        elif not ensure_absent(ou_spec):
            # ou does not exist
            log.info("Creating new OU '%s' under parent '%s'" %
                     (ou_spec['Name'], parent_name))
            if args['--exec']:
                new_ou = org_client.create_organizational_unit(
                    ParentId=lookup(deployed['ou'], 'Name', parent_name, 'Id'),
                    Name=ou_spec['Name'])['OrganizationalUnit']
                manage_policy_attachments(org_client, args, log,
                                          deployed['policies'], ou_spec,
                                          new_ou['Id'])
                manage_account_moves(org_client, args, log,
                                     deployed['accounts'], ou_spec,
                                     new_ou['Id'])
                if ('Child_OU' in ou_spec and isinstance(new_ou, dict)
                        and 'Id' in new_ou):
                    # recurse
                    manage_ou(org_client, args, log, deployed,
                              ou_spec['Child_OU'], new_ou['Name'])
Example #3
0
def display_provisioned_accounts(log, deployed_accounts):
    """
    Print report of currently deployed accounts in AWS Organization.
    """
    header = "Provisioned Accounts in Org:"
    overbar = '_' * len(header)
    log.info("\n%s\n%s" % (overbar, header))
    for a_name in sorted(map(lambda a: a['Name'], deployed_accounts)):
        a_id = lookup(deployed_accounts, 'Name', a_name, 'Id')
        a_email = lookup(deployed_accounts, 'Name', a_name, 'Email')
        spacer = ' ' * (24 - len(a_name))
        log.info("%s%s%s\t\t%s" % (a_name, spacer, a_id, a_email))
Example #4
0
def display_provisioned_groups(credentials, log, deployed):
    """
    Print report of currently deployed IAM groups in Auth account.
    List group memebers, attached policies and delegation assume role
    profiles.
    """
    iam_resource = boto3.resource('iam', **credentials)
    header = "Provisioned IAM Groups in Auth Account:"
    overbar = '_' * len(header)
    log.info("\n\n%s\n%s" % (overbar, header))
    for name in sorted(map(lambda g: g['GroupName'], deployed['groups'])):
        group = iam_resource.Group(name)
        members = list(group.users.all())
        attached_policies = list(group.attached_policies.all())
        assume_role_resources = [p.policy_document['Statement'][0]['Resource']
                for p in list(group.policies.all()) if
                p.policy_document['Statement'][0]['Action'] == 'sts:AssumeRole']
        log.info("\n%s\t%s" % ('Name:', name))
        log.info("%s\t%s" % ('Arn:', group.arn))
        if members:
            log.info("Members:")
            log.info("\n".join(["  %s" % u.name for u in members]))
        if attached_policies:
            log.info("Policies:")
            log.info("\n".join(["  %s" % p.arn for p in attached_policies]))
        if assume_role_resources:
            log.info("Assume role profiles:")
            log.info("  Account\tRole ARN")
            profiles = {}
            for role_arn in assume_role_resources:
                account_name = lookup(deployed['accounts'], 'Id',
                        role_arn.split(':')[4], 'Name')
                profiles[account_name] =  role_arn
            for account_name in sorted(profiles.keys()):
                log.info("  %s:\t%s" % (account_name, profiles[account_name]))
Example #5
0
def manage_delegations(args, log, deployed, auth_spec):
    """
    Create and manage cross account access delegations based on 
    delegation specifications.  Manages delegation roles in 
    trusting accounts and group policies in Auth (trusted) account.
    """
    for d_spec in auth_spec['delegations']:
        if not validate_delegation_spec(args, log, d_spec):
            log.error("Delegation spec for '%s' invalid" % d_spec['RoleName'])
            return
        if d_spec['RoleName'] == auth_spec['org_access_role']:
            log.error("Refusing to manage delegation '%s'" % d_spec['RoleName'])
            return
        # process roles in trusting accounts
        if d_spec['TrustingAccount'] != 'ALL':
            for account_name in d_spec['TrustingAccount']:
                if not lookup(deployed['accounts'], 'Name', account_name):
                    log.error("Can not create delegation role '%s' in account "
                            "'%s'.  Account '%s' not found in Org" %
                            (d_spec['RoleName'], account_name, account_name))
        for account in deployed['accounts']:
            credentials = get_assume_role_credentials(
                    account['Id'],
                    auth_spec['org_access_role'])
            manage_delegation_role(credentials, args, log,
                    deployed, auth_spec, account['Name'], d_spec)
        # process groups in Auth account
        set_group_assume_role_policies(args, log, deployed, auth_spec, d_spec)
Example #6
0
def place_unmanged_accounts(org_client, args, log, deployed, account_list,
                            dest_parent):
    """
    Move any unmanaged accounts into the default OU.
    """
    for account in account_list:
        account_id = lookup(deployed['accounts'], 'Name', account, 'Id')
        dest_parent_id = lookup(deployed['ou'], 'Name', dest_parent, 'Id')
        source_parent_id = get_parent_id(org_client, account_id)
        if dest_parent_id and dest_parent_id != source_parent_id:
            log.info("Moving unmanged account '%s' to default OU '%s'" %
                     (account, dest_parent))
            if args['--exec']:
                org_client.move_account(AccountId=account_id,
                                        SourceParentId=source_parent_id,
                                        DestinationParentId=dest_parent_id)
Example #7
0
def manage_policies(org_client, args, log, deployed_policies, policy_spec):
    """
    Manage Service Control Policies in the AWS Organization.  Make updates
    according to the policy specification ('policy_spec').  Do not touch
    the default policy.  Do not delete an attached policy.
    """
    for p_spec in policy_spec:
        policy_name = p_spec['Name']
        # dont touch default policy
        if not policy_name == args['default_policy']:
            policy_id = lookup(deployed_policies, 'Name', policy_name, 'Id')
            # policy already exists
            if policy_id:
                # check if we need to delete policy
                if ensure_absent(p_spec):
                    log.info("Deleting policy '%s'" % (policy_name))
                    # dont delete attached policy
                    if org_client.list_targets_for_policy(
                            PolicyId=policy_id)['Targets']:
                        log.error(
                            "Cannot delete policy '%s'. Still attached to OU" %
                            (policy_name))
                    elif args['--exec']:
                        org_client.delete_policy(PolicyId=policy_id)
                # check for policy updates
                elif (p_spec['Description'] != lookup(deployed_policies, 'Id',
                                                      policy_id, 'Description')
                      or specify_policy_content(p_spec) != get_policy_content(
                          org_client, policy_id)):
                    log.info("Updating policy '%s'" % (policy_name))
                    if args['--exec']:
                        org_client.update_policy(
                            PolicyId=policy_id,
                            Content=specify_policy_content(p_spec),
                            Description=p_spec['Description'],
                        )
            # create new policy
            elif not ensure_absent(p_spec):
                log.info("Creating policy '%s'" % (policy_name))
                if args['--exec']:
                    org_client.create_policy(
                        Content=specify_policy_content(p_spec),
                        Description=p_spec['Description'],
                        Name=p_spec['Name'],
                        Type='SERVICE_CONTROL_POLICY')
Example #8
0
def manage_custom_policy(iam_client, policy_name, args, log, auth_spec):
    """
    Create or update a custom IAM policy in an account based on
    a policy specification.  Returns the policy arn.
    """
    p_spec = lookup(auth_spec['custom_policies'], 'PolicyName', policy_name)
    if not p_spec:
        log.error("Custom Policy spec for '%s' not found in auth-spec." %
                policy_name)
        log.error("Policy creation failed.")
        return None
    if not validate_policy_spec(args, log, p_spec):
        log.error("Custom Policy spec for '%' invalid." % policy_name)
        log.error("Policy creation failed.")
        return None
    policy_doc = json.dumps(dict(
            Version='2012-10-17',
            Statement=p_spec['Statement']))
    custom_policies = iam_client.list_policies(Scope='Local')['Policies']
    policy = lookup(custom_policies, 'PolicyName', policy_name)
    if not policy:
        log.info("Creating custom policy '%s'." % policy_name)
        if args['--exec']:
            return iam_client.create_policy(
                PolicyName=p_spec['PolicyName'],
                Path=munge_path(auth_spec['default_path'], p_spec),
                Description=p_spec['Description'],
                PolicyDocument=policy_doc)['Policy']['Arn']
        return None
    else:
        current_doc = iam_client.get_policy_version(
                PolicyArn=policy['Arn'],
                VersionId=policy['DefaultVersionId']
                )['PolicyVersion']['Document']
        if json.dumps(current_doc) != policy_doc:
            log.info("Updating custom policy '%s'." % policy_name)
            if args['--exec']:
                iam_client.create_policy_version(
                        PolicyArn=policy['Arn'],
                        PolicyDocument=policy_doc,
                        SetAsDefault=True)
        return policy['Arn']
Example #9
0
def display_provisioned_users(log, deployed):
    """
    Print report of currently deployed IAM users in Auth account.
    """
    header = "Provisioned IAM Users in Auth Account:"
    overbar = '_' * len(header)
    log.info("\n%s\n%s\n" % (overbar, header))
    for name in sorted([u['UserName'] for u in deployed['users']]):
        arn = lookup(deployed['users'], 'UserName', name, 'Arn')
        spacer = ' ' * (12 - len(name))
        log.info("%s%s\t%s" % (name, spacer, arn))
Example #10
0
def create_accounts(org_client, args, log, deployed_accounts, account_spec):
    """
    Compare deployed_accounts to list of accounts in the accounts spec.
    Create accounts not found in deployed_accounts.
    """
    for a_spec in account_spec['accounts']:
        if not lookup(deployed_accounts, 'Name', a_spec['Name'],):
            # check if it is still being provisioned
            created_accounts = scan_created_accounts(org_client)
            if lookup(created_accounts, 'AccountName', a_spec['Name']):
                log.warn("New account '%s' is not yet available" %
                        a_spec['Name'])
                break
            # create a new account
            log.info("Creating account '%s'" % (a_spec['Name']))
            if args['--exec']:
                new_account = org_client.create_account(
                        AccountName=a_spec['Name'], Email=a_spec['Email'])
                create_id = new_account['CreateAccountStatus']['Id']
                log.info("CreateAccountStatus Id: %s" % (create_id))
                # validate creation status
                counter = 0
                maxtries = 5
                while counter < maxtries:
                    creation = org_client.describe_create_account_status(
                            CreateAccountRequestId=create_id
                            )['CreateAccountStatus']
                    if creation['State'] == 'IN_PROGRESS':
                        time.sleep(5)
                        log.info("Account creation in progress for '%s'" %
                                a_spec['Name'])
                    elif creation['State'] == 'SUCCEEDED':
                        log.info("Account creation succeeded")
                        break
                    elif creation['State'] == 'FAILED':
                        log.error("Account creation failed: %s" %
                                creation['FailureReason'])
                        break
                    counter += 1
                if counter == maxtries and creation['State'] == 'IN_PROGRESS':
                     log.warn("Account creation still pending. Moving on!")
Example #11
0
def manage_group_policies(credentials, args, log, deployed, auth_spec):
    """
    Attach managed policies to groups based on group specification
    """
    iam_client = boto3.client('iam', **credentials)
    iam_resource = boto3.resource('iam', **credentials)
    auth_account = lookup(deployed['accounts'], 'Id',
            auth_spec['auth_account_id'], 'Name')
    for g_spec in auth_spec['groups']:
        if ('Policies' in g_spec and g_spec['Policies']
                and not ensure_absent(g_spec)
                and lookup(deployed['groups'], 'GroupName', g_spec['Name'])):
            group = iam_resource.Group(g_spec['Name'])
            attached_policies = [p.policy_name for p
                    in list(group.attached_policies.all())]
            # attach missing policies
            for policy_name in g_spec['Policies']:
                if not policy_name in attached_policies:
                    policy_arn = get_policy_arn(iam_client, policy_name, args,
                            log, auth_spec)
                    log.info("Attaching policy '%s' to group '%s' in "
                            "account '%s'." % (policy_name, g_spec['Name'],
                            auth_account))
                    if args['--exec']:
                        group.attach_policy(PolicyArn=policy_arn)
                elif lookup(auth_spec['custom_policies'], 'PolicyName',
                        policy_name):
                    policy_arn = get_policy_arn(iam_client, policy_name, args,
                            log, auth_spec)
            # datach obsolete policies
            for policy_name in attached_policies:
                if not policy_name in g_spec['Policies']:
                    policy_arn = get_policy_arn(iam_client, policy_name, args,
                            log, auth_spec)
                    log.info("Detaching policy '%s' from group '%s' in "
                            "account '%s'." % (policy_name, g_spec['Name'],
                            auth_account))
                    if args['--exec']:
                        group.detach_policy(PolicyArn=policy_arn)
Example #12
0
def manage_policy_attachments(org_client, args, log, deployed_policies,
                              ou_spec, ou_id):
    """
    Attach or detach specified Service Control Policy to a deployed 
    OrganizatinalUnit.  Do not detach the default policy ever.
    """
    # create lists policies_to_attach and policies_to_detach
    attached_policy_list = list_policies_in_ou(org_client, ou_id)
    if 'Policies' in ou_spec and isinstance(ou_spec['Policies'], list):
        spec_policy_list = ou_spec['Policies']
    else:
        spec_policy_list = []
    policies_to_attach = [
        p for p in spec_policy_list if p not in attached_policy_list
    ]
    policies_to_detach = [
        p for p in attached_policy_list
        if p not in spec_policy_list and p != args['default_policy']
    ]
    # attach policies
    for policy_name in policies_to_attach:
        if not lookup(deployed_policies, 'Name', policy_name):
            raise RuntimeError("spec-file: ou_spec: policy '%s' not defined" %
                               policy_name)
        if not ensure_absent(ou_spec):
            log.info("Attaching policy '%s' to OU '%s'" %
                     (policy_name, ou_spec['Name']))
            if args['--exec']:
                org_client.attach_policy(PolicyId=lookup(
                    deployed_policies, 'Name', policy_name, 'Id'),
                                         TargetId=ou_id)
    # detach policies
    for policy_name in policies_to_detach:
        log.info("Detaching policy '%s' from OU '%s'" %
                 (policy_name, ou_spec['Name']))
        if args['--exec']:
            org_client.detach_policy(PolicyId=lookup(deployed_policies, 'Name',
                                                     policy_name, 'Id'),
                                     TargetId=ou_id)
Example #13
0
def get_policy_arn(iam_client, policy_name, args, log, auth_spec):
    """
    Return the policy arn of the named IAM policy in an account.
    Checks AWS scope first, then calls manage_custom_policy() for
    local scope policies.
    """
    aws_policies = iam_client.list_policies(Scope='AWS',
            MaxItems=500)['Policies']
    policy_arn = lookup(aws_policies, 'PolicyName', policy_name, 'Arn')
    if policy_arn:
        return policy_arn
    else:
        return manage_custom_policy(iam_client, policy_name, args,
                log, auth_spec)
Example #14
0
def manage_group_members(iam_client, args, log, deployed, auth_spec):
    """
    Populate users into groups based on group specification.
    """
    for g_spec in auth_spec['groups']:
        if (lookup(deployed['groups'], 'GroupName', g_spec['Name'])
                and not ensure_absent(g_spec)):
            response = iam_client.get_group(
                    GroupName=g_spec['Name'])['Users']
            current_members = [user['UserName'] for user in response
                    if 'UserName' in user]
            if 'Members' in g_spec and g_spec['Members']:
                spec_members = g_spec['Members']
            else:
                spec_members = []
            add_users = [username for username in spec_members
                    if username not in current_members]
            remove_users = [username for username in current_members
                    if username not in spec_members]
            for username in add_users:
                if lookup(deployed['users'], 'UserName', username):
                    log.info("Adding user '%s' to group '%s'." %
                            (username, g_spec['Name']))
                    if args['--exec']:
                        iam_client.add_user_to_group(
                                GroupName=g_spec['Name'],
                                UserName=username)
                else:
                    log.error("User '%s' not found. Can not add user to "
                            "group '%s'" % (username, g_spec['Name']))
            for username in remove_users:
                log.info("Removig user '%s' from group '%s'." %
                        (username, g_spec['Name']))
                if args['--exec']:
                    iam_client.remove_user_from_group(
                            GroupName=g_spec['Name'],
                            UserName=username)
Example #15
0
def manage_account_moves(org_client, args, log, deployed_accounts, ou_spec,
                         dest_parent_id):
    """
    Alter deployed AWS Organization.  Ensure accounts are contained
    by designated OrganizationalUnits based on OU specification.
    """
    if 'Accounts' in ou_spec and ou_spec['Accounts']:
        for account in ou_spec['Accounts']:
            account_id = lookup(deployed_accounts, 'Name', account, 'Id')
            if not account_id:
                log.warn("Account '%s' not yet in Org" % account)
            else:
                source_parent_id = get_parent_id(org_client, account_id)
                if dest_parent_id != source_parent_id:
                    log.info("Moving account '%s' to OU '%s'" %
                             (account, ou_spec['Name']))
                    if args['--exec']:
                        org_client.move_account(
                            AccountId=account_id,
                            SourceParentId=source_parent_id,
                            DestinationParentId=dest_parent_id)
Example #16
0
def create_groups(iam_client, args, log, deployed, auth_spec):
    """
    Manage IAM groups based on group specification
    """
    for g_spec in auth_spec['groups']:
        path = munge_path(auth_spec['default_path'], g_spec)
        group = lookup(deployed['groups'], 'GroupName', g_spec['Name'])
        if group:
            if ensure_absent(g_spec):
                # check if group has users
                if iam_client.get_group(GroupName=g_spec['Name'])['Users']:
                    log.error("Group '%s' still has users.  "
                             "Can't delete." % g_spec['Name'])
                # delete group
                else:
                    log.info("Deleting group '%s'" % g_spec['Name'])
                    if args['--exec']:
                        # delete group policies
                        for policy_name in iam_client.list_group_policies(
                                GroupName=g_spec['Name'])['PolicyNames']:
                            iam_client.delete_group_policy(
                                    GroupName=g_spec['Name'],
                                    PolicyName=policy_name)
                        iam_client.delete_group(GroupName=g_spec['Name'])
            elif group['Path'] != path:
                # update group
                log.info("Updating path on group '%s'" % g_spec['Name'])
                if args['--exec']:
                    iam_client.update_group(
                            GroupName=g_spec['Name'], NewPath=path)
        elif not ensure_absent(g_spec):
            # create group
            log.info("Creating group '%s'" % g_spec['Name'])
            if args['--exec']:
                response = iam_client.create_group(
                        GroupName=g_spec['Name'], Path=path)
                log.info(response['Group']['Arn'])
Example #17
0
def create_users(iam_client, args, log, deployed, auth_spec):
    """
    Manage IAM users based on user specification
    """
    for u_spec in auth_spec['users']:
        path = munge_path(auth_spec['default_path'], u_spec)
        user = lookup(deployed['users'], 'UserName', u_spec['Name'])
        if user:
            if ensure_absent(u_spec):
                log.info("Deleting user '%s'" % u_spec['Name'])
                if args['--exec']:
                    iam_client.delete_user( UserName=u_spec['Name'])
                    log.info(response['User']['Arn'])
            elif user['Path'] != path:
                log.info("Updating path on user '%s'" % u_spec['Name'])
                if args['--exec']:
                    iam_client.update_user(
                            UserName=u_spec['Name'], NewPath=path)
        elif not ensure_absent(u_spec):
            log.info("Creating user '%s'" % u_spec['Name'])
            if args['--exec']:
                response = iam_client.create_user(
                        UserName=u_spec['Name'], Path=path)
                log.info(response['User']['Arn'])
Example #18
0
def manage_delegation_role(credentials, args, log, deployed,
        auth_spec, account_name, d_spec):
    """
    Create and manage a cross account access delegetion role in an
    account based on delegetion specification.
    """
    iam_client = boto3.client('iam', **credentials)
    iam_resource = boto3.resource('iam', **credentials)
    role = iam_resource.Role(d_spec['RoleName'])

    # check if role should not exist
    if (account_name not in d_spec['TrustingAccount']
            and d_spec['TrustingAccount'] != 'ALL'
            or ensure_absent(d_spec)):
        try:
            role.load()
        except ClientError as e:
            if e.response['Error']['Code'] == 'NoSuchEntity':
                return
            else:
                raise e
        except:
            raise
        # delete delegation role
        log.info("Deleting role '%s' from account '%s'" %
                (d_spec['RoleName'], account_name))
        if args['--exec']:
            for p in list(role.attached_policies.all()):
                role.detach_policy(PolicyArn=p.arn)
            role.delete()
        return

    # assemble assume role policy document for delegation role
    principal = "arn:aws:iam::%s:root" % auth_spec['auth_account_id']
    statement = dict(
            Effect='Allow',
            Principal=dict(AWS=principal),
            Action='sts:AssumeRole')
    mfa = True
    if 'RequireMFA' in d_spec and d_spec['RequireMFA'] == False:
        mfa = False
    if mfa:
        statement['Condition'] = {
                'Bool':{'aws:MultiFactorAuthPresent':'true'}}
    policy_doc = json.dumps(dict(
            Version='2012-10-17', Statement=[statement]))

    # get iam role object.  create role if it does not exist (i.e. won't load)
    try:
        role.load()
    except ClientError as e:
        if e.response['Error']['Code'] == 'NoSuchEntity':
            log.info("Creating role '%s' in account '%s'" %
                    (d_spec['RoleName'], account_name))
            if args['--exec']:
                iam_client.create_role(
                        Description=d_spec['Description'],
                        Path=munge_path(auth_spec['default_path'], d_spec),
                        RoleName=d_spec['RoleName'],
                        AssumeRolePolicyDocument=policy_doc)
                if 'Policies' in d_spec and d_spec['Policies']:
                    role.load()
                    for policy_name in d_spec['Policies']:
                        policy_arn = get_policy_arn(iam_client, policy_name,
                                args, log, auth_spec)
                        log.info("Attaching policy '%s' to role '%s' "
                                "in account '%s'" %
                                (policy_name, d_spec['RoleName'], account_name))
                        if args['--exec'] and policy_arn:
                            role.attach_policy(PolicyArn=policy_arn)
                return
            else:
                return
        else:
            raise e
    except:
        raise

    # update delegation role if needed
    if json.dumps(role.assume_role_policy_document) != policy_doc:
        log.info("Updating policy document in role '%s' in account '%s'" %
                (d_spec['RoleName'], account_name))
        if args['--exec']:
            iam_client.update_assume_role_policy(
                RoleName=role.role_name,
                PolicyDocument=policy_doc)
    if role.description != d_spec['Description']:
        log.info("Updating description in role '%s' in account '%s'" %
                (d_spec['RoleName'], account_name))
        if args['--exec']:
            iam_client.update_role_description(
                RoleName=role.role_name,
                Description=d_spec['Description'])

    # manage policy attachments
    attached_policies = [p.policy_name for p
            in list(role.attached_policies.all())]
    for policy_name in d_spec['Policies']:
        # attach missing policies
        if not policy_name in attached_policies:
            policy_arn = get_policy_arn(iam_client, policy_name, args,
                    log, auth_spec)
            log.info("Attaching policy '%s' to role '%s' in account '%s'" %
                    (policy_name, d_spec['RoleName'], account_name))
            if args['--exec'] and policy_arn:
                role.attach_policy(PolicyArn=policy_arn)
        elif lookup(auth_spec['custom_policies'], 'PolicyName',policy_name):
            policy_arn = get_policy_arn(iam_client, policy_name, args,
                    log, auth_spec)
    for policy_name in attached_policies:
        # datach obsolete policies
        if not policy_name in d_spec['Policies']:
            policy_arn = get_policy_arn(iam_client, policy_name, args,
                    log, auth_spec)
            log.info("Detaching policy '%s' from role '%s' in account '%s'" %
                    (policy_name, d_spec['RoleName'], account_name))
            if args['--exec'] and policy_arn:
                role.detach_policy(PolicyArn=policy_arn)
Example #19
0
def set_group_assume_role_policies(args, log, deployed, auth_spec, d_spec):
    """
    Assign and manage assume role trust policies on IAM groups in
    Auth account.
    """
    credentials = get_assume_role_credentials(
            auth_spec['auth_account_id'],
            auth_spec['org_access_role'])
    iam_resource = boto3.resource('iam', **credentials)
    group = iam_resource.Group(d_spec['TrustedGroup'])
    auth_account = lookup(deployed['accounts'], 'Id',
            auth_spec['auth_account_id'], 'Name')
    try:
        group.load()
    except ClientError as e:
        if e.response['Error']['Code'] == 'NoSuchEntity':
            log.error("Group '%s' not found in account '%s'" %
                    (d_spec['TrustedGroup'], auth_account))
            log.error("Can not create group assume role policy for "
                    "delegation '%s'" % d_spec['RoleName'])
            return
        else:
            raise e
    except:
        raise

    # make list of existing group policies which match this role name
    group_policies_for_role = [p.policy_name
            for p in list(group.policies.all())
            if d_spec['RoleName'] in p.policy_name.split('-')]

    # test if delegation should be deleted
    if ensure_absent(d_spec): 
        for policy_name in group_policies_for_role:
            log.info("Deleting assume role group policy '%s' from group '%s' "
                    "in account '%s'" %
                    (policy_name, d_spec['TrustedGroup'], auth_account))
            if args['--exec']:
                group.Policy(policy_name).delete()
        return

    if d_spec['TrustingAccount'] == 'ALL':
        trusting_accounts = [a['Name'] for a in deployed['accounts']]
    else:
        trusting_accounts = d_spec['TrustingAccount']

    # keep track of managed group policies as we process them
    managed_policies = []
    for account in trusting_accounts:
        account_id = lookup(deployed['accounts'], 'Name', account, 'Id')
        policy_name = "%s-%s" % (account, d_spec['RoleName'])
        managed_policies.append(policy_name)

        # assemble assume role policy document
        statement = dict(
                Effect='Allow',
                Action='sts:AssumeRole',
                Resource="arn:aws:iam::%s:role%s%s" % (
                        account_id,
                        munge_path(auth_spec['default_path'], d_spec),
                        d_spec['RoleName'])) 
        policy_doc = json.dumps(dict(
                Version='2012-10-17',
                Statement=[statement]))

        # create or update group policy
        if not policy_name in group_policies_for_role:
            log.info("Creating assume role policy '%s' for group '%s' in "
                    "account '%s'." % (policy_name, d_spec['TrustedGroup'],
                    auth_account))
            if args['--exec']:
                group.create_policy(
                        PolicyName=policy_name,
                        PolicyDocument=policy_doc)
        elif json.dumps(group.Policy(policy_name).policy_document) != policy_doc:
            log.info("Updating assume role policy '%s' for group '%s' in "
                    "account '%s'." % (policy_name, d_spec['TrustedGroup'],
                    auth_account))
            if args['--exec']:
                group.Policy(policy_name).put(PolicyDocument=policy_doc)

    # purge any policies for this role that are no longer being managed
    for policy_name in group_policies_for_role:
        if policy_name not in managed_policies:
            log.info("Deleting obsolete policy '%s' from group '%s' in "
                    "account '%s'." % (policy_name, d_spec['TrustedGroup'],
                    auth_account))
            if args['--exec']:
                group.Policy(policy_name).delete()