ansible-collections / azure

Development area for Azure Collections
https://galaxy.ansible.com/azure/azcollection
GNU General Public License v3.0
246 stars 332 forks source link

Azure stack ADFS authentification fail MSIS9602 #1143

Closed mysiki closed 1 year ago

mysiki commented 1 year ago
SUMMARY

I work on Azure Stack with corporate ADFS. I using Azure_preview module without issue. Since I update to AzCollection, the authentification process do not work anymore.
I using .azure/credentials file

ISSUE TYPE
COMPONENT NAME

azure_rm_common.py ?

ANSIBLE VERSION
ansible 2.9.27
  configured module search path = ['/root/.ansible/collections/ansible_collections/*']
  ansible python module location = /venv/.venv/lib/python3.10/site-packages/ansible
  executable location = /venv/.venv/bin/ansible
  python version = 3.10.11 (main, Apr  6 2023, 01:16:54) [GCC 12.2.1 20220924]
COLLECTION VERSION

Azure collection 1.14.0

CONFIGURATION

Nothing

OS / ENVIRONMENT

Linux under container

STEPS TO REPRODUCE

WORK : With Azure preview module (ans requirement pip)

ansible all -i a, -c local -m azure_rm_resourcegroup_facts -a profile="myprofile"

KO : With Azure collection 1.14 (and requirement pip)

ansible all -i a, -c local -m azure.azcollection.azure_rm_resourcegroup_info -a profile="myprofile"
EXPECTED RESULTS

Connection work

ACTUAL RESULTS
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: msrest.exceptions.AuthenticationError: , AdalError: Get Token request returned http error: 400 and server response: {"error":"invalid_resource","error_description":"MSIS9602: The received \u0027resource\u0027 parameter is invalid. The authorization server can not find a registered resource with the specified identifier."}
fatal: [a]: FAILED! => {
    "changed": false,
    "rc": 1
}

MSG:

MODULE FAILURE
See stdout/stderr for the exact error

MODULE_STDERR:

Traceback (most recent call last):
  File "/venv/.venv/lib/python3.10/site-packages/msrestazure/azure_active_directory.py", line 364, in set_token
    token = self._context.acquire_token_with_client_credentials(
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 179, in acquire_token_with_client_credentials
    return self._acquire_token(token_func)
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 128, in _acquire_token
    return token_func(self)
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 177, in token_func
    return token_request.get_token_with_client_credentials(client_secret)
  File "/venv/.venv/lib/python3.10/site-packages/adal/token_request.py", line 312, in get_token_with_client_credentials
    token = self._oauth_get_token(oauth_parameters)
  File "/venv/.venv/lib/python3.10/site-packages/adal/token_request.py", line 112, in _oauth_get_token
    return client.get_token(oauth_parameters)
  File "/venv/.venv/lib/python3.10/site-packages/adal/oauth2_client.py", line 289, in get_token
    raise AdalError(return_error_string, error_response)
adal.adal_error.AdalError: Get Token request returned http error: 400 and server response: {"error":"invalid_resource","error_description":"MSIS9602: The received \u0027resource\u0027 parameter is invalid. The authorization server can not find a registered resource with the specified identifier."}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 102, in <module>
  File "<stdin>", line 94, in _ansiballz_main
  File "<stdin>", line 40, in invoke_module
  File "/usr/lib/python3.10/runpy.py", line 224, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/usr/lib/python3.10/runpy.py", line 96, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload_75ukievp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload.zip/ansible_collections/azure/azcollection/plugins/modules/azure_rm_resourcegroup_info.py", line 235, in <module>
  File "/tmp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload_75ukievp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload.zip/ansible_collections/azure/azcollection/plugins/modules/azure_rm_resourcegroup_info.py", line 231, in main
  File "/tmp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload_75ukievp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload.zip/ansible_collections/azure/azcollection/plugins/modules/azure_rm_resourcegroup_info.py", line 160, in __init__
  File "/tmp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload_75ukievp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload.zip/ansible_collections/azure/azcollection/plugins/module_utils/azure_rm_common.py", line 465, in __init__
  File "/tmp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload_75ukievp/ansible_azure.azcollection.azure_rm_resourcegroup_info_payload.zip/ansible_collections/azure/azcollection/plugins/module_utils/azure_rm_common.py", line 1573, in __init__
  File "/venv/.venv/lib/python3.10/site-packages/msrestazure/azure_active_directory.py", line 355, in __init__
    self.set_token()
  File "/venv/.venv/lib/python3.10/site-packages/msrestazure/azure_active_directory.py", line 371, in set_token
    raise_with_traceback(AuthenticationError, "", err)
  File "/venv/.venv/lib/python3.10/site-packages/msrest/exceptions.py", line 51, in raise_with_traceback
    raise error.with_traceback(exc_traceback)
  File "/venv/.venv/lib/python3.10/site-packages/msrestazure/azure_active_directory.py", line 364, in set_token
    token = self._context.acquire_token_with_client_credentials(
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 179, in acquire_token_with_client_credentials
    return self._acquire_token(token_func)
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 128, in _acquire_token
    return token_func(self)
  File "/venv/.venv/lib/python3.10/site-packages/adal/authentication_context.py", line 177, in token_func
    return token_request.get_token_with_client_credentials(client_secret)
  File "/venv/.venv/lib/python3.10/site-packages/adal/token_request.py", line 312, in get_token_with_client_credentials
    token = self._oauth_get_token(oauth_parameters)
  File "/venv/.venv/lib/python3.10/site-packages/adal/token_request.py", line 112, in _oauth_get_token
    return client.get_token(oauth_parameters)
  File "/venv/.venv/lib/python3.10/site-packages/adal/oauth2_client.py", line 289, in get_token
    raise AdalError(return_error_string, error_response)
msrest.exceptions.AuthenticationError: , AdalError: Get Token request returned http error: 400 and server response: {"error":"invalid_resource","error_description":"MSIS9602: The received \u0027resource\u0027 parameter is invalid. The authorization server can not find a registered resource with the specified identifier."}
Fred-sun commented 1 year ago

@mysiki https://github.com/ansible-collections/azure/blob/dev/requirements-azure.txt


link: https://github.com/ansible-collections/azure/blob/dev/requirements-azure.txt
mysiki commented 1 year ago

Yes the requirement are install. What is your point? 'need to install the requirements' (that is done) or 'install the dev branch requirements'?

Fred-sun commented 1 year ago

@mysiki I tested it locally, after installing v1.14.0 and its dependent files, I executed it without any errors. Could you please try again? Or try again in a different environment, thank you!


fred@DESKTOP-RUEHQGC:~/tasks/346/template$ ansible all -i a, -c local -m azure.azcollection.azure_rm_resourcegroup_info -a "name=v-xisuRG03"
a | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "resourcegroups": [
        {
            "id": "/subscriptions/xxxxxxxxxxxxxxxxxxxxxxxxx/resourceGroups/v-xisuRG03",
            "location": "eastus",
            "name": "v-xisuRG03",
            "properties": {
                "provisioningState": "Succeeded"
            },
            "tags": {
                "required_tag1": "yes_please",
                "required_tag2": "yes_please",
                "required_tag3": "yes_please"
            }
        }
    ]
}
mysiki commented 1 year ago

Thx for the test, are you using SPN ? How have you create the SPN (SPN create have specific parameter ? ) ? Are you using .azure/credentials file for authentication ? It's possible than some configuration are missing in ADFS or SPN ? I don't have access to ADFS (manage by other team).

Fred-sun commented 1 year ago

@mysiki Yes! I used the SPN, credential location ~/.azure/credentials.

mysiki commented 1 year ago

Come back after many test and trace (and python level up - thanks epdb :D).

I finally make it work but I have 2 issue.

First : The problem (as the error message say) is related to the 'resource' flag in the token. I can see than in azure_rm_common.py file, the 'resource' variable have change.

This is the view of my endpoints :

pp vars(self._cloud_environment.endpoints)
{'active_directory': 'https://adfs.fr1.restricted.corp/adfs',
 'active_directory_graph_resource_id': 'https://graph.fr1.corp/',
 'active_directory_resource_id': 'https://management.adfs.azurestack.local/<tenant>',
 'batch_resource_id': None,
 'gallery': 'https://providers.azurestack.local:30016/',
 'management': 'https://management.fr1.corp',
 'microsoft_graph_resource_id': None,
 'resource_manager': 'https://management.fr1.corp',
 'sql_management': None}
#Old work for me (than are not set in azure_rm_common.py but in msrestazure/azure_active_directory.py): 
resource = self._cloud_environment.endpoints.active_directory_resource_id

#New don't work for me
graph_resource = self._cloud_environment.endpoints.active_directory_graph_resource_id
rm_resource = self._cloud_environment.endpoints.resource_manager
...
resource=graph_resource if self.is_ad_resource else rm_resource,
...

This can be see in https://github.com/ansible-collections/azure/blob/4193719303dde69575ea08526d3353d234ce6d9d/plugins/module_utils/azure_rm_common.py#L1573

In fact, I see than in case of user authentication acquire_token_with_client_certificate or acquire_token_with_username_password is it active_directory_resource_id instead of active_directory_graph_resource_id that is use.

So, it's normal than the resource variable not use active_directory_resource_id ? If yes, it's seems than I can't 'force' is value (?) so I need to check with ADFS team in order to change the endpoint.

Second : The is_ad_resource than permit to control usage of graph_resource versus rm_resource. How this parameter is calculated ? I need to force it in order to use graph_resource ? https://github.com/ansible-collections/azure/blob/4193719303dde69575ea08526d3353d234ce6d9d/plugins/module_utils/azure_rm_common.py#L1579

Thx for your help

Fred-sun commented 1 year ago

@mysiki is_ad_resource is False by default and is set to True only for azure_rm_ad* related modules. In addition, GraphRBA will soon be deprecated in favor of msgraph(#1112), and is_ad_resource will be deleted. Thanks!

mysiki commented 1 year ago

ok for is_ad_resource.

And for active_directory_graph_resource_id instead of active_directory_resource_id in SPN case ?

msgraph mean than the next version will not use ADAL ?

Fred-sun commented 1 year ago

@mysiki No, ADAL will be abandoned, not completely removed for now, we will use MSgraph instead. Thanks!

lm-sig commented 1 year ago

As of collection version 1.15.0 I can no longer use this collection with Azure Stack Hub. Even with 1.14.0 it only partially works. This issue regarding module 'azure.azcollection.azure_rm_resourcegroup_info' works if you modify 'azure_rm_common.py' per mysiki's comment for version 1.14.0. However, other modules, such as 'azure.azcollection.azure_rm_virtualmachine_info' do not work. Modules appear to take different API paths depending on the module from my debugging. Errors show up for calls when the 'is_track2' flag is true.

The 'is_track2' calls use 'ClientSecretCredential()' and do not pass an 'authority' parameter. The default authority is Azure public cloud. Obviously this does not work for Azure Stack Hub. After modifying 'azure_rm_common.py' to use an authority parameter (pointing to the Stack Hub ADFS URL) I then get a MSIS9602 error again. I can't seem to find where the 'bad' resource parameter is coming from for this API call.

mysiki commented 1 year ago

FYI, I pack ansible and all my needed dep in docker image.

So I force the version 1.14.0

AZURECOLLECTIONVERSION=1.14.0

git -c advice.detachedHead=false clone https://github.com/ansible-collections/azure.git -b v${AZURECOLLECTIONVERSION} /tmp/azure_collection/
pip install -r /tmp/azure_collection/requirements-azure.txt
ansible-galaxy collection install azure.azcollection:${AZURECOLLECTIONVERSION} 

and at the end of my docker, I copy a patched file azure_rm_common.py with the following line :

Line

# line 1538
graph_resource = self._cloud_environment.endpoints.active_directory_resource_id

# line 1544
resource=graph_resource,

# Total block
## FIX HERE
            graph_resource = self._cloud_environment.endpoints.active_directory_resource_id
            rm_resource = self._cloud_environment.endpoints.resource_manager
            self.azure_credentials = ServicePrincipalCredentials(client_id=self.credentials['client_id'],
                                                                 secret=self.credentials['secret'],
                                                                 tenant=self.credentials['tenant'],
                                                                 cloud_environment=self._cloud_environment,
                                                                 resource=graph_resource,
                                                                 verify=self._cert_validation_mode == 'validate')
            self.azure_credential_track2 = client_secret.ClientSecretCredential(client_id=self.credentials['client_id'],
                                                                                client_secret=self.credentials['secret'],
                                                                                tenant_id=self.credentials['tenant'])
lm-sig commented 1 year ago

Yes, I have done those modifications. It only helps module 'azure.azcollection.azure_rm_resourcegroup_info' work. The module 'azure.azcollection.azure_rm_virtualmachine_info' does not work. Does 'azure.azcollection.azure_rm_virtualmachine_info' work for you and your Azure Stack Hub? What version of Azure Stack Hub are you running?

mysiki commented 1 year ago

@lm-sig Work again on azure stack and like you say, my fix do not fix all ... I have another error on public if (resolution name error this time) instead of I can create RG (so azure stack url is ok). I will try to debug it again. I suspect a bad configuration in azure stack regarding the graph setting. But I'm only client, I canno't check or change the configuration.

Have you finish to find some workaround ?

lm-sig commented 1 year ago

I used Terraform and its Azure Stack Hub provider because I could not get the Ansible modules to work. I used Ansible for other purposes, but I could not use Ansible for the provisioning of the VM object in Stack Hub.

mysiki commented 1 year ago

Back again, @Fred-sun does this collection support Azure stack anymore ?

I try to update ansible, collection and all package, and nothing work.

For exemple, I see than in https://github.com/ansible-collections/azure/blob/5d8ab4e35b0e1d366794506867f779523fa9d9de/plugins/module_utils/azure_rm_common.py#L1581C61-L1581C61 the authority is missing

## Work by adding authority arg
            self.azure_credential_track2 = client_secret.ClientSecretCredential(client_id=self.credentials['client_id'],
                                                                     client_secret=self.credentials['secret'],
                                                                      tenant_id=self.credentials['tenant'],
                                                                      authority=self._adfs_authority_url)

It also seems than all module authentication use azure_credential_track2 than force scopes to /.default but in my stack, I need to use url management/tenant

So, can you help me to understand :

thx