@@ -0,0 +1,3114 @@
+# Example Python script for automated API token rotation in combination %0A# with a HashiCorp vault server%0A%0Aimport requests%0A%0A# CONFIGURATION%0A# configure list of all secrets we want to rotate%0ASECRETS = %5B 'dynatrace/automation_script1', 'dynatrace/automation_script2' %5D %0A# HashiCorp vault information%0AVAULT = 'http://YOUR_VAULT_SERVER_ADDRESS:8200/v1/secret/data/'%0AX_VAULT_TOKEN = 'YOUR_VAULT_ACCESS_KEY'%0A# Dynatrace master token must have 'token management' permission assigned %0ADT_MASTER_TOKEN = 'dynatrace/master'%0A# Your Dynatrace environment URL%0ADT_URL = 'https://YOURENVIRONMENT.live.dynatrace.com'%0A# END CONFIGURATION%0A%0Adef vault_receive_secret(secret_path, vault, token):%0A    resp = requests.get(url=vault + '' + secret_path, headers=%7B'x-vault-token' : X_VAULT_TOKEN%7D)%0A    if resp.status_code == 200:%0A        return True, resp.json()%5B'data'%5D%5B'data'%5D%5B'token'%5D %0A    return False, %7B%7D%0A%0Adef dt_receive_token_info(token, dt_url, dt_api_token):%0A    resp = requests.post(url=dt_url + '/api/v1/tokens/lookup/', json=%7B'token' : token%7D, headers=%7B'Authorization' : 'Api-Token ' + dt_api_token%7D)%0A    if resp.status_code == 200:%0A        return True, resp.json() %0A    return False, %7B%7D%0A%0A# fetch master token '/dynatrace/master' from vault%0Am_ret = requests.get(url=VAULT + '' + DT_MASTER_TOKEN, headers=%7B'x-vault-token' : X_VAULT_TOKEN%7D)%0Aif m_ret.status_code != 200:%0A    print('There was no master token found within your vault under path /dynatrace/master')%0A    exit()%0Aelse:%0A    DT_MASTER_TOKEN = m_ret.json()%5B'data'%5D%5B'data'%5D%5B'token'%5D%0A%0Afor secret in SECRETS:%0A    print('%3ERotate: ' + secret)%0A    # fetch old secret from vault%0A    success, old_sec = vault_receive_secret(secret, VAULT, X_VAULT_TOKEN)%0A    if success:%0A        # receive secret metainfos from Dynatrace%0A        success, t_info = dt_receive_token_info(old_sec, DT_URL, DT_MASTER_TOKEN)%0A        if success:%0A            # create new secret with same scope as old%0A            resp = requests.post(url=DT_URL + '/api/v1/tokens', json=t_info, headers=%7B'Authorization' : 'Api-Token ' + DT_MASTER_TOKEN%7D)%0A            if resp.status_code == 201:%0A                new_token = resp.json()%5B'token'%5D %0A                # store new token in secret vault%0A                c_ret = requests.post(url=VAULT + secret, json=%7B 'data' : %7B 'token': new_token%7D%7D, headers=%7B'x-vault-token' : X_VAULT_TOKEN%7D)%0A                if c_ret.status_code == 200:%0A                    # if creation was successful delete old Dynatrace token through Dynatrace API%0A                    d_resp = requests.delete(url=DT_URL + '/api/v1/tokens/' + t_info%5B'id'%5D, headers=%7B'Authorization' : 'Api-Token ' + DT_MASTER_TOKEN%7D)%0A                    if d_resp.status_code == 204:%0A                        print('  Old Dynatrace token successfully deleted')%0A                        print('  Token rotation successful')%0A                    else:%0A                        print('  Failed to delete old Dynatrace token')%0A            else:%0A                print('Failed to rotate secret: ' + secret)%0A        else:%0A            print('  Api token not found in Dynatrace')%0A    else:%0A        print('  Secret not found in vault')%0A    %0A

Create rotate.py