コード例 #1
0
 def test_service_principal_auth_client_secret(self):
     sp_auth = ServicePrincipalAuth('verySecret!')
     result = sp_auth.get_entry_to_persist('sp_id1', 'tenant1')
     self.assertEqual(result, {
         'servicePrincipalId': 'sp_id1',
         'servicePrincipalTenant': 'tenant1',
         'accessToken': 'verySecret!'
     })
コード例 #2
0
 def test_service_principal_auth_client_secret(self):
     sp_auth = ServicePrincipalAuth('verySecret!')
     result = sp_auth.get_entry_to_persist('sp_id1', 'tenant1')
     self.assertEqual(result, {
         'servicePrincipalId': 'sp_id1',
         'servicePrincipalTenant': 'tenant1',
         'accessToken': 'verySecret!'
     })
コード例 #3
0
    def test_service_principal_auth_client_cert(self):
        curr_dir = os.path.dirname(os.path.realpath(__file__))
        test_cert_file = os.path.join(curr_dir, 'sp_cert.pem')
        sp_auth = ServicePrincipalAuth(test_cert_file)

        result = sp_auth.get_entry_to_persist('sp_id1', 'tenant1')
        self.assertEqual(result, {
            'servicePrincipalId': 'sp_id1',
            'servicePrincipalTenant': 'tenant1',
            'certificateFile': test_cert_file,
            'thumbprint': 'F0:6A:53:84:8B:BE:71:4A:42:90:D6:9D:33:52:79:C1:D0:10:73:FD'
        })
コード例 #4
0
    def test_service_principal_auth_client_cert(self):
        curr_dir = os.path.dirname(os.path.realpath(__file__))
        test_cert_file = os.path.join(curr_dir, 'sp_cert.pem')
        sp_auth = ServicePrincipalAuth(test_cert_file)

        result = sp_auth.get_entry_to_persist('sp_id1', 'tenant1')
        self.assertEqual(result, {
            'servicePrincipalId': 'sp_id1',
            'servicePrincipalTenant': 'tenant1',
            'certificateFile': test_cert_file,
            'thumbprint': 'F0:6A:53:84:8B:BE:71:4A:42:90:D6:9D:33:52:79:C1:D0:10:73:FD'
        })
コード例 #5
0
    def test_find_subscriptions_from_service_principal_id(self, mock_auth_context):
        mock_auth_context.acquire_token_with_client_credentials.return_value = self.token_entry1
        mock_arm_client = mock.MagicMock()
        mock_arm_client.subscriptions.list.return_value = [self.subscription1]
        finder = SubscriptionFinder(lambda _, _2: mock_auth_context,
                                    None,
                                    lambda _: mock_arm_client)
        mgmt_resource = 'https://management.core.windows.net/'
        # action
        subs = finder.find_from_service_principal_id('my app', ServicePrincipalAuth('my secret'),
                                                     self.tenant_id, mgmt_resource)

        # assert
        self.assertEqual([self.subscription1], subs)
        mock_arm_client.tenants.list.assert_not_called()
        mock_auth_context.acquire_token.assert_not_called()
        mock_auth_context.acquire_token_with_client_credentials.assert_called_once_with(
            mgmt_resource, 'my app', 'my secret')
コード例 #6
0
    def test_find_subscriptions_from_service_principal_using_cert(self, mock_auth_context):
        mock_auth_context.acquire_token_with_client_certificate.return_value = self.token_entry1
        mock_arm_client = mock.MagicMock()
        mock_arm_client.subscriptions.list.return_value = [self.subscription1]
        finder = SubscriptionFinder(lambda _, _2: mock_auth_context,
                                    None,
                                    lambda _: mock_arm_client)
        mgmt_resource = 'https://management.core.windows.net/'

        curr_dir = os.path.dirname(os.path.realpath(__file__))
        test_cert_file = os.path.join(curr_dir, 'sp_cert.pem')

        # action
        subs = finder.find_from_service_principal_id('my app', ServicePrincipalAuth(test_cert_file),
                                                     self.tenant_id, mgmt_resource)

        # assert
        self.assertEqual([self.subscription1], subs)
        mock_arm_client.tenants.list.assert_not_called()
        mock_auth_context.acquire_token.assert_not_called()
        mock_auth_context.acquire_token_with_client_certificate.assert_called_once_with(
            mgmt_resource, 'my app', mock.ANY, mock.ANY)
コード例 #7
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
コード例 #8
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('{}: {}'.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