aruba / aruba-ansible-modules

Aruba Ansible Modules
Apache License 2.0
80 stars 36 forks source link

HTTP 400 using arubaoss_config_bkup #76

Closed erishiamu closed 4 years ago

erishiamu commented 4 years ago

We're trying to automate config backups nightly for an aruba switch stack (currently one, we're planning to replace existing brocades with these and want a solution in place before we do so).

Model/OS Version: Product: Aruba JL322 Name: Aruba 2930M-48G-PoE+ Switch Date: Nov 1 2019 19:24:11 Build: 208 Version: WC.16.10.0002

We have the following in the hosts:

[aruba-sitecode] HOSTNAME ansible_host=#.#.#.# ansible_network_os=aruba ansible_connection=local

[aruba-blr:vars] ansible_user=serviceaccount ansible_pass=password ansible_command_timeout=80

And this playbook:

We are able to authenticate against the api with curl/postman and get a cookie. When we attempt to run the playbook we get the following failure:

fatal: [HOSTNAME]: FAILED! => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "body": "400 Bad Request

Bad Request

Access is unauthorized.

", "changed": false, "connection": "close", "content-length": "89", "content-type": "text/html", "invocation": { "module_args": { "api_version": "v7.0", "config_type": "CT_RUNNING_CONFIG", "file_name": "running_config_BLR-ARUBASTACK-01_20200102.txt", "forced_reboot": null, "host": "#.#.#.#", "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "port": 443, "provider": { "api_version": null, "host": "#.#.#.#", "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", "port": 443, "ssh_keyfile": null, "timeout": 30, "transport": "aossapi", "use_proxy": false, "use_ssl": true, "username": "serviceaccount", "validate_certs": false }, "recovery_mode": null, "server_ip": "TFTPSERVERIP", "server_name": null, "server_passwd": null, "server_type": "ST_TFTP", "sftp_port": 22, "ssh_keyfile": null, "state": "create", "timeout": 30, "use_ssl": true, "user_name": "serviceaccount", "username": "serviceaccount", "validate_certs": false, "wait_for_apply": true } }, "msg": "HTTP Error 400: Bad Request", "server": "eHTTP v2.0", "status": 400, "url": "https://#.#.#.#:443/rest/v7.0/system/config/cfg_backup_files" }

We have the following questions:

Is there something obviously wrong with the playbook or am I omitting a setting? The only things I've been able to find on the airheads community are either people complaining about a lack of depth for the api and ansible documentation, or alagoutte referring people to open issues here rather than there.

Do we need to specify an api version? If I specify nothing I receive: None is not valid api version. using aossapi v6.0 instead if I specify 6.0(or 6, or 7.0) I receive: 6.0 is not valid api version. using aossapi v6.0 instead And the output has a v7.0 uri.

Are we able to specify an SSL port? We would like the web interface port configured 8443 but as far as I can tell there isn't a way to feed it a port.

Last, is there a better way to get a running config locally to our ansible system? Its much easier on our arista, brocade, and cisco devices as we can just run show run and drop the output to file. I was not able to get that working with aruba_command, is there a module in this pack I can try which allows ssh/cli interface rather than API?

We're not in the string and it spits out some text about missing a version

HPE's api documentation is fairly unthorough in this case. We have aaa authorization none set, we're not specifying a command

alagoutte commented 4 years ago

Hi,

What do you have configure for HTTPS access to the switch ?

About port, yes it will be a good idea to have option to custom this

erishiamu commented 4 years ago

Hi,

Not sure what you mean by that?

We have this configured for AAA, if this is what you're asking?

aaa authorization rest-uri radius aaa authentication console login radius local aaa authentication console enable radius local aaa authentication telnet login radius local aaa authentication telnet enable radius local aaa authentication web login radius local aaa authentication web enable radius local aaa authentication ssh login radius local aaa authentication ssh enable radius local aaa authentication rest login radius local aaa authentication rest enable radius local aaa authentication port-access eap-radius

REST Interface - Server Configuration

REST Interface : Enabled REST Operational Status : Up REST Session Idle Timeout : 600 seconds HTTP Access : Enabled HTTPS Access : Enabled SSL Port : 443

tchiapuziowong commented 4 years ago

Hi @erishiamu !

Were you able to get the module working by changing the ansible_network_os to be arubaoss like I mentioned in your Airheads post?

alagoutte commented 4 years ago

What login do you are using ?

if you remove aaa authentication rest login radius local aaa authentication rest enable radius local

and use manager account for REST API, it is working ?

erishiamu commented 4 years ago

I'm not sure how to remove those? "no aaa authentication rest" isn't a valid command, would setting it to aaa authentication rest login local / enable local work? The API documentation does not advise how to remove these from the config, only how to set them.

We're currently using a domain account with radius auth against a windows domain controller running NPS.

EDIT: Okay yes running aaa authentication rest login/enable local removes those lines from the config.

I receive authentication failed trying to use the local manager account with curl or with the playbook.

tchiapuziowong commented 4 years ago

REST API should be enabled on whichever account you're using to login with Ansible - I'm not too sure where this issue is at this moment, could you clarify if you're still having the original issue or if another has come up?

erishiamu commented 4 years ago

Hello,

You replied to my crossposting of this to airheads also. I changed the os in the hosts file to arubaoss without any change in the behavior. This is the same issue, I was simply replying to alagoutte's request to disable radius for the rest api and try the local manager account (which did not work).

"REST API should be enabled on whichever account you're using to login with Ansible" - I'm not sure what exactly you mean by this. We're specifying a domain service account which has manager access to the switch in the ansible hostfile (and referencing that account in the playbook). I'm able to use that account / password with curl to authenticate successfully and receive a cookie, but receive 400 bad request / unauthorized if I run the playbook listed in the OP.

I can clarify if needed, apologies if there was confusion.

Using the playbook in the op or this curl command: curl --noproxy #.#.#.# -X POST https://#.#.#.#:443/rest/v7.0/login-sessions -d '{"userName":"SERVICEACCOUNT", "password":"PASSWORD"}' -k with these set in the config: aaa authentication rest login radius local aaa authentication rest enable radius local and with aaa authorization rest-uri none set to allow unauthorized uri access per tab completion on the switch: BLR-ARUBASTACK-01(config)# aaa authorization rest-uri local Authorize rest-uri using local groups. radius Authorize rest-uri using RADIUS. none Do not require authorization for rest-uri access.

The curl command authenticates and provides me a cookie: {"uri":"/login-sessions","cookie":"sessionId=COOKIE"}

The playbook provides this output. "body": "<HTML><TITLE>400 Bad Request</TITLE><H1>Bad Request</H1>Access is unauthorized.<P></HTML>",

This is the original issue and what I am still facing. I have also tried setting aaa authorization rest-uri radius on the switch, which causes both the playbook and curl command to fail authentication instead. I am specifying the VSAs listed in the API documentation 16.10 pdf:

image

But that documentation does not provide me with the vendor ID nor did I see a way to determine it in the documentation. I'm currently specifying the VSAs as RADIUS standard, and as .* which the documentation says is a wildcard accepted for all three required values:

image

which I assume is why it fails. If you can advise how to obtain the Vendor ID for the switch I'd be happy to correct that and test. The only thing I've found both reading the various documentation PDFs and from web searching is this command:

show aaa radius-attributes | include Aruba,Value

from this thread on airheads, and show aaa radius-attributes is not a valid command on this switch.

Is that more clear? Apologies for the confusion I did not mean to duplicate the conversation and am happy to have it either here or on airheads, whichever you feel is more appropriate.

tchiapuziowong commented 4 years ago

Hmm okay I'm looking more towards Ansible being the problem since you're able to successfully send commands through curl, I would say lets start at that state. Configure your device to the original state where curl was working. Have you gotten any other arubaoss module to work with your environment or are you having a specific issue with the config_bkup?

Looking at your example inventory:

[aruba-sitecode]
HOSTNAME ansible_host=#.#.#.# ansible_network_os=aruba ansible_connection=local

[aruba-blr:vars]
ansible_user=serviceaccount
ansible_pass=password
ansible_command_timeout=80

and your example playbook:

- hosts: aruba-sitecode
  gather_facts: false
  vars:
    date: "{{ lookup('pipe', 'date +%Y%m%d') }}"
    filename: "running_config_{{ inventory_hostname }}_{{date}}.txt"
  tasks:
    - name: show run
      arubaoss_config_bkup:
        config_type: CT_RUNNING_CONFIG
        server_type: ST_TFTP
        server_ip: #.#.#.#
        file_name: "{{filename}}"
        use_ssl: True
        user_name: "{{ ansible_user }}"
        password: "{{ ansible_pass }}"

You should be defining the variable ansible_password instead of ansible_pass and you shouldn't be passing in those variables into the module, Ansible will attempt to login using REST using the inventory variables ansible_user and ansible_password.

From your curl command example, your inventory should look like this:

[aruba-sitecode]
HOSTNAME ansible_host=#.#.#.# ansible_network_os=arubaoss ansible_connection=local

[aruba-blr:vars]
ansible_user=SERVICEACCOUNT
ansible_password=PASSWORD
ansible_command_timeout=80

But the error is stating a BAD REQUEST and not a FAILED LOGIN. Could you remove those extra variables from the module reference, change the password variable in the inventory and see if that works?

Your task should look like this:

- hosts: aruba-sitecode
  gather_facts: false
  vars:
    date: "{{ lookup('pipe', 'date +%Y%m%d') }}"
    filename: "running_config_{{ inventory_hostname }}_{{date}}.txt"
  tasks:
    - name: show run
      arubaoss_config_bkup:
        config_type: CT_RUNNING_CONFIG
        server_type: ST_TFTP
        server_ip: #.#.#.#
        file_name: "{{filename}}"

I'll do research on the Vendor ID portion of your question and see what I can come up with. I'd like to narrow down if it's an issue with the switch's authorization configuration or if it's with Ansible, if that makes sense?

erishiamu commented 4 years ago

Yeah I gotcha. We are married to ansible as a solution for this unless it proves to be totally untenable. We are currently only leveraging this module, I can test another one for the sake of argument if you believe it would be valuable. I don't want to make changes, is there a good one which can be used read only or to query something?

I've made your suggested edits in a new yml file. I did include use_ssl: true (but tried without, and the behavior is the same on port 80 rather than 443)

[aruba-sitecode] HOSTNAME ansible_host=#.#.#.# ansible_network_os=arubaoss ansible_connection=local

[aruba-sitecode:vars] ansible_user=serviceaccount ansible_password=password ansible_command_timeout=80

--- - hosts: aruba-sitecode gather_facts: false ` vars:` ` date: "{{ lookup('pipe', 'date +%Y%m%d') }}"` ` filename: "running_config_{{ inventory_hostname }}_{{date}}.txt"` tasks: - name: show run arubaoss_config_bkup: config_type: CT_RUNNING_CONFIG server_type: ST_TFTP server_ip: 10.100.1.51 # file_name: "{{filename}}" file_name: test.txt

Issue appears unchanged.

image

tchiapuziowong commented 4 years ago

hmm okay are you able to manually tftp the configuration off the switch? Does the file in the TFTP server have the correct permissions?

erishiamu commented 4 years ago

Yes maam, without issue.

image

image

I also see a bunch of successful login/logout for my SA for rest in the webui that look to correlate with my attempts to run the playbook.

image

tchiapuziowong commented 4 years ago

Are you able to execute any POST commands using curl on your device or only GET? Can you try this command: curl --noproxy #.#.#.# --cookie "sessionId=" -i -k -X POST http://#.#.#.#/rest/v4/cli -d '{"cmd": "show running"}'

erishiamu commented 4 years ago

Nope.

image

tchiapuziowong commented 4 years ago

Ah okay yeah so it looks like your device isn't authorizing POST commands specifically... That's what you were attempting to fix by adding the Vendor ID to your Radius configuration right? This isn't expected in your environment?

tchiapuziowong commented 4 years ago

Also from that post you linked : https://community.arubanetworks.com/t5/Security/ArubaOS-Admin-Authentication-with-Microsoft-NPS/td-p/433832

show aaa radius-attributes is supposed to be executed on the Mobility Master or Controller not the switch, are you able to try that at all?

erishiamu commented 4 years ago

I was attempting to add the vendor ID so we could ensure that we were actually authorizing the API successfully as we're receiving Unauthorized messages despite it ostensibly being not required. I currently have aaa authorization rest-uri none set so it should not require authorization, is that an incorrect reading of the built in help?

To be clear, GET is also not working. The original command was a post to authenticate, trying a get example from the documentation also provides the same.

Here is a get example from the api documentation with the same response: image

I'm unclear what a mobility master or controller device is, I missed that detail. This is a switch stack, we're not utilizing any separate Aruba appliance to manage these.

EDIT: Okay yeah we are not using a virtual or physical appliance for these. I can't imagine the only way to obtain the vendor ID to use the provided VSAs is to deploy this?

alagoutte commented 4 years ago

Hi,

For me, it is a Authorization issue... You need to use Vendor ID (ID 11) from HPE (and not Aruba) https://github.com/FreeRADIUS/freeradius-server/blob/master/share/dictionary/radius/dictionary.hp#L78

erishiamu commented 4 years ago

I will try that.

erishiamu commented 4 years ago

Alright, using the correct vendor ID has not altered the behavior. If I have aaa authorization rest-uri none set, I am able to authenticate with curl to get a cookie but receive 400 / unauthorized when trying to post or get or using the playbook. If aaa authorization rest-uri radius is set I am unable to login with curl to get a cookie and receive authentication failed from that attempt and from the playbook.

In either case the NPS server logs (event log and the IAS accounting log) show successful authentications to the client twice.

I need some clarity here: If I have aaa authorization rest-uri none, why is it providing an authorization failure? The built in help for this command indicates:

none Do not require authorization for rest-uri access.

Likewise, why does requiring aaa authorization rest-uri radius cause authentication failures on the switch? The NPS server performing RADIUS auth still sees those as successful and logs that it granted access to the client and lists both the correct caller station (the centos VM running ansible) and the correct client/policy.

tchiapuziowong commented 4 years ago

So just to understand when you have aaa authorization rest-uri none are you able to perform GET or POST commands using curl and not Ansible?

erishiamu commented 4 years ago

No. I am only able to obtain a cookie, every other get or post command tried (the one provided by you as well as examples from the api documentation) provide the same HTTP 400 Unauthorized.

erishiamu commented 4 years ago

Hello,

Apologies, hoping to follow up on this?

tchiapuziowong commented 4 years ago

Hi @erishiamu this doesn't seem to be an issue with Ansible but more your environment with aaa authorization, were you able to successfully use the SSH CLI module at all? How to install/use CLI modules and tasks for Switch and CX in Ansible

tchiapuziowong commented 4 years ago

@erishiamu when you removed the lines from the config - were you able to run any POST or GET commands after authentication? aaa authentication rest login radius local aaa authentication rest enable radius local aaa authorization rest-uri none

erishiamu commented 4 years ago

If I remove the radius authentication from the switch I am able to run a post to show run as you indicated previously in the thread and receive a base64 coded response.

image

tchiapuziowong commented 4 years ago

yes that's expected. you'll have to decode the response, your playbook should look like the following:

---
- hosts: switch1
  gather_facts: False
  tasks:
    -
      block:
        # Login to ArubaOS Switch
        - name: Login to ArubaOS Switch
          uri:
            url: "https://{{ ansible_host }}/rest/v4/login-sessions"
            method: POST
            headers:
              Accept: "application/json"
              Content-Type: "application/json"
            body: {"userName": "{{ ansible_user }}", "password": "{{ ansible_password }}"}
            body_format: json
            validate_certs: no
            status_code: 201
          register: switch_session

        - name: Execute show running command and register output
          uri:
            url: "https://{{ ansible_host }}/rest/v4/cli"
            method: POST
            headers:
               Cookie: '{{ switch_session.json.cookie }}'
            body_format: json
            body: {"cmd": "show running"}
            validate_certs: no
            status_code: 200,202
          register: response
          failed_when: response.json.status != "CCS_SUCCESS"

        - set_fact:
            running_config:  "{{ response.json.result_base64_encoded | b64decode }}"

      rescue:
        - debug:
            var: response.msg

      always:

        # Logout from ArubaOS Switch
        - name: logout from switch
          uri:
            url: 'https://{{ ansible_host }}/rest/v4/login-sessions'
            method: DELETE
            body_format: json
            return_content: no
            validate_certs: no
            headers:
              cookie: '{{ switch_session.json.cookie }}'
            status_code: 204
          register: logout_response

I added a block around logging in and logging out to ensure the session is always closed

erishiamu commented 4 years ago

RE the other modules for ssh_cli on switch. I did attempt to utilize those instead of relying on the API however experienced difficulties getting them to work, and had numerous questions RE the inventory configuration and what is required for the ssh_cli workflow. It is substantially more involved than the inventory setup for this or any other module we've leveraged in the past, it is not clear to me how the various variable subfolders interact and when trying to follow the workflow for setting up inventory it seems to not be resolving the mac address into the ip specified and is falling back to normal DNS resolution on the system. I'm sure this is largely due to my unfamiliarity with Ansible in general, but up until we started trying to get Aruba's working I've been able to muddle my way through. If the API is the preferred method in general (which was the impression I got from some research) then we'd rather leverage that, but if I could achieve clarity on the other module's inventory, which settings are required, and if possible a way to configure it relying on only the hostfile rather than having to create a branch, multiple yml files in different locations requiring the mac address of the management vlan's port on each switch stack that would be fine as well.

erishiamu commented 4 years ago

Alright. So I'm able to utilize the manager account/password with radius disabled for to do a config backup. I have not implemented your more complicated workflow but I appreciate your providing that. If we need more complicated interactions than a config backup that will no doubt be incredibly helpful.

I imagine at this point its worth reaching out to support directly for assistance on getting the api to behave over radius/ questions involving the strange behavior with authorization?

tchiapuziowong commented 4 years ago

correct! I would suggest reaching out to support and they can work with you hand in hand!

erishiamu commented 4 years ago

Alrighty. I appreciate the help with this issue for sure, it was absolutely helpful on my end despite arriving at a fundamentally different issue than initially suspected!