Ansible is an IT automation engine for cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
Ansible provides a faster and efficient way to automate the processes for the identification, triage, and response to security events.
In the following we will cover a simple yet effective use case: to report authentication anomaly and forbid access by temporarily suspending user's account on our Identity Management System (IdM), Apache Syncope.
In this post we're going to show how to automate the suspension of a Syncope user through an Ansible Collection.
ansible 2.9+
python 3.6+
An istance of Apache Syncope 2.1+ up and running for testing
At first we initialize the collection and create the skeleton directory structure of our project launching this command, prefererably in a folder named ansible_collections
:
$ ansible-galaxy collection init tirasa.SyncopeAnsible
Next, in the plugins folder of our collection, we have to provide a python script that will implement the actual integration with Syncope.
We've used an object-oriented approach, so at the beginning of the script we define our class and its constructor. Here we specify arguments for the Ansible module:
class SyncopeUserHandler(object):
def __init__(self):
self.argument_spec = dict(
action=dict(type='str', choices=['change status'], required=True),
adminUser=dict(type='str', required=True),
adminPwd=dict(type='str', required=True),
serverName=dict(type='str', required=True),
syncopeUser=dict(type='str', required=True),
newStatus=dict(type='str', choices=['SUSPEND', 'ACTIVATE', 'REACTIVATE'], required=True),
changeStatusOnSyncope=dict(type='str', required=True)
)
self.module = AnsibleModule(
argument_spec=self.argument_spec
)
Then we provide the core method of our plugin, that simply sends a POST request to Syncope' REST endpoint for updating user status:
def change_user_status_rest_call(self):
url = self.module.params['serverName'] + "/syncope/rest/users/" + self.module.params['syncopeUser'] + "/status"
headers = {'Accept': 'application/json',
'Content-Type': 'application/json',
'Prefer': 'return-content',
'X-Syncope-Domain': 'Master'
}
payload = {
"operation": "ADD_REPLACE",
"value": "org.apache.syncope.common.lib.types.StatusPatchType",
"onSyncope": self.module.params['changeStatusOnSyncope'],
"key": self.module.params['syncopeUser'],
"type": self.module.params['newStatus']
}
admin = self.module.params['adminUser']
password = self.module.params['adminPwd']
result = dict(
changed=False,
message=''
)
try:
resp = requests.post(url, headers=headers, auth=(admin, password), data=json.dumps(payload))
resp_json = resp.json()
if resp_json is None or resp is None or resp.status_code != 200:
self.module.fail_json(msg="Error while changing status")
except Exception as e:
res = json.load(e)
self.module.fail_json(msg=res)
result['message'] = resp_json
result['changed'] = True
self.module.exit_json(**result)
def main():
change_status = SyncopeUserHandler()
change_status.change_user_status_rest_call()
if __name__ == '__main__':
main()
We are finally ready to write the playbook to perform the update of user status:
- name: run syncope_user_handler module
syncope_user_handler:
action: "change status"
adminUser: {admin}
adminPwd: {password}
serverName: {server}
syncopeUser: {userId}
changeStatusOnSyncope: "true"
newStatus: "SUSPEND" # REACTIVATE, ACTIVATE, SUSPEND
register: results
- name: syncope_user_handler result message
debug:
msg: '{{ results }}'
If we have an Apache Syncope instance available we can easily test this playbook: first, we fill with proper values the needed arguments, then we can launch the playbook with:
$ ansible-playbook -M . ./playbook.yml
The code above is part of our Open Source Ansible Collection.