Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azure_rm_roleassignment fails with 'Error creating role assignment: (RoleAssignmentExists)' #1137

Closed
Mohammad-Atif-Khan opened this issue Apr 3, 2023 · 35 comments · May be fixed by #1807
Closed
Labels
medium_priority Medium priority not a bug Not a bug question Further information is requested work in In trying to solve, or in working with contributors

Comments

@Mohammad-Atif-Khan
Copy link

SUMMARY

When trying to use the azure_rm_roleassignment module and the requested assignment exists, the task fails reporting the same:

    Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.
    Code: RoleAssignmentExists 
    Message: The role assignment already exists.

instead of continuing with a 'success' since the module should be idempotent.

ISSUE TYPE
  • Bug Report
COMPONENT NAME

azure_rm_roleassignment

ANSIBLE VERSION
/usr/local/lib/python3.8/site-packages/paramiko/transport.py:236: CryptographyDeprecationWarning: Blowfish has been deprecated
  "class": algorithms.Blowfish,
ansible [core 2.12.5.post0]
  config file = None
  configured module search path = ['/home/runner/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/local/lib/python3.8/site-packages/ansible
  ansible collection location = /home/runner/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/local/bin/ansible
  python version = 3.8.13 (default, Jun 24 2022, 15:27:57) [GCC 8.5.0 20210514 (Red Hat 8.5.0-13)]
  jinja version = 3.1.2
  libyaml = True
COLLECTION VERSION
bash-4.4# ansible-galaxy collection list azure.azcollection.azure_rm_roleassignment
ERROR! Unexpected Exception, this is probably a bug: module 'lib' has no attribute 'X509_V_FLAG_CB_ISSUER_CHECK'
the full traceback was:

Traceback (most recent call last):
  File "/usr/local/bin/ansible-galaxy", line 97, in <module>
    mycli = getattr(__import__("ansible.cli.%s" % sub, fromlist=[myclass]), myclass)
  File "/usr/local/lib/python3.8/site-packages/ansible/cli/galaxy.py", line 24, in <module>
    from ansible.galaxy.api import GalaxyAPI
  File "/usr/local/lib/python3.8/site-packages/ansible/galaxy/api.py", line 28, in <module>
    from ansible.module_utils.urls import open_url, prepare_multipart
  File "/usr/local/lib/python3.8/site-packages/ansible/module_utils/urls.py", line 115, in <module>
    from urllib3.contrib.pyopenssl import PyOpenSSLContext
  File "/usr/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py", line 46, in <module>
    import OpenSSL.SSL
  File "/usr/local/lib/python3.8/site-packages/OpenSSL/__init__.py", line 8, in <module>
    from OpenSSL import crypto, SSL
  File "/usr/local/lib/python3.8/site-packages/OpenSSL/crypto.py", line 1517, in <module>
    class X509StoreFlags(object):
  File "/usr/local/lib/python3.8/site-packages/OpenSSL/crypto.py", line 1537, in X509StoreFlags
    CB_ISSUER_CHECK = _lib.X509_V_FLAG_CB_ISSUER_CHECK
AttributeError: module 'lib' has no attribute 'X509_V_FLAG_CB_ISSUER_CHECK'
CONFIGURATION

OS / ENVIRONMENT

I'm using ansible-navigator with an Execution Environment on docker CE. The above outputs are from inside the EE container.
The collection version is v1.15.0 as confirmed by looking at changelog:

bash-4.4# head /usr/share/ansible/collections/ansible_collections/azure/azcollection/CHANGELOG.md 
# Change Log

## v1.15.0 (2023-03-15)

This is the build file for anisble-builder if that is of interest:

---
version: 1

build_arg_defaults:
  EE_BASE_IMAGE: 'quay.io/ansible/ansible-runner:latest'

dependencies:
  galaxy: requirements.yml

additional_build_steps:
  append:
    - RUN echo Build Complete
    - RUN uname -a
STEPS TO REPRODUCE
  1. Assign a role to a resource (a resource group in my case) using the module
  2. Re-run the exact same task on the same resource group (role assignment) and it fails, reporting that the assignment already exists
- name: "[CRU_] [IAM] Update IAM of given RG"
  azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ rg_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"

where role_definition is the output of the azure_rm_roledefinition_info module, containing fully qualified definition ID.

EXPECTED RESULTS

The module should simply continue with status 'Ok' (ie unchanged) and not fail as it does currently

ACTUAL RESULTS

The task fails with Code: RoleAssignmentExists

invocation:
  module_args:
      ad_user:
      adfs_authority_url: null 
      api_profile: latest 
      assignee_object_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 
      auth_source: auto 
      cert_validation_mode: null 
      client_id: null 
      cloud_environment: AzureCloud 
      id: null 
      log_mode: null 
      log_path: null 
      name: null 
      password: null 
      profile: null 
      role_definition_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 
      scope: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG-Ansible-Resources 
      secret: null 
      state: present 
      subscription_id: null 
      tenant: null 
      thumbprint: null 
      x509_certificate_path: null 
  msg: |- 
    Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.
    Code: RoleAssignmentExists 
    Message: The role assignment already exists.

@Mohammad-Atif-Khan
Copy link
Author

Mohammad-Atif-Khan commented Apr 3, 2023

@paultaiton as requested, please see output of ###azure_rm_roleassignment_info with the same parameters:

  invocation:
    module_args:
      ad_user: null
      adfs_authority_url: null
      api_profile: latest
      assignee: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      assignee_object_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      auth_source: auto
      cert_validation_mode: null
      client_id: null
      cloud_environment: AzureCloud
      id: null
      log_mode: null
      log_path: null
      name: null
      password: null
      profile: null
      role_definition_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
      scope: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG-Ansible-Resources
      secret: null
      strict_scope_match: false 
      subscription_id: null     
      tenant: null
      thumbprint: null
      x509_certificate_path: null
  roleassignments:
  - assignee_object_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG-Ansible-Resources/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    name: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    principal_id: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    principal_type: Group
    role_definition_id: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/providers/Microsoft.Authorization/roleDefinitions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    scope: /subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/RG-Ansible-Resources
    type: Microsoft.Authorization/roleAssignments
resolved_action: azure.azcollection.azure_rm_roleassignment_info
start: '2023-04-03T22:10:53.204558'
task: '[CRU_] [IAM] Get existing IAM on given RG'
task_action: azure.azcollection.azure_rm_roleassignment_info

#460

@paultaiton
Copy link
Contributor

I apologize for the delay, I haven't had a chance to look at this yet.
I will try to review it in more depth this week. Based on what you've pasted, it should work, and this use case was previously tested, so there may be some dificulty in narrowing down the problem.

@Fred-sun
Copy link
Collaborator

@paultaiton There is no problem for me to create and re-create role assignments locally. Could you please share your playbook and log details? This will help solve the current problem, and if possible, you can try to reinstall a new environment, thank you!

Case:
- name: create role assignment by id
  azure_rm_roleassignment:
    id: "{{ az_resource_group.resourcegroups[0].id }}/providers/Microsoft.Authorization/roleAssignments/{{ uuid }}"
    assignee_object_id: "{{ az_role_assignments.roleassignments[0].principal_id }}"
    role_definition_id: "/subscriptions/{{ az_resource_group.resourcegroups[0].id.split('/')[2] }}/providers/Microsoft.Authorization/roleDefinitions/{{ az_role_definition_guid }}"

- name: create role assignment by id --------- secondary
  azure_rm_roleassignment:
    id: "{{ az_resource_group.resourcegroups[0].id }}/providers/Microsoft.Authorization/roleAssignments/{{ uuid }}"
    assignee_object_id: "{{ az_role_assignments.roleassignments[0].principal_id }}"
    role_definition_id: "/subscriptions/{{ az_resource_group.resourcegroups[0].id.split('/')[2] }}/providers/Microsoft.Authorization/roleDefinitions/{{ az_role_definition_guid }}"

Output:
TASK [create role assignment by id] ************************************************************************************changed: [localhost]

TASK [create role assignment by id --------- secondary] ****************************************************************ok: [localhost]

@Fred-sun Fred-sun added question Further information is requested medium_priority Medium priority work in In trying to solve, or in working with contributors labels Apr 10, 2023
@paultaiton
Copy link
Contributor

@Fred-sun in your test, did the second run come back as changed = false ? I'm assuming yes, but want to confirm.

@Mohammad-Atif-Khan
Copy link
Author

hi @Fred-sun ,

here is the full tasks.yml file that is called from another playbook using include_tasks module:

---
- name: "[VALDN] Subscription"
  block:
    - name: "[VALDN] Get subscription_id for {{ subscription }}"
      azure.azcollection.azure_rm_subscription_info:
        tenant: "{{ tenant_id }}"
        name: "{{ subscription|trim }}"
      register: subinfo_result
    - name: Failed to locate unique subscription
      ansible.builtin.fail:
        msg: "{{ subinfo_result.subscriptions|length }} subscription(s) found with given name: {{ subscription }}"
      when: subinfo_result.subscriptions|length < 1 or subinfo_result.subscriptions|length > 1
    - name: "[VALDN] Set subscription_id"
      ansible.builtin.set_fact:
        subscription_id: "{{ subinfo_result.subscriptions[0].subscription_id }}"
  when: subscription_id is not defined or subscription_id == None

- name: "[VALDN] Get RG ID for {{ rg_name }} in {{ subscription_id }}"
  azure.azcollection.azure_rm_resourcegroup_info:
    subscription_id: "{{ subscription_id }}"
    name: "{{ rg_name|trim }}"
  register: rginfo_result
- name: "Failed to locate RG"
  ansible.builtin.fail:
    msg: "'{{ rg_name }}' could not be found in subscription {{ subscription_id }}"
  when: rginfo_result.resourcegroups|length < 1 or rginfo_result.resourcegroups|length > 1
- name: "[CRU_] [RG] Set rg_info"
  ansible.builtin.set_fact:
    rg_info: "{{ rginfo_result.resourcegroups[0] }}"

- name: "[VALDN] Validate IAM inputs"
  block:
    - name: "[VALDN] Set RBAC Role Group name"
      ansible.builtin.set_fact:
        role_group_name: "{{ rbac_group }}"
      when: rbac_group is defined and rbac_group != None    
    - name: "[VALDN] Check if Role Group with intended name exists"
      azure.azcollection.azure_rm_adgroup_info:
        attribute_name: displayName
        attribute_value: "{{ role_group_name }}"
        tenant: "{{ tenant_id }}"
      register: adgroup_info    
    - name: "[VALDN] Role group '{{ rbac_group }}' exists and will be used"
      ansible.builtin.debug:
        msg: "Role group exists ({{ role_group_name }}) and **will be used**"
      when: adgroup_info.ad_groups|length>0    
    - name: "[VALDN] Role group '{{ rbac_group }}' does not exist - it will be created"
      ansible.builtin.debug:
        msg: "Role group with name provided does not exist and **will be created**: '{{ role_group_name }}'"
      when: adgroup_info.ad_groups|length<1
    - name: "[VALDN] Get Object IDs for ITC users"
      azure.azcollection.azure_rm_aduser_info:
        user_principal_name: "{{ item }}"
        tenant: "{{ tenant_id }}"
      loop: "{{ itc_accounts.split(',')|map('trim') }}"
      register: itc_objects
      when: itc_accounts is defined and itc_accounts != None
  when: not (access_needed is not defined or not access_needed|bool)

- name: "[CRU_] [AAD] Set adgroup_object_id"
  ansible.builtin.set_fact:
    adgroup_object_id: "{{ adgroup_info.ad_groups[0].object_id }}"
  when: "'ad_groups' in adgroup_info and adgroup_info.ad_groups|length>0"
- name: "[CRU_] [AAD] Create new Role group ({{ role_group_name }})"
  azure.azcollection.azure_rm_adgroup:
    display_name: "{{ role_group_name }}"
    mail_nickname: None
    tenant: "{{ tenant_id }}"
  register: adgroup_info_tmp
  when: adgroup_info.ad_groups|length<1
- name: "[CRU_] [AAD] Reset adgroup_info"
  ansible.builtin.set_fact:
    adgroup_object_id: "{{ adgroup_info_tmp.object_id }}"
  when: "'object_id' in adgroup_info_tmp"

- name: "[CRU_] [AAD] Update Role Group with ITC accounts"
  azure.azcollection.azure_rm_adgroup:
    object_id: "{{ adgroup_object_id }}"
    present_members: #"{{ itc_accounts.split(',') }}"
      - "https://graph.windows.net/{{ tenant_id }}/directoryObjects/{{ item.ad_users[0].object_id }}"
    tenant: "{{ tenant_id }}"
    subscription_id: "{{ subscription_id }}"
  loop: "{{ itc_objects.results }}"
  when: itc_accounts is defined and itc_accounts != None

- name: "[CRU_] [IAM] Get 'Contributor' role definition ID in RG's scope"
  azure.azcollection.azure_rm_roledefinition_info:
    scope: "{{ rg_info.id }}"
    role_name: 'Contributor'
  register: role_definition

# - ansible.builtin.debug:
#     msg: "{{ role_definition.roledefinitions[0].id|split('/')|last }}"

- name: "[CRU_] [IAM] Get existing IAM on given RG"
  azure.azcollection.azure_rm_roleassignment_info:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ rg_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: result


- name: "[CRU_] [IAM] Update IAM of given RG"
  azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ rg_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: result
  until: result is not failed 
  retries: 1
  delay: 10

the relevant output as shared earlier is as follows, please let me know if you were asking for something else:

TASK [[CRU_] [IAM] Update IAM of given RG] ***********************************************************************
FAILED - RETRYING: [localhost]: [CRU_] [IAM] Update IAM of given RG (1 retries left).
fatal: [localhost]: FAILED! => {"attempts": 1, "changed": false, "msg": "Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.\nCode: RoleAssignmentExists\nMessage: The role assignment already exists."}

PLAY RECAP *******************************************************************************************************
localhost                  : ok=13   changed=0    unreachable=0    failed=1    skipped=5    rescued=0    ignored=0   

I've run this on a new EE since the first time the issue occurred (and upgraded the collection version from v1.14.0 to v1.15.0 in the process.

I noticed you've used id parameter instead of scope that I've used (and not sure where you get the uuid from?), perhaps that is the key differentiator - can you try with scope instead?

@Fred-sun
Copy link
Collaborator

@Fred-sun in your test, did the second run come back as changed = false ? I'm assuming yes, but want to confirm.

@paultaiton Yes, idempotent! Thanks!

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan The use of scope is as follows:

- name: create role assignment by scope ---- first
  azure_rm_roleassignment:
    scope: "{{ az_resource_group.resourcegroups[0].id }}"
    assignee_object_id: "{{ az_role_assignments.roleassignments[0].principal_id }}"
    role_definition_id: "/subscriptions/{{ az_resource_group.resourcegroups[0].id.split('/')[2] }}/providers/Microsoft.Authorization/roleDefinitions/{{ az_role_definition_guid }}"

- name: create role assignment by scope -------- secondary
  azure_rm_roleassignment:
    scope: "{{ az_resource_group.resourcegroups[0].id }}"
    assignee_object_id: "{{ az_role_assignments.roleassignments[0].principal_id }}"
    role_definition_id: "/subscriptions/{{ az_resource_group.resourcegroups[0].id.split('/')[2] }}/providers/Microsoft.Authorization/roleDefinitions/{{ az_role_definition_guid }}"

results:

TASK [create role assignment by scope ---- first] **********************************************************************
changed: [localhost]

TASK [create role assignment by scope -------- secondary] **************************************************************
ok: [localhost]

@Mohammad-Atif-Khan
Copy link
Author

@Fred-sun thanks, but that is exactly how I've been using it.

I just tested it again without Execution Environment and I still get the same error. I even tried bypassing ansible-navigator and using ansible-playbook to run it but still the same.

It seems like the get_roleassignment() is either returning None or one of the conditions is not evaluating to True, leading to the execution of create_roleassignment()

I cannot get debug print statements to work (sorry I've not developed a module yet) - can you advise how I could get some messages out to stdout? I'm trying to debug the module myself but I cannot get any messages out to view during the execution. I've tried the vanilla print and also self.results['debug_print'].append('Getting Role assignment') but to no luck.

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan Repeated tests have not met your problem. Can you try it in a different environment? Also, makesure that the version installed is v1.15.0(latest version). Thanks!

@paultaiton
Copy link
Contributor

@Mohammad-Atif-Khan Repeated tests have not met your problem. Can you try it in a different environment? Also, makesure that the version installed is v1.15.0(latest version). Thanks!

I have also tried replicating the reported issue without success.

@Fred-sun
Copy link
Collaborator

@paultaiton Can I have a look at your full script? Thanks!

@Mohammad-Atif-Khan
Copy link
Author

I did try it in a new environment (v1.15.0) and got the same error.

I'm using a workaround, where I run the info module and check if the role assignment exists first and then conditionally run the role assignment thereafter.

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan If the roleassignment you created does not exist, can you successfully create it? Thanks!

@Mohammad-Atif-Khan
Copy link
Author

Mohammad-Atif-Khan commented Apr 21, 2023

@Fred-sun , yes, correct. If did not exist it creates it correctly; however if it does exist, it returns an error.

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan Are you still using the script in comments? Thanks!

@paultaiton
Copy link
Contributor

@paultaiton Can I have a look at your full script? Thanks!

---
- name: Role Assignment Info Play
  hosts: localhost
  gather_facts: false  # not necessary at this time; localhost provides no useful info.
  tasks:
    - name: List Role Assignments at scope
      azure.azcollection.azure_rm_roleassignment:
        assignee_object_id: "{{ az_role_assignment_assignee | default(omit) }}"
        id: "{{ az_role_assignment_id | default(omit) }}"
        name: "{{ az_role_assignment_name | default(omit) }}"
        role_definition_id: "{{ az_role_definition_id | default(omit) }}"
        scope: "{{ az_role_assignment_scope | default(omit) }}"
        state: present
        subscription_id: "{{ az_subscription_id | default(omit) }}"
      register: az_role_assignment

It's pretty basic, I do everything via parameters for testing. I cannot get it to fail on creating a role assignment that already exists.

@Mohammad-Atif-Khan
Copy link
Author

hi @Fred-sun ,

I only modified it to use the workaround I mentioned before. Here is the relevant YAML:

- name: "[CRU_] [IAM] Get existing IAM on given RG"
  azure.azcollection.azure_rm_roleassignment_info:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ rg_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: assignment_info


- name: "[CRU_] [IAM] Update IAM of given RG"
  azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ rg_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: result
  until: result is not failed 
  retries: 1
  delay: 10
  when: assignment_info.roleassignments|length<1

Something very strange I noticed: I retried the original playbook (without workaround), but on a different subscription, and it worked! It did not fail for an existing assignment.

Any idea what could explain that behavior?

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan I have also noticed this problem and I am dealing with it. Thank you!

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan The creation fails because a role has been created for the resource group in the specified id. When you create a role, a message is displayed indicating a failure. You can try it by specifying a new ID (different resource group). Thanks!

@Mohammad-Atif-Khan
Copy link
Author

I'm not sure I follow. Is the problem with the role as opposed to a role assignment?

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan Is your problem still there? As mentioned earlier, information about a role that should be assigned to you is used with its role, resulting in a failure to assign --- (RoleAssignmentExists)Thanks !

@Fred-sun Fred-sun added the not a bug Not a bug label Mar 29, 2024
@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan If you have no further questions, I will close it in a week. Thank you!

@Mohammad-Atif-Khan
Copy link
Author

Mohammad-Atif-Khan commented Mar 29, 2024 via email

@lukapetrovic-git
Copy link

Hi, i am having the exact same issue, its like the module is not idempotent:

Using the following:

Collection version 2.4.0

Ansible version:

ansible [core 2.16.7]
  config file = /home/luka/Documents/repos/dti/infra/infrastructure-ansible/playbooks/linux/kubernetes/ansible.cfg
  configured module search path = ['/home/luka/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/luka/Documents/repos/dti/infra/infrastructure-ansible/playbooks/linux/kubernetes
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
  jinja version = 3.0.3
  libyaml = True

If the role assignment does not exists, it gets created:

changed: [localhost] => (item={'path': 'subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx}) => {
    "ansible_loop_var": "scp",
    "assignee_object_id": "113849cf-2614-4c2c-bbf8-17f737833900",
    "changed": true,
    "id": "/subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx/providers/Microsoft.Authorization/roleAssignments/2152a52a-2b9a-439e-bc66-1d3562d8bd25",
    "invocation": {
        "module_args": {
            "ad_user": null,
            "adfs_authority_url": null,
            "api_profile": "latest",
            "assignee_object_id": "113849cf-2614-4c2c-bbf8-17f737833900",
            "auth_source": "auto",
            "cert_validation_mode": null,
            "client_id": null,
            "cloud_environment": "AzureCloud",
            "disable_instance_discovery": false,
            "id": null,
            "log_mode": null,
            "log_path": null,
            "name": null,
            "password": null,
            "profile": null,
            "role_definition_id": "/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
            "scope": "subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx",
            "secret": null,
            "state": "present",
            "subscription_id": null,
            "tenant": null,
            "thumbprint": null,
            "x509_certificate_path": null
        }
    },
    "name": "2152a52a-2b9a-439e-bc66-1d3562d8bd25",
    "principal_type": "ServicePrincipal",
    "role_definition_id": "/subscriptions/xxx-xxx-xxx/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
    "scope": "/subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx",
    "scp": {
        "path": "subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx"
    },
    "type": "Microsoft.Authorization/roleAssignments"
}

Next time it errors out:

The full traceback is:
  File "/tmp/ansible_azure.azcollection.azure_rm_roleassignment_payload_cp_abkd3/ansible_azure.azcollection.azure_rm_roleassignment_payload.zip/ansible_collections/azure/azcollection/plugins/modules/azure_rm_roleassignment.py", line 271, in create_roleassignment
  File "/home/luka/.local/lib/python3.10/site-packages/azure/mgmt/authorization/v2020_04_01_preview/operations/_role_assignments_operations.py", line 359, in create
    map_error(status_code=response.status_code, response=response, error_map=error_map)
  File "/home/luka/.local/lib/python3.10/site-packages/azure/core/exceptions.py", line 112, in map_error
    raise error
failed: [localhost] (item={'path': 'subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx'}) => {
    "ansible_loop_var": "scp",
    "changed": false,
    "invocation": {
        "module_args": {
            "ad_user": null,
            "adfs_authority_url": null,
            "api_profile": "latest",
            "assignee_object_id": "113849cf-2614-4c2c-bbf8-17f737833900",
            "auth_source": "auto",
            "cert_validation_mode": null,
            "client_id": null,
            "cloud_environment": "AzureCloud",
            "disable_instance_discovery": false,
            "id": null,
            "log_mode": null,
            "log_path": null,
            "name": null,
            "password": null,
            "profile": null,
            "role_definition_id": "/providers/Microsoft.Authorization/roleDefinitions/4633458b-17de-408a-b874-0445c86b69e6",
            "scope": "subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx",
            "secret": null,
            "state": "present",
            "subscription_id": null,
            "tenant": null,
            "thumbprint": null,
            "x509_certificate_path": null
        }
    },
    "msg": "Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.\nCode: RoleAssignmentExists\nMessage: The role assignment already exists.",
    "scp": {
        "path": "subscriptions/xxx-xxx-xxx/resourceGroups/xxx-xxx-xxx/providers/Microsoft.KeyVault/vaults/xxx-xxx-xxx"
    }
}

@paultaiton
Copy link
Contributor

@lukapetrovic-git

It's been quite a while since I've worked on any azure ansible code, so I'm a bit rusty.
One thing that does stand out to me, is that your scope does not have the preceeding ' / ' character. If you look at the other examples, it starts with "/subscriptions/" and yours is "subscriptions/" . Can you look at your invokation code, and modify it to include that slash preceeding the path?

@Mohammad-Atif-Khan
Copy link
Author

Hi @Fred-sun ,
Several versions later, the issue still persists.
The module is not idempotent, ie, it does not exit with success (no change) if the role assignment already exists. Instead, it exits with an error - this is not the expected behaviour.

can we please fix this? I don't think it is a big ask at all since other modules support idempotency.

It is quite disappointing to find such bugs in a collection that Microsoft maintains and which is also advertised as certified collection under the commercial offering of AWX in RHAAP.

@Fred-sun
Copy link
Collaborator

Fred-sun commented Oct 31, 2024

@Mohammad-Atif-Khan I am very sorry for replying to your question so late. But for the error you mentioned, I also only see if the scope definition does not ‘/‘ start causing this error(subscriptions/xxx/resourceGroups/v-xisuRG03 ---- /subscriptions/xxxx/resourceGroups/v-xisuRG03). In order to better solve this problem, can you provide the full playbook ad print the execution information of ansible-playbook tasks.yml -*** -vvvv during execution? Thank you!

@Mohammad-Atif-Khan
Copy link
Author

Hi @Fred-sun,
thanks but there was a leading / in the scope already and it did not work.

I added another / to share the output for below which made it // and it still throws the same error.

In any case, the module works when the role assignment does not exist and it clearly is made to exit with error code when it does, so it has to be a bug or a miss in the idempotency implementation for this module, right?

- name: "[CRU_] [IAM] Update IAM of given resource"
  azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "/{{ target_resource_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: result
TASK [[CRU_] [IAM] Update IAM of given resource] ***********************************************************************************************************************************
task path: /workspaces/IaC-Parametric/ST002-RG_Access/subtasks_role_assignment.yml:16
<127.0.0.1> ESTABLISH LOCAL CONNECTION FOR USER: 1000
<127.0.0.1> EXEC /bin/sh -c 'echo ~1000 && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /runner/.ansible/tmp `"&& mkdir "` echo /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902 `" && echo ansible-tmp-1730387614.0594773-154-177627573376902="` echo /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902 `" ) && sleep 0'
Using module file /usr/share/ansible/collections/ansible_collections/azure/azcollection/plugins/modules/azure_rm_roleassignment.py
<127.0.0.1> PUT /runner/.ansible/tmp/ansible-local-14mb985sbs/tmpc04br1nm TO /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902/AnsiballZ_azure_rm_roleassignment.py
<127.0.0.1> EXEC /bin/sh -c 'chmod u+x /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902/ /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902/AnsiballZ_azure_rm_roleassignment.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c '/usr/bin/python3 /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902/AnsiballZ_azure_rm_roleassignment.py && sleep 0'
<127.0.0.1> EXEC /bin/sh -c 'rm -f -r /runner/.ansible/tmp/ansible-tmp-1730387614.0594773-154-177627573376902/ > /dev/null 2>&1 && sleep 0'
FAILED - RETRYING: [localhost]: [CRU_] [IAM] Update IAM of given resource (5 retries left).Result was: {
    "attempts": 1,
    "changed": false,
    "invocation": {
        "module_args": {
            "ad_user": null,
            "adfs_authority_url": null,
            "api_profile": "latest",
            "assignee_object_id": "jftivj7h-38bb-7597-831f-214f3c0c15ff",
            "auth_source": "auto",
            "cert_validation_mode": null,
            "client_id": null,
            "cloud_environment": "AzureCloud",
            "disable_instance_discovery": false,
            "id": null,
            "log_mode": null,
            "log_path": null,
            "name": null,
            "password": null,
            "profile": null,
            "role_definition_id": "/subscriptions/jftivj7h-38bb-7597-831f-214f3c0c15ff/providers/Microsoft.Authorization/roleDefinitions/jftivj7h-38bb-7597-831f-214f3c0c15ff",
            "scope": "//subscriptions/jftivj7h-38bb-7597-831f-214f3c0c15ff/resourceGroups/RG-AnsibleDev-01/providers/Microsoft.Sql/servers/sql-glb-pub-ansiblesql-tst-02",
            "secret": null,
            "state": "present",
            "subscription_id": null,
            "tenant": null,
            "thumbprint": null,
            "x509_certificate_path": null
        }
    },
    "msg": "Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.\nCode: RoleAssignmentExists\nMessage: The role assignment already exists.",
    "retries": 6
}

@Fred-sun
Copy link
Collaborator

Fred-sun commented Nov 1, 2024

@Mohammad-Atif-Khan The '{{target_resource_info.id}}' start is already '/' please do not add '/', please try again, thank you!

- name: "[CRU_] [IAM] Update IAM of given resource"
  azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "{{ role_definition.roledefinitions[0].id }}"
    scope: "{{ target_resource_info.id }}"
    assignee_object_id: "{{ adgroup_object_id }}"
  register: result

@Fred-sun
Copy link
Collaborator

Fred-sun commented Nov 2, 2024

@Mohammad-Atif-Khan Why add '/'? Please delete and try again. Thank you!

scope: "/{{ target_resource_info.id }}"  ---- > scope: "{{ target_resource_info.id }}"

@Mohammad-Atif-Khan
Copy link
Author

Hi @Fred-sun ,
it fails with both variations. I added the leading slash as you requested it be tested.

Another very interesting observation: I could not reproduce this error on a different target tenant!

@Fred-sun
Copy link
Collaborator

@Mohammad-Atif-Khan Is it possible that your current account has a special setting that prevents you from accessing the assigned user information?

@BenTheCloudGuy
Copy link

This module clearly has issues. I see the above closed without resolution and I'm also encountering this issue. I'm not sure what I'm missing here. It creates the RoleAssignment and then fails on subsequent runs.

/home/vscode/.ansible/collections/ansible_collections

Collection Version


azure.azcollection 3.1.0
community.general 10.2.0

TASK [Configure SPN as Keyvault Contributor] *********************************************************************************************************
fatal: [localhost]: FAILED! => {"changed": false, "msg": "Error creating role assignment: (RoleAssignmentExists) The role assignment already exists.\nCode: RoleAssignmentExists\nMessage: The role assignment already exists."}

`

  • name: Configure SPN as Keyvault Contributor
    azure.azcollection.azure_rm_roleassignment:
    role_definition_id: "/subscriptions/{{ lookup('env', 'AZURE_SUBSCRIPTION_ID') }}/providers/Microsoft.Authorization/roleDefinitions/00482a5a-887f-4fb3-b363-3b7fe8e74483"
    assignee_object_id: "{{ SPN_OBJECT_ID }}"
    scope: "/subscriptions/{{ lookup('env', 'AZURE_SUBSCRIPTION_ID') }}/"
    state: present
    register: azRole
    `

@Fred-sun
Copy link
Collaborator

@BenTheCloudGuy Because I did not encounter this problem in the local test, and repeated simulation many times. Could you please describe this problem and detailed logs in detail, so as to analyze this problem? Thank you!

@Fred-sun
Copy link
Collaborator

@BenTheCloudGuy Already fixed in #1807, The scope in the return value does not end with /, so the / in the configuration value is deleted when comparing.
Your error cause by the test case scope configuration ends with /, Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
medium_priority Medium priority not a bug Not a bug question Further information is requested work in In trying to solve, or in working with contributors
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants