Repository: ansible/ansible
Pull request: openssl_csr: Improved documentation on subject_alt_name possible values
##### SUMMARY

openssl_csr: Improved documentation on subject_alt_name possible values

##### ISSUE TYPE

 - Docs Pull Request

##### COMPONENT NAME

  * openssl_csr

##### ANSIBLE VERSION

  * devel

##### ADDITIONAL INFORMATION

  * N/A

Fixes: https://github.com/ansible/ansible/issues/35550

Problem statement:
OpenSSL.crypto.Error: [('X509 V3 routines', 'v2i_GENERAL_NAME_ex', 'missing value'), ('X509 V3 routines', 'X509V3_EXT_nconf', 'error in extension')]
##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME

openssl_csr

##### ANSIBLE VERSION

Latest unstable version:
```
ansible 2.5.0 (devel 9001a8794f) last updated 2018/01/31 14:40:56 (GMT +200)
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/home/actionmystique/Ansible/git-yang-networkop/ansible-101/library']
  ansible python module location = /media/actionmystique/SAMSUNG5-Shared/home/actionmystique/src/Ansible/git-ansible/lib/ansible
  executable location = /home/actionmystique/src/Ansible/git-ansible/bin/ansible
  python version = 2.7.14+ (default, Jan 23 2018, 14:47:36) [GCC 7.2.0]
```
##### CONFIGURATION
```
inventory   = ./hosts
library        = /home/actionmystique/Ansible/git-yang-networkop/ansible-101/library
forks = 1000
gathering = explicit
gather_timeout = 30
roles_path = /home/actionmystique/Ansible/Roles/roles
private_role_vars = yes
hash_behaviour = merge
log_path = /var/log/ansible.log
retry_files_enabled = False
show_custom_stats = True
timeout = 120
pipelining = True
connect_timeout = 240
connect_retry_timeout = 180
```
##### OS / ENVIRONMENT
- host: Ubuntu 17.10 4.13
- paramiko: 2.4.0

##### SUMMARY

Exception running openssl_csr.
The output makes it hard to comprehend the error & debug it.
The error messages seem to indicate a 'missing value' regarding "subjectAltName", although it is defined & handed over to the module.
Maybe I'm missing something.
Also, it would be easier to display the usual {{ invocation.module_args }} dictionary for debugging purposes (the playbook has been run with the maximum verbosity of 4).

##### STEPS TO REPRODUCE

**Role**: :

```
- name: Generating an OpenSSL Certificate Signing Request (CSR)
  openssl_csr:
        common_name:                    "{{ csr.common_name }}"
        country_name:                   "{{ csr.country_name }}"
        digest:                         "{{ csr.digest }}"
        email_address:                  "{{ csr.email_address }}"
        extended_key_usage:             "{{ csr.extended_key_usage }}"
        extended_key_usage_critical:    "{{ csr.extended_key_usage_critical }}"
        force:                          "{{ csr.force }}"
        key_usage:                      "{{ csr.key_usage }}"
        key_usage_critical:             "{{ csr.key_usage_critical }}"
        locality_name:                  "{{ csr.locality_name }}"
        organization_name:              "{{ csr.organization_name }}"
        organizational_unit_name:       "{{ csr.organizational_unit_name }}"
        path:                           "{{ csr.path }}"
        privatekey_passphrase:          "{{ priv.passphrase }}"
        privatekey_path:                "{{ priv.path }}"
        state:                          present
        state_or_province_name:         "{{ csr.state_or_province_name }}"
        subject_alt_name:               "{{ csr.subject_alt_name }}"
        subject_alt_name_critical:      "{{ csr.subject_alt_name_critical }}"
        version:                        "{{ csr.version }}"
  register: tls_csr_return
```

##### EXPECTED RESULTS

The module should generate a CSR.

##### ACTUAL RESULTS: Playbook (with all related variables manually shown)

```
        "csr": {
            "common_name": "xev_spine_31", 
            "country_name": "FR", 
            "digest": "sha512", 
            "email_address": "manciot.jeanchristophe@gmail.com", 
            "extended_key_usage": [
                "serverAuth", 
                "clientAuth", 
                "codeSigning", 
                "emailProtection", 
                "timeStamping", 
                "OCSPSigning", 
                "ipsecIKE"
            ], 
            "extended_key_usage_critical": false, 
            "force": true, 
            "key_usage": [
                "digitalSignature", 
                "nonRepudiation", 
                "keyEncipherment", 
                "dataEncipherment", 
                "keyAgreement"
            ], 
            "key_usage_critical": false, 
            "locality_name": "xxxxxxxxxxxxxxxxxxxxx", 
            "organization_name": "xxxxxxxxxxxxxxxxxxxxxx", 
            "organizational_unit_name": "xxxxxxxxxxxxxxxxxxxx", 
            "path": "/media/actionmystique/SAMSUNG5-Virtual/Labs/GNS3/git-Ansible-Labs-Collection/Distributed-Cisco-IOS-XE-Clouds/16.6.1/Ansible/files/.tls/ios_xev/16.6.1/XEv_Spine_31/xev_spine_31.actionmystique.net.csr", 
            "state_or_province_name": "xxxxxxxxxxxxxxxxx", 
            "subject_alt_name": "xev_spine_31.actionmystique.net", 
            "subject_alt_name_critical": false, 
            "version": 3
        }, 
...
        "priv": {
...
            "passphrase": "", 
            "path": "/media/actionmystique/SAMSUNG5-Virtual/Labs/GNS3/git-Ansible-Labs-Collection/Distributed-Cisco-IOS-XE-Clouds/16.6.1/Ansible/files/.tls/ios_xev/16.6.1/XEv_Spine_31/rsakey.prv", 
...
        }, 
...
 ___________________________________________________________
/ TASK [tls_csr : Generating an OpenSSL Certificate Signing \
\ Request (CSR)]                                            /
 -----------------------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

task path: /media/actionmystique/SAMSUNG5-Shared/home/actionmystique/Repositories/SDX-Live/Roles/roles/tls_csr/tasks/main.yml:63
Using module file /media/actionmystique/SAMSUNG5-Shared/home/actionmystique/src/Ansible/git-ansible/lib/ansible/modules/crypto/openssl_csr.py
<172.21.85.131> ESTABLISH LOCAL CONNECTION FOR USER: root
<172.21.85.131> EXEC /bin/sh -c '/usr/bin/python && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py", line 520, in <module>
    main()
  File "/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py", line 498, in main
    csr.generate(module)
  File "/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py", line 327, in generate
    extensions.append(crypto.X509Extension(b"subjectAltName", self.subjectAltName_critical, altnames.encode('ascii')))
  File "/usr/local/lib/python2.7/dist-packages/OpenSSL/crypto.py", line 777, in __init__
    _raise_current_error()
  File "/usr/local/lib/python2.7/dist-packages/OpenSSL/_util.py", line 54, in exception_from_error_queue
    raise exception_type(errors)
OpenSSL.crypto.Error: [('X509 V3 routines', 'v2i_GENERAL_NAME_ex', 'missing value'), ('X509 V3 routines', 'X509V3_EXT_nconf', 'error in extension')]

fatal: [XEv_Spine_31]: FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Traceback (most recent call last):\n  File \"/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py\", line 520, in <module>\n    main()\n  File \"/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py\", line 498, in main\n    csr.generate(module)\n  File \"/tmp/ansible_gSnBxH/ansible_module_openssl_csr.py\", line 327, in generate\n    extensions.append(crypto.X509Extension(b\"subjectAltName\", self.subjectAltName_critical, altnames.encode('ascii')))\n  File \"/usr/local/lib/python2.7/dist-packages/OpenSSL/crypto.py\", line 777, in __init__\n    _raise_current_error()\n  File \"/usr/local/lib/python2.7/dist-packages/OpenSSL/_util.py\", line 54, in exception_from_error_queue\n    raise exception_type(errors)\nOpenSSL.crypto.Error: [('X509 V3 routines', 'v2i_GENERAL_NAME_ex', 'missing value'), ('X509 V3 routines', 'X509V3_EXT_nconf', 'error in extension')]\n", 
    "module_stdout": "", 
    "msg": "MODULE FAILURE", 
    "rc": 1
}
```

Hints from issue discussion:
Files identified in the description:
* [lib/ansible/modules/crypto/openssl_csr.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/crypto/openssl_csr.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @Spredzy
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Hello @jean-christophe-manciot thanks for the report.

The issue relies on the definition of the `subject_alt_name`.

Currently you have: `subject_alt_name: xev_spine_31.actionmystique.net`
It should be: `subject_alt_name: DNS:xev_spine_31.actionmystique.net`

It doesn't have to be a DNS name, hence the need for one to specify the type. More here https://en.wikipedia.org/wiki/Subject_Alternative_Name

Let me know if that fixes your issue.


@Spredzy 
Thanks for your swift reply.
Yes, adding DNS: in front of the FQDN solves this issue.
Could you please detail all the allowed **keywords** for "subject_alt_name" and update the [doc](https://docs.ansible.com/ansible/2.4/openssl_csr_module.html) accordingly?
@jean-christophe-manciot done

Commit message: openssl_csr: Improved documentation on subject_alt_name possible values

Patch to review:
diff --git a/lib/ansible/modules/crypto/openssl_csr.py b/lib/ansible/modules/crypto/openssl_csr.py
index 3a37080a098d22..8aa0e75d587bd7 100644
--- a/lib/ansible/modules/crypto/openssl_csr.py
+++ b/lib/ansible/modules/crypto/openssl_csr.py
@@ -107,6 +107,8 @@
         description:
             - SAN extension to attach to the certificate signing request
             - This can either be a 'comma separated string' or a YAML list.
+            - Values should be prefixed by their options. (ie. email, URI, DNS, RID, IP, dirName, otherName and the ones specific to your CA)
+            - More at U(https://tools.ietf.org/html/rfc5280#section-4.2.1.6)
     subject_alt_name_critical:
         required: false
         aliases: [ 'subjectAltName_critical' ]


Code review comments:
diff_hunk: @@ -107,6 +107,8 @@
         description:
             - SAN extension to attach to the certificate signing request
             - This can either be a 'comma separated string' or a YAML list.
+            - Values should be prefixed by their options. (ie. email, URI, DNS, RID, IP, dirName, otherName and the ones specific to your CA)
path: lib/ansible/modules/crypto/openssl_csr.py
text: @user1:
Should not `C()` be used around `email`, `URI` and the others ?