Thycotic Secret Server Integration with AppViewX
The Thycotic Secret Server password management software uses security controls to proactively protect enterprise infrastructure and networks. The enterprise-grade Privileged Account Management (PAM) solution is available both on premise and in the cloud and can provide password security for all types of privileged accounts quickly and easily.
Key Features:
· Scalable and resilient architecture for an enterprise password management solution
· Cloud-based capabilities for password changing, discovery, Active Directory integration, and more
· Built-in security and high availability
· Passwords are tied with secret names, allowing users to generate complex passwords directly in Thycotic Different servers or hostnames can be configured to a specific secret name
What’s a Secret?
Secrets are individually-named sets of sensitive information created from Secret templates. Secret security can be centrally managed through Sharing settings for each individual Secret. All Secret field information is securely encrypted before being stored in the database, with a detailed audit trail for access and history.
What is Heartbeat?
A Heartbeat allows properly configured Secrets to have entered credentials automatically tested for accuracy at any given interval. Using a Heartbeat on Secrets will ensure that credentials stored in the Secret Server are up-to-date and can alert administrators if these credentials are changed outside of the Secret Server. A Heartbeat helps manage Secrets and prevents them from being out of sync. Email alerts are triggered when a Heartbeat fails for any Secret that a specific user has View access to.
Automate Thycotic Secret Server Password Management with AppViewX
· In the Thycotic Secret system, everything is Secret ID[IC1] . AppViewX fetches the Secret ID based on the Secret name (Thycotic Rest APIs are available for this function). AppViewX maintains a separate configuration for all Secret names that are being automated.
· AppViewX can get complete Secret details, such as username, current password, and host or servers which a particular Secret refers to by using the Secret ID.
· AppViewX VW creates a new random password from the Thycotic server using Thycotic Rest API.
· AppViewX then logs into all hosts or servers and changes the password to the new password, which is generated from the Thycotic engine.
· AppViewX updates the new password with the Secret name or Secret ID.
AppViewX Process Flow
Key Features of Thycotic Password Management with AppViewX:
· By using AppViewX VW, security teams can schedule this utility to run on a regular basis — monthly, weekly, daily, or even hourly
· The only input that needs to be configured are the Secret names
· This utility can be used for any type of server (e.g. Linux, Windows, etc.)
· New passwords that are under 20 characters are generated by the Thycotic server Passwords above 20 characters are generated using the same algorithm as Thycotic
· Different servers are configured in the Thycotic server and tied to a different Secret name
· Multiple devices can be added to a single Secret name (Devices can be added in the ‘note’ field of the Secret name
· Passwords for these devices can be changed in a scheduled manner — on a monthly or weekly basis
This approach offers two different safety mechanisms:
Naturally, changing the passwords of different users, including the root user, can bear certain risks. Here’s what AppViewX can do to mitigate these risks:
· If anything goes wrong during password change, AppViewX can revert the change back using the Revert Back Mechanism
· AppViewX stores both the old and new passwords with a timestamp in a secure location (DB or a specific file path)
Below is a Thycotic Python Utility used by AppViewX for this Integration:
Packages used:
1. requests_ntlm: For making winauth webservices to the Thycotic Sever
2. multiprocessing: In the event where there are several servers associated with a single Secret, the user needs to log into all devices at the same time
3. paramiko : For connecting the destination device through an SSH protocol
import requests
import sys
import json
from requests_ntlm import HttpNtlmAuth
import multiprocessing
from multiprocessing import Pool
import paramiko
import traceback
import time
from functools import partial
class ThycoticUtility():
def __init__(self, thycotic_server_username, thycotic_server_password, thycotic_server_base_url):
self.username = thycotic_server_username
self.password = thycotic_server_password
self.secret_server_uri = "https://"+thycotic_server_base_url+"/SecretServer/winauthwebservices/api/v1/"
def retrieve_secret_details(self, secret_id):
"""
Function retreive the password username and hostname details based on secret ID from
arg1: secret_id(String) -> Secret ID for the secret name
return: secret_details_dict(Dictionary) -> Which contains the username, passwords and what are the
hostnames are associated
"""
secret_details_dict = {}
try:
secret = requests.get(self.secret_server_uri+"secrets/"+str(secret_id)+"",
auth=HttpNtlmAuth(self.username, self.password), verify=False)
json_request = secret.json()
json_request = json_request['items']
for att in json_request:
if att['slug'] == "password":
secret_details_dict['password'] = att['itemValue']
if att['slug'] == "username":
secret_details_dict['username'] = att['itemValue']
if att['slug'] == "notes":
secret_details_dict['hostname'] = att['itemValue'].split(',')
except:
error = sys.exc_info()
AVX::LOG(error)
return secret_details_dict
def generate_random_password(self):
"""
Function to generate random password, It gives a random password from Thycotic server
return: secret_password(String) -> Random password generated by the Thycotic server
"""
try:
api = self.secret_server_uri + "secret-templates/generate-password/2"
secret_password = requests.post(
api, auth=HttpNtlmAuth(self.username, self.password), verify=False)
return secret_password.json()
except:
error = sys.exc_info()
AVX::LOG(error)
return None
def retrieve_secret_id(self, secret_name):
"""
Function to get the Secret ID based on Secret Name.
arg1: secret_name(String) -> Secret name which is mentioned Thycotic Server.
return: secret_id(String) -> Secret ID configured in Thycotic server for the corresponding Secret Name.
"""
try:
secrets = requests.get(self.secret_server_uri+"secrets?filter.searchText="+secret_name+"",
auth=HttpNtlmAuth(self.username, self.password), verify=False)
json_request = secrets.json()
secret_name_found = json_request['records'][0]['name']
if(secret_name_found.lower() == secret_name.lower()):
secret_id = json_request['records'][0]['id']
return secret_id
else:
return None
except:
error = sys.exc_info()
raise Exception(error)
def update_password(self, secret_id, new_password):
"""
Function to update the new password for the secrets in thycotic
Server based on the secret ID
arg1: secret_id(String) -> Secret ID for the secret name which we need to update the password
arg2: new_password(String) -> New
retrun: True if the updation is suucessfull False if not
"""
secret = requests.get(self.secret_server_uri+"secrets/"+str(secret_id)+"",
auth=HttpNtlmAuth(self.username, self.password), verify=False)
payload_data = secret.json()
for att in payload_data['items']:
if 'isPassword' in att and att['isPassword']:
att['itemValue'] = new_password
header = {'Content-Type':'application/json'}
update_response = requests.put(self.secret_server_uri+"secrets/"+str(secret_id)+"",
auth=HttpNtlmAuth(self.username, self.password),headers=header, data =json.dumps(payload_data),verify=False)
if update_response.reason == 'OK' and update_response.status_code == 200:
AVX::LOG('Password updation for Secret ID: '+str(secret_id)+ ' Successfully Completed.')
return True
else:
AVX::LOG('Password updation for Secret ID: '+str(secret_id)+ ' Failed with reason:'+str(update_response.reason))return False
Please find the below code snippet for getting the device connection logic and changing password mechanism
def change_password_operation(device, username, password, new_password):
"""
Function to execute rndc sync clean command across all the GTM device
arg1: device(String)-> device hostname
arg2: username(String) -> Username of the account which trying to update the password
arg3: password(String) -> Current password for the user.
arg4: new_password(String) -> New password for the user.
return: status_dict(dictionary) -> Key-> device, value -> Status(Failed/Success).
"""
status_dict = {}
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.load_host_keys(os.path.expanduser(os.path.join("~", ".ssh", "known_hosts")))
try:
ssh.connect(hostname=device, port=22, username=username, password=password)
except:
status_dict.update({device:'Failed'})
ssh.close()
return status_dict
channel = ssh.invoke_shell()
channel.send('passwd')
channel.send('\n')
time.sleep(2)
channel.send(str(password))
channel.send('\n')
time.sleep(2)
channel.send(str(new_password))
channel.send('\n')
time.sleep(2)
channel.send(str(new_password))
channel.send('\n')
time.sleep(2)
output = channel.recv(10000).decode('utf-8')
if 'all authentication tokens updated successfully.' in output:
status_dict.update({device:'Success'})
ssh.close()
return status_dict
else:
status_dict.update({device:'Failed'})
ssh.close()return status_dict