Last active
January 14, 2025 09:01
-
-
Save Exchizz/505583c3e7a54b20f3e41d5f868a9272 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import requests | |
| import json | |
| import boto3 | |
| from bs4 import BeautifulSoup | |
| from pprint import pprint | |
| from datetime import datetime | |
| # This code signs-in to Cost Explorer so that Reports can be created programmatically | |
| # (At the moment of writing, this is not supported via officiel API) | |
| # For some reasy, creating/updating reports requires different credentials than boto3-credentials obtains. Trying to create # a report fails with "status: 400". | |
| # To create a report, you need to set header '"x-amz-target": "AWSInsightsIndexService.CreateReport"', sign the request (fx. # using SigV4Auth from botocore.aut) and POST whatever you'd like the report to consist of. | |
| # For inspiration, see the first comment in this gist. | |
| class AWSAPI: | |
| def __init__(self): | |
| self._rsession = requests.Session() | |
| def getSignInTokenFromCredentials(self, credentials): | |
| signInToken = json.loads(self._rsession.get( | |
| "https://signin.aws.amazon.com/federation", | |
| params={ | |
| "Action": "getSigninToken", | |
| "Session": json.dumps({ | |
| "sessionId": credentials.access_key, | |
| "sessionKey": credentials.secret_key, | |
| "sessionToken": credentials.token | |
| }) | |
| } | |
| ).text)["SigninToken"] | |
| return signInToken | |
| def loginToAws(self, signInToken): | |
| print("Exchanging credentials for SignInToken") | |
| login_rsp = self._rsession.get( | |
| "https://signin.aws.amazon.com/federation", | |
| params={ | |
| "Action": "login", | |
| "Issuer": None, | |
| "Destination": "https://us-east-1.console.aws.amazon.com/costmanagement", | |
| "SigninToken": signInToken | |
| } | |
| ) | |
| if login_rsp.status_code != 200: | |
| raise Exception("Failed to login to AWS") | |
| else: | |
| return True | |
| def getCSRFToken(self): | |
| print("Getting CSRF Token and cookies from SignInToken") | |
| cm_rsp = self._rsession.get("https://us-east-1.console.aws.amazon.com/costmanagement", params={"hashArgs": "","oauthStart": int(datetime.now().timestamp())}) | |
| _csrf_token = None | |
| for m in BeautifulSoup(cm_rsp.text, "html.parser").find_all("meta"): | |
| if m.get("name") == "tb-data": | |
| _csrf_token = json.loads(m["content"])["csrfToken"] | |
| return _csrf_token | |
| def getCostExplorerCredentials(self, csrf_token): | |
| print("Getting Cost Explorer credentials from CSRF Token and cookies") | |
| rsp = self._rsession.post("https://us-east-1.console.aws.amazon.com/costmanagement/tb/creds", headers={"X-CSRF-Token": csrf_token}) | |
| key = rsp.json() | |
| return key | |
| if __name__ == "__main__": | |
| boto_session = boto3.Session(region_name='us-east-1') | |
| credentials = boto_session.get_credentials() | |
| awsapi = AWSAPI() | |
| signInToken = awsapi.getSignInTokenFromCredentials(credentials) | |
| awsapi.loginToAws(signInToken) | |
| csrf_token = awsapi.getCSRFToken() | |
| credentials = awsapi.getCostExplorerCredentials(csrf_token) | |
| print() | |
| print("export AWS_ACCESS_KEY_ID='" + credentials["accessKeyId"] + "'") | |
| print("export AWS_SECRET_ACCESS_KEY='" + credentials["secretAccessKey"] + "'") | |
| print("export AWS_SESSION_TOKEN='" + credentials["sessionToken"] + "'") | |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To create a cost explorer report, see example here: