Skip to content

Instantly share code, notes, and snippets.

@mtippett
Created April 12, 2025 00:18
Show Gist options
  • Save mtippett/dea33e80c6980e2c46978933b909c583 to your computer and use it in GitHub Desktop.
Save mtippett/dea33e80c6980e2c46978933b909c583 to your computer and use it in GitHub Desktop.
Sample code for generating a presigned URL for getCallerIdentity
import botocore.session
from botocore.awsrequest import AWSRequest
from botocore.auth import SigV4Auth
import urllib.parse
def generate_presigned_sts_url(region_name="us-east-1"):
"""
Generate a pre-signed URL for STS GetCallerIdentity in the given region.
Returns the fully signed URL as a string.
"""
# Create a new botocore session and get credentials.
session = botocore.session.get_session()
credentials = session.get_credentials().get_frozen_credentials()
# The STS endpoint for the given region. STS is a global service, but
# you can specify a region anyway (e.g. "us-east-1").
sts_endpoint = f"https://sts.{region_name}.amazonaws.com"
# The STS request parameters for GetCallerIdentity
query_params = {
"Action": "GetCallerIdentity",
"Version": "2011-06-15"
}
# Construct the AWSRequest
request = AWSRequest(
method="GET",
url=sts_endpoint,
params=query_params
)
# Sign the request using Signature Version 4
signer = SigV4Auth(credentials, "sts", region_name)
signer.add_auth(request)
# request.url now contains the fully signed URL with query parameters (including Signature).
presigned_url = request.url
return presigned_url
if __name__ == "__main__":
# Generate the pre-signed URL
url = generate_presigned_sts_url(region_name="us-east-1")
print("Pre-signed STS URL:", url)
Calling the pre-signed URL from the server
import requests
import xml.etree.ElementTree as ET
def verify_caller_identity(presigned_url):
"""
Given a pre-signed STS GetCallerIdentity URL, call STS and parse
the returned identity details.
"""
response = requests.get(presigned_url)
if response.status_code != 200:
raise Exception(f"Error calling STS: {response.status_code} - {response.text}")
# The response is XML. For example:
# <GetCallerIdentityResponse>
# <GetCallerIdentityResult>
# <Arn>arn:aws:sts::123456789012:assumed-role/...</Arn>
# <UserId>...</UserId>
# <Account>123456789012</Account>
# </GetCallerIdentityResult>
# ...
# </GetCallerIdentityResponse>
root = ET.fromstring(response.text)
# We can navigate to GetCallerIdentityResult
namespace = {"sts": "https://sts.amazonaws.com/doc/2011-06-15/"} # Not strictly required to define in this minimal example if you parse by tag name directly.
# Parse out the relevant fields
arn = root.find(".//Arn")
account = root.find(".//Account")
user_id = root.find(".//UserId")
# Return them for further use
return {
"Arn": arn.text if arn is not None else None,
"Account": account.text if account is not None else None,
"UserId": user_id.text if user_id is not None else None
}
if __name__ == "__main__":
# Typically, you'd receive the URL from the client
# For demonstration, paste the pre-signed URL here:
presigned_sts_url = "<REPLACE_WITH_PRESIGNED_STS_URL_FROM_CLIENT>"
identity = verify_caller_identity(presigned_sts_url)
print("Retrieved identity from STS:", identity)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment