VMware’s SDDC has a great feature whereby it can manage credentials for all the applications and appliances within its scope, such as vCenter, NSX-T, WSA, vRealize suite etc. The best part of this management is the periodic rotation feature which keeps security bods happy and systems secure.
If you are familiar the SDDC manager, you have inevitably used the lookup_passwords function to extract the latest password for a particular appliance or application. It’s clunky and requires you to SSH onto the SDDC manager, which in itself can be a pain.
In our system we run Hashicorp Vault for secrets management, so the logical next step was to extract the credentials from SDDC manager and pass them into Vault so all secrets are accessible centrally.
The following script works very neatly and creates a logical secrets structure within Vault, based upon the various variables and constructs passed out by the SDDC manager.
We now set this script to run periodically to maintain parity between the SDDC manager and Vault.
Hopefully this helps or inspires someone who is bored of running lookup_passwords !!
import json import os import requests from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) debug = 0 # Grab relevant output environment variables from the gitlab-ci scripts. access_token = os.environ['SDDC_TOKEN'] vault_pass = os.environ['VAULT_ROTATE_PWD'] sddc_base_url = os.environ['SDDC_MANAGER'] vault_base_url = os.environ['VAULT_SERVER_URL'] vault_role = os.environ['VAULT_AUTH_ROLE'] vault_namespace = os.environ['VAULT_NAMESPACE'] # Print generic varibales print("Starting script with the following variables. Role: " + vault_role + " | Namespace: " + vault_namespace) if debug == 1: print("Using Vault Token: " + vault_pass) print("Base URLs:") print(sddc_base_url) print(vault_base_url) # Set Vault headers vault_session = requests.Session() vault_session.headers.update({ "X-Vault-Namespace" : vault_namespace }) #optional if using namespaces within Vault vault_session.headers.update({ "Content-Type" : "application/json" }) vault_session.headers.update({ "Accept" : "application/json" }) # Obtain Vault Login Token vault_login_url = vault_base_url + "/v1/auth/ldap/login/<service_account_name>" data = { "password": vault_pass} vault_json = json.dumps(data) response = vault_session.post(vault_login_url,data = vault_json, verify = False, proxies = None) if response.status_code == 200: json_response = json.loads(response.content) vault_token = json_response['auth']['client_token'] else: raise NameError("Failed to obtain Vault token") # Grab all the credentials from SDDC Manager credentials_url = sddc_base_url + '/v1/credentials' # Set Headers session = requests.Session() basic_auth_header = "Bearer " + access_token session.headers.update({"authorization" : basic_auth_header}) session.headers.update({"accept" : "application/json"}) session.headers.update({"content-type" : "application/json"}) # Execute call and parse JSON response = session.get(credentials_url,verify = False, proxies = None) if response.status_code == 200: credentials_json = json.loads(response.content) print("Credential dump obtained from SDDC Manager") # Create Vault headers vault_session = requests.Session() vault_session.headers.update({ "X-Vault-Token" : vault_token }) vault_session.headers.update({ "X-Vault-Namespace" : vault_namespace }) vault_session.headers.update({ "Content-Type" : "application/json" }) vault_session.headers.update({ "Accept" : "application/json" }) # Iterate through all records and extract relevant vars. for credential in credentials_json['elements']: domain_name = credential['resource']['domainName'].lower() resource_type = credential['resource']['resourceType'].lower() resource_name = credential['resource']['resourceName'].lower() credential_type = credential['credentialType'].lower() account_type = credential['accountType'].lower() username = credential['username'].lower() modification_time = credential['modificationTimestamp'] # Some SDDC credentials don't have password records so skip them... if 'password' in credential: password = credential['password'] # Create Vault path and push record path = '/v1/data/sddc/' + domain_name + '/' + resource_type + '/' + resource_name + '/' + credential_type + '/' + account_type + '/' + username vault_url = vault_base_url + path data = { "options": { "max_versions": "12" }, "data": { "password": password , "last_modified" : modification_time }} json_data = json.dumps(data) response = vault_session.post(vault_url, data = json_data,verify = False, proxies = None) print("Attempting to upload record to Vault: " + vault_url) print(response.text) if response.status_code == 200: print("Successful Upload") else: raise NameError("Failed Upload") else: raise NameError("Failed to obtain credentials from SDDC manager")