1

I have multiple users from 4x different LDAP domains and am trying to automate a way of adding them across multiple servers. Attributes for each user/group are static except for the identity_source_id which can be one of 4 possible values.

I would like to select the correct identity_source_id value based on the name value.

First step is to get the LDAP IDs and Domains from each server Using

  • GET fqdn/policy/api/v1/aaa/ldap-identity-sources
  • register: id_source_results

I'm able to get the LDAP ID and Domain Name for each LDAP Config on the server. Then

- name: set fact to store ID and domain_name
  set_fact:
    id_domain: "{{ id_domain|d([]) + [{'id': item.id, 'domain_name': item.domain_name }] }}" 
  with_items: "{{id_source_results.json.results }}"

- name: Create dict for domain_name to id
  set_fact:
    id_domain_dict: "{{ id_domain | items2dict(key_name='domain_name', value_name='id' ) }}"

- name: Print dict
  debug:
    var: id_domain_dict

Gives

    "id_domain_dict": {
        "north.acme.com": "1111111-aaaaa",
        "south.acme.com": "2222222-bbbbb",
        "east.acme.com": "3333333-ccccc",
        "west.acme.com": "4444444-ddddd"
    }

The playbook i'm using to push the config is

- name: List LDAP Identity Sources
  ansible.builtin.uri:
    url: https://{{inventory_hostname}}/api/v1/aaa/role-bindings
    validate_certs: no
    timeout: 15
    force_basic_auth: yes
    url_username: "administrator"
    url_password: "{{ admin_password }}"
    method: POST
    body_format: json
    body: 
    [{
      "name": "frank@NORTH.ACME.COM",
      "type": "remote_user",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "admin",
          "role_display_name": "Admin"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "frank@NORTH.ACME.COM"
    },
    {
      "name": "ruth@SOUTH.ACME.COM",
      "type": "remote_user",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "network_engineer",
          "role_display_name": "Network Engineer"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "ruth@SOUTH.ACME.COM"
    },
    {
      "name": "finance_team@east.acme.com",
      "type": "remote_group",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "finance_admin",
          "role_display_name": "Finance Admin"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "finance_team@east.acme.com"
    },
    {
      "name": "auditors@west.acme.com",
      "type": "remote_group",
      "identity_source_type": "LDAP",
      "identity_source_id": "{{id_domain_dict.value}}",
      "roles": [
        {
          "role": "read-only",
          "role_display_name": "Read-Only"
        }
      ],
      "resource_type": "RoleBinding",
      "display_name": "auditors@west.acme.com"
    }]
    return_content: yes
    status_code: 200
  delegate_to: localhost

Because the API Post body is static, i can't figure out how to select the correct value from id_domain_dict. eg for auditors@west.acme.com the id_domain_dict.value should be 4444444-ddddd

I've tried splitting the user value using "@" but can't get this to work

{% for k,v in id_domain_dict.items %}
{% domain = {{name}}.split('@') %}
{% if domain[1] in k %}
{{ v }}
{% endfor %}

I've also tried

"identity_source_id": "{{ v if domain[1] in k '' }}"

But have been unsuccessful in all attempts

piercjs
  • 133
  • 8

1 Answers1

0
  • Simplify the dictionary
  id_domain_dict: "{{ dict(id_source_results.json.results|
                           json_query('[].[domain_name, id]')) }}"

gives

  id_domain_dict:
    east.acme.com: 3333333-ccccc
    north.acme.com: 1111111-aaaaa
    south.acme.com: 2222222-bbbbb
    west.acme.com: 4444444-ddddd
  • Put the body into a variable. For example, create a YAML file and read it
shell> cat body.yml 
- display_name: frank@NORTH.ACME.COM
  identity_source_id: '{{ id_domain_dict.value }}'
  identity_source_type: LDAP
  name: frank@NORTH.ACME.COM
  resource_type: RoleBinding
  roles:
  - {role: admin, role_display_name: Admin}
  type: remote_user
- display_name: ruth@SOUTH.ACME.COM
  identity_source_id: '{{ id_domain_dict.value }}'
  identity_source_type: LDAP
  name: ruth@SOUTH.ACME.COM
  resource_type: RoleBinding
  roles:
  - {role: network_engineer, role_display_name: Network Engineer}
  type: remote_user
- display_name: finance_team@east.acme.com
  identity_source_id: '{{ id_domain_dict.value }}'
  identity_source_type: LDAP
  name: finance_team@east.acme.com
  resource_type: RoleBinding
  roles:
  - {role: finance_admin, role_display_name: Finance Admin}
  type: remote_group
- display_name: auditors@west.acme.com
  identity_source_id: '{{ id_domain_dict.value }}'
  identity_source_type: LDAP
  name: auditors@west.acme.com
  resource_type: RoleBinding
  roles:
  - {role: read-only, role_display_name: Read-Only}
  type: remote_group
  body: "{{ lookup('file', 'body.yml')|from_yaml }}"

gives

  body:
  - display_name: frank@NORTH.ACME.COM
    identity_source_id: '{{ id_domain_dict.value }}'
    identity_source_type: LDAP
    name: frank@NORTH.ACME.COM
    resource_type: RoleBinding
    roles:
    - role: admin
      role_display_name: Admin
    type: remote_user
  - display_name: ruth@SOUTH.ACME.COM
    identity_source_id: '{{ id_domain_dict.value }}'
    identity_source_type: LDAP
    name: ruth@SOUTH.ACME.COM
    resource_type: RoleBinding
    roles:
    - role: network_engineer
      role_display_name: Network Engineer
    type: remote_user
  - display_name: finance_team@east.acme.com
    identity_source_id: '{{ id_domain_dict.value }}'
    identity_source_type: LDAP
    name: finance_team@east.acme.com
    resource_type: RoleBinding
    roles:
    - role: finance_admin
      role_display_name: Finance Admin
    type: remote_group
  - display_name: auditors@west.acme.com
    identity_source_id: '{{ id_domain_dict.value }}'
    identity_source_type: LDAP
    name: auditors@west.acme.com
    resource_type: RoleBinding
    roles:
    - role: read-only
      role_display_name: Read-Only
    type: remote_group
  • Select the names, split the domains, extract ids, and create the list of the dictionaries
  domains: "{{ body|map(attribute='name')|
                    map('split', '@')|map('last')|map('lower')|
                    map('extract', id_domain_dict)|
                    map('community.general.dict_kv', 'identity_source_id') }}"

gives

  domains:
  - identity_source_id: 1111111-aaaaa
  - identity_source_id: 2222222-bbbbb
  - identity_source_id: 3333333-ccccc
  - identity_source_id: 4444444-ddddd
  • Combine the items of the lists
  body_update: "{{ body|zip(domains)|map('combine') }}"

gives the structure you're looking for

  body_update:
  - display_name: frank@NORTH.ACME.COM
    identity_source_id: 1111111-aaaaa
    identity_source_type: LDAP
    name: frank@NORTH.ACME.COM
    resource_type: RoleBinding
    roles:
    - role: admin
      role_display_name: Admin
    type: remote_user
  - display_name: ruth@SOUTH.ACME.COM
    identity_source_id: 2222222-bbbbb
    identity_source_type: LDAP
    name: ruth@SOUTH.ACME.COM
    resource_type: RoleBinding
    roles:
    - role: network_engineer
      role_display_name: Network Engineer
    type: remote_user
  - display_name: finance_team@east.acme.com
    identity_source_id: 3333333-ccccc
    identity_source_type: LDAP
    name: finance_team@east.acme.com
    resource_type: RoleBinding
    roles:
    - role: finance_admin
      role_display_name: Finance Admin
    type: remote_group
  - display_name: auditors@west.acme.com
    identity_source_id: 4444444-ddddd
    identity_source_type: LDAP
    name: auditors@west.acme.com
    resource_type: RoleBinding
    roles:
    - role: read-only
      role_display_name: Read-Only
    type: remote_group
  • Use it in the body
  {{ body_update|to_nice_json }}

gives

    [
        {
            "display_name": "frank@NORTH.ACME.COM",
            "identity_source_id": "1111111-aaaaa",
            "identity_source_type": "LDAP",
            "name": "frank@NORTH.ACME.COM",
            "resource_type": "RoleBinding",
            "roles": [
                {
                    "role": "admin",
                    "role_display_name": "Admin"
                }
            ],
            "type": "remote_user"
        },
        {
            "display_name": "ruth@SOUTH.ACME.COM",
            "identity_source_id": "2222222-bbbbb",
            "identity_source_type": "LDAP",
            "name": "ruth@SOUTH.ACME.COM",
            "resource_type": "RoleBinding",
            "roles": [
                {
                    "role": "network_engineer",
                    "role_display_name": "Network Engineer"
                }
            ],
            "type": "remote_user"
        },
        {
            "display_name": "finance_team@east.acme.com",
            "identity_source_id": "3333333-ccccc",
            "identity_source_type": "LDAP",
            "name": "finance_team@east.acme.com",
            "resource_type": "RoleBinding",
            "roles": [
                {
                    "role": "finance_admin",
                    "role_display_name": "Finance Admin"
                }
            ],
            "type": "remote_group"
        },
        {
            "display_name": "auditors@west.acme.com",
            "identity_source_id": "4444444-ddddd",
            "identity_source_type": "LDAP",
            "name": "auditors@west.acme.com",
            "resource_type": "RoleBinding",
            "roles": [
                {
                    "role": "read-only",
                    "role_display_name": "Read-Only"
                }
            ],
            "type": "remote_group"
        }
    ]

Example of a complete playbook for testing

- hosts: localhost

  vars:

    id_source_results:
      json:
        results:
          - {id: 1111111-aaaaa, domain_name: north.acme.com}
          - {id: 2222222-bbbbb, domain_name: south.acme.com}
          - {id: 3333333-ccccc, domain_name: east.acme.com}
          - {id: 4444444-ddddd, domain_name: west.acme.com}

    id_domain_dict: "{{ dict(id_source_results.json.results|
                             json_query('[].[domain_name, id]')) }}"

    body: "{{ lookup('file', 'body.yml')|from_yaml }}"
    domains: "{{ body|map(attribute='name')|
                      map('split', '@')|map('last')|map('lower')|
                      map('extract', id_domain_dict)|
                      map('community.general.dict_kv', 'identity_source_id') }}"
    body_update: "{{ body|zip(domains)|map('combine') }}"

  tasks:

    - debug:
        var: id_domain_dict
    - debug:
        var: body
    - debug:
        var: domains
    - debug:
        var: body_update

    - debug:
        msg: |
          {{ body_update|to_nice_json }}
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63