0

Hello Developer Community!

This is my first post here :-) I'm relatively new to Ansible and would like to get some help about the following. I'm trying to create some scripts to manage features on Citrix NetScaler VPX. In this specific case, I would like to deploy an SSL cipher group containing the defined SSL ciphers. I have the following data structure defined in a YAML file:

nsapp_sslciphergroup:
  - ciphergroupname:                   "TEST_1"
    sslcipher:
      - ciphername:                    "TLS1.3-AES256-GCM-SHA384"
        cipherpriority:                "1"
      - ciphername:                    "TLS1.3-CHACHA20-POLY1305-SHA256"
        cipherpriority:                "2"
      - ciphername:                    "TLS1.3-AES128-GCM-SHA256"
        cipherpriority:                "3"

  - ciphergroupname:                   "TEST_2"
    sslcipher:
      - ciphername:                    "TLS1.2-ECDHE-RSA-AES256-GCM-SHA384"
        cipherpriority:                "1"
      - ciphername:                    "TLS1.2-ECDHE-RSA-AES128-GCM-SHA256"
        cipherpriority:                "2"
      - ciphername:                    "TLS1.2-ECDHE-ECDSA-AES256-GCM-SHA384"
        cipherpriority:                "3"

NetScaler as such does not allow binding the same cipher into the given cipher group again, so before making any changes, I need somehow to check if the cipher group and its bindings already exist or not. So first run is okay, but any consecutive runs fail because the given ciphername is already bond to the ciphergroup. Current code is the following:

- name: "Add SSL ciphergroup binding(s)"
  netscaler_nitro_request:
    <<: *nitro_login
    operation: add
    resource: sslcipher_sslciphersuite_binding
    name: ""
    attributes:
          ciphergroupname: "{{ item.0.ciphergroupname }}"
          ciphername: "{{ item.1.ciphername }}"
          cipherpriority: "{{ item.1.cipherpriority }}"
  register: add_sslcipher_sslciphersuite_binding_result
  with_subelements:
    - "{{ nsapp_sslciphergroup }}"
    - "sslcipher"
    - skip_missing: true

In order to check what is the current configuration before running the script again, I have the following code:

- name: "Check if SSL ciphergroup binding(s) are already defined"
  netscaler_nitro_request:
    <<: *nitro_login
    operation: get
    resource: sslcipher_sslciphersuite_binding
    name: "{{ item.ciphergroupname }}"
    attributes:
          ciphergroupname: "{{ item.ciphergroupname }}"
  register: get_sslcipher_sslciphersuite_binding_result
  with_items: "{{ nsapp_sslciphergroup }}"

This code results the following (registered in the "get_sslcipher_sslciphersuite_binding_result" variable), if the ciphergroup is already defined with its bindings (and have a similar output for "TEST_2" group also with ist respective bindings):

"nitro_object": [
    {
        "ciphergroupname": "TEST_1", 
        "ciphername": "TLS1.3-AES256-GCM-SHA384", 
        "cipherpriority": "1", 
        "description": "TLSv1.3 Kx=any      Au=any  Enc=AES-GCM(256) Mac=AEAD   HexCode=0x1302", 
        "peflags": "4", 
        "stateflag": "512"
    }, 
    {
        "ciphergroupname": "TEST_1", 
        "ciphername": "TLS1.3-CHACHA20-POLY1305-SHA256", 
        "cipherpriority": "2", 
        "description": "TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD   HexCode=0x1303", 
        "peflags": "4", 
        "stateflag": "512"
    }, 
    {
        "ciphergroupname": "TEST_1", 
        "ciphername": "TLS1.3-AES128-GCM-SHA256", 
        "cipherpriority": "3", 
        "description": "TLSv1.3 Kx=any      Au=any  Enc=AES-GCM(128) Mac=AEAD   HexCode=0x1301", 
        "peflags": "4", 
        "stateflag": "512"
    }
], 

I'm playing with adding a "when" clause after the "with_subelements" section, but the add section of the script always wants to run.

Could anybody please advise what is the correct way to check if the "get_sslcipher_sslciphersuite_binding_result" variable contains the given ciphername for the given ciphergroup?

Many thanks in advance!

Belabacsi
  • 121
  • 2
  • 10

2 Answers2

0

The solution is to let the module report failure and test the errorcode

failed_when: 
  - add_sslcipher_sslciphersuite_binding_result.nitro_errorcode != 0
  - add_sslcipher_sslciphersuite_binding_result.nitro_errorcode != 3741

Given the module returns "0" on a successful update of the resource, probably it would be possible to make it idempotent with

changed_when:
  - add_sslcipher_sslciphersuite_binding_result.nitro_errorcode == 0


Not idempotent.

Q: NetScaler as such does not allow binding the same cipher into the given cipher group again, so before making any changes, I need somehow to check if the cipher group and its bindings already exist or not. So first run is okay, but any consecutive runs fail because the given ciphername is already bond to the ciphergroup. Current code is the following:

- name: "Add SSL ciphergroup binding(s)"
  netscaler_nitro_request:
    <<: *nitro_login
    operation: add
    resource: sslcipher_sslciphersuite_binding
    name: ""
    attributes:
          ciphergroupname: "{{ item.0.ciphergroupname }}"
          ciphername: "{{ item.1.ciphername }}"
          cipherpriority: "{{ item.1.cipherpriority }}"
  register: add_sslcipher_sslciphersuite_binding_result
  with_subelements:
    - "{{ nsapp_sslciphergroup }}"
    - "sslcipher"
    - skip_missing: true

Most of the NetScaler REST API queries work in this way, no idempotency at all.

A: Idempotency is the key feature of Ansible. Quoting from Glossary

Idempotency: An operation is idempotent if the result of performing it once is exactly the same as the result of performing it repeatedly without any intervening actions.

There is no sign in the documentation that the module netscaler_nitro_request might not be idempotent.

Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
  • Unfortunately, in case of NetScaler, this is not the case :-( Most of the NetScaler REST API queries work in this way, no idempotency at all. – Belabacsi Sep 01 '19 at 16:25
0

Just hacked it :-) The NS error code of "Specified cipher is already bound with higher priority" is 3741. Simply added it in a failed_when condition.

- name: "Add SSL ciphergroup binding(s) if they do *NOT* exist"
  netscaler_nitro_request:
    <<: *nitro_login
    operation: add
    resource: sslcipher_sslciphersuite_binding
    name: ""
    attributes:
          ciphergroupname: "{{ item.0.ciphergroupname }}"
          ciphername: "{{ item.1.ciphername }}"
          cipherpriority: "{{ item.1.cipherpriority }}"
  register: add_sslcipher_sslciphersuite_binding_result
  until: ( add_sslcipher_sslciphersuite_binding_result is succeeded )
  retries: 6
  delay: 5
  with_subelements:
    - "{{ nsapp_sslciphergroup }}"
    - "sslcipher"
    - skip_missing: true
  failed_when: ( (add_sslcipher_sslciphersuite_binding_result.nitro_errorcode != 0) and (add_sslcipher_sslciphersuite_binding_result.nitro_errorcode != 3741) )
- debug: 
    var: add_sslcipher_sslciphersuite_binding_result
  tags: [ never, debug ]
- assert:
    that: ( (add_sslcipher_sslciphersuite_binding_result.results[{{ item }}].nitro_errorcode == 0) or (add_sslcipher_sslciphersuite_binding_result.results[{{ item }}].nitro_errorcode == 3741) )
    fail_msg: "[ERROR] Operation failed!"
    success_msg: "[OK] Operation successful." 
  loop: "{{ nsapp_sslciphergroup }}" 
  loop_control:
    index_var: item
Belabacsi
  • 121
  • 2
  • 10