forked from ansible/ansible
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
aci_aaa_user_certificate: Add a certificate to an AAA user (ansible#3…
…4602) * aci_user_certificate: Add a certificate to a user A new ACI module to add a X.509 certificate to a user. * Add integration tests
- Loading branch information
Showing
5 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
174 changes: 174 additions & 0 deletions
174
lib/ansible/modules/network/aci/aci_aaa_user_certificate.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
#!/usr/bin/python | ||
# -*- coding: utf-8 -*- | ||
|
||
# Copyright: (c) 2018, Dag Wieers (dagwieers) <[email protected]> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community'} | ||
|
||
DOCUMENTATION = r''' | ||
--- | ||
module: aci_aaa_user_certificate | ||
short_description: Manage AAA user certificates (aaa:UserCert) | ||
description: | ||
- Manage AAA user and appuser certificates. | ||
- More information from the internal APIC class I(aaa:UserCert) at | ||
U(https://developer.cisco.com/site/aci/docs/apis/apic-mim-ref/). | ||
author: | ||
- Dag Wieers (@dagwieers) | ||
version_added: '2.5' | ||
notes: | ||
- The C(user) must exist before using this module in your playbook. | ||
The M(aci_user) module can be used for this. | ||
options: | ||
user: | ||
description: | ||
- The name of the user to add a certificate to. | ||
certificate: | ||
description: | ||
- The PEM format public key extracted from the X.509 certificate. | ||
aliases: [ cert_data, certificate_data ] | ||
certificate_name: | ||
description: | ||
- The name of the user certificate entry in ACI. | ||
aliases: [ cert_name ] | ||
user_type: | ||
description: | ||
- Whether this is a normal user or an appuser. | ||
choices: [ user, userapp ] | ||
default: user | ||
state: | ||
description: | ||
- Use C(present) or C(absent) for adding or removing. | ||
- Use C(query) for listing an object or multiple objects. | ||
choices: [ absent, present, query ] | ||
default: present | ||
extends_documentation_fragment: aci | ||
''' | ||
|
||
EXAMPLES = r''' | ||
- name: Add a certificate to user | ||
aci_aaa_user_certificate: | ||
hostname: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
user: admin | ||
certificate_name: admin | ||
certificate_data: '{{ lookup("file", "pki/admin.crt") }}' | ||
state: present | ||
- name: Remove a certificate of a user | ||
aci_aaa_user_certificate: | ||
hostname: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
user: admin | ||
certificate_name: admin | ||
state: absent | ||
- name: Query a certificate of a user | ||
aci_aaa_user_certificate: | ||
hostname: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
user: admin | ||
certificate_name: admin | ||
state: query | ||
- name: Query all certificates of a user | ||
aci_aaa_user_certificate: | ||
hostname: apic | ||
username: admin | ||
password: SomeSecretPassword | ||
user: admin | ||
state: query | ||
''' | ||
|
||
RETURN = r''' # ''' | ||
|
||
from ansible.module_utils.network.aci.aci import ACIModule, aci_argument_spec | ||
from ansible.module_utils.basic import AnsibleModule | ||
|
||
ACI_MAPPING = dict( | ||
appuser=dict( | ||
aci_class='aaaAppUser', | ||
aci_mo='userext/appuser-', | ||
), | ||
user=dict( | ||
aci_class='aaaUser', | ||
aci_mo='userext/user-', | ||
), | ||
) | ||
|
||
|
||
def main(): | ||
argument_spec = aci_argument_spec | ||
argument_spec.update( | ||
certificate=dict(type='str', aliases=['certificate_data', 'data']), | ||
certificate_name=dict(type='str', aliases=['cert_name']), | ||
state=dict(type='str', default='present', choices=['absent', 'present', 'query']), | ||
user=dict(type='str', required=True), | ||
user_type=dict(type='str', default='user', choices=['appuser', 'user']), | ||
) | ||
|
||
module = AnsibleModule( | ||
argument_spec=argument_spec, | ||
supports_check_mode=True, | ||
required_if=[ | ||
['state', 'absent', ['user', 'certificate_name']], | ||
['state', 'present', ['user', 'certificate', 'certificate_name']], | ||
], | ||
) | ||
|
||
certificate = module.params['certificate'] | ||
certificate_name = module.params['certificate_name'] | ||
state = module.params['state'] | ||
user = module.params['user'] | ||
user_type = module.params['user_type'] | ||
|
||
aci = ACIModule(module) | ||
aci.construct_url( | ||
root_class=dict( | ||
aci_class=ACI_MAPPING[user_type]['aci_class'], | ||
aci_rn=ACI_MAPPING[user_type]['aci_mo'] + user, | ||
filter_target='eq({0}.name, "{1}")'.format(ACI_MAPPING[user_type]['aci_class'], user), | ||
module_object=user, | ||
), | ||
subclass_1=dict( | ||
aci_class='aaaUserCert', | ||
aci_rn='usercert-{0}'.format(certificate_name), | ||
filter_target='eq(aaaUserCert.name, "{0}")'.format(certificate_name), | ||
module_object=certificate_name, | ||
), | ||
) | ||
aci.get_existing() | ||
|
||
if state == 'present': | ||
# Filter out module params with null values | ||
aci.payload( | ||
aci_class='aaaUserCert', | ||
class_config=dict( | ||
data=certificate, | ||
name=certificate_name, | ||
), | ||
) | ||
|
||
# Generate config diff which will be used as POST request body | ||
aci.get_diff(aci_class='aaaUserCert') | ||
|
||
# Submit changes if module not in check_mode and the proposed is different than existing | ||
aci.post_config() | ||
|
||
elif state == 'absent': | ||
aci.delete_config() | ||
|
||
module.exit_json(**aci.result) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Empty file.
14 changes: 14 additions & 0 deletions
14
test/integration/targets/aci_aaa_user_certificate/pki/admin.crt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
-----BEGIN CERTIFICATE----- | ||
MIICODCCAaGgAwIBAgIJAIt8XMntue0VMA0GCSqGSIb3DQEBCwUAMDQxDjAMBgNV | ||
BAMMBUFkbWluMRUwEwYDVQQKDAxZb3VyIENvbXBhbnkxCzAJBgNVBAYTAlVTMCAX | ||
DTE4MDEwOTAwNTk0NFoYDzIxMTcxMjE2MDA1OTQ0WjA0MQ4wDAYDVQQDDAVBZG1p | ||
bjEVMBMGA1UECgwMWW91ciBDb21wYW55MQswCQYDVQQGEwJVUzCBnzANBgkqhkiG | ||
9w0BAQEFAAOBjQAwgYkCgYEAohG/7axtt7CbSaMP7r+2mhTKbNgh0Ww36C7Ta14i | ||
v+VmLyKkQHnXinKGhp6uy3Nug+15a+eIu7CrgpBVMQeCiWfsnwRocKcQJWIYDrWl | ||
XHxGQn31yYKR6mylE7Dcj3rMFybnyhezr5D8GcP85YRPmwG9H2hO/0Y1FUnWu9Iw | ||
AQkCAwEAAaNQME4wHQYDVR0OBBYEFD0jLXfpkrU/ChzRvfruRs/fy1VXMB8GA1Ud | ||
IwQYMBaAFD0jLXfpkrU/ChzRvfruRs/fy1VXMAwGA1UdEwQFMAMBAf8wDQYJKoZI | ||
hvcNAQELBQADgYEAOmvre+5tgZ0+F3DgsfxNQqLTrGiBgGCIymPkP/cBXXkNuJyl | ||
3ac7tArHQc7WEA4U2R2rZbEq8FC3UJJm4nUVtCPvEh3G9OhN2xwYev79yt6pIn/l | ||
KU0Td2OpVyo0eLqjoX5u2G90IBWzhyjFbo+CcKMrSVKj1YOdG0E3OuiJf00= | ||
-----END CERTIFICATE----- |
16 changes: 16 additions & 0 deletions
16
test/integration/targets/aci_aaa_user_certificate/pki/admin.key
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
-----BEGIN PRIVATE KEY----- | ||
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKIRv+2sbbewm0mj | ||
D+6/tpoUymzYIdFsN+gu02teIr/lZi8ipEB514pyhoaerstzboPteWvniLuwq4KQ | ||
VTEHgoln7J8EaHCnECViGA61pVx8RkJ99cmCkepspROw3I96zBcm58oXs6+Q/BnD | ||
/OWET5sBvR9oTv9GNRVJ1rvSMAEJAgMBAAECgYByu3QO0qF9h7X3JEu0Ld4cKBnB | ||
giQ2uJC/et7KxIJ/LOvw9GopBthyt27KwG1ntBkJpkTuAaQHkyNns7vLkNB0S0IR | ||
+owVFEcKYq9VCHTaiQU8TDp24gN+yPTrpRuH8YhDVq5SfVdVuTMgHVQdj4ya4VlF | ||
Gj+a7+ipxtGiLsVGrQJBAM7p0Fm0xmzi+tBOASUAcVrPLcteFIaTBFwfq16dm/ON | ||
00Khla8Et5kMBttTbqbukl8mxFjBEEBlhQqb6EdQQ0sCQQDIhHx1a9diG7y/4DQA | ||
4KvR3FCYwP8PBORlSamegzCo+P1OzxiEo0amX7yQMA5UyiP/kUsZrme2JBZgna8S | ||
p4R7AkEAr7rMhSOPUnMD6V4WgsJ5g1Jp5kqkzBaYoVUUSms5RASz4+cwJVCwTX91 | ||
Y1jcpVIBZmaaY3a0wrx13ajEAa0dOQJBAIpjnb4wqpsEh7VpmJqOdSdGxb1XXfFQ | ||
sA0T1OQYqQnFppWwqrxIL+d9pZdiA1ITnNqyvUFBNETqDSOrUHwwb2cCQGArE+vu | ||
ffPUWQ0j+fiK+covFG8NL7H+26NSGB5+Xsn9uwOGLj7K/YT6CbBtr9hJiuWjM1Al | ||
0V4ltlTuu2mTMaw= | ||
-----END PRIVATE KEY----- |
136 changes: 136 additions & 0 deletions
136
test/integration/targets/aci_aaa_user_certificate/tasks/main.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# Test code for the ACI modules | ||
# Copyright: (c) 2017, Dag Wieers (dagwieers) <[email protected]> | ||
# | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
# | ||
- name: Test that we have an ACI APIC host, ACI username and ACI password | ||
fail: | ||
msg: 'Please define the following variables: aci_hostname, aci_username and aci_password.' | ||
when: aci_hostname is not defined or aci_username is not defined or aci_password is not defined | ||
|
||
|
||
# CLEAN ENVIRONMENT | ||
- name: Remove any pre-existing certificate | ||
aci_aaa_user_certificate: &cert_absent | ||
hostname: '{{ aci_hostname }}' | ||
username: '{{ aci_username }}' | ||
password: '{{ aci_password }}' | ||
use_proxy: no | ||
validate_certs: no | ||
user: admin | ||
certificate_name: admin | ||
state: absent | ||
delegate_to: localhost | ||
|
||
|
||
# ADD USER CERTIFICATE | ||
- name: Add user certificate (check_mode) | ||
aci_aaa_user_certificate: &cert_present | ||
hostname: '{{ aci_hostname }}' | ||
username: '{{ aci_username }}' | ||
password: '{{ aci_password }}' | ||
use_proxy: no | ||
validate_certs: no | ||
user: admin | ||
certificate_name: admin | ||
certificate: "{{ lookup('file', 'pki/admin.crt') }}" | ||
state: present | ||
check_mode: yes | ||
delegate_to: localhost | ||
register: cm_add_cert | ||
|
||
- name: Add user certificate (normal mode) | ||
aci_aaa_user_certificate: *cert_present | ||
delegate_to: localhost | ||
register: nm_add_cert | ||
|
||
- name: Add user certificate again (check mode) | ||
aci_aaa_user_certificate: *cert_present | ||
check_mode: yes | ||
delegate_to: localhost | ||
register: cm_add_cert_again | ||
|
||
- name: Add user certificate again (normal mode) | ||
aci_aaa_user_certificate: *cert_present | ||
delegate_to: localhost | ||
register: nm_add_cert_again | ||
|
||
- name: Verify add_cert | ||
assert: | ||
that: | ||
- cm_add_cert.changed == nm_add_cert.changed == true | ||
- cm_add_cert_again.changed == nm_add_cert_again.changed == false | ||
|
||
|
||
# QUERY ALL USER CERTIFICATES | ||
- name: Query all user certificates (check_mode) | ||
aci_aaa_user_certificate: &cert_query | ||
hostname: '{{ aci_hostname }}' | ||
username: '{{ aci_username }}' | ||
password: '{{ aci_password }}' | ||
use_proxy: no | ||
validate_certs: no | ||
user: admin | ||
state: query | ||
check_mode: yes | ||
delegate_to: localhost | ||
register: cm_query_all_certs | ||
|
||
- name: Query all user certificates (normal mode) | ||
aci_aaa_user_certificate: *cert_query | ||
delegate_to: localhost | ||
register: nm_query_all_certs | ||
|
||
- name: Verify query_all_certs | ||
assert: | ||
that: | ||
- cm_query_all_certs.changed == nm_query_all_certs.changed == false | ||
# NOTE: Order of certs is not stable between calls | ||
#- cm_query_all_certs == nm_query_all_certs | ||
|
||
|
||
# QUERY OUR USER CERTIFICATE | ||
- name: Query our certificate (check_mode) | ||
aci_aaa_user_certificate: | ||
<<: *cert_query | ||
certificate_name: admin | ||
check_mode: yes | ||
register: cm_query_cert | ||
|
||
- name: Query our certificate (normal mode) | ||
aci_aaa_user_certificate: | ||
<<: *cert_query | ||
certificate_name: admin | ||
register: nm_query_cert | ||
|
||
- name: Verify query_cert | ||
assert: | ||
that: | ||
- cm_query_cert.changed == nm_query_cert.changed == false | ||
- cm_query_cert == nm_query_cert | ||
|
||
|
||
# REMOVE CERTIFICATE | ||
- name: Remove certificate (check_mode) | ||
aci_tenant: *cert_absent | ||
check_mode: yes | ||
register: cm_remove_cert | ||
|
||
- name: Remove certificate (normal mode) | ||
aci_tenant: *cert_absent | ||
register: nm_remove_cert | ||
|
||
- name: Remove certificate again (check_mode) | ||
aci_tenant: *cert_absent | ||
check_mode: yes | ||
register: cm_remove_cert_again | ||
|
||
- name: Remove certificate again (normal mode) | ||
aci_tenant: *cert_absent | ||
register: nm_remove_cert_again | ||
|
||
- name: Verify remove_cert | ||
assert: | ||
that: | ||
- cm_remove_cert.changed == nm_remove_cert.changed == true | ||
- cm_remove_cert_again.changed == nm_remove_cert_again.changed == false |