Ejemplo n.º 1
0
def check_service_principal(cli_ctx,
                            resource_id,
                            namespace,
                            resource_type,
                            root_type=None):
    from azure.cli.core._profile import (
        ServicePrincipalAuth,
        _authentication_context_factory,
    )

    try:
        # Get SP token
        sp_auth = ServicePrincipalAuth(SELF_DESTRUCT["clientSecret"])
        context = _authentication_context_factory(cli_ctx,
                                                  SELF_DESTRUCT["tenantId"],
                                                  None)
        resource = cli_ctx.cloud.endpoints.active_directory_resource_id
        token = sp_auth.acquire_token(context, resource,
                                      SELF_DESTRUCT["clientId"])

        # Check permissions for resource
        uri = "https://management.azure.com{}/providers/Microsoft.Authorization/permissions?api-version=2015-07-01".format(
            resource_id)
        headers = {"Authorization": "Bearer {}".format(token["accessToken"])}
        r = requests.get(uri, headers=headers)

        # TODO: Check expiration date of SP

        # If we can't read permissions - it may or may not be an actual problem
        # It's perfectly valid to create a "Delete Storage Accounts in resource group X only" cleanup role that can't read roleAssignments
        # I'd prefer always-correct behavior - so fail fast here
        if r.status_code != 200:
            error = r.json()
            LOGGER.error(
                "There was a failure when checking service principal permissions. Your self-destruct sequence cannot be activated!"
            )
            LOGGER.error("%s: %s", error["error"]["code"],
                         error["error"]["message"])
            return False
    except Exception:  # pylint: disable=broad-except
        LOGGER.error(
            "There was a failure when checking service principal permissions. Your self-destruct sequence cannot be activated!"
        )
        return False

    # This is a mine field of complex behavior
    # action: '*' means everything, unless there's an overriding notAction
    # There can be wildcards inlined in both actions and notActions
    # Namespaces often don't match product names, etc
    permissions = r.json()["value"][0]
    reqs = {
        "*",
        "{}/*".format(namespace),  # Microsoft.Storage/*
        "{}/*/delete".format(namespace),  # Microsoft.Storage/*/delete
        "{}/{}/*".format(namespace,
                         resource_type),  # Microsoft.Storage/storageAccounts
        "{}/{}/delete".format(
            namespace,
            resource_type),  # Microsoft.Storage/storageAccounts/delete
    }
    if root_type:
        reqs.add("{}/{}/{}/*".format(namespace, root_type, resource_type))
        reqs.add("{}/{}/{}/delete".format(namespace, root_type, resource_type))

    actions = set(permissions["actions"])
    not_actions = set(permissions["notActions"])

    if not reqs.intersection(actions) or reqs.intersection(not_actions):
        LOGGER.error(
            "Service principal delete permissions could not be verified. Your self-destruct sequence cannot be activated!"
        )
        LOGGER.error("Needed: one of %s", reqs)
        LOGGER.error("Allow: %s", actions)
        LOGGER.error("Deny: %s", not_actions)
        return False

    return True
def check_service_principal(cli_ctx,
                            resource_id,
                            namespace,
                            resource_type,
                            root_type=None):
    from azure.cli.core._profile import ServicePrincipalAuth, _authentication_context_factory

    try:
        # Get SP token
        sp_auth = ServicePrincipalAuth(self_destruct['clientSecret'])
        context = _authentication_context_factory(cli_ctx,
                                                  self_destruct['tenantId'],
                                                  None)
        resource = cli_ctx.cloud.endpoints.active_directory_resource_id
        token = sp_auth.acquire_token(context, resource,
                                      self_destruct['clientId'])

        # Check permissions for resource
        uri = "https://management.azure.com{}/providers/Microsoft.Authorization/permissions?api-version=2015-07-01".format(
            resource_id)
        headers = {'Authorization': 'Bearer {}'.format(token['accessToken'])}
        r = requests.get(uri, headers=headers)

        # TODO: Check expiration date of SP

        # If we can't read permissions - it may or may not be an actual problem
        # It's perfectly valid to create a "Delete Storage Accounts in resource group X only" cleanup role that can't read roleAssignments
        # I'd prefer always-correct behavior - so fail fast here
        if r.status_code != 200:
            error = r.json()
            logger.error(
                'There was a failure when checking service principal permissions. Your self-destruct sequence cannot be activated!'
            )
            logger.error('{}: {}'.format(error['error']['code'],
                                         error['error']['message']))
            return False
    except Exception:
        logger.error(
            'There was a failure when checking service principal permissions. Your self-destruct sequence cannot be activated!'
        )
        return False

    # This is a mine field of complex behavior
    # action: '*' means everything, unless there's an overriding notAction
    # There can be wildcards inlined in both actions and notActions
    # Namespaces often don't match product names, etc
    permissions = r.json()['value'][0]
    reqs = {
        '*',
        '{}/*'.format(namespace),  # Microsoft.Storage/*
        '{}/*/delete'.format(namespace),  # Microsoft.Storage/*/delete
        '{}/{}/*'.format(namespace,
                         resource_type),  # Microsoft.Storage/storageAccounts
        '{}/{}/delete'.format(
            namespace,
            resource_type)  # Microsoft.Storage/storageAccounts/delete
    }
    if root_type:
        reqs.add('{}/{}/{}/*'.format(namespace, root_type, resource_type))
        reqs.add('{}/{}/{}/delete'.format(namespace, root_type, resource_type))

    actions = set(permissions['actions'])
    not_actions = set(permissions['notActions'])

    if not reqs.intersection(actions) or reqs.intersection(not_actions):
        logger.error(
            'Service principal delete permissions could not be verified. Your self-destruct sequence cannot be activated!'
        )
        logger.error('Needed: one of {}'.format(reqs))
        logger.error('Allow: {}'.format(actions))
        logger.error('Deny: {}'.format(not_actions))
        return False

    return True