diff options
Diffstat (limited to 'ansible_collections/cyberark/pas')
56 files changed, 5699 insertions, 0 deletions
diff --git a/ansible_collections/cyberark/pas/.DS_Store b/ansible_collections/cyberark/pas/.DS_Store Binary files differnew file mode 100644 index 000000000..c21215883 --- /dev/null +++ b/ansible_collections/cyberark/pas/.DS_Store diff --git a/ansible_collections/cyberark/pas/CONTRIBUTING.md b/ansible_collections/cyberark/pas/CONTRIBUTING.md new file mode 100644 index 000000000..97d53cb0a --- /dev/null +++ b/ansible_collections/cyberark/pas/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Contributing to the Ansible Security Automation Collection + +Thanks for your interest in the Ansible Security Automation collection. + +For general community guidelines, please see the [community repo](https://github.com/cyberark/community). + +## Pull Request Workflow + +Currently, this repository is source-available and not open to contributions. Please continue to follow this repository for updates and open-source availability diff --git a/ansible_collections/cyberark/pas/FILES.json b/ansible_collections/cyberark/pas/FILES.json new file mode 100644 index 000000000..bef13dac3 --- /dev/null +++ b/ansible_collections/cyberark/pas/FILES.json @@ -0,0 +1,488 @@ +{ + "files": [ + { + "name": ".", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": ".DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "06521a08299939cac5d58311a8e54a50f370e264ce599fce1b24c155db49dad0", + "format": 1 + }, + { + "name": "LICENSE", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f717ec697e01e78397a7c8a6f13b78070ea4503346ba65202ccaa055f34f0261", + "format": 1 + }, + { + "name": "plugins", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/.DS_Store", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "9fb1a681718842e1c421f5e0b8c3ac05f77e4717115b99beee920a4282d479a9", + "format": 1 + }, + { + "name": "plugins/event_source", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/event_source/cyberark-eda-json-v1.0.xsl", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "14cc4b68daaf5955cf35432331f720a2ab038d05dc3db2e9828895bf2cf9a921", + "format": 1 + }, + { + "name": "plugins/event_source/syslog.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7f2476298fc3942811e865f00c8d8099981c7353c5156bb3a15c0c4d5304819e", + "format": 1 + }, + { + "name": "plugins/modules", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "plugins/modules/cyberark_account.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "116db33283c897cbc2d3a4d3f3e0b3d16021e41b2060b2b265a30e5c59ef365e", + "format": 1 + }, + { + "name": "plugins/modules/cyberark_user.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "88346fd9883d77e1f6631e23fdf88bed4b659f1f5ce2542f3afa4814193c0469", + "format": 1 + }, + { + "name": "plugins/modules/cyberark_credential.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "63a79fd9eeda9f571a4a4020bca8c5ea836431df433212c01995133bb713705c", + "format": 1 + }, + { + "name": "plugins/modules/cyberark_authentication.py", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "7e7451bc50d5a6a5d44f01bee1581e0b30ed72da2e410b508ead9c75c02f2af5", + "format": 1 + }, + { + "name": "tests", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "tests/change_test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c5de68ecfc9f53db7c766c42ca5984624ba8859ac8dd0d3326a0ea92e9ba4641", + "format": 1 + }, + { + "name": "tests/provision_user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "886b820d493fe19407c14522b66fc74c456d1f30df27116482acb4480e6d620b", + "format": 1 + }, + { + "name": "tests/test.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "49c4dab3f755c0c0fd3f4010097bc8af0c31c34caee162d8a980f10e72ec4d1d", + "format": 1 + }, + { + "name": "tests/provision_account.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "885a0748fa873047be277636fc265bc0a986ffbf2e33cc7deda9a317cf7ff87b", + "format": 1 + }, + { + "name": "tests/enable_user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "91f1863e86bd2c890732285cf101dab9fc78c6deac91e9a8964135444f74ee36", + "format": 1 + }, + { + "name": "tests/deprovision_user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "77be4201572460a644b0298698123089f7d526feb09ddfad51fa839766c736d6", + "format": 1 + }, + { + "name": "tests/changepolicy.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "756ac18b033fc4a7e208e31c9e3da6a33acadc2f8b07ed8adb18e1daa9da9915", + "format": 1 + }, + { + "name": "tests/reset_user_password.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "179c40338463a55bf504034de04c58b62525a696667adde36fc8f3d79b8b81fb", + "format": 1 + }, + { + "name": "tests/disable_user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "cd03538b91445bba1f80b3390f857a54afe55bc8b6f7f056881f62a51e506cad", + "format": 1 + }, + { + "name": "tests/deprovision_account.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "679689e8c958366a772b3cca71e3e43873d18583b12b81bf788af7c2a14d1d02", + "format": 1 + }, + { + "name": "meta", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "meta/runtime.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "db1dfe098d05c998eb62c32cf99d3b7bbf93afc0a1f0b4704b024eaa7c7b6848", + "format": 1 + }, + { + "name": "roles", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/aimprovider", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/aimprovider/tasks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/aimprovider/tasks/uninstallAIMProvider.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "2a3dce24d9d2f05edbee3ad2ee14b733fdcfdc6494e2fb9550c5dd02fbe1f734", + "format": 1 + }, + { + "name": "roles/aimprovider/tasks/installAIMProvider.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f334faee54008e6101414771409a9aa7f98b62e4996269003dca84441d4f6db5", + "format": 1 + }, + { + "name": "roles/aimprovider/tasks/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "224814783560fc317b2df277f2542273747f533abf493c891b03a0e496d8feab", + "format": 1 + }, + { + "name": "roles/aimprovider/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f1d69c30a1131171ac7acad895d588ab08b20896751d1db2fcb510103b37bc5b", + "format": 1 + }, + { + "name": "roles/aimprovider/defaults", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "roles/aimprovider/defaults/main.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "56a96c0b8c7e35aed626b90d3b3020b0aa6b34ccd08cf1fdab08778b5c2f5839", + "format": 1 + }, + { + "name": "docs", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/cyberark_account.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "95508e0e44993426f59af04652c7dcaeacc3aad7279573f570d1fd705ff0a755", + "format": 1 + }, + { + "name": "docs/images", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "docs/images/platform_account_properties.JPG", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "82e22cb050df050bd5af8680d341f61d48beafbf9c30cb40fe994c684151d8d4", + "format": 1 + }, + { + "name": "docs/images/eda-pta-syslog.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "b83470678d39e86b460a4e6b21c618b8015090e2dbd2d8296766e8b4f64073d1", + "format": 1 + }, + { + "name": "docs/images/eda_disableuser_kafka.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a265629b84ea81402306ea137ce3669608177bd5bfc6463d0144156b08d57830", + "format": 1 + }, + { + "name": "docs/images/eda_disableuser_webhook.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a968cb0de979628ac398870f908be350cb7baa0ef589876949cade89e69a2ae9", + "format": 1 + }, + { + "name": "docs/images/rsyslog-webhook.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "0d828047be1cdf5608223fd8fb95830bd122b55273b3d9d91afb2b13ee931c5d", + "format": 1 + }, + { + "name": "docs/images/full-cyberark-logo.jpg", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "5d910c2159e7caded5286414d0329d7e0f084676fcb80610efffa5be7214452b", + "format": 1 + }, + { + "name": "docs/images/eda-syslog.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "53494d3c2029136e10675b9a1063e7e516b87da70445ba7fcb2c70801635e9c8", + "format": 1 + }, + { + "name": "docs/images/rsyslog-kafka.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8112d7af4f66ceeb8665199a269a3817ee81268116d0205921492aa636dfb8f3", + "format": 1 + }, + { + "name": "docs/images/eda_pta_disable_user_syslog.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "6a258913dea76f7b6a4525ca5fa20818a9e2585e32c5d988f71deb3c724384eb", + "format": 1 + }, + { + "name": "docs/images/cyberark_logo.jpg", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "535e69685a6e58c210d685abe0fb4f8990bdca029ef41f30c130000f9a596631", + "format": 1 + }, + { + "name": "docs/images/eda_disable_user_syslog.png", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8754056835abf11bf5ca125e80414a3d78a572bea4952d0c5daf97346f55c745", + "format": 1 + }, + { + "name": "docs/cyberark_credential.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "903afbe64bbbbd94f8c2571eee2890a9380c4ebc0d5e94184ba3111672a708bf", + "format": 1 + }, + { + "name": "docs/aimprovider.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f1d69c30a1131171ac7acad895d588ab08b20896751d1db2fcb510103b37bc5b", + "format": 1 + }, + { + "name": "docs/cyberark_authentication.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c8c121019f265ba222a968a2fe94d1724e02490d3f637b7bc5645c97caa2f423", + "format": 1 + }, + { + "name": "docs/cyberark_user.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "1b1e3a133afead30cc3c7ae40fd2d26e8f0032e188b55b6d4d0f06e015b9701d", + "format": 1 + }, + { + "name": "docs/cyberark_eda.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "3f75ebf09e764a54338e13f8315fa5628034f84a1ca60a322d606a1c96e769fd", + "format": 1 + }, + { + "name": "README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "8f163f0bfa5d572f89fb02db1acf39330d9e5d56e5eb3a87500a9c6b07fc0291", + "format": 1 + }, + { + "name": "rulebooks", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "rulebooks/disable_pas_user_webhook.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "aaf528f7dc4f268793df315d4e5b78ccf2d1f14ff2f312e0c089d6014b59b708", + "format": 1 + }, + { + "name": "rulebooks/pta_notify.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "fce3b40b7c3ddd6b3be7ddfda3369584e3bb6e8ac84e0ef40454022472955830", + "format": 1 + }, + { + "name": "rulebooks/cyberark_test_rule.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "ac03ca12b8957fff3a352641886ab24a2f0eb31a2888602f9e3557583f3a0736", + "format": 1 + }, + { + "name": "rulebooks/disable_pas_user_kafka.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "4a8fd969fbf4244bfa1de34afce843b0e5bac4c8d444f413a2d479ffb49e87e2", + "format": 1 + }, + { + "name": "rulebooks/pta_disable_notify.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "199aef6aa3bf71d6aa7b261778a5545103a292c33f4bd85122ea7010a722c0bd", + "format": 1 + }, + { + "name": "rulebooks/disable_user.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "d6cd1b632262eb0c6eac20213fedd1dc2274ca6df1a1a27feaeac9fd3a2f169d", + "format": 1 + }, + { + "name": "rulebooks/inventory.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "c0ce0d7e6d03184e9cd4202f377174d36736b4dd9fb1ab8b79cf909fb0b70ffc", + "format": 1 + }, + { + "name": "CONTRIBUTING.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "27344573191496c7506f67129c6b88d8a05ad8c99e069fa7c27f8f17f61bda57", + "format": 1 + }, + { + "name": "custom-cred-types", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "custom-cred-types/cyberark-pas-restapi", + "ftype": "dir", + "chksum_type": null, + "chksum_sha256": null, + "format": 1 + }, + { + "name": "custom-cred-types/cyberark-pas-restapi/input.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f4adbb5b1da168dea98a8fd85d5a4b109c346b3deed95cfd06f160c5db4ce927", + "format": 1 + }, + { + "name": "custom-cred-types/cyberark-pas-restapi/injector.yml", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "f61c7965c5570860c7345b15f5ce4eea14b7ea4e51548060e023f6dd75879b4c", + "format": 1 + }, + { + "name": "custom-cred-types/cyberark-pas-restapi/README.md", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "a07b281e2ab653ee3b61a36a7cced24051b2c2a8a7b14fdc8632b2c34f31e2c5", + "format": 1 + } + ], + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/LICENSE b/ansible_collections/cyberark/pas/LICENSE new file mode 100644 index 000000000..d6296a340 --- /dev/null +++ b/ansible_collections/cyberark/pas/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 CyberArk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ansible_collections/cyberark/pas/MANIFEST.json b/ansible_collections/cyberark/pas/MANIFEST.json new file mode 100644 index 000000000..73d64bb7a --- /dev/null +++ b/ansible_collections/cyberark/pas/MANIFEST.json @@ -0,0 +1,43 @@ +{ + "collection_info": { + "namespace": "cyberark", + "name": "pas", + "version": "1.0.19", + "authors": [ + "CyberArk Business Development (@cyberark-bizdev)", + "Edward Nunez (@enunez-cyberark)", + "Joe Garcia (@infamousjoeg)" + ], + "readme": "README.md", + "tags": [ + "cyberark", + "access", + "security", + "account", + "epv", + "vault", + "identity", + "credential", + "secret", + "privileged" + ], + "description": "This is a Collection of the CyberArk Ansible Security Automation toolkit.", + "license": [ + "MIT" + ], + "license_file": null, + "dependencies": {}, + "repository": "https://github.com/cyberark/ansible-security-automation-collection", + "documentation": null, + "homepage": null, + "issues": "https://github.com/cyberark/ansible-security-automation-collection/issues" + }, + "file_manifest_file": { + "name": "FILES.json", + "ftype": "file", + "chksum_type": "sha256", + "chksum_sha256": "963cff01c982a389719c2948de6d0c8e18531926af68e1f238789385e49cec71", + "format": 1 + }, + "format": 1 +}
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/README.md b/ansible_collections/cyberark/pas/README.md new file mode 100644 index 000000000..43842e7dc --- /dev/null +++ b/ansible_collections/cyberark/pas/README.md @@ -0,0 +1,73 @@ +<!-- please note this has to be a absolute URL since otherwise it will not show up on galaxy.ansible.com --> +![cyberark logo|](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/full-cyberark-logo.jpg?raw=true) + +## CyberArk Ansible Security Automation Collection + +************* + +## Collection + +#### cyberark.pas + +This collection is the CyberArk Ansible Security Automation project and can be found on [ansible galaxy](https://galaxy.ansible.com/cyberark/pas). This is aimed to enable the automation of securing privileged access by storing privileged accounts in the Enterprise Password Vault (EPV), controlling user's access to privileged accounts in EPV, and securely retreiving secrets using Application Access Manager (AAM). +The collection includes [support for Event-Driven Ansible](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/cyberark_eda.md) by providing an event-source plugin for syslog and also guidance on how to use it. + + +The following modules will allow CyberArk administrators to automate the following tasks: + +#### Requirements + +- CyberArk Privileged Account Security Web Services SDK +- CyberArk AAM Central Credential Provider (**Only required for cyberark_credential**) + +#### Role Variables + +None. +<br> +<br> + +## Modules + +#### cyberark_authentication + +- Using the CyberArk Web Services SDK, authenticate and obtain an auth token to be passed as a variable in playbooks +- Logoff of an authenticated REST API session<br> +[Playbooks and Module Info](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/cyberark_authentication.md) + +#### cyberark_user + +- Add a CyberArk User +- Delete a CyberArk User +- Update a CyberArk User's account parameters + - Enable/Disable, change password, mark for change at next login, etc +<br>[Playbooks and Module Info](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/cyberark_user.md)<br/> + +#### cyberark_account + +- Add Privileged Account to the EPV +- Delete account objects +- Modify account properties +- Rotatate privileged credentials<br> +[Playbooks and Module Info](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/cyberark_account.md) + +#### cyberark_credential + +- Using AAM Central Credential Provider (CCP), to securely retreive secrets and account properties from EPV to be registered for use in playbooks<br> +[Playbooks and Module Info](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/cyberark_credential.md) + +## Roles + +#### aimprovider + +- Install agent-based Credential Provider (AIM) on Linux hosts +[Playbooks and Module Info](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/aimprovider.md) + +#### Python3 + +- The modules will work with either python2 or python3. + +#### Author Information +- CyberArk Business Development Technical Team + - @enunez-cyberark + - @cyberark-bizdev + diff --git a/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/README.md b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/README.md new file mode 100644 index 000000000..852ff7db4 --- /dev/null +++ b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/README.md @@ -0,0 +1,32 @@ +# CyberArk PAS REST API + +Custom Credential Type for Ansible Tower + +## Installation + +1. Login to Ansible Tower as a Tower Administrator. +2. Under Administration, click on Credential Type. +3. Click the green [ + ] in the top right-hand corner to create a new Custom Credential Type. +4. Set the name of your Credential Type. e.g. `CyberArk PAS REST API` +5. Under `Input Configuration` select `YAML`. +6. Copy and paste the [input.yml](input.yml) into the text field for `Input Configuration`. +7. Under `Injector Configuration` select `YAML`. +8. Copy and paste the [injector.yml](injector.yml) into the text field for `Injector Configuration`. +9. Click `Save` at the bottom to save the Custom Credential Type. + +## Usage + +Reference the following environment variables within your Ansible Playbook when using this Credential Type: + +* `CYBERARK_API_URL` \ +This is the Base URI of your CyberArk Password Vault Web Access (PVWA). _e.g. `https://pvwa.cyberark.com`_ + +* `CYBERARK_API_USERNAME` \ +This is the username to use when logging into the CyberArk PAS Web Services SDK (REST API). + +* `CYBERARK_API_PASSWORD` \ +This is the password associated with the username provided for login. + +## Maintainer + +Joe Garcia, CISSP - DevOps Security Engineer, CyberArk - [@infamousjoeg](https://github.com/infamousjoeg) diff --git a/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/injector.yml b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/injector.yml new file mode 100644 index 000000000..4d6edc5fe --- /dev/null +++ b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/injector.yml @@ -0,0 +1,4 @@ +extra_vars: + CYBERARK_API_PASSWORD: '{{ password }}' + CYBERARK_API_URL: '{{ pvwa_url }}' + CYBERARK_API_USERNAME: '{{ username }}' diff --git a/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/input.yml b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/input.yml new file mode 100644 index 000000000..59a8441e0 --- /dev/null +++ b/ansible_collections/cyberark/pas/custom-cred-types/cyberark-pas-restapi/input.yml @@ -0,0 +1,18 @@ +fields: + - id: username + type: string + label: Username + help_text: CyberArk REST API Username + - id: password + type: string + label: Password + secret: true + help_text: CyberArk REST API Password + - id: pvwa_url + type: string + label: PVWA URL + help_text: 'CyberArk PVWA URL e.g. https://pvwa.cyberark.com' +required: + - username + - password + - pvwa_url diff --git a/ansible_collections/cyberark/pas/docs/aimprovider.md b/ansible_collections/cyberark/pas/docs/aimprovider.md new file mode 100644 index 000000000..e39863539 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/aimprovider.md @@ -0,0 +1,91 @@ +cyberark.pas.aimprovider +==================== + +Role to install/uninstall CyberArk's AIM Credential Provider. + +Requirements +------------ + +- CyberArk Privileged Account Security Web Services SDK. +- `cyberark.pas` Collection from Ansible Galaxy or Automation Hub + +Role Variables +-------------- +``` +# CyberArk's Privileged Account Security Web Services SDK api base URL (example: https://components.cyberark.local) +rest_api_url: "" + +# Whether to validate certificates for REST api calls. If false, SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates. +validate_certs: true + +# Zip file with distribution of AIM Provider (example: /tmp/binaries/RHELinux x64-Rls-v9.8.zip); this file is located in the Ansible server, and it will be copied to the Ansible nodes. It should point to the current version of AIM distribution to be used when delivering to the nodes in a central folder within the Ansible server. +zip_file_name: "" + +# Folder name within the ZIP file that will be used. By default, it's taken from zip file name, for example: "RHELinux x64" +folder_name: '{{zip_file_name.split("/")[-1].split("-Rls")[0]}}' + +# CyberArk location for App Provider user to be created +app_provider_user_location: "\\Applications" + +# CyberArk Vault Address +vault_address: "" + +# Whether to use shared logon authentication. If true, it will use the "Shared Logon Authentication" as described in the CyberArk's document "Privileged Account Security Web Services SDK Implementation Guide" +use_shared_logon_authentication: false + +# State - can be "present"/"absent" for install/uninstall. +state: "present" +``` + + +Additionally: +- **app_provider_user_group**: The name of the group the Provider user will be added to. + +Dependencies +------------ + +None. + + +Example Playbook +---------------- + +1) Install CyberArk AIM Provider. + +``` +--- +- hosts: all + + roles: + + - role: cyberark.pas.aimprovider + api_base_url: "https://components.cyberark.local" + validate_certs: false + zip_file_name: "/tmp/binaries/RHELinux x64-Rls-v9.8.zip" + vault_address: "10.0.1.10" + use_shared_logon_authentication: true +``` + +2) Uninstall CyberArk AIM Provider. +``` +--- +- hosts: all + + roles: + + - role: cyberark.pas.aimprovider + api_base_url: "https://components.cyberark.local" + use_shared_logon_authentication: true + state: "absent" + validate_certs: false +``` + +License +------- + +MIT + +Author Information +------------------ + +- Edward Nunez (edward.nunez@cyberark.com) diff --git a/ansible_collections/cyberark/pas/docs/cyberark_account.md b/ansible_collections/cyberark/pas/docs/cyberark_account.md new file mode 100644 index 000000000..7ddb4e4d5 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/cyberark_account.md @@ -0,0 +1,278 @@ +# cyberark_account + +Allows for adding, deleting, modifying a privileged credential within the Cyberark Vault. The request uses the Privileged Account Security Web Services SDK.<br> + +The ability to modify consists of the following: + +* Password (see secret_management) +* Safe +* Platform +* Address +* Object Name +* Username +* Platform Account Properties + * These are the parameters listed in the Platform under `UI & Workflows -> Properties` and are unique to each Platform (see image below) +* Remote Machines Access + +![Platform Account Properties](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/platform_account_properties.JPG?raw=true) + +### secret_management +The `secret_management` dictionary provides the capability to set a CPM password rotation flag on an existing account. + +The available options are as follows:<br> + +`automatic_management_enabled`: bool<br> +`manual_management_reason`: This is a string value that populates the Reason field is you have set an account to not be managed by the CPM. This value is only necessary if `automatic_management_enabled` is set to false.<br> +`management_action`: This value indicates what type CPM management flag will be placed on the account +* change - <br> +* change_immediately - <br> +* reconcile - <br> + +`new_secret`: This parameter is available to set the value of the new password<br> +`perform_secret_management`: This parameter was allows the option to place a CPM management flag on an account upon creation of an account object. +* always - All `secret_management` actions will follow the table below at all times. +* on_create - Will place a CPM management flag according to the table below ONLY on creation of an account object. + +#### Secret Management Action Table +| management_action | new_secret | Action | +| :---------: | :----: | :----- | +| change | populated | change password to set value at next scheduled rotation | +| change | NULL | rotate password at next scheduled rotation | +| change_immediately | populated | change immediately to the set value | +| change_immediately | NULL | rotate immediately | +| reconcile | populated | reconcile immediately NOT to set value | +| reconcile | NULL | reconcile immediately | +| NULL | populated | set value in Vault ONLY | + + +### identified_by +This property allows for the module to confidently identify the account object needing to be identified. If multiple accounts are returned from the modules initial `Get Accounts` it will use the value(s) set in the `identified_by` parameter to direct which account is selected from the list. + +**EXAMPLE:** +``` +-Playbook Parameters- + +cyberark_account: + identified_by: "address,username,platform_id" + safe: "testSafe" + address: "dev.local" + username: "admin" + platform_id: WinDomain + + -This is the query sent to CyberArk Web SDK: +/api/Accounts?filter=safeName eq testSafe&search= admin dev.local + +**This could return multiple accounts in the testSafe** + +RETURNED: +account1 + username: administrator + address: cyberark.dev.local + safe: testSafe + policyID: WinDomain + +account2 + username: admin + address: dev.local + safe: testSafe + policyID: WinDomain +``` +With the `identified_by` parameter set the `cyberark_account` module will select the account2 object becauses the values of the `address`, `username` and `platform_id` parameters are identical matches to the values of account2 properties. + +#### Limitations +**Idempotency** - All actions taken in the module adhere to the Ansible idempotency guidelines _except_ for password change. If you have the playbook set to modify a password it will send a password change request every time the playbook is run, even if you are defining the next password value and it is the same password that is set in other runs.<br> +**Remote Machines Access** - When modifying the values in the `remote_machines_access` dictionary be mindful of the `platform_id` value. Remote Machines Access values are stored at the Vault database level and not stored as File Categories. It is a function that is only available with the `WinDomain` platform and if you attempt to assign these values to another platform it will cause errors in the PSM functionality. + + +#### Available Fields +``` +options: + state: + description: + - Assert the desired state of the account C(present) to creat or update and account object. Set to C(absent) for deletion of an account object + required: true + default: present + choices: [present, absent] + type: str + logging_level: + description: + - Parameter used to define the level of troubleshooting output to the C(logging_file) value + required: true + choices: [NOTSET, DEBUG, INFO] + type: str + logging_file: + description: + - Setting the log file name and location for troubleshooting logs + required: false + default: /tmp/ansible_cyberark.log + type: str + api_base_url: + description: + - A string containing the base URL of the server hosting CyberArk's Privileged Account Security Web Services SDK + - Example: U(https://<IIS_Server_Ip>/PasswordVault/api/) + required: true + type: str + validate_certs: + description: + - If C(false), SSL certificate chain will not be validated. This should only set to C(true) if you have a root CA certificate installed on each node. + required: false + default: true + type: bool + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the different values to perform actions on a logged-on CyberArk session, please see M(cyberark_authentication) module for an example of cyberark_session. + required: true + type: dict + identified_by: + description: + - When an API call is made to Get Accounts, often times the default parameters passed will identify more than one account. This parameter is used to confidently identify a single account when the default query can return multiple results. + required: false + default: username,address,platform_id + type: str + safe: + description: + - The safe in the Vault where the privileged account is to be located + required: true + type: str + platform_id: + description: + - The PolicyID of the Platform that is to be managing the account + required: false + type: str + address: + description: + - The adress of the endpoint where the privileged account is located + required: false + type: str + name: + description: + - The ObjectID of the account + required: false + type: str + secret_type: + description: + - The value that identifies what type of account it will be. + required: false + default: password + choices: [password, key] + type: str + secret: + description: + - The initial password for the creation of the account + required: false + type: str + username: + description: + - The username associated with the account + required: false + type: str + secret_management + description: + - Set of parameters associated with the management of the credential + required: false + suboptions: + automatic_management_enabled: + description: + - Parameter that indicates whether the CPM will manage the password or not + default: true + type: bool + manual_management_reason: + description: + - String value indicating why the CPM will NOT manage the password + type: str + management_action: + description: + - CPM action flag to be placed on the account object for credential rotation + choices: [change, change_immediately, reconcile] + type: str + new_secret: + description: + - The actual password value that will be assigned for the CPM action to be taken + type: str + perform_management_action: + description: + - C(always) will perform the management action in every action + - C(on_create) will only perform the management action right after the account is created + choices: [always, on_create] + default: always + type: str + remote_machines_access: + description: + - Set of parameters for defining PSM endpoint access targets + required: false + type: dict + suboptions: + remote_machines: + description: + - List of targets allowed for this account + type: str + access_restricted_to_remote_machines: + description: + - Whether or not to restrict access only to specified remote machines + type: bool + platform_account_properties: + description: + - Object containing key-value pairs to associate with the account, as defined by the account platform. These properties are validated against the mandatory and optional properties of the specified platform's definition. Optional properties that do not exist on the account will not be returned here. Internal properties are not returned. + required: false + type: dict + suboptions: + KEY: + description: + - Freeform key value associated to the mandatory or optional property assigned to the specified Platform's definition. + aliases: [Port, ExtrPass1Name, database] + type: str +``` + +## Example Playbooks + + +```yaml + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark.pas.cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Creating an Account using the PAS WebServices SDK + cyberark.pas.cyberark_account: + logging_level: DEBUG + identified_by: "address,username" + safe: "Test" + address: "cyberark.local" + username: "administrator-x" + platform_id: WinServerLocal + secret: "@N&Ibl3!" + platform_account_properties: + LogonDomain: "cyberark" + OwnerName: "ansible_user" + secret_management: + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Rotate credential via reconcile and providing the password to be changed to + cyberark.pas.cyberark_account: + identified_by: "address,username" + safe: "Domain_Admins" + address: "prod.cyberark.local" + username: "admin" + platform_id: WinDomain + platform_account_properties: + LogonDomain: "PROD" + secret_management: + new_secret: "Ama123ah12@#!Xaamdjbdkl@#112" + management_action: "reconcile" + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: reconcileaccount + + - name: Logoff from CyberArk Vault + cyberark.pas.cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" +``` diff --git a/ansible_collections/cyberark/pas/docs/cyberark_authentication.md b/ansible_collections/cyberark/pas/docs/cyberark_authentication.md new file mode 100644 index 000000000..7ea60d591 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/cyberark_authentication.md @@ -0,0 +1,104 @@ +# cyberark_authentication + + +Authenticates to CyberArk Vault using Privileged Account Security Web Services SDK and creates a session fact that can be used by other modules. It returns an Ansible fact called `cyberark_session`. Every module can use this fact as `cyberark_session` parameter. + + +#### Available Fields +``` +options: + state: + default: present + choices: [present, absent] + description: + - Specifies if an authentication logon/logoff and a cyberark_session should be added/removed. + username: + description: + - The name of the user who will logon to the Vault. + password: + description: + - The password of the user. + new_password: + description: + - The new password of the user. This parameter is optional, and enables you to change a password. + api_base_url: + description: + - A string containing the base URL of the server hosting CyberArk's Privileged Account Security Web Services SDK. + validate_certs: + type: bool + default: 'true' + description: + - If C(false), SSL certificates will not be validated. This should only + set to C(false) used on personally controlled sites using self-signed + certificates. + use_shared_logon_authentication: + type: bool + default: 'false' + description: + - Whether or not Shared Logon Authentication will be used. + use_radius_authentication: + type: bool + default: 'false' + description: + - Whether or not users will be authenticated via a RADIUS server. Valid values are true/false. + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the different values to perform actions on a logged-on CyberArk session. + timeout: + type: int + default: 10 + description: + - Allows you set a timeout for when your authenticating to Cyberark +``` +## Example Playbooks + +**Shared Logon Authentication.**<br/> +Shared authentication is based on a user credential file that is stored in the PVWA web server. During shared authentication, only the user defined in the credential file can log on to the PVWA, but multiple users can use the logon token. + +This type of authentication requires the playbook to manage the users as the Vault can't identify which specific user performs each action. + +Multiple concurrent connections can be created using the same token, without affecting each other. + +The shared user is defined in a user credential file, whose location is specified in the WSCredentialFile parameter, in the appsettings section of the PVWAweb.config file: + +```xml +<add key="WSCredentialFile" value="C:\CyberArk\Password Vault Web Access\CredFiles\WSUser.ini"/> +``` +> Make sure that this user can access the PVWA interface.<br/> +> Make sure the user only has the permissions in the Vault that they require. + +It is recommended to secure connections between Ansible and the REST Web Services when using Shared Logon Authentication, using Client Authentication. + +In addition to SSL, use Client Authentication to authenticate Ansible using a client certificate. + +[Configuring client authentication via certificates](https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/SDK/Configuring%20Client%20Authentication%20via%20Client%20Certificates.htm) + +```yaml +- name: Logon to CyberArk Vault using PAS Web Services SDK - use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + use_shared_logon_authentication: true +``` + +**CyberArk Authentication**<br/> +This method authenticates a user to the Vault and returns a token that can be used in subsequent web services calls. In addition, this method allows you to set a new password. + +Users can authenticate using **CyberArk**, **LDAP** or **RADIUS** authentication. + +```yaml +- name: Logon to CyberArk Vault using PAS Web Services SDK - Not use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + username: "{{ password_object.password }}" + password: "{{ password_object.passprops.username }}" + use_shared_logon_authentication: false +``` +**Logoff**<br/> +This method logs off the user and removes the Vault session. + +```yaml +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }} +``` diff --git a/ansible_collections/cyberark/pas/docs/cyberark_credential.md b/ansible_collections/cyberark/pas/docs/cyberark_credential.md new file mode 100644 index 000000000..046d8b2a7 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/cyberark_credential.md @@ -0,0 +1,127 @@ +# cyberark_credential + +Creates a URI for retrieving a credential from a password object stored in the Cyberark Vault. The request uses the Privileged Account Security Web Services SDK through the Central Credential Provider by requesting access with an Application ID. + +**Requirements:** +- CyberArk AAM Central Credential Provider +- ApplicationID with the following permissions on the safe containing the credential being requested: + - List Accounts + - Retrieve Accounts +> **NOTE:** The CCP's Provider user (Prov_hostaname) needs to have the following permissions on the safe containing the credential being requested: +>> List Accounts<br> +>> Retrieve Accounts<br> +>> View Safe Members<br> + +## Query +This field is semicolon delimited value that is the exact syntax that goes in the URI<br> +If you use the `object` parameter then there is no need to use any other parameter as the ObjectID is a unique value.<br> +**Example:** +``` + query: "Safe=test;UserName=admin" + OR + query: "Object=OperatingSystem-administrator-dev.local" +``` + +## Available Fields + +``` +options: + api_base_url: + description: + - A string containing the base URL of the server hosting the Central Credential Provider + required: true + type: string + validate_certs: + description: + - If C(false), SSL certificate chain will not be validated. This should only set to C(true) if you have a root CA certificate installed on each node. + type: bool + required: false + default: false + type: bool + app_id: + description: + - A string containing the Application ID authorized for retrieving the credential + required: true + type: string + query: + description: + - A string containing details of the object being queried + required: true + parameters: + Safe=<safe name> + Folder=<folder name within safe> + Object=<object name> + UserName=<username of object> + Address=<address listed for object> + Database=<optional file category for database objects> + PolicyID=<platform id managing object> + connection_timeout: + description: + - An integer value of the allowed time before the request returns failed + required: false + default: '30' + type: integer + query_format: + description: + - The format for which your Query will be received by the CCP + required: false + default: 'Exact' + choices: [Exact, Regexp] + type: choice + fail_request_on_password_change: + description: + - A boolean parameter for completing the request in the middle of a password change of the requested credential + required: false + default: false + type: bool + client_cert: + description: + - A string containing the file location and name of the client certificate used for authentication + required: false + type: string + client_key: + description: + - A string containing the file location and name of the private key of the client certificate used for authentication + required: false + type: string + reason: + description: + - Reason for requesting credential if required by policy + required: false + type: string +``` + + + +## Example Playbooks + +```yaml +- name: credential retrieval basic + cyberark_credential: + api_base_url: "http://10.10.0.1" + app_id: "TestID" + query: "Safe=test;UserName=admin" + register: result + + result: + { api_base_url }"/AIMWebService/api/Accounts?AppId="{ app_id }"&Query="{ query } + + +- name: credential retrieval advanced + cyberark_credential: + api_base_url: "https://components.cyberark.local" + validate_certs: true + client_cert: /etc/pki/ca-trust/source/client.pem + client_key: /etc/pki/ca-trust/source/priv-key.pem + app_id: "TestID" + query: "Safe=test;UserName=admin" + connection_timeout: 60 + query_format: Exact + fail_request_on_password_change: true + reason: "requesting credential for Ansible deployment" + register: result + + result: + { api_base_url }"/AIMWebService/api/Accounts?AppId="{ app_id }"&Query="{ query }"&ConnectionTimeout="{ connection_timeout }"&QueryFormat="{ query_format }"&FailRequestOnPasswordChange="{ fail_request_on_password_change } + +``` diff --git a/ansible_collections/cyberark/pas/docs/cyberark_eda.md b/ansible_collections/cyberark/pas/docs/cyberark_eda.md new file mode 100644 index 000000000..d58b8f4b4 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/cyberark_eda.md @@ -0,0 +1,161 @@ +# Event-Driven Ansible + +The CyberArk PAM Self-Hosted solution can be configured to export syslogs to Ansible as an event source. Once Ansible EDA ingests the event it will act on rule-based criteria contained in an Ansible Rulebook and will call Ansible Playbooks to initiate action when the conditions contained in the rulebook are met. + +The following options will be available to configure CyberArk as Event Source: + +**VAULT** +* CyberArk to Rsyslog to EDA Webhook +* CyberArk to Rsyslog to EDA Kafka Topic +* CyberArk Syslog as EDA event source (UDP Protocol) + +**PTA** +* CyberArk PTA Syslog to EDA event source (UDP Protocol) + + +**NOTE**: For Rsyslog work, it was tested successfully with rsyslogd 8.2306.0.master (aka 2023.06) running on Ubuntu + + +## CyberArk to Rsyslog to EDA Webhook + +![CyberArk to Rsyslog to EDA Webhook](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/rsyslog-webhook.png?raw=true) + +### Vault Configuration +Follow the steps under [Security Information and Event Management (SIEM) Applications](https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASIMP/DV-Integrating-with-SIEM-Applications.htm) documentation to setup the integration: + +* Copy the [cyberark-eda-json-v1.0.xsl](https://github.com/cyberark/ansible-security-automation-collection/blob/master/plugins/event_source/cyberark-eda-json-v1.0.xsl) XSL Translator file to the Server\Syslog folder. +* See sample syslog configuration for DBPARM.ini below +* Recommended to use TCP and port 514 as it's default rsyslog port. + +``` +[SYSLOG] +UseLegacySyslogFormat=Yes +SyslogTranslatorFile=Syslog\cyberark-eda-json-v1.0.xsl +SyslogServerIP=<INSERT RSYSLOG IP HERE> +SyslogServerPort=514 +SyslogServerProtocol=TCP +``` + +### Rsyslog server configuration to forward to event to webhook +Create a conf file in /etc/rsyslog.d/webhook.conf with the following content: +``` +template(name="CyberarkFormat" type="string" + string="%syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n") +module(load="omprog") +if ($hostname == 'VAULT') then +{ + action(type="omprog" + binary="/tmp/run_curl.py" + output="/tmp/output.log" + template="CyberarkFormat") +} +``` + +Hostname will need be changed accordingly to your environment. If the syslog message are from a vault server, it will forward the event using the python script to the EDA webhook. + +Here is an example of a python script to forward the information using the webhook: +``` +#!/usr/bin/python +import urllib2 +import sys +value = sys.stdin.readline() +file = open('/tmp/debug.txt', 'a') +file.write(value) +file.close +#data = '{"nw_src": "10.0.0.1/32", "nw_dst": "10.0.0.2/32", "nw_proto": "ICMP", "actions": "ALLOW", "priority": "10"}' #test data +data = value +url = 'http://ubuntu:5000/endpoint' +req = urllib2.Request(url, data, {'Content-Type': 'application/json'}) +f = urllib2.urlopen(req) +for x in f: + print(x) +f.close() +``` + +![Sample run of disable_pas_user_webhook.yml](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda_disableuser_webhook.png?raw=true) + +## CyberArk to Rsyslog to EDA Kafka Topic + +![CyberArk to Rsyslog to EDA Kafka Topic](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/rsyslog-kafka.png?raw=true) + +### Vault Configuration +Follow the steps under [Security Information and Event Management (SIEM) Applications](https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASIMP/DV-Integrating-with-SIEM-Applications.htm) documentation to setup the integration: + +* Copy the [cyberark-eda-json-v1.0.xsl](https://github.com/cyberark/ansible-security-automation-collection/blob/master/plugins/event_source/cyberark-eda-json-v1.0.xsl) XSL Translator file to the Server\Syslog folder. +* See sample syslog configuration for DBPARM.ini below +* Recommended to use TCP and port 514 as it's default rsyslog port. + +``` +[SYSLOG] +UseLegacySyslogFormat=Yes +SyslogTranslatorFile=Syslog\ansible-json-v1.0.xsl +SyslogServerIP=<INSERT RSYSLOG IP HERE> +SyslogServerPort=514 +SyslogServerProtocol=TCP +``` + +### Rsyslog server configuration to forward to Kafka topic +Create a conf file in /etc/rsyslog.d/ansible_kafka.conf with the following content: + +``` +$EscapeControlCharactersOnReceive off +template(name="CyberarkFormat" type="string" + string="%syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n") +if ($hostname == 'VAULT') then +{ + action(type="omkafka" broker=["ubuntu:9092"] topic="ansible" confParam="compression.codec=snappy" template="CyberarkFormat") +} +``` + +Hostname will need be changed accordingly to your environment. If the syslog message are from a vault server, it will forward to a Kafka topic on Kafka server in ubuntu on port 9092. + +### Kafka Topic +Rsyslog use the omkafka plugin to forward the vault rsyslog to the Kafka topic. This plugin may need to be install by your admin as it's not enabled by default. +``` +yum install rsyslog-kafka +``` + +Refer to Kafka documentation: https://kafka.apache.org/quickstart how to stand up a Kafka server and view topic. + +![Sample rulebook](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda_disableuser_kafka.png?raw=true) + +The rulebook above listens on a Kafka ansible topic for suspended user and will disable the user and email admin via email. + +## CyberArk Syslog as EDA event source (UDP Protocol) +This EDA plugin acts as a syslog listener on specific port using UDP bypassing the need of an existing rsyslog server. + +![CyberArk Syslog as EDA event source (UDP Protocol)](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda-syslog.png?raw=true) + +Follow the steps under [Security Information and Event Management (SIEM) Applications](https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASIMP/DV-Integrating-with-SIEM-Applications.htm) documentation to setup the integration: + + +* Copy the [cyberark-eda-json-v1.0.xsl](https://github.com/cyberark/ansible-security-automation-collection/blob/master/plugins/event_source/cyberark-eda-json-v1.0.xsl) XSL Translator file to the Server\Syslog folder. +* See sample syslog configuration for DBPARM.ini below +* • Currently only UDP is supported for the syslog event-source plugin + +``` +[SYSLOG] +UseLegacySyslogFormat=Yes +SyslogTranslatorFile=Syslog\ansible-json-v1.0.xsl +SyslogServerIP=<INSERT RSYSLOG IP HERE> +SyslogServerPort=1514 +SyslogServerProtocol=UDP +``` + +![Sample rulebook](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda_disable_user_syslog.png?raw=true) + + +## CyberArk PTA Syslog to EDA event source (UDP Protocol) + +![CyberArk PTA Syslog to EDA event source (UDP Protocol)](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda-pta-syslog.png?raw=true) + +Please refer to the following documentation for instructions on how to setup PTA to sent data to SIEM: +[Send PTA syslog Records to SIEM](https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PTA/Outbound-Sending-%20PTA-syslog-Records-to-SIEM.htm?tocpath=Administrator%7CComponents%7CPrivileged%20Threat%20Analytics%7CConfigure%20Privileged%20Threat%20Analytics%7CSend%20PTA%20Data%7CSend%20PTA%20syslog%20Records%20to%20SIEM%7C_____0) + +In the PTA server's local systemparm.properties file have a line with: + +``` +syslog_outbound=[{\"siem\": \"SIEM\", \"format\": \"CEF\", \"host\": \"ANSIBLE_EDA_SERVER\", \"port\": << PORT FOR THE ANSIBLE EVENT-SOURCE EDA PLUGIN >>, \"protocol\": \"UDP\"}] +``` + +![Sample rulebook](https://github.com/cyberark/ansible-security-automation-collection/blob/master/docs/images/eda_pta_disable_user_syslog.png?raw=true)
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/docs/cyberark_user.md b/ansible_collections/cyberark/pas/docs/cyberark_user.md new file mode 100644 index 000000000..c61e173ac --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/cyberark_user.md @@ -0,0 +1,163 @@ +# cyberark_user + +This module allows admins to Add, Delete, and Modify CyberArk Vault Users. The ability to modify consists of the following: + +* Enable User<br> +* Disable User<br> +* Add/Remove Group<br> +* Set New Password<br> +* Force "change password at next login"<br> +* Modify User Information Fields<br> + * Email<br> + * First Name<br> + * Last Name<br> + * Expiry Date<br> + * User Type<br> + * Location<br> + +#### Limitations +**Idempotency** - All actions taken in the playbook adhere to the Ansible idempotency guidelines _except_ for password change. If you have the playbook set to modify a password it will "modify" the password every time the playbook is run, even if it is the same password.<br> +**Group Creation** - If the value for `group_name` does not exist in the Vault it will not create that group, the user action that was expected will fail. + +#### Available Fields + +``` +options: + username: + description: + - The name of the user who will be queried (for details), added, updated or deleted. + type: str + required: true + state: + description: + - Specifies the state needed for the user present for create user, absent for delete user. + type: str + choices: [ absent, present ] + default: present + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the different values to perform actions on a logged-on CyberArk session, + please see M(cyberark_authentication) module for an example of cyberark_session. + type: dict + required: true + initial_password: + description: + - The password that the new user will use to log on the first time. + - This password must meet the password policy requirements. + - This parameter is required when state is present -- Add User. + type: str + new_password: + description: + - The user updated password. Make sure that this password meets the password policy requirements. + type: str + email: + description: + - The user email address. + type: str + first_name: + description: + - The user first name. + type: str + last_name: + description: + - The user last name. + type: str + change_password_on_the_next_logon: + description: + - Whether or not the user must change their password in their next logon. + type: bool + default: false + expiry_date: + description: + - The date and time when the user account will expire and become disabled. + type: str + user_type_name: + description: + - The type of user. + - The parameter defaults to C(EPVUser). + type: str + disabled: + description: + - Whether or not the user will be disabled. + type: bool + default: false + location: + description: + - The Vault Location for the user. + type: str + group_name: + description: + - The name of the group the user will be added to. + type: str +``` +## Example Playbooks + +This playbook will check if username `admin` exists, if it does not, it will provision the user in the Vault, add it to the `Auditors` group and set the account to be changed at first logon. + +```yaml +- name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: https://components.cyberark.local + use_shared_logon_authentication: true + +- name: Create user, add to Group + cyberark_user: + username: admin + first_name: "Cyber" + last_name: "Admin" + email: "cyber.admin@ansibledev.com" + initial_password: PA$$Word123 + user_type_name: EPVUser + change_password_on_the_next_logon: true + group_name: Auditors + state: present + cyberark_session: '{{ cyberark_session }}' + register: cyberarkaction + +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: '{{ cyberark_session }}' +``` + +This playbook will identify the user and delete it from the CyberArk Vault based on the `state: absent` parameter. + +```yaml +- name: Logon to CyberArk Vault using PAS Web Services SDK - use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + use_shared_logon_authentication: true + +- name: Removing a CyberArk User + cyberark_user: + username: "ansibleuser" + state: absent + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" +``` +This playbook is an example of disabling a user based on the `disabled: true` value with that authentication using the credential set in Tower. +```yaml +- name: Logon to CyberArk Vault using PAS Web Services SDK - Not use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + username: "{{ password_object.password }}" + password: "{{ password_object.passprops.username }}" + use_shared_logon_authentication: false + +- name: Disabling a CyberArk User + cyberark_user: + username: "ansibleuser" + disabled: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" +``` diff --git a/ansible_collections/cyberark/pas/docs/images/cyberark_logo.jpg b/ansible_collections/cyberark/pas/docs/images/cyberark_logo.jpg Binary files differnew file mode 100644 index 000000000..e24741c3f --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/cyberark_logo.jpg diff --git a/ansible_collections/cyberark/pas/docs/images/eda-pta-syslog.png b/ansible_collections/cyberark/pas/docs/images/eda-pta-syslog.png Binary files differnew file mode 100644 index 000000000..213498341 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda-pta-syslog.png diff --git a/ansible_collections/cyberark/pas/docs/images/eda-syslog.png b/ansible_collections/cyberark/pas/docs/images/eda-syslog.png Binary files differnew file mode 100644 index 000000000..298f38ccb --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda-syslog.png diff --git a/ansible_collections/cyberark/pas/docs/images/eda_disable_user_syslog.png b/ansible_collections/cyberark/pas/docs/images/eda_disable_user_syslog.png Binary files differnew file mode 100644 index 000000000..768aac4b0 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda_disable_user_syslog.png diff --git a/ansible_collections/cyberark/pas/docs/images/eda_disableuser_kafka.png b/ansible_collections/cyberark/pas/docs/images/eda_disableuser_kafka.png Binary files differnew file mode 100644 index 000000000..0d2c49f88 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda_disableuser_kafka.png diff --git a/ansible_collections/cyberark/pas/docs/images/eda_disableuser_webhook.png b/ansible_collections/cyberark/pas/docs/images/eda_disableuser_webhook.png Binary files differnew file mode 100644 index 000000000..9c3f54c30 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda_disableuser_webhook.png diff --git a/ansible_collections/cyberark/pas/docs/images/eda_pta_disable_user_syslog.png b/ansible_collections/cyberark/pas/docs/images/eda_pta_disable_user_syslog.png Binary files differnew file mode 100644 index 000000000..ed9c0d73c --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/eda_pta_disable_user_syslog.png diff --git a/ansible_collections/cyberark/pas/docs/images/full-cyberark-logo.jpg b/ansible_collections/cyberark/pas/docs/images/full-cyberark-logo.jpg Binary files differnew file mode 100644 index 000000000..f44fdcdf0 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/full-cyberark-logo.jpg diff --git a/ansible_collections/cyberark/pas/docs/images/platform_account_properties.JPG b/ansible_collections/cyberark/pas/docs/images/platform_account_properties.JPG Binary files differnew file mode 100644 index 000000000..4ae11e3b6 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/platform_account_properties.JPG diff --git a/ansible_collections/cyberark/pas/docs/images/rsyslog-kafka.png b/ansible_collections/cyberark/pas/docs/images/rsyslog-kafka.png Binary files differnew file mode 100644 index 000000000..657923023 --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/rsyslog-kafka.png diff --git a/ansible_collections/cyberark/pas/docs/images/rsyslog-webhook.png b/ansible_collections/cyberark/pas/docs/images/rsyslog-webhook.png Binary files differnew file mode 100644 index 000000000..4e713aafb --- /dev/null +++ b/ansible_collections/cyberark/pas/docs/images/rsyslog-webhook.png diff --git a/ansible_collections/cyberark/pas/meta/runtime.yml b/ansible_collections/cyberark/pas/meta/runtime.yml new file mode 100644 index 000000000..1b754c9c2 --- /dev/null +++ b/ansible_collections/cyberark/pas/meta/runtime.yml @@ -0,0 +1,2 @@ +--- + requires_ansible: '>=2.9'
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/plugins/.DS_Store b/ansible_collections/cyberark/pas/plugins/.DS_Store Binary files differnew file mode 100644 index 000000000..e707c03aa --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/.DS_Store diff --git a/ansible_collections/cyberark/pas/plugins/event_source/cyberark-eda-json-v1.0.xsl b/ansible_collections/cyberark/pas/plugins/event_source/cyberark-eda-json-v1.0.xsl new file mode 100644 index 000000000..d9ee36467 --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/event_source/cyberark-eda-json-v1.0.xsl @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:import href="./Syslog/RFC5424Changes.xsl"/> +<xsl:output method='text' version='1.0' encoding='UTF-8' indent='no'/> + +<!-- version control variables --> +<xsl:variable name="format" select="'cyberark-eda-json'"/> +<xsl:variable name="version" select="'1.0'"/> + +<!-- configuration --> +<xsl:variable name="include_raw" select="0"/> <!-- save a "raw" key with the original XML --> + +<!-- main object with header info --> +<xsl:template match="/"> + <xsl:apply-imports/> + <xsl:text>{"format":"</xsl:text><xsl:value-of select="$format"/> + <xsl:text>","version":"</xsl:text><xsl:value-of select="$version"/> + <xsl:text>"</xsl:text> + <xsl:choose> + <xsl:when test="$include_raw=1"> + <xsl:text>,"raw":</xsl:text> + <xsl:call-template name="json-string"> + <xsl:with-param name="text"> + <xsl:apply-templates select="*" mode="raw"/> + </xsl:with-param> + </xsl:call-template> + </xsl:when> + </xsl:choose> + <xsl:text>,</xsl:text> + <xsl:apply-templates select="*" mode="object"/> + <!-- this text below includes the terminating newline --> + <xsl:text>}
</xsl:text> +</xsl:template> + +<xsl:template match="*" mode="raw"> + <xsl:value-of select="concat('<', name())" /> + <xsl:for-each select="@*"> + <xsl:value-of select="concat(' ', name(), '="', ., '"')"/> + </xsl:for-each> + <xsl:text>></xsl:text> + <xsl:apply-templates mode="raw"/> + <xsl:value-of select="concat('</', name(), '>')" /> + </xsl:template> + +<!-- serialize objects --> +<xsl:template match="*" mode="object"> + <xsl:text>"</xsl:text> + <xsl:value-of select="name()"/><xsl:text>":</xsl:text><xsl:call-template name="value"> + <xsl:with-param name="parent" select="1"/> + </xsl:call-template> +</xsl:template> + +<!-- serialize array elements --> +<xsl:template match="*" mode="array"> + <xsl:call-template name="value"/> +</xsl:template> + +<!-- value of node serializer --> +<xsl:template name="value"> + <xsl:param name="parent"/> + <xsl:variable name="childName" select="name(*[1])"/> + <xsl:choose> + <xsl:when test="not(*|@*)"> + <xsl:choose> + <xsl:when test="$parent=1"> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="."/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="name()"/> + </xsl:call-template> + <xsl:text>:</xsl:text> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="."/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> + </xsl:when> + <xsl:when test="count(*[name()=$childName]) > 1"> + <xsl:text>{</xsl:text> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="$childName"/> + </xsl:call-template> + <xsl:text>:[</xsl:text> + <xsl:apply-templates select="*" mode="array"/> + <xsl:text>]}</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>{</xsl:text> + <xsl:apply-templates select="@*" mode="attrs"/> + <xsl:if test='count(@*)>0 and count(*)>0'>,</xsl:if> + <xsl:apply-templates select="*" mode="object"/> + <xsl:text>}</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:if test="following-sibling::*"><xsl:text>,</xsl:text></xsl:if> +</xsl:template> + +<!-- serialize attributes --> +<xsl:template match="@*" mode="attrs"> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="name()"/> + </xsl:call-template> + <xsl:text>:</xsl:text> + <xsl:call-template name="json-string"> + <xsl:with-param name="text" select="."/> + </xsl:call-template> + <xsl:if test="position()!=last()"><xsl:text>,</xsl:text></xsl:if> +</xsl:template> + +<!-- json-string converts a text to a quoted and escaped JSON string --> +<xsl:template name="json-string"> + <xsl:param name="text"/> + <xsl:variable name="tmp"> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="$text"/> + <xsl:with-param name="from" select="'\'"/> + <xsl:with-param name="to" select="'\\'"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="tmp2"> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="$tmp"/> + <xsl:with-param name="from" select="'
'"/> + <xsl:with-param name="to" select="'\n'"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="tmp3"> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="$tmp2"/> + <xsl:with-param name="from" select="'
'"/> + <xsl:with-param name="to" select="'\r'"/> + </xsl:call-template> + </xsl:variable> + <xsl:variable name="tmp4"> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="$tmp3"/> + <xsl:with-param name="from" select="'	'"/> + <xsl:with-param name="to" select="'\t'"/> + </xsl:call-template> + </xsl:variable> + <xsl:text>"</xsl:text> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="$tmp4"/> + <xsl:with-param name="from" select="'"'"/> + <xsl:with-param name="to" select="'\"'"/> + </xsl:call-template> + <xsl:text>"</xsl:text> +</xsl:template> + +<!-- replace all occurences of the character(s) `from' + by the string `to' in the string `string'.--> +<xsl:template name="string-replace"> + <xsl:param name="string"/> + <xsl:param name="from"/> + <xsl:param name="to"/> + <xsl:choose> + <xsl:when test="contains($string,$from)"> + <xsl:value-of select="substring-before($string,$from)"/> + <xsl:value-of select="$to"/> + <xsl:call-template name="string-replace"> + <xsl:with-param name="string" select="substring-after($string,$from)"/> + <xsl:with-param name="from" select="$from"/> + <xsl:with-param name="to" select="$to"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$string"/> + </xsl:otherwise> + </xsl:choose> +</xsl:template> + +</xsl:stylesheet> diff --git a/ansible_collections/cyberark/pas/plugins/event_source/syslog.py b/ansible_collections/cyberark/pas/plugins/event_source/syslog.py new file mode 100644 index 000000000..2fbe1916c --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/event_source/syslog.py @@ -0,0 +1,173 @@ +#!/usr/bin/python +# Copyright: (c) 2017, Ansible Project +# 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 + +""" +syslog.py + +An ansible-rulebook event source module for receiving events via a syslog. + +Arguments: + host: The hostname to listen to. Set to 0.0.0.0 to listen on all + interfaces. Defaults to 127.0.0.1 + port: The TCP port to listen to. Defaults to 1514 + +""" + +import asyncio +import json +import logging +import socketserver +from typing import Any, Dict +import re + +def parse(str_input): + """ + Parse a string in CEF format and return a dict with the header values + and the extension data. + """ + + logger = logging.getLogger() + # Create the empty dict we'll return later + values = dict() + + # This regex separates the string into the CEF header and the extension + # data. Once we do this, it's easier to use other regexes to parse each + # part. + header_re = r'((CEF:\d+)([^=\\]+\|){,7})(.*)' + + res = re.search(header_re, str_input) + + if res: + header = res.group(1) + extension = res.group(4) + + # Split the header on the "|" char. Uses a negative lookbehind + # assertion to ensure we don't accidentally split on escaped chars, + # though. + spl = re.split(r'(?<!\\)\|', header) + + # If the input entry had any blanks in the required headers, that's wrong + # and we should return. Note we explicitly don't check the last item in the + # split list becuase the header ends in a '|' which means the last item + # will always be an empty string (it doesn't exist, but the delimiter does). + if "" in spl[0:-1]: + logger.warning(f'Blank field(s) in CEF header. Is it valid CEF format?') + return None + + # Since these values are set by their position in the header, it's + # easy to know which is which. + values["DeviceVendor"] = spl[1] + values["DeviceProduct"] = spl[2] + values["DeviceVersion"] = spl[3] + values["DeviceEventClassID"] = spl[4] + values["Name"] = spl[5] + values["DeviceName"] = spl[5] + if len(spl) > 6: + values["Severity"] = spl[6] + values["DeviceSeverity"] = spl[6] + + # The first value is actually the CEF version, formatted like + # "CEF:#". Ignore anything before that (like a date from a syslog message). + # We then split on the colon and use the second value as the + # version number. + cef_start = spl[0].find('CEF') + if cef_start == -1: + return None + (cef, version) = spl[0][cef_start:].split(':') + values["CEFVersion"] = version + + # The ugly, gnarly regex here finds a single key=value pair, + # taking into account multiple whitespaces, escaped '=' and '|' + # chars. It returns an iterator of tuples. + spl = re.findall(r'([^=\s]+)=((?:[\\]=|[^=])+)(?:\s|$)', extension) + for i in spl: + # Split the tuples and put them into the dictionary + values[i[0]] = i[1] + + # Process custom field labels + for key in list(values.keys()): + # If the key string ends with Label, replace it in the appropriate + # custom field + if key[-5:] == "Label": + customlabel = key[:-5] + # Find the corresponding customfield and replace with the label + for customfield in list(values.keys()): + if customfield == customlabel: + values[values[key]] = values[customfield] + del values[customfield] + del values[key] + else: + # return None if our regex had now output + # logger.warning('Could not parse record. Is it valid CEF format?') + return None + + # Now we're done! + logger.debug('Returning values: ' + str(values)) + return values + + +class SyslogProtocol(asyncio.DatagramProtocol): + def __init__(self, edaQueue): + super().__init__() + self.edaQueue = edaQueue + def connection_made(self, transport) -> "Used by asyncio": + self.transport = transport + + def datagram_received(self, data, addr): + asyncio.get_event_loop().create_task(self.datagram_received_async( data, addr)) + + async def datagram_received_async(self, indata, addr) -> "Main entrypoint for processing message": + # Syslog event data received, and processed for EDA + logger = logging.getLogger() + rcvdata = indata.decode() + logger.info(f"Received Syslog message: {rcvdata}") + data = parse(rcvdata) + + if data is None: + # if not CEF, we will try JSON load of the text from first curly brace + try: + value = rcvdata[rcvdata.index("{"):len(rcvdata)] + #logger.info("value after encoding:%s", value1) + data = json.loads(value) + #logger.info("json:%s", data) + except json.decoder.JSONDecodeError as jerror: + logger.error(jerror) + data = rcvdata + except UnicodeError as e: + logger.error(e) + + if data: + #logger.info("json data:%s", data) + queue = self.edaQueue + await queue.put({"cyberark": data}) + +async def main(queue: asyncio.Queue, args: Dict[str, Any]): + logger = logging.getLogger() + + loop = asyncio.get_event_loop() + host = args.get("host") or '0.0.0.0' + port = args.get("port") or 1514 + transport, protocol = await asyncio.get_running_loop().create_datagram_endpoint( + lambda: SyslogProtocol(queue), + local_addr=((host, port))) + logger.info(f"Starting cyberark.pas.syslog [Host={host}, port={port}]") + try: + while True: + await asyncio.sleep(3600) # Serve for 1 hour. + finally: + transport.close() + + +if __name__ == "__main__": + + class MockQueue: + async def put(self, event): + pass #print(event) + + asyncio.run(main(MockQueue(), {})) diff --git a/ansible_collections/cyberark/pas/plugins/modules/cyberark_account.py b/ansible_collections/cyberark/pas/plugins/modules/cyberark_account.py new file mode 100644 index 000000000..e23b493bf --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/modules/cyberark_account.py @@ -0,0 +1,1309 @@ +#!/usr/bin/python +# Copyright: (c) 2017, Ansible Project +# 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 = """ +--- +module: cyberark_account +short_description: Module for CyberArk Account object creation, deletion, and + modification using PAS Web Services SDK. +author: + - CyberArk BizDev (@cyberark-bizdev) + - Edward Nunez (@enunez-cyberark) + - James Stutes (@jimmyjamcabd) +version_added: '1.0.0' +description: + - Creates a URI for adding, deleting, modifying a privileged credential + within the Cyberark Vault. The request uses the Privileged Account + Security Web Services SDK. + + +options: + state: + description: + - Assert the desired state of the account C(present) to creat or + update and account object. Set to C(absent) for deletion of an + account object. + required: false + default: present + choices: [present, absent] + type: str + logging_level: + description: + - Parameter used to define the level of troubleshooting output to + the C(logging_file) value. + required: false + choices: [NOTSET, DEBUG, INFO] + type: str + logging_file: + description: + - Setting the log file name and location for troubleshooting logs. + required: false + default: /tmp/ansible_cyberark.log + type: str + api_base_url: + description: + - A string containing the base URL of the server hosting CyberArk's + Privileged Account Security Web Services SDK. + - Example U(https://<IIS_Server_Ip>/PasswordVault/api/) + required: false + type: str + validate_certs: + description: + - If C(false), SSL certificate chain will not be validated. This + should only set to C(true) if you have a root CA certificate + installed on each node. + required: false + default: true + type: bool + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the + different values to perform actions on a logged-on CyberArk + session, please see M(cyberark.pas.cyberark_authentication) module for an + example of cyberark_session. + required: true + type: dict + identified_by: + description: + - When an API call is made to Get Accounts, often times the default + parameters passed will identify more than one account. This + parameter is used to confidently identify a single account when + the default query can return multiple results. + required: false + default: username,address,platform_id + type: str + safe: + description: + - The safe in the Vault where the privileged account is to be + located. + required: true + type: str + platform_id: + description: + - The PolicyID of the Platform that is to be managing the account + required: false + type: str + address: + description: + - The address of the endpoint where the privileged account is + located. + required: false + type: str + name: + description: + - The ObjectID of the account + required: false + type: str + secret_type: + description: + - The value that identifies what type of account it will be. + required: false + default: password + choices: [password, key] + type: str + secret: + description: + - The initial password for the creation of the account + required: false + type: str + new_secret: + description: + - The new secret/password to be stored in CyberArk Vault. + type: str + username: + description: + - The username associated with the account. + required: false + type: str + secret_management: + description: + - Set of parameters associated with the management of the + credential. + required: false + type: dict + suboptions: + automatic_management_enabled: + description: + - Parameter that indicates whether the CPM will manage + the password or not. + default: false + type: bool + manual_management_reason: + description: + - String value indicating why the CPM will NOT manage + the password. + type: str + management_action: + description: + - CPM action flag to be placed on the account object + for credential rotation. + choices: [change, change_immediately, reconcile] + type: str + new_secret: + description: + - The actual password value that will be assigned for + the CPM action to be taken. + type: str + perform_management_action: + description: + - C(always) will perform the management action in + every action. + - C(on_create) will only perform the management action + right after the account is created. + choices: [always, on_create] + default: always + type: str + remote_machines_access: + description: + - Set of parameters for defining PSM endpoint access targets. + required: false + type: dict + suboptions: + remote_machines: + description: + - List of targets allowed for this account. + type: str + access_restricted_to_remote_machines: + description: + - Whether or not to restrict access only to specified + remote machines. + type: bool + platform_account_properties: + description: + - Object containing key-value pairs to associate with the account, + as defined by the account platform. These properties are + validated against the mandatory and optional properties of the + specified platform's definition. Optional properties that do not + exist on the account will not be returned here. Internal + properties are not returned. + required: false + type: dict + suboptions: + KEY: + description: + - Freeform key value associated to the mandatory or + optional property assigned to the specified + Platform's definition. + aliases: [Port, ExtrPass1Name, database] + type: str +""" + +EXAMPLES = """ + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Creating an Account using the PAS WebServices SDK + cyberark_account: + logging_level: DEBUG + identified_by: "address,username" + safe: "Test" + address: "cyberark.local" + username: "administrator-x" + platform_id: WinServerLocal + secret: "@N&Ibl3!" + platform_account_properties: + LogonDomain: "cyberark" + OwnerName: "ansible_user" + secret_management: + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: + - Rotate credential via reconcile and providing the password to + bechanged to. + cyberark_account: + identified_by: "address,username" + safe: "Domain_Admins" + address: "prod.cyberark.local" + username: "admin" + platform_id: WinDomain + platform_account_properties: + LogonDomain: "PROD" + secret_management: + new_secret: "Ama123ah12@#!Xaamdjbdkl@#112" + management_action: "reconcile" + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: reconcileaccount + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + +""" +RETURN = """ +changed: + description: + - Identify if the playbook run resulted in a change to the account in + any way. + returned: always + type: bool +failed: + description: Whether playbook run resulted in a failure of any kind. + returned: always + type: bool +status_code: + description: Result HTTP Status code. + returned: success + type: int + sample: "200, 201, -1, 204" +result: + description: A json dump of the resulting action. + returned: success + type: complex + contains: + address: + description: + - The adress of the endpoint where the privileged account is + located. + returned: successful addition and modification + type: str + sample: dev.local + createdTime: + description: + - Timeframe calculation of the timestamp of account creation. + returned: successful addition and modification + type: int + sample: "1567824520" + id: + description: Internal ObjectID for the account object identified + returned: successful addition and modification + type: int + sample: "25_21" + name: + description: The external ObjectID of the account + returned: successful addition and modification + type: str + sample: + - Operating System-WinServerLocal-cyberark.local-administrator + platformAccountProperties: + description: + - Object containing key-value pairs to associate with the + account, as defined by the account platform. + returned: successful addition and modification + type: complex + contains: + KEY VALUE: + description: + - Object containing key-value pairs to associate with the + account, as defined by the account platform. + returned: successful addition and modification + type: str + sample: + - "LogonDomain": "cyberark" + - "Port": "22" + platformId: + description: + - The PolicyID of the Platform that is to be managing the + account. + returned: successful addition and modification + type: str + sample: WinServerLocal + safeName: + description: + - The safe in the Vault where the privileged account is to + be located. + returned: successful addition and modification + type: str + sample: Domain_Admins + secretManagement: + description: + - Set of parameters associated with the management of + the credential. + returned: successful addition and modification + type: complex + contains: + automaticManagementEnabled: + description: + - Parameter that indicates whether the CPM will manage + the password or not. + returned: successful addition and modification + type: bool + lastModifiedTime: + description: + - Timeframe calculation of the timestamp of account + modification. + returned: successful addition and modification + type: int + sample: "1567824520" + manualManagementReason: + description: + - Reason for disabling automatic management of the account + returned: if C(automaticManagementEnabled) is set to false + type: str + sample: This is a static account + secretType: + description: + - The value that identifies what type of account it will be + returned: successful addition and modification + type: list + sample: + - key + - password + userName: + description: The username associated with the account + returned: successful addition and modification + type: str + sample: administrator +""" + + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.urls import open_url +from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.six.moves.urllib.parse import quote +from ansible.module_utils.six.moves.http_client import HTTPException +import json +import logging + +_empty = object() + +ansible_specific_parameters = [ + "state", + "api_base_url", + "validate_certs", + "cyberark_session", + "identified_by", + "logging_level", + "logging_file", + "new_secret", + "secret_management.management_action", + "secret_management.new_secret", + "management_action", + "secret_management.perform_management_action", +] + +cyberark_fixed_properties = [ + "createdTime", + "id", + "name", + "lastModifiedTime", + "safeName", + "secretType", + "secret", +] + +removal_value = "NO_VALUE" + +cyberark_reference_fieldnames = { + "username": "userName", + "safe": "safeName", + "platform_id": "platformId", + "secret_type": "secretType", + "platform_account_properties": "platformAccountProperties", + "secret_management": "secretManagement", + "manual_management_reason": "manualManagementReason", + "automatic_management_enabled": "automaticManagementEnabled", + "remote_machines_access": "remoteMachinesAccess", + "access_restricted_to_remote_machines": "accessRestrictedToRemoteMachines", + "remote_machines": "remoteMachines", +} + +ansible_reference_fieldnames = { + "userName": "username", + "safeName": "safe", + "platformId": "platform_id", + "secretType": "secret_type", + "platformAccountProperties": "platform_account_properties", + "secretManagement": "secret_management", + "manualManagementReason": "manual_management_reason", + "automaticManagementEnabled": "automatic_management_enabled", + "remoteMachinesAccess": "remote_machines_access", + "accessRestrictedToRemoteMachines": "access_testricted_to_remoteMachines", + "remoteMachines": "remote_machines", +} + + +def equal_value(existing, parameter): + if isinstance(existing, str): + return existing == str(parameter) + elif isinstance(parameter, str): + return str(existing) == parameter + else: + return existing == parameter + + +def update_account(module, existing_account): + + logging.debug("Updating Account") + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, and headers + result = {"result": existing_account} + changed = False + last_status_code = -1 + + HTTPMethod = "PATCH" + end_point = "/PasswordVault/api/Accounts/%s" % existing_account["id"] + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + payload = {"Operations": []} + + # Determining whether to add or update properties + for parameter_name in list(module.params.keys()): + if ( + parameter_name not in ansible_specific_parameters + and module.params[parameter_name] is not None + ): + module_parm_value = module.params[parameter_name] + cyberark_property_name = referenced_value( + parameter_name, cyberark_reference_fieldnames, default=parameter_name + ) + existing_account_value = referenced_value( + cyberark_property_name, + existing_account, + keys=list(existing_account.keys()), + ) + if cyberark_property_name not in cyberark_fixed_properties: + if module_parm_value is not None and isinstance( + module_parm_value, dict + ): + # Internal child values + replacing = {} + adding = {} + removing = {} + for child_parm_name in list(module_parm_value.keys()): + nested_parm_name = "%s.%s" % (parameter_name, child_parm_name) + if nested_parm_name not in ansible_specific_parameters: + child_module_parm_value = module_parm_value[child_parm_name] + child_cyberark_property_name = referenced_value( + child_parm_name, + cyberark_reference_fieldnames, + default=child_parm_name, + ) + child_existing_account_value = referenced_value( + child_cyberark_property_name, + existing_account_value, + list(existing_account_value.keys()) + if existing_account_value is not None + else {}, + ) + path_value = "/%s/%s" % ( + cyberark_property_name, + child_cyberark_property_name, + ) + if child_existing_account_value is not None: + logging.debug( + ( + "child_module_parm_value: %s " + "child_existing_account_value=%s path=%s" + ), + child_module_parm_value, + child_existing_account_value, + path_value + ) + if child_module_parm_value == removal_value: + removing.update( + { + child_cyberark_property_name: child_existing_account_value + } + ) + elif ( + child_module_parm_value is not None + and not equal_value( + child_existing_account_value, + child_module_parm_value, + ) + ): + # Updating a property + replacing.update( + { + child_cyberark_property_name: child_module_parm_value + } + ) + elif ( + child_module_parm_value is not None + and child_module_parm_value != removal_value + ): + # Adding a property value + adding.update( + { + child_cyberark_property_name: child_module_parm_value + } + ) + logging.debug( + "parameter_name=%s value=%s existing=%s", + path_value, + child_module_parm_value, + child_existing_account_value + ) + # Processing child operations + if len(list(adding.keys())) > 0: + payload["Operations"].append( + { + "op": "add", + "path": "/%s" % cyberark_property_name, + "value": adding, + } + ) + if len(list(replacing.keys())) > 0: + payload["Operations"].append( + { + "op": "replace", + "path": "/%s" % cyberark_property_name, + "value": replacing, + } + ) + if len(removing) > 0: + payload["Operations"].append( + { + "op": "remove", + "path": "/%s" % cyberark_property_name, + "value": removing, + } + ) + else: + if existing_account_value is not None: + if module_parm_value == removal_value: + payload["Operations"].append( + {"op": "remove", "path": "/%s" % cyberark_property_name} + ) + elif not equal_value(existing_account_value, module_parm_value): + # Updating a property + payload["Operations"].append( + { + "op": "replace", + "value": module_parm_value, + "path": "/%s" % cyberark_property_name, + } + ) + elif module_parm_value != removal_value: + # Adding a property value + payload["Operations"].append( + { + "op": "add", + "value": module_parm_value, + "path": "/%s" % cyberark_property_name, + } + ) + logging.debug( + "parameter_name=%s value=%s existing=%s", + parameter_name, module_parm_value, existing_account_value + ) + + if len(payload["Operations"]) != 0: + if module.check_mode: + logging.debug("Proceeding with Update Account (CHECK_MODE)") + logging.debug("Operations => %s", json.dumps(payload)) + result = {"result": existing_account} + changed = True + last_status_code = -1 + else: + logging.debug("Proceeding with Update Account") + + logging.debug( + "Processing invidual operations (%d) => %s", + len(payload["Operations"]), + json.dumps(payload), + ) + for operation in payload["Operations"]: + individual_payload = [operation] + try: + logging.debug(" ==> %s", json.dumps([operation])) + response = open_url( + api_base_url + end_point, + method=HTTPMethod, + headers=headers, + data=json.dumps(individual_payload), + validate_certs=validate_certs, + ) + + result = {"result": json.loads(response.read())} + changed = True + last_status_code = response.getcode() + + # return (True, result, response.getcode()) + + except (HTTPError, HTTPException) as http_exception: + + if isinstance(http_exception, HTTPError): + res = json.load(http_exception) + else: + res = to_text(http_exception) + + module.fail_json( + msg=( + "Error while performing update_account." + "Please validate parameters provided." + "\n*** end_point=%s%s\n ==> %s" + % (api_base_url, end_point, res) + ), + payload=individual_payload, + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing update_account." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + payload=individual_payload, + headers=headers, + status_code=-1, + ) + + return (changed, result, last_status_code) + + +def add_account(module): + + logging.debug("Adding Account") + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, and headers + result = {} + HTTPMethod = "POST" + end_point = "/PasswordVault/api/Accounts" + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + payload = {"safeName": module.params["safe"]} + + for parameter_name in list(module.params.keys()): + if ( + parameter_name not in ansible_specific_parameters + and module.params[parameter_name] is not None + ): + cyberark_property_name = referenced_value( + parameter_name, cyberark_reference_fieldnames, default=parameter_name + ) + if isinstance(module.params[parameter_name], dict): + payload[cyberark_property_name] = {} + for dict_key in list(module.params[parameter_name].keys()): + cyberark_child_property_name = referenced_value( + dict_key, cyberark_reference_fieldnames, default=dict_key + ) + logging.debug( + ( + "parameter_name =%s.%s cyberark_property_name=%s " + "cyberark_child_property_name=%s" + ), + parameter_name, + dict_key, + cyberark_property_name, + cyberark_child_property_name, + ) + if ( + parameter_name + "." + dict_key + not in ansible_specific_parameters + and module.params[parameter_name][dict_key] is not None + ): + payload[cyberark_property_name][ + cyberark_child_property_name + ] = deep_get( + module.params[parameter_name], dict_key, _empty, False + ) + else: + if parameter_name not in cyberark_reference_fieldnames: + module_parm_value = deep_get( + module.params, parameter_name, _empty, False + ) + if ( + module_parm_value is not None + and module_parm_value != removal_value + ): + payload[ + parameter_name + ] = module_parm_value # module.params[parameter_name] + else: + module_parm_value = deep_get( + module.params, parameter_name, _empty, True + ) + if ( + module_parm_value is not None + and module_parm_value != removal_value + ): + payload[ + cyberark_reference_fieldnames[parameter_name] + ] = module_parm_value # module.params[parameter_name] + logging.debug("parameter_name =%s", parameter_name) + + logging.debug("Add Account Payload => %s", json.dumps(payload)) + + try: + + if module.check_mode: + logging.debug("Proceeding with Add Account (CHECK_MODE)") + return (True, {"result": None}, -1) + else: + logging.debug("Proceeding with Add Account") + response = open_url( + api_base_url + end_point, + method=HTTPMethod, + headers=headers, + data=json.dumps(payload), + validate_certs=validate_certs, + ) + + result = {"result": json.loads(response.read())} + + return (True, result, response.getcode()) + + except (HTTPError, HTTPException) as http_exception: + + if isinstance(http_exception, HTTPError): + res = json.load(http_exception) + else: + res = to_text(http_exception) + + module.fail_json( + msg=( + "Error while performing add_account." + "Please validate parameters provided." + "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, res) + ), + payload=payload, + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing add_account." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + payload=payload, + headers=headers, + status_code=-1, + ) + + +def delete_account(module, existing_account): + + if module.check_mode: + logging.debug("Deleting Account (CHECK_MODE)") + return (True, {"result": None}, -1) + else: + logging.debug("Deleting Account") + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, and headers + result = {} + HTTPMethod = "DELETE" + end_point = "/PasswordVault/api/Accounts/%s" % existing_account["id"] + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + try: + + response = open_url( + api_base_url + end_point, + method=HTTPMethod, + headers=headers, + validate_certs=validate_certs, + ) + + result = {"result": None} + + return (True, result, response.getcode()) + + except (HTTPError, HTTPException) as http_exception: + + if isinstance(http_exception, HTTPError): + res = json.load(http_exception) + else: + res = to_text(http_exception) + + module.fail_json( + msg=( + "Error while performing delete_account." + "Please validate parameters provided." + "\n*** end_point=%s%s\n ==> %s" % (api_base_url, end_point, res) + ), + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing delete_account." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + headers=headers, + status_code=-1, + ) + + +def reset_account_if_needed(module, existing_account): + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Credential changes + management_action = deep_get( + module.params, "secret_management.management_action", "NOT_FOUND", False + ) + cpm_new_secret = deep_get( + module.params, "secret_management.new_secret", "NOT_FOUND", False + ) + logging.debug( + "management_action: %s cpm_new_secret: %s", management_action, cpm_new_secret + ) + + # Prepare result, end_point, and headers + result = {} + end_point = None + payload = {} + existing_account_id = None + if existing_account is not None: + existing_account_id = existing_account["id"] + elif module.check_mode: + existing_account_id = 9999 + + if ( + management_action == "change" + and cpm_new_secret is not None + and cpm_new_secret != "NOT_FOUND" + ): + logging.debug("CPM change secret for next CPM cycle") + end_point = ( + "/PasswordVault/API/Accounts/%s/SetNextPassword" + ) % existing_account_id + payload["ChangeImmediately"] = False + payload["NewCredentials"] = cpm_new_secret + elif management_action == "change_immediately" and ( + cpm_new_secret == "NOT_FOUND" or cpm_new_secret is None + ): + logging.debug("CPM change_immediately with random secret") + end_point = ("/PasswordVault/API/Accounts/%s/Change") % existing_account_id + payload["ChangeEntireGroup"] = True + elif management_action == "change_immediately" and ( + cpm_new_secret is not None and cpm_new_secret != "NOT_FOUND" + ): + logging.debug("CPM change immediately secret for next CPM cycle") + end_point = ( + "/PasswordVault/API/Accounts/%s/SetNextPassword" + ) % existing_account_id + payload["ChangeImmediately"] = True + payload["NewCredentials"] = cpm_new_secret + elif management_action == "reconcile": + logging.debug("CPM reconcile secret") + end_point = ("/PasswordVault/API/Accounts/%s/Reconcile") % existing_account_id + elif ( + "new_secret" in list(module.params.keys()) + and module.params["new_secret"] is not None + ): + logging.debug("Change Credential in Vault") + end_point = ( + "/PasswordVault/API/Accounts/%s/Password/Update" + ) % existing_account_id + payload["ChangeEntireGroup"] = True + payload["NewCredentials"] = module.params["new_secret"] + + if end_point is not None: + + if module.check_mode: + logging.debug("Proceeding with Credential Rotation (CHECK_MODE)") + return (True, result, -1) + else: + logging.debug("Proceeding with Credential Rotation") + + result = {"result": None} + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + HTTPMethod = "POST" + try: + + response = open_url( + api_base_url + end_point, + method=HTTPMethod, + headers=headers, + data=json.dumps(payload), + validate_certs=validate_certs, + ) + + return (True, result, response.getcode()) + + except (HTTPError, HTTPException) as http_exception: + + if isinstance(http_exception, HTTPError): + res = json.load(http_exception) + else: + res = to_text(http_exception) + + module.fail_json( + msg=( + "Error while performing reset_account." + "Please validate parameters provided." + "\n*** end_point=%s%s\n ==> %s" + ) + % (api_base_url, end_point, res), + headers=headers, + payload=payload, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing delete_account." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + headers=headers, + payload=payload, + status_code=-1, + ) + + else: + return (False, result, -1) + + +def referenced_value(field, dct, keys=None, default=None): + return dct[field] if field in (keys if keys is not None else dct) else default + + +def deep_get(dct, dotted_path, default=_empty, use_reference_table=True): + result_dct = {} + for key in dotted_path.split("."): + try: + key_field = key + if use_reference_table: + key_field = referenced_value( + key, cyberark_reference_fieldnames, default=key + ) + + if len(list(result_dct.keys())) == 0: # No result_dct set yet + result_dct = dct + + logging.debug( + "keys=%s key_field=>%s key=>%s", + ",".join(list(result_dct.keys())), + key_field, + key, + ) + result_dct = ( + result_dct[key_field] + if key_field in list(result_dct.keys()) + else result_dct[key] + ) + if result_dct is None: + return default + + except KeyError as e: + logging.debug("KeyError %s", to_text(e)) + if default is _empty: + raise + return default + return result_dct + + +def get_account(module): + + logging.debug("Finding Account") + + identified_by_fields = module.params["identified_by"].split(",") + logging.debug("Identified_by: %s", json.dumps(identified_by_fields)) + safe_filter = ( + quote("safeName eq ") + quote(module.params["safe"]) + if "safe" in module.params and module.params["safe"] is not None + else None + ) + search_string = None + for field in identified_by_fields: + if field not in ansible_specific_parameters: + search_string = "%s%s" % ( + search_string + " " if search_string is not None else "", + deep_get(module.params, field, "NOT FOUND", False), + ) + + logging.debug("Search_String => %s", search_string) + logging.debug("Safe Filter => %s", safe_filter) + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + end_point = None + if search_string is not None and safe_filter is not None: + end_point = "/PasswordVault/api/accounts?filter=%s&search=%s" % ( + safe_filter, + quote(search_string.lstrip()), + ) + elif search_string is not None: + end_point = ("/PasswordVault/api/accounts?search=%s") % (search_string.lstrip()) + else: + end_point = "/PasswordVault/api/accounts?filter=%s" % (safe_filter) + + logging.debug("End Point => %s", end_point) + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + try: + + logging.debug("Executing: " + api_base_url + end_point) + response = open_url( + api_base_url + end_point, + method="GET", + headers=headers, + validate_certs=validate_certs, + ) + + result_string = response.read() + accounts_data = json.loads(result_string) + + logging.debug("RESULT => %s", json.dumps(accounts_data)) + + if accounts_data["count"] == 0: + return (False, None, response.getcode()) + else: + how_many = 0 + first_record_found = None + for account_record in accounts_data["value"]: + logging.debug("Acct Record => %s", json.dumps(account_record)) + found = False + for field in identified_by_fields: + record_field_value = deep_get(account_record, field, "NOT FOUND") + logging.debug( + ( + "Comparing field %s | record_field_name=%s " + "record_field_value=%s module.params_value=%s" + ), + field, + field, + record_field_value, + deep_get(module.params, field, "NOT FOUND"), + ) + if record_field_value != "NOT FOUND" and ( + record_field_value + == deep_get(module.params, field, "NOT FOUND", False) + ): + found = True + else: + found = False + break + if found: + how_many = how_many + 1 + if first_record_found is None: + first_record_found = account_record + + logging.debug( + "How Many: %d First Record Found => %s", + how_many, + json.dumps(first_record_found), + ) + if how_many > 1: # too many records found + module.fail_json( + msg=( + "Error while performing get_account. " + "Too many rows (%d) found matching your criteria!" + ) + % how_many + ) + else: + return (how_many == 1, first_record_found, response.getcode()) + + except (HTTPError, HTTPException) as http_exception: + + if http_exception.code == 404: + return (False, None, http_exception.code) + else: + module.fail_json( + msg=( + "Error while performing get_account." + "Please validate parameters provided." + "\n*** end_point=%s%s\n ==> %s" + % (api_base_url, end_point, to_text(http_exception)) + ), + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing get_account." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + headers=headers, + status_code=-1, + ) + + +def main(): + + fields = { + "state": { + "type": "str", + "choices": ["present", "absent"], + "default": "present", + }, + "logging_level": {"type": "str", "choices": ["NOTSET", "DEBUG", "INFO"]}, + "logging_file": {"type": "str", "default": "/tmp/ansible_cyberark.log"}, + "api_base_url": {"type": "str"}, + "validate_certs": {"type": "bool", "default": "true"}, + "cyberark_session": {"required": True, "type": "dict", "no_log": True}, + "identified_by": { + "required": False, + "type": "str", + "default": "username,address,platform_id", + }, + "safe": {"required": True, "type": "str"}, + "platform_id": {"required": False, "type": "str"}, + "address": {"required": False, "type": "str"}, + "name": {"required": False, "type": "str"}, + "secret_type": { + "required": False, + "type": "str", + "choices": ["password", "key"], + "default": "password", + }, + "secret": {"required": False, "type": "str", "no_log": True}, + "new_secret": {"required": False, "type": "str", "no_log": True}, + "username": {"required": False, "type": "str"}, + "secret_management": { + "required": False, + "type": "dict", + "options": { + "automatic_management_enabled": { + "type": "bool", + "default": False, + }, + "manual_management_reason": {"type": "str"}, + "management_action": { + "type": "str", + "choices": ["change", "change_immediately", "reconcile"], + }, + "new_secret": {"type": "str", "no_log": True}, + "perform_management_action": { + "type": "str", + "choices": ["on_create", "always"], + "default": "always", + }, + }, + "no_log": False, + }, + "remote_machines_access": { + "required": False, + "type": "dict", + "options": { + "remote_machines": {"type": "str"}, + "access_restricted_to_remote_machines": {"type": "bool"}, + }, + }, + "platform_account_properties": {"required": False, "type": "dict"}, + } + + module = AnsibleModule(argument_spec=fields, supports_check_mode=True) + + if module.params["logging_level"] is not None: + logging.basicConfig( + filename=module.params["logging_file"], level=module.params["logging_level"] + ) + + logging.info("Starting Module") + + state = module.params["state"] + + (found, account_record, status_code) = get_account(module) + logging.debug( + "Account was %s, status_code=%s", "FOUND" if found else "NOT FOUND", status_code + ) + + changed = False + result = {"result": account_record} + + if state == "present": + + if found: # Account already exists + (changed, result, status_code) = update_account(module, account_record) + else: # Account does not exist + (changed, result, status_code) = add_account(module) + + perform_management_action = "always" + if "secret_management" in list(module.params.keys()): + secret_management = module.params["secret_management"] + if secret_management is not None and "perform_management_action" in list( + secret_management.keys() + ): + perform_management_action = secret_management[ + "perform_management_action" + ] + + logging.debug("Result=>%s", json.dumps(result)) + if perform_management_action == "always" or ( + perform_management_action == "on_create" and not found + ): + (account_reset, no_result, no_status_code) = reset_account_if_needed( + module, result["result"] + ) + if account_reset: + changed = True + + elif found and state == "absent": + (changed, result, status_code) = delete_account(module, account_record) + + module.exit_json(changed=changed, result=result, status_code=status_code) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cyberark/pas/plugins/modules/cyberark_authentication.py b/ansible_collections/cyberark/pas/plugins/modules/cyberark_authentication.py new file mode 100644 index 000000000..c8efae3ed --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/modules/cyberark_authentication.py @@ -0,0 +1,392 @@ +#!/usr/bin/python +# Copyright: (c) 2017, Ansible Project +# 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": "certified", +} + +DOCUMENTATION = """ +--- +module: cyberark_authentication +short_description: CyberArk Authentication using PAS Web Services SDK. +author: + - Edward Nunez (@enunez-cyberark) + - Cyberark Bizdev (@cyberark-bizdev) +version_added: '1.0.0' +description: + - Authenticates to CyberArk Vault using Privileged Account Security + Web Services SDK and creates a session fact that can be used by other + modules. It returns an Ansible fact called I(cyberark_session). Every + module can use this fact as C(cyberark_session) parameter. +options: + state: + default: present + choices: [present, absent] + description: + - Specifies if an authentication logon/logoff and a + cyberark_session should be added/removed. + type: str + username: + description: + - The name of the user who will logon to the Vault. + type: str + password: + description: + - The password of the user. + type: str + new_password: + description: + - The new password of the user. This parameter is optional, + and enables you to change a password. + type: str + api_base_url: + description: + - A string containing the base URL of the server hosting + CyberArk's Privileged Account Security Web Services SDK. + type: str + validate_certs: + type: bool + default: 'true' + description: + - If C(false), SSL certificates will not be validated. This + should only set to C(false) used on personally controlled + sites using self-signed certificates. + use_ldap_authentication: + type: bool + default: 'false' + description: + - Whether or not LDAP will be used. + use_windows_authentication: + type: bool + default: 'false' + description: + - Whether or not Windows will be used. + use_cyberark_authentication: + type: bool + default: 'false' + description: + - Whether or not LDAP will be used. + use_radius_authentication: + type: bool + default: 'false' + description: + - Whether or not users will be authenticated via a RADIUS + server. Valid values are true/false. + connection_number: + type: int + description: + - To support multiple connections for same user specify + - different value for this parameter. + concurrentSession: + type: bool + default: false + description: + - Whether or not to allow concurrent sessions for the same user. + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the + different values to perform actions on a logged-on CyberArk + session. + type: dict + timeout: + description: + - Allows you set a timeout for when your authenticating to Cyberark + default: 10 + type: int +""" + +EXAMPLES = """ +- name: Logon - use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + use_shared_logon_authentication: true + +- name: Logon - Not use_shared_logon_authentication + cyberark_authentication: + api_base_url: "{{ web_services_base_url }}" + username: "{{ password_object.password }}" + password: "{{ password_object.passprops.username }}" + use_shared_logon_authentication: false + +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" +""" + +RETURN = """ +cyberark_session: + description: Authentication facts. + returned: success + type: complex + contains: + api_base_url: + description: + - Base URL for API calls. Returned in the cyberark_session, + so it can be used in subsequent calls. + type: str + returned: always + token: + description: + - The token that identifies the session, encoded in BASE 64. + type: str + returned: always + use_shared_logon_authentication: + description: + - Whether or not Shared Logon Authentication was used to + establish the session. + type: bool + returned: always + validate_certs: + description: Whether or not SSL certificates should be validated. + type: bool + returned: always +""" + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.urls import open_url +from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.six.moves.http_client import HTTPException +import json + + +def processAuthentication(module): + + # Getting parameters from module + + api_base_url = module.params["api_base_url"] + validate_certs = module.params["validate_certs"] + username = module.params["username"] + password = module.params["password"] + new_password = module.params["new_password"] + + use_radius = module.params["use_radius_authentication"] + use_ldap = module.params["use_ldap_authentication"] + use_windows = module.params["use_windows_authentication"] + use_cyberark = module.params["use_cyberark_authentication"] + + # connection_number = module.params["connection_number"] + state = module.params["state"] + cyberark_session = module.params["cyberark_session"] + + concurrentSession = module.params["concurrentSession"] + + timeout = module.params["timeout"] + + # if in check mode it will not perform password changes + if module.check_mode and new_password is not None: + new_password = None + + # Defining initial values for open_url call + headers = { + "Content-Type": "application/json", + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + payload = "" + + if state == "present": # Logon Action + + # Different end_points based on the use of desired method of auth + + if use_ldap: + end_point = "/PasswordVault/API/Auth/LDAP/Logon" + payload_dict = {"username": username, "password": password} + + elif use_radius: + end_point = "/PasswordVault/API/Auth/radius/Logon" + + elif use_windows: + end_point = "/PasswordVault/API/auth/Windows/Logon" + + else: + use_cyberark = True + end_point = "/PasswordVault/API/Auth/CyberArk/Logon" + + # The payload will contain username, password + # and optionally use_radius_authentication and new_password + payload_dict = {"username": username, "password": password} + + if new_password is not None and use_cyberark: + payload_dict["newPassword"] = new_password + + # COMMENT: I dont know what this is for and the old api seems like it didnt have this field + # if connection_number is not None: + # payload_dict["connectionNumber"] = connection_number + + if concurrentSession: + payload_dict["concurrentSession"] = True + + payload = json.dumps(payload_dict) + + else: # Logoff Action + + # Get values from cyberark_session already established + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + headers["Authorization"] = cyberark_session["token"] + + # All off the logoff with the same endpoint + end_point = "/PasswordVault/API/Auth/Logoff" + + result = None + changed = False + response = None + + try: + + response = open_url( + api_base_url + end_point, + method="POST", + headers=headers, + data=payload, + validate_certs=validate_certs, + timeout=timeout, + ) + + except (HTTPError, HTTPException) as http_exception: + + module.fail_json( + msg=( + "Error while performing authentication." + "Please validate parameters provided, and ability to logon to " + "CyberArk.\n*** end_point=%s%s\n ==> %s" + ) + % (api_base_url, end_point, to_text(http_exception)), + payload=payload, + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing authentication." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + payload=payload, + headers=headers, + status_code=-1, + ) + + if response.getcode() == 200: # Success + + if state == "present": # Logon Action + + # Result token from REST Api uses a different key based + # the use of shared logon authentication + token = "" + try: + token = str(json.loads(response.read())) + + # the new one just returns a token + # if use: + # token = json.loads(response.read())["LogonResult"] + # else: + # token = json.loads(response.read())["CyberArkLogonResult"] + except Exception as e: + module.fail_json( + msg="Error obtaining token\n%s" % (to_text(e)), + payload=payload, + headers=headers, + status_code=-1, + ) + + # Preparing result of the module + result = { + "cyberark_session": { + "token": token, + "api_base_url": api_base_url, + "validate_certs": validate_certs, + } + } + + if new_password is not None: + # Only marks change if new_password was received resulting + # in a password change + changed = True + + else: # Logoff Action clears cyberark_session + + result = {"cyberark_session": {}} + + return (changed, result, response.getcode()) + + else: + module.fail_json(msg="error in end_point=>" + end_point, headers=headers) + + +def main(): + + fields = { + "api_base_url": {"type": "str"}, + "validate_certs": {"type": "bool", "default": "true"}, + "username": {"type": "str"}, + "password": {"type": "str", "no_log": True}, + "new_password": {"type": "str", "no_log": True}, + "use_radius_authentication": {"default": False, "type": "bool"}, + "use_windows_authentication": {"default": False, "type": "bool"}, + "use_ldap_authentication": {"default": False, "type": "bool"}, + "use_cyberark_authentication": {"default": False, "type": "bool"}, + "concurrentSession": {"default": False, "type": "bool"}, + "connection_number": {"type": "int"}, + "state": { + "type": "str", + "choices": ["present", "absent"], + "default": "present", + }, + "cyberark_session": {"type": "dict"}, + "timeout": {"default": 10, "type": "int"}, + } + + # cyberark and radius -> mutually_exclusive is cyberark and ldap + # ldap and radius + # windows has to be by itself + + mutually_exclusive = [ + [ + "use_windows_authentication", + "use_ldap_authentication", + "use_cyberark_authentication", + "use_radius_authentication", + ], + ["use_radius_authentication", "new_password"], + ["use_windows_authentication", "new_password"], + ["use_ldap_authentication", "new_password"], + ["api_base_url", "cyberark_session"], + ] + + required_if = [ + ("state", "present", ["api_base_url"]), + ("state", "absent", ["cyberark_session"]), + ] + + required_together = [["username", "password"]] + + module = AnsibleModule( + argument_spec=fields, + mutually_exclusive=mutually_exclusive, + required_if=required_if, + required_together=required_together, + supports_check_mode=True, + ) + + (changed, result, status_code) = processAuthentication(module) + + module.exit_json(changed=changed, ansible_facts=result, status_code=status_code) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cyberark/pas/plugins/modules/cyberark_credential.py b/ansible_collections/cyberark/pas/plugins/modules/cyberark_credential.py new file mode 100644 index 000000000..128d03b32 --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/modules/cyberark_credential.py @@ -0,0 +1,337 @@ +#!/usr/bin/python +# Copyright: (c) 2017, Ansible Project +# 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 = """ +--- +module: cyberark_credential +short_description: Credential retrieval using AAM Central Credential Provider. +author: + - Edward Nunez (@enunez-cyberark) + - CyberArk BizDev (@cyberark-bizdev) + - Erasmo Acosta (@erasmix) + - James Stutes (@JimmyJamCABD) +version_added: '1.0.0' +description: + - Creates a URI for retrieving a credential from a password object stored + in the Cyberark Vault. The request uses the Privileged Account Security + Web Services SDK through the Central Credential Provider by requesting + access with an Application ID. + +options: + api_base_url: + type: str + required: true + description: + - A string containing the base URL of the server hosting the + Central Credential Provider. + validate_certs: + type: bool + required: false + default: true + description: + - If C(false), SSL certificate chain will not be validated. This + should only set to C(true) if you have a root CA certificate + installed on each node. + app_id: + type: str + required: true + description: + - A string containing the Application ID authorized for retrieving + the credential. + query: + type: str + required: true + description: + - A string containing details of the object being queried; + - Possible parameters could be Safe, Folder, Object + - (internal account name), UserName, Address, Database, + - PolicyID. + connection_timeout: + type: int + required: false + default: '30' + description: + - An integer value of the allowed time before the request returns + failed. + query_format: + type: str + required: false + default: Exact + choices: [Exact, Regexp] + description: + - The format for which your Query will be received by the CCP. + fail_request_on_password_change: + type: bool + required: false + default: false + description: + - A boolean parameter for completing the request in the middle of + a password change of the requested credential. + client_cert: + type: str + required: false + description: + - A string containing the file location and name of the client + certificate used for authentication. + client_key: + type: str + required: false + description: + - A string containing the file location and name of the private + key of the client certificate used for authentication. + reason: + type: str + required: false + description: + - Reason for requesting credential if required by policy; + - It must be specified if the Policy managing the object + - requires it. +""" + +EXAMPLES = """ + tasks: + - name: credential retrieval basic + cyberark_credential: + api_base_url: "http://10.10.0.1" + app_id: "TestID" + query: "Safe=test;UserName=admin" + register: result + + - name: credential retrieval advanced + cyberark_credential: + api_base_url: "https://components.cyberark.local" + validate_certs: true + client_cert: /etc/pki/ca-trust/source/client.pem + client_key: /etc/pki/ca-trust/source/priv-key.pem + app_id: "TestID" + query: "Safe=test;UserName=admin" + connection_timeout: 60 + query_format: Exact + fail_request_on_password_change: true + reason: "requesting credential for Ansible deployment" + register: result + +""" + +RETURN = """ +changed: + description: + - Identify if the playbook run resulted in a change to the account in + any way. + returned: always + type: bool +failed: + description: Whether playbook run resulted in a failure of any kind. + returned: always + type: bool +status_code: + description: Result HTTP Status code. + returned: success + type: int + sample: "200, 201, -1, 204" +result: + description: A json dump of the resulting action. + returned: success + type: complex + contains: + Address: + description: The target address of the credential being queried + type: str + returned: if required + Content: + description: The password for the object being queried + type: str + returned: always + CreationMethod: + description: This is how the object was created in the Vault + type: str + returned: always + DeviceType: + description: + - An internal File Category for more granular management of + Platforms. + type: str + returned: always + Folder: + description: + - The folder within the Safe where the credential is stored. + type: str + returned: always + Name: + description: + - The Cyberark unique object ID of the credential being + queried. + type: str + returned: always + PasswordChangeInProcess: + description: If the password has a change flag placed by the CPM + type: bool + returned: always + PolicyID: + description: Whether or not SSL certificates should be validated. + type: str + returned: if assigned to a policy + Safe: + description: The safe where the queried credential is stored + type: str + returned: always + Username: + description: The username of the credential being queried + type: str + returned: if required + LogonDomain: + description: The Address friendly name resolved by the CPM + type: str + returned: if populated + CPMDisabled: + description: + - A description of why this vaulted credential is not being + managed by the CPM. + type: str + returned: if CPM management is disabled and a reason is given +""" + +from ansible.module_utils._text import to_text +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.urls import open_url +from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.six.moves.urllib.parse import quote +from ansible.module_utils.six.moves.http_client import HTTPException +import json + + +def retrieve_credential(module): + + # Getting parameters from module + + api_base_url = module.params["api_base_url"] + validate_certs = module.params["validate_certs"] + app_id = module.params["app_id"] + query = module.params["query"] + connection_timeout = module.params["connection_timeout"] + query_format = module.params["query_format"] + fail_request_on_password_change = module.params["fail_request_on_password_change"] + client_cert = None + client_key = None + + if "client_cert" in module.params: + client_cert = module.params["client_cert"] + if "client_key" in module.params: + client_key = module.params["client_key"] + + end_point = ( + "/AIMWebService/api/Accounts?AppId=%s&Query=%s&" + "ConnectionTimeout=%s&QueryFormat=%s" + "&FailRequestOnPasswordChange=%s" + ) % ( + quote(app_id), + quote(query), + connection_timeout, + query_format, + fail_request_on_password_change, + ) + + if "reason" in module.params and module.params["reason"] is not None: + reason = quote(module.params["reason"]) + end_point = end_point + "&reason=%s" % reason + + result = None + response = None + + try: + + response = open_url( + api_base_url + end_point, + method="GET", + validate_certs=validate_certs, + client_cert=client_cert, + client_key=client_key, + ) + + except (HTTPError, HTTPException) as http_exception: + + module.fail_json( + msg=( + "Error while retrieving credential." + "Please validate parameters provided, and permissions for " + "the application and provider in CyberArk." + "\n*** end_point=%s%s\n ==> %s" + % (api_base_url, end_point, to_text(http_exception)) + ), + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while retrieving credential." + "\n*** end_point=%s%s\n%s" + % (api_base_url, end_point, to_text(unknown_exception)) + ), + status_code=-1, + ) + + if response.getcode() == 200: # Success + + # Result token from REST Api uses a different key based + try: + result = json.loads(response.read()) + except Exception as exc: + module.fail_json( + msg=("Error obtain cyberark credential result " "from http body\n%s") + % (to_text(exc)), + status_code=-1, + ) + + return (result, response.getcode()) + + else: + module.fail_json(msg="error in end_point=>" + end_point) + + +def main(): + + fields = { + "api_base_url": {"required": True, "type": "str"}, + "app_id": {"required": True, "type": "str"}, + "query": {"required": True, "type": "str"}, + "reason": {"required": False, "type": "str"}, + "connection_timeout": {"required": False, "type": "int", "default": 30}, + "query_format": { + "required": False, + "type": "str", + "choices": ["Exact", "Regexp"], + "default": "Exact", + }, + "fail_request_on_password_change": { + "required": False, + "type": "bool", + "default": False, + }, + "validate_certs": {"type": "bool", "default": True}, + "client_cert": {"type": "str", "required": False}, + "client_key": {"type": "str", "required": False, "no_log": True}, + } + + module = AnsibleModule(argument_spec=fields, supports_check_mode=True) + + (result, status_code) = retrieve_credential(module) + + module.exit_json(changed=False, result=result, status_code=status_code) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cyberark/pas/plugins/modules/cyberark_user.py b/ansible_collections/cyberark/pas/plugins/modules/cyberark_user.py new file mode 100644 index 000000000..2e4bedbe9 --- /dev/null +++ b/ansible_collections/cyberark/pas/plugins/modules/cyberark_user.py @@ -0,0 +1,782 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2017, Ansible Project +# 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": "certified", +} + +DOCUMENTATION = r""" +--- +module: cyberark_user +short_description: CyberArk User Management using PAS Web Services SDK. +author: + - Edward Nunez (@enunez-cyberark) + - Cyberark Bizdev (@cyberark-bizdev) + - Erasmo Acosta (@erasmix) + - James Stutes (@jimmyjamcabd) +version_added: '1.0.0' +description: + - CyberArk User Management using PAS Web Services SDK, + It currently supports the following actions Get User Details, Add User, + Update User, Delete User. + +options: + username: + description: + - The name of the user who will be queried (for details), added, + updated or deleted. + type: str + required: true + state: + description: + - Specifies the state needed for the user present for create user, + absent for delete user. + type: str + choices: [ absent, present ] + default: present + logging_level: + description: + - Parameter used to define the level of troubleshooting output to + the C(logging_file) value. + required: false + choices: [NOTSET, DEBUG, INFO] + default: NOTSET + type: str + logging_file: + description: + - Setting the log file name and location for troubleshooting logs. + required: false + default: /tmp/ansible_cyberark.log + type: str + cyberark_session: + description: + - Dictionary set by a CyberArk authentication containing the + different values to perform actions on a logged-on CyberArk + session, please see M(cyberark.pas.cyberark_authentication) module for an + example of cyberark_session. + type: dict + required: true + initial_password: + description: + - The password that the new user will use to log on the first time. + - This password must meet the password policy requirements. + - This parameter is required when state is present -- Add User. + type: str + new_password: + description: + - The user updated password. Make sure that this password meets + the password policy requirements. + type: str + email: + description: + - The user email address. + type: str + first_name: + description: + - The user first name. + type: str + last_name: + description: + - The user last name. + type: str + change_password_on_the_next_logon: + description: + - Whether or not the user must change their password in their + next logon. + type: bool + default: false + domain_name: + description: + - The name of the user domain. + type: str + member_type: + description: + - The type of member. + type: str + expiry_date: + description: + - The date and time when the user account will expire and become + disabled. + type: str + user_type_name: + description: + - The type of user. + - The parameter defaults to C(EPVUser). + type: str + disabled: + description: + - Whether or not the user will be disabled. + type: bool + default: false + location: + description: + - The Vault Location for the user. + type: str + group_name: + description: + - The name of the group the user will be added to. + - Causes an additional lookup in cyberark + - Will be ignored if vault_id is used + - Will cause a failure if group is missing or more than one group with that name exists + type: str + timeout: + description: + - How long to wait for the server to send data before giving up + type: float + default: 10 + vault_id: + description: + - The ID of the user group to add the user to + - Prefered over group_name + type: int + authorization: + description: + - A list of authorization options for this user. + - Options can include AddSafes and AuditUsers + - The default provides backwards compatability with older versions of the collection + type: list + elements: str + default: + - AddSafes + - AuditUsers +""" + +EXAMPLES = r""" +- name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: https://components.cyberark.local + use_shared_logon_authentication: true + +- name: Create user & immediately add it to a group + cyberark_user: + username: username + initial_password: password + user_type_name: EPVUser + change_password_on_the_next_logon: false + group_name: GroupOfUser + state: present + cyberark_session: '{{ cyberark_session }}' + +- name: Make sure user is present and reset user credential if present + cyberark_user: + username: Username + new_password: password + disabled: false + state: present + cyberark_session: '{{ cyberark_session }}' + +- name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: '{{ cyberark_session }}' +""" + +RETURN = r""" +changed: + description: Whether there was a change done. + type: bool + returned: always +cyberark_user: + description: Dictionary containing result properties. + returned: always + type: complex + contains: + result: + description: user properties when state is present + type: dict + returned: success +status_code: + description: Result HTTP Status code + returned: success + type: int + sample: 200 +""" + +import json + +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils._text import to_text +from ansible.module_utils.six.moves import http_client as httplib +from ansible.module_utils.six.moves.urllib.error import HTTPError +from ansible.module_utils.urls import open_url +from ansible.module_utils.six.moves.urllib.parse import quote +import logging + + +def construct_url(api_base_url, end_point): + return "{baseurl}/{endpoint}".format(baseurl=api_base_url.rstrip("/"), endpoint=end_point.lstrip("/")) + + +def user_details(module): + + # Get username from module parameters, and api base url + # along with validate_certs from the cyberark_session established + username = module.params["username"] + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, and headers + result = {} + end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{pusername}".format(pusername=username) + url = construct_url(api_base_url, end_point) + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + try: + + response = open_url( + url, + method="GET", + headers=headers, + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + result = {"result": json.loads(response.read())} + + return (False, result, response.getcode()) + + except (HTTPError, httplib.HTTPException) as http_exception: + + if http_exception.code == 404: + return (False, None, http_exception.code) + else: + module.fail_json( + msg=( + "Error while performing user_details." + "Please validate parameters provided." + "\n*** end_point=%s\n ==> %s" + % (url, to_text(http_exception)) + ), + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing user_details." + "\n*** end_point=%s\n%s" + % (url, to_text(unknown_exception)) + ), + headers=headers, + status_code=-1, + ) + + +def user_add_or_update(module, HTTPMethod, existing_info): + + # Get username from module parameters, and api base url + # along with validate_certs from the cyberark_session established + username = module.params["username"] + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, paylod, and headers + result = {} + payload = {} + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + # end_point and payload sets different depending on POST/PUT + # for POST -- create -- payload contains username + # for PUT -- update -- username is part of the endpoint + if HTTPMethod == "POST": + end_point = "PasswordVault/api/Users" + payload["UserName"] = username + if ( + "initial_password" in list(module.params.keys()) + and module.params["initial_password"] is not None + ): + payload["InitialPassword"] = module.params["initial_password"] + + elif HTTPMethod == "PUT": + # With the put in this old format, we can not update the vaultAuthorization + end_point = "/PasswordVault/WebServices/PIMServices.svc/Users/{pusername}".format(pusername=username) + + # --- Optionally populate payload based on parameters passed --- + if "new_password" in module.params and module.params["new_password"] is not None: + payload["NewPassword"] = module.params["new_password"] + + if "email" in module.params and module.params["email"] is not None: + payload["Email"] = module.params["email"] + + if "first_name" in module.params and module.params["first_name"] is not None: + payload["FirstName"] = module.params["first_name"] + + if "last_name" in module.params and module.params["last_name"] is not None: + payload["LastName"] = module.params["last_name"] + + if ( + "change_password_on_the_next_logon" in module.params + and module.params["change_password_on_the_next_logon"] is not None + ): + payload["ChangePasswordOnTheNextLogon"] = module.params[ + "change_password_on_the_next_logon" + ] + + if "expiry_date" in module.params and module.params["expiry_date"] is not None: + payload["ExpiryDate"] = module.params["expiry_date"] + + if ( + "user_type_name" in module.params + and module.params["user_type_name"] is not None + ): + payload["UserTypeName"] = module.params["user_type_name"] + # In API V2 the parameter is called userType, V2 ignores the UserTypeName + payload["userType"] = module.params["user_type_name"] + + if "disabled" in module.params and module.params["disabled"] is not None: + payload["Disabled"] = module.params["disabled"] + + if "location" in module.params and module.params["location"] is not None: + payload["Location"] = module.params["location"] + + if module.params.get("authorization", None) is not None: + payload["vaultAuthorization"] = module.params["authorization"] + + # -------------------------------------------------------------- + logging.debug( + "HTTPMethod = " + HTTPMethod + " module.params = " + json.dumps(module.params) + ) + logging.debug("Existing Info: %s", json.dumps(existing_info)) + logging.debug("payload => %s", json.dumps(payload)) + + if HTTPMethod == "PUT" and ( + "new_password" not in module.params or module.params["new_password"] is None + ): + logging.info("Verifying if needs to be updated") + proceed = False + updateable_fields = [ + "Email", + "FirstName", + "LastName", + "ChangePasswordOnTheNextLogon", + "ExpiryDate", + "UserTypeName", + "Disabled", + "Location", + "UserTypeName", + "vaultAuthorization", + ] + for field_name in updateable_fields: + logging.debug("#### field_name : %s", field_name) + if ( + field_name in payload + and field_name in existing_info + and payload[field_name] != existing_info[field_name] + ): + logging.debug("Changing value for %s", field_name) + proceed = True + else: + proceed = True + + if proceed: + logging.info("Proceeding to either update or create") + url = construct_url(api_base_url, end_point) + try: + + # execute REST action + response = open_url( + url, + method=HTTPMethod, + headers=headers, + data=json.dumps(payload), + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + + result = {"result": json.loads(response.read())} + + return (True, result, response.getcode()) + + except (HTTPError, httplib.HTTPException) as http_exception: + + module.fail_json( + msg=( + "Error while performing user_add_or_update." + "Please validate parameters provided." + "\n*** end_point=%s\n ==> %s" + % (url, to_text(http_exception)) + ), + payload=payload, + headers=headers, + status_code=http_exception.code, + ) + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing user_add_or_update." + "\n*** end_point=%s\n%s" + % (url, to_text(unknown_exception)) + ), + payload=payload, + headers=headers, + status_code=-1, + ) + else: + return (False, existing_info, 200) + + +def resolve_username_to_id(module): + username = module.params["username"] + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + url = construct_url(api_base_url, "PasswordVault/api/Users?search={pusername}".format(pusername=username)) + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + try: + response = open_url( + url, + method="GET", + headers=headers, + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + users = json.loads(response.read()) + # Return None if the user does not exist + user_id = None + # Say we have two users: 'someone' and 'someoneelse', a search on someone will return both + # So we will lopp over and see if the username returned matches the username we searched for + # If so, and we somehow found more than one raise an error + for user in users['Users']: + if user['username'] == username: + if user_id is None: + user_id = user['id'] + else: + module.fail_json(msg=("Found more than one user matching %s, this should be impossible" % (username))) + + # If we made it here we had 1 or 0 users, return them + logging.debug("Resolved username {%s} to ID {%s}", username, user_id) + return user_id + + except (HTTPError, httplib.HTTPException) as http_exception: + exception_text = to_text(http_exception) + module.fail_json(msg=( + "Error while performing user_search." + "Please validate parameters provided." + "\n*** end_point=%s\n ==> %s" + % (url, exception_text)), + headers=headers, + status_code=http_exception.code, + ) + except Exception as unknown_exception: + module.fail_json(msg=( + "Unknown error while performing user search." + "\n*** end_point=%s\n%s" + % (url, to_text(unknown_exception))), + headers=headers, + status_code=-1, + ) + + +def user_delete(module): + + # Get username from module parameters, and api base url + # along with validate_certs from the cyberark_session established + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, and headers + result = {} + vault_user_id = resolve_username_to_id(module) + # If the user was not found by username we can return unchanged + if vault_user_id is None: + return (False, result, None) + + end_point = ("PasswordVault/api/Users/{pvaultuserid}").format(pvaultuserid=vault_user_id) + + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + url = construct_url(api_base_url, end_point) + + try: + + # execute REST action + response = open_url( + url, + method="DELETE", + headers=headers, + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + + result = {"result": {}} + + return (True, result, response.getcode()) + + except (HTTPError, httplib.HTTPException) as http_exception: + + exception_text = to_text(http_exception) + if http_exception.code == 404 and "ITATS003E" in exception_text: + # User does not exist + result = {"result": {}} + return (False, result, http_exception.code) + else: + module.fail_json( + msg=( + "Error while performing user_delete." + "Please validate parameters provided." + "\n*** end_point=%s\n ==> %s" + % (url, exception_text) + ), + headers=headers, + status_code=http_exception.code, + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing user_delete." + "\n*** end_point=%s\n%s" + % (url, to_text(unknown_exception)) + ), + headers=headers, + status_code=-1, + ) + + +def resolve_group_name_to_id(module): + group_name = module.params["group_name"] + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + url = construct_url(api_base_url, "/PasswordVault/api/UserGroups?search={pgroupname}".format(pgroupname=quote(group_name))) + try: + response = open_url( + url, + method="GET", + headers=headers, + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + groups = json.loads(response.read()) + # Return None if the user does not exist + group_id = None + # Say we have two groups: 'groupone' and 'grouptwo', a search on group will return both + # So we will lopp over and see if the groupname returned matches the groupsname we searched for + # If so, and we somehow found more than one raise an error + for group in groups['value']: + if group['groupName'] == group_name: + if group_id is None: + group_id = group['id'] + else: + module.fail_json(msg=("Found more than one group matching %s. Use vault_id instead" % (group_name))) + # If we made it here we had 1 or 0 users, return them + logging.debug("Resolved group_name %s to ID %s", group_name, group_id) + return group_id + + except (HTTPError, httplib.HTTPException) as http_exception: + module.fail_json(msg=( + "Error while looking up group %s.\n*** end_point=%s\n ==> %s" + % (group_name, url, to_text(http_exception))), + payload={}, + headers=headers, + status_code=http_exception.code, + ) + except Exception as unknown_exception: + module.fail_json(msg=( + "Unknown error while looking up group %s.\n*** end_point=%s\n%s" + % (group_name, url, to_text(unknown_exception))), + payload={}, + headers=headers, + status_code=-1, + ) + + +def user_add_to_group(module): + + # Get username, and groupname from module parameters, and api base url + # along with validate_certs from the cyberark_session established + + # Not needed for new version + username = module.params["username"] + group_name = module.params["group_name"] + vault_id = module.params["vault_id"] + member_type = ( + "Vault" + if module.params["member_type"] is None + else module.params["member_type"] + ) + domain_name = module.params["domain_name"] if member_type == "domain" else None + + cyberark_session = module.params["cyberark_session"] + api_base_url = cyberark_session["api_base_url"] + validate_certs = cyberark_session["validate_certs"] + + # Prepare result, end_point, headers and payload + result = {} + headers = { + "Content-Type": "application/json", + "Authorization": cyberark_session["token"], + "User-Agent": "CyberArk/1.0 (Ansible; cyberark.pas)" + } + + # If we went "old school" and were provided a group_name instead of a vault_id we need to resolve it + if group_name and not vault_id: + # If we were given a group_name we need to lookup the vault_id + vault_id = resolve_group_name_to_id(module) + if vault_id is None: + module.fail_json(msg="Unable to find a user group named {pgroupname}, please create that before adding a user to it".format(pgroupname=group_name)) + + end_point = ("/PasswordVault/api/UserGroups/{pvaultid}/Members").format(pvaultid=vault_id) + + # For some reason the group add uses username instead of id + payload = {"memberId": username, "memberType": member_type} + if domain_name: + payload["domainName"] = domain_name + + url = construct_url(api_base_url, end_point) + try: + + # execute REST action + response = open_url( + url, + method="POST", + headers=headers, + data=json.dumps(payload), + validate_certs=validate_certs, + timeout=module.params['timeout'], + ) + + result = {"result": {}} + + return (True, result, response.getcode()) + + except (HTTPError, httplib.HTTPException) as http_exception: + + exception_text = to_text(http_exception) + exception_body = json.loads(http_exception.read().decode()) + if http_exception.code == 409 and ("ITATS262E" in exception_text or exception_body.get("ErrorCode", "") == "PASWS213E"): + # User is already member of Group + return (False, None, http_exception.code) + else: + module.fail_json( + msg=( + "Error while performing user_add_to_group." + "Please validate parameters provided." + "\n*** end_point=%s\n ==> %s" + % (url, exception_text) + ), + payload=payload, + headers=headers, + status_code=http_exception.code, + response=http_exception.read().decode(), + ) + + except Exception as unknown_exception: + + module.fail_json( + msg=( + "Unknown error while performing user_add_to_group." + "\n*** end_point=%s\n%s" + % (url, to_text(unknown_exception)) + ), + payload=payload, + headers=headers, + status_code=-1, + ) + + +def main(): + + module = AnsibleModule( + argument_spec=dict( + username=dict(type="str", required=True), + state=dict(type="str", default="present", choices=["absent", "present"]), + logging_level=dict( + type="str", default="NOTSET", choices=["NOTSET", "DEBUG", "INFO"] + ), + logging_file=dict(type="str", default="/tmp/ansible_cyberark.log"), + cyberark_session=dict(type="dict", required=True), + initial_password=dict(type="str", no_log=True), + new_password=dict(type="str", no_log=True), + email=dict(type="str"), + first_name=dict(type="str"), + last_name=dict(type="str"), + change_password_on_the_next_logon=dict(type="bool", default=False), + expiry_date=dict(type="str"), + user_type_name=dict(type="str"), + disabled=dict(type="bool", default=False), + location=dict(type="str"), + group_name=dict(type="str"), + vault_id=dict(type="int"), + member_type=dict(type="str"), + domain_name=dict(type="str"), + timeout=dict(type="float", default=10), + authorization=dict(type="list", elements="str", required=False, default=['AddSafes', 'AuditUsers']), + ) + ) + + if module.params["logging_level"] is not None: + logging.basicConfig( + filename=module.params["logging_file"], level=module.params["logging_level"] + ) + + logging.info("Starting Module") + + state = module.params["state"] + group_name = module.params["group_name"] + vault_id = module.params["vault_id"] + + if state == "present": + (changed, result, status_code) = user_details(module) + + if status_code == 200: + # User already exists + + (changed, result, status_code) = user_add_or_update( + module, "PUT", result["result"] + ) + + elif status_code == 404: + # User does not exist, proceed to create it + (changed, result, status_code) = user_add_or_update(module, "POST", None) + + # Add user to group if needed + if group_name is not None or vault_id is not None: + (group_change, no_result, no_status_code) = user_add_to_group(module) + changed = changed or group_change + + elif state == "absent": + (changed, result, status_code) = user_delete(module) + + module.exit_json(changed=changed, cyberark_user=result, status_code=status_code) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/cyberark/pas/roles/aimprovider/README.md b/ansible_collections/cyberark/pas/roles/aimprovider/README.md new file mode 100644 index 000000000..e39863539 --- /dev/null +++ b/ansible_collections/cyberark/pas/roles/aimprovider/README.md @@ -0,0 +1,91 @@ +cyberark.pas.aimprovider +==================== + +Role to install/uninstall CyberArk's AIM Credential Provider. + +Requirements +------------ + +- CyberArk Privileged Account Security Web Services SDK. +- `cyberark.pas` Collection from Ansible Galaxy or Automation Hub + +Role Variables +-------------- +``` +# CyberArk's Privileged Account Security Web Services SDK api base URL (example: https://components.cyberark.local) +rest_api_url: "" + +# Whether to validate certificates for REST api calls. If false, SSL certificates will not be validated. This should only be used on personally controlled sites using self-signed certificates. +validate_certs: true + +# Zip file with distribution of AIM Provider (example: /tmp/binaries/RHELinux x64-Rls-v9.8.zip); this file is located in the Ansible server, and it will be copied to the Ansible nodes. It should point to the current version of AIM distribution to be used when delivering to the nodes in a central folder within the Ansible server. +zip_file_name: "" + +# Folder name within the ZIP file that will be used. By default, it's taken from zip file name, for example: "RHELinux x64" +folder_name: '{{zip_file_name.split("/")[-1].split("-Rls")[0]}}' + +# CyberArk location for App Provider user to be created +app_provider_user_location: "\\Applications" + +# CyberArk Vault Address +vault_address: "" + +# Whether to use shared logon authentication. If true, it will use the "Shared Logon Authentication" as described in the CyberArk's document "Privileged Account Security Web Services SDK Implementation Guide" +use_shared_logon_authentication: false + +# State - can be "present"/"absent" for install/uninstall. +state: "present" +``` + + +Additionally: +- **app_provider_user_group**: The name of the group the Provider user will be added to. + +Dependencies +------------ + +None. + + +Example Playbook +---------------- + +1) Install CyberArk AIM Provider. + +``` +--- +- hosts: all + + roles: + + - role: cyberark.pas.aimprovider + api_base_url: "https://components.cyberark.local" + validate_certs: false + zip_file_name: "/tmp/binaries/RHELinux x64-Rls-v9.8.zip" + vault_address: "10.0.1.10" + use_shared_logon_authentication: true +``` + +2) Uninstall CyberArk AIM Provider. +``` +--- +- hosts: all + + roles: + + - role: cyberark.pas.aimprovider + api_base_url: "https://components.cyberark.local" + use_shared_logon_authentication: true + state: "absent" + validate_certs: false +``` + +License +------- + +MIT + +Author Information +------------------ + +- Edward Nunez (edward.nunez@cyberark.com) diff --git a/ansible_collections/cyberark/pas/roles/aimprovider/defaults/main.yml b/ansible_collections/cyberark/pas/roles/aimprovider/defaults/main.yml new file mode 100644 index 000000000..483c6afb3 --- /dev/null +++ b/ansible_collections/cyberark/pas/roles/aimprovider/defaults/main.yml @@ -0,0 +1,27 @@ +--- + +# Default values for possible input parameters + +# CyberArk's Privileged Account Security Web Services SDK api base URL +rest_api_url: "" + +# Whether to validate certificates for REST api calls +validate_certs: true + +# Zip file with distribution of AIM Provider +zip_file_name: "" + +# Folder name within the ZIP file that will be used by default is taken from zip file name. +folder_name: '{{zip_file_name.split("/")[-1].split("-Rls")[0]}}' + +# CyberArk location for App Provider user to be created +app_provider_user_location: "\\Applications" + +# CyberArk Vault Address +vault_address: "" + +# Whether to use shared logon authentication +use_shared_logon_authentication: false + +# State - the state of the provider: present mean installing the provide and Absent means uninstalling +state: "present" diff --git a/ansible_collections/cyberark/pas/roles/aimprovider/tasks/installAIMProvider.yml b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/installAIMProvider.yml new file mode 100644 index 000000000..ea2217202 --- /dev/null +++ b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/installAIMProvider.yml @@ -0,0 +1,152 @@ +--- +- name: Validating Role Parameters + assert: + that: + - zip_file_name != '' + - vault_address != '' + - api_base_url != '' + - folder_name != '' + - app_provider_user_location != '' + - state == "present" + - (not use_shared_logon_authentication|default(false) and password_object is defined) or + (use_shared_logon_authentication|default(false) and password_object is not defined) + + +- debug: msg="Installation params => zip_file_name = {{zip_file_name}} folder_name={{folder_name}}" + +- block: + + - name: Copy provider zip to target and unzip + unarchive: src="{{zip_file_name}}" dest=/tmp + + - name: Rename aimparms and copy to var/tmp + command: cp "/tmp/{{folder_name}}/aimparms.sample" /var/tmp/aimparms + + - name: Replace parameters" in /var/tmp/aimparms + replace: + dest: /var/tmp/aimparms + regexp: "{{item.regexp}}" + replace: "{{item.replace}}" + with_items: + - {regexp: '^AcceptCyberArkEULA=.*$', replace: 'AcceptCyberArkEULA=Yes'} + - {regexp: '^LicensedProducts=.*$', replace: 'LicensedProducts=AIM'} + - {regexp: '^.?CreateVaultEnvironment=.*$', replace: 'CreateVaultEnvironment=no'} + - {regexp: '^VaultFilePath=.*$', replace: 'VaultFilePath=/tmp/{{folder_name}}/Vault.ini'} + + + - name: Change Vault.ini to the right address + replace: + dest: "/tmp/{{folder_name}}/Vault.ini" + regexp: '^ADDRESS=.*$' + replace: 'ADDRESS={{vault_address}}' + + - name: Change permission on createcredfile + file: + path: "/tmp/{{folder_name}}/CreateCredFile" + mode: 0755 + + - find: + paths: "/tmp/{{folder_name}}" + patterns: "CARKaim-*.rpm" + register: aimrpm + + # debug: msg="{{aimrpm.files[0].path}}" + + - name: Install Provider + package: name='{{aimrpm.files[0].path}}' state=present + + - name: Verify status of service after installing Provider + command: service aimprv status + register: command_result + ignore_errors: true + args: + warn: false + + # debug: msg="status of service RC={{command_result.rc}}" + + - name: Logon to CyberArk Vault using PAS Web Services SDK - use_shared_logon_authentication + cyberark.pas.cyberark_authentication: + api_base_url: "{{ api_base_url }}" + use_shared_logon_authentication: true + validate_certs: "{{ validate_certs }}" + changed_when: false + when: (command_result.rc != 0 and use_shared_logon_authentication|default(false)) + + - name: Logon to CyberArk Vault using PAS Web Services SDK - Not use_shared_logon_authentication + cyberark.pas.cyberark_authentication: + api_base_url: "{{ api_base_url }}" + username: "{{ password_object.password }}" + password: "{{ password_object.passprops.username }}" + validate_certs: "{{ validate_certs }}" + changed_when: false + when: (command_result.rc != 0 and not use_shared_logon_authentication|default(false)) + + # name: Debug message + # debug: + # msg: "{{ cyberark_session.token }}" + # when: (command_result.rc != 0) + + - name: Create provider user + cyberark.pas.cyberark_user: + username: "Prov_{{ ansible_hostname }}" + initial_password: "Cyberark1" + user_type_name: "AppProvider" + location: "{{ app_provider_user_location }}" + group_name: "{{ app_provider_user_group }}" + change_password_on_the_next_logon: false + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + when: (command_result.rc != 0) + + # debug: + # msg: "USERCREATED => {{cyberarkaction}}" + # when: (command_result.rc != 0 and cyberarkaction.status_code == 201) + + - name: Reset provider user credential + cyberark.pas.cyberark_user: + username: "Prov_{{ ansible_hostname }}" + new_password: "Cyberark1" + disabled: false + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + when: (command_result.rc != 0 and cyberarkaction.status_code == 200) + + - name: Logoff from CyberArk Vault + cyberark.pas.cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + changed_when: false + when: (command_result.rc != 0) + + - name: Create Provider Initial Cred File + command: /opt/CARKaim/bin/createcredfile /etc/opt/CARKaim/vault/appprovideruser.cred Password -Username Prov_{{ ansible_hostname }} -Password Cyberark1 + when: (command_result.rc != 0) + + - name: Set vault.ini Into Place + command: cp "/tmp/{{folder_name}}/Vault.ini" /etc/opt/CARKaim/vault/vault.ini + + - name: Start Provider Service + service: name=aimprv state=started + when: (command_result.rc != 0) + + - name: Remove /tmp/{{folder_name}} + file: + path: '/tmp/{{folder_name}}' + state: absent + + - name: Remove /var/tmp/aimparms + file: + path: '/var/tmp/aimparms' + state: absent + + rescue: + + - name: Remove /tmp/{{folder_name}} + file: + path: '/tmp/{{folder_name}}' + state: absent + + - fail: + msg: "AIM Credential Provider Installation failed!" diff --git a/ansible_collections/cyberark/pas/roles/aimprovider/tasks/main.yml b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/main.yml new file mode 100644 index 000000000..9e65e1c61 --- /dev/null +++ b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Validating Role Parameters + assert: + that: + - api_base_url != '' + - state in ["present", "absent"] + - (not use_shared_logon_authentication|default(false) and password_object is defined) or + (use_shared_logon_authentication|default(false) and password_object is not defined) + +- name: Verify status of aimprv service initially + command: service aimprv status + register: service_already_running + ignore_errors: true + changed_when: false + args: + warn: false + +- debug: msg="status of service RC={{service_already_running.rc}}" + +- import_tasks: installAIMProvider.yml + when: (state == "present" and service_already_running.rc != 0) + +- import_tasks: uninstallAIMProvider.yml + when: (state == "absent" and service_already_running.rc == 0)
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/roles/aimprovider/tasks/uninstallAIMProvider.yml b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/uninstallAIMProvider.yml new file mode 100644 index 000000000..75c15f7e2 --- /dev/null +++ b/ansible_collections/cyberark/pas/roles/aimprovider/tasks/uninstallAIMProvider.yml @@ -0,0 +1,61 @@ +--- +- block: + + - name: Uninstall Provider + package: name='CARKaim' state=absent + + - name: Logon to CyberArk Vault using PAS Web Services SDK - use_shared_logon_authentication + cyberark.pas.cyberark_authentication: + api_base_url: "{{ api_base_url }}" + use_shared_logon_authentication: true + validate_certs: "{{ validate_certs }}" + when: (use_shared_logon_authentication) + + - name: Logon to CyberArk Vault using PAS Web Services SDK - Not use_shared_logon_authentication + cyberark.pas.cyberark_authentication: + api_base_url: "{{ api_base_url }}" + username: "{{ password_object.password }}" + password: "{{ password_object.passprops.username }}" + validate_certs: "{{ validate_certs }}" + changed_when: false + when: (not use_shared_logon_authentication) + + # name: Debug message + # debug: + # msg: "{{ cyberark_session }}" + # when: (cyberark_session.token is defined) + + - name: Remove Provider User + cyberark.pas.cyberark_user: + username: "Prov_{{ansible_hostname}}" + state: absent + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + ignore_errors: true + when: (cyberark_session.token is defined) + + # debug: + # msg: "USERDETAILS => {{cyberarkaction}}" + # when: (cyberarkaction.status_code == 200) + + - name: Logoff from CyberArk Vault + cyberark.pas.cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + changed_when: false + when: (cyberark_session.token is defined) + + - name: Remove /etc/opt/CARKaim + file: + path: '/etc/opt/CARKaim' + state: absent + + - name: Remove /var/opt/CARKaim + file: + path: '/var/opt/CARKaim' + state: absent + + rescue: + + - fail: + msg: "AIM Credential Provider Uninstall failed!"
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/rulebooks/cyberark_test_rule.yml b/ansible_collections/cyberark/pas/rulebooks/cyberark_test_rule.yml new file mode 100644 index 000000000..021ac4b65 --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/cyberark_test_rule.yml @@ -0,0 +1,25 @@ +- name: Demo rules with CyberArk syslog as source + hosts: localhost + sources: + - cyberark.pas.syslog: + host: 0.0.0.0 + port: 1514 + rules: + - name: Check For User Suspension Event, Then Disable The User and Notify + condition: event.cyberark.syslog.audit_record.Severity == "Error" and event.cyberark.syslog.audit_record.MessageID == "5" + action: + run_playbook: + name: disable_user.yml + extra_vars: + username: "{{ event.cyberark.syslog.audit_record.Issuer }}" + - name: Check For PTA irregular IP OR irregular Hours Access and Notify + condition: event.cyberark.DeviceEventClassID == "25" or event.cyberark.DeviceEventClassID == "23" + action: + run_playbook: + name: pta_disable_notify.yml + extra_vars: + username: "{{ event.cyberark.suser }}" + #username: "{{ event.cyberark.suser | ansible.builtin.regex_search('^[a-zA-Z0-9_]+') }}" + eventname: "{{ event.cyberark.DeviceName }}" + eventurl: "{{ event.cyberark.PTALink }}" + station: "{{ event.cyberark.shost }}" diff --git a/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_kafka.yml b/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_kafka.yml new file mode 100644 index 000000000..b25590d9b --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_kafka.yml @@ -0,0 +1,15 @@ +- name: Demo rules with kafka as source + hosts: localhost + sources: + - cyberark.eda.kafka: + topic: ansible + host: localhost + port: 9092 + rules: + - name: Check For User Suspension Event, Then Disable The User and Notify + condition: event.body.syslog.audit_record.Severity == "Error" and event.body.syslog.audit_record.MessageID == "5" + action: + run_playbook: + name: ../../../cyberark/pas/tests/disable_user.yml + extra_vars: + username: "{{ event.body.syslog.audit_record.Issuer }}" diff --git a/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_webhook.yml b/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_webhook.yml new file mode 100644 index 000000000..a39e1bc7c --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/disable_pas_user_webhook.yml @@ -0,0 +1,16 @@ +--- +- name: Demo rules with webhook as source + hosts: all + sources: + - cyberark.eda.webhook: + host: 0.0.0.0 + port: 5000 + + rules: + - name: Listen For User Suspension Event Webhook, Then Disble The User + condition: event.payload.syslog.audit_record.Severity == "Error" and event.payload.syslog.audit_record.MessageID == "5" + action: + run_playbook: + name: ../../../cyberark/pas/tests/disable_user.yml + extra_vars: + username: "{{ event.payload.syslog.audit_record.Issuer }}" diff --git a/ansible_collections/cyberark/pas/rulebooks/disable_user.yml b/ansible_collections/cyberark/pas/rulebooks/disable_user.yml new file mode 100644 index 000000000..9b86ca8bb --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/disable_user.yml @@ -0,0 +1,42 @@ +--- +- hosts: all + connection: local + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "https://BASE_URL" + validate_certs: false + username: "USERNAME" + password: "PASSWORD" + + - name: Disabling a CyberArk User + cyberark_user: + username: "{{ username }}" #this is password from the running yml when condition is met + disabled: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Sending an e-mail using Gmail SMTP servers + community.general.mail: + host: SMTPSERVER + port: PORT + username: username@mail.com + password: password + to: First Last <first.last@mail.com> + subject: Ansible-Rulebook Report + body: Ansible Rulebook disabled Cyberark user '{{ username }}' due to too many login attempts. + delegate_to: localhost diff --git a/ansible_collections/cyberark/pas/rulebooks/inventory.yml b/ansible_collections/cyberark/pas/rulebooks/inventory.yml new file mode 100644 index 000000000..bbf327095 --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/inventory.yml @@ -0,0 +1,5 @@ +--- +ungrouped: + hosts: + localhost: + ansible_host: 127.0.0.1 diff --git a/ansible_collections/cyberark/pas/rulebooks/pta_disable_notify.yml b/ansible_collections/cyberark/pas/rulebooks/pta_disable_notify.yml new file mode 100644 index 000000000..5f216a43b --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/pta_disable_notify.yml @@ -0,0 +1,42 @@ +--- +- hosts: all + connection: local + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "https://BASE_URL" + validate_certs: false + username: "USERNAME" + password: "PASSWORD" + + - name: Disabling a CyberArk User + cyberark_user: + username: "{{ username | regex_search('.+?(?=\\()') }}" #more optimal handle user case like suser=testuserFirst.testuserLast@acme.com(Vault user) match up to ( char + disabled: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Sending an e-mail using Gmail SMTP servers + community.general.mail: + host: SMTPSERVER + port: PORT + username: username@mail.com + password: password + to: First Last <first.last@mail.com> + subject: Ansible-Rulebook Report + body: Ansible Rulebook notify of PTA Event {{ username }} - {{ eventname }} - from host {{ station }} - For more info please visit - {{ eventurl }} - user disabled! + delegate_to: localhost diff --git a/ansible_collections/cyberark/pas/rulebooks/pta_notify.yml b/ansible_collections/cyberark/pas/rulebooks/pta_notify.yml new file mode 100644 index 000000000..94ed251d2 --- /dev/null +++ b/ansible_collections/cyberark/pas/rulebooks/pta_notify.yml @@ -0,0 +1,19 @@ +--- +- hosts: all + connection: local + + collections: + - cyberark.pas + + tasks: + + - name: Sending an e-mail using Gmail SMTP servers + community.general.mail: + host: SMTPSERVER + port: PORT + username: username@mail.com + password: password + to: First Last <first.last@mail.com> + subject: Ansible-Rulebook Report + body: Ansible Rulebook notify of PTA Event '{{ username | ansible.builtin.regex_search('^[a-zA-Z0-9_]+') }}' '{{ eventname }}' from host '{{ station }}' For more info please visit - '{{ eventurl }}' + delegate_to: localhost diff --git a/ansible_collections/cyberark/pas/tests/change_test.yml b/ansible_collections/cyberark/pas/tests/change_test.yml new file mode 100644 index 000000000..8fc9e4abf --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/change_test.yml @@ -0,0 +1,37 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Rotate credential via reconcile and providing the password to be changed to + cyberark_account: + identified_by: "address,username" + safe: "Test" + address: "prod.cyberark.local" + username: "admin" + platform_id: WinDomain + platform_account_properties: + ReconcileAccount: "Operating System-WinServerLocal-cyberark.local-administrator-x" + LogonDomain: "PROD" + secret_management: +# new_secret: "Ama123ah12@#!Xaamdjbdkl@#112" +# management_action: "reconcile" + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: reconcileaccount + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}"
\ No newline at end of file diff --git a/ansible_collections/cyberark/pas/tests/changepolicy.yml b/ansible_collections/cyberark/pas/tests/changepolicy.yml new file mode 100644 index 000000000..7ec9045f4 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/changepolicy.yml @@ -0,0 +1,41 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + + - name: Debug message + debug: + var: cyberark_session + + - name: Account + cyberark_account: + identified_by: "address,username" + safe: "Test" + address: "cyberark.local" + username: "cyberark-administrator" + platform_id: WinDomain-Level2 + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Debug message + debug: var=cyberark_session diff --git a/ansible_collections/cyberark/pas/tests/deprovision_account.yml b/ansible_collections/cyberark/pas/tests/deprovision_account.yml new file mode 100644 index 000000000..6e5bb50d3 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/deprovision_account.yml @@ -0,0 +1,42 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + + - name: Debug message + debug: + var: cyberark_session + + - name: Account + cyberark_account: + logging_level: DEBUG + identified_by: "address,username" + safe: "Test" + address: "cyberark.local" + username: "cyberark-administrator" + state: absent + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Debug message + debug: var=cyberark_session diff --git a/ansible_collections/cyberark/pas/tests/deprovision_user.yml b/ansible_collections/cyberark/pas/tests/deprovision_user.yml new file mode 100644 index 000000000..76e76cba4 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/deprovision_user.yml @@ -0,0 +1,39 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + + - name: Debug message + debug: + var: cyberark_session + + - name: Removing a CyberArk User + cyberark_user: + username: "ansibleuser" + state: absent + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Debug message + debug: var=cyberark_session diff --git a/ansible_collections/cyberark/pas/tests/disable_user.yml b/ansible_collections/cyberark/pas/tests/disable_user.yml new file mode 100644 index 000000000..cad8d3018 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/disable_user.yml @@ -0,0 +1,31 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Disabling a CyberArk User + cyberark_user: + username: "ansibleuser" + disabled: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" diff --git a/ansible_collections/cyberark/pas/tests/enable_user.yml b/ansible_collections/cyberark/pas/tests/enable_user.yml new file mode 100644 index 000000000..5b6c5a273 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/enable_user.yml @@ -0,0 +1,32 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Enabling a CyberArk User and forcing a password change at next logon + cyberark_user: + username: "ansibleuser" + disabled: false + state: present + change_password_on_the_next_logon: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" diff --git a/ansible_collections/cyberark/pas/tests/provision_account.yml b/ansible_collections/cyberark/pas/tests/provision_account.yml new file mode 100644 index 000000000..753ae228b --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/provision_account.yml @@ -0,0 +1,41 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Account + cyberark_account: + identified_by: "address,username" + safe: "Test" + address: "cyberark.local" + username: "cyberark-administrator" + platform_id: WinDomain-Level2 + secret: "CyberarkFirst" + platform_account_properties: + LogonDomain: "RedHatAnsible" + OwnerName: "James Stutes" + Port: 8080 + secret_management: + automatic_management_enabled: true + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" diff --git a/ansible_collections/cyberark/pas/tests/provision_user.yml b/ansible_collections/cyberark/pas/tests/provision_user.yml new file mode 100644 index 000000000..e7bbbb790 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/provision_user.yml @@ -0,0 +1,37 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Creating a CyberArk User, setting a simple password but forcing a password change at next logon + cyberark_user: + username: "ansibleuser" + first_name: "Ansible" + last_name: "User" + email: "ansibleuser@demo.com" + initial_password: "Cyberark1" + user_type_name: "EPVUser" + group_name: "AnsibleAdmins" + disabled: false + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" diff --git a/ansible_collections/cyberark/pas/tests/reset_user_password.yml b/ansible_collections/cyberark/pas/tests/reset_user_password.yml new file mode 100644 index 000000000..d25a04cdc --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/reset_user_password.yml @@ -0,0 +1,33 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + - name: Enabling a CyberArk User and forcing a password change at next logon + cyberark_user: + username: "ansibleuser" + disabled: false + new_password: Cyberark1 + state: present + change_password_on_the_next_logon: true + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" diff --git a/ansible_collections/cyberark/pas/tests/test.yml b/ansible_collections/cyberark/pas/tests/test.yml new file mode 100644 index 000000000..7c0834434 --- /dev/null +++ b/ansible_collections/cyberark/pas/tests/test.yml @@ -0,0 +1,65 @@ +--- +- hosts: localhost + + collections: + - cyberark.pas + + tasks: + + - name: Logon to CyberArk Vault using PAS Web Services SDK + cyberark_authentication: + api_base_url: "http://components.cyberark.local" + validate_certs: false + username: "bizdev" + password: "Cyberark1" + + + - name: Debug message + debug: + var: cyberark_session + + - name: User + cyberark_user: + username: "testuser" + initial_password: "Cyberark1" + user_type_name: "EPVUser" + change_password_on_the_next_logon: false + group_name: "Auditors" + disabled: false + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Account + cyberark_account: +# logging_level: DEBUG + identified_by: "address,username" + name: "EDWARD_ACCOUNT" + safe: "Test" + address: "10.0.1.20" + username: "james_test" + platform_id: WinServerLocal + platform_account_properties: + LogonDomain: "10.0.1.20" + secret_management: + automatic_management_enabled: false + manual_management_reason: "No Reason" + state: present + cyberark_session: "{{ cyberark_session }}" + register: cyberarkaction + + - name: Debug message + debug: + var: cyberarkaction + + - name: Logoff from CyberArk Vault + cyberark_authentication: + state: absent + cyberark_session: "{{ cyberark_session }}" + + - name: Debug message + debug: var=cyberark_session |