-
Notifications
You must be signed in to change notification settings - Fork 76
Open
Description
Background
We have a project of modernizing our docker image builds and are building them inside kubernetes pods. We leverage AWS IAM roles for service accounts (IRSA).
Some our images use apt-transport-s3 to source debian packages from our s3 buckets.
Using IRSA our pods do not have access to IMDSv2 or directly have access to aws creds. During our docker image builds we don't want to pass creds directly to the build as that could lead to secrets leaking into the image layers.
Proposal
I would like to contribute an additional way of gathering aws creds from the environment variables AWS_ROLE_ARN
and AWS_WEB_IDENTITY_TOKEN_FILE
.
High level sample code. I've not yet tested this code and will edit accordingly after I get a working POC.
import json
import urllib.request
import urllib.parse
import datetime
# Set your environment variables or manually configure
ROLE_ARN = 'arn:aws:iam::123456789012:role/YourRole'
WEB_IDENTITY_TOKEN_FILE = '/path/to/your/web-identity-token' # Path to your web identity token file
REGION = 'us-west-2'
SERVICE = 'sts'
HOST = f'{SERVICE}.{REGION}.amazonaws.com'
# Load the web identity token from the specified file
with open(WEB_IDENTITY_TOKEN_FILE, 'r') as f:
web_identity_token = f.read().strip()
# Set up parameters for the assume-role-with-web-identity request
params = {
'Action': 'AssumeRoleWithWebIdentity',
'RoleArn': ROLE_ARN,
'RoleSessionName': 'YourSessionName',
'WebIdentityToken': web_identity_token,
'Version': '2011-06-15', # Specify the API version
}
# Set up the datetime for signature
now = datetime.datetime.utcnow()
timestamp = now.strftime('%Y%m%dT%H%M%SZ')
date = now.strftime('%Y%m%d')
# Create the canonical request
canonical_querystring = urllib.parse.urlencode(sorted(params.items()))
canonical_headers = f'host:{HOST}\nx-amz-date:{timestamp}\n'
signed_headers = 'host;x-amz-date'
payload_hash = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' # Empty body, hashed
canonical_request = f'GET\n/\n{canonical_querystring}\n{canonical_headers}\n{signed_headers}\n{payload_hash}'
# Create the string to sign
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = f'{date}/{REGION}/{SERVICE}/aws4_request'
string_to_sign = f'{algorithm}\n{timestamp}\n{credential_scope}\n{hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()}'
# Create the signing key
def sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def get_signature_key(secret_key, date_stamp, region_name, service_name):
k_date = sign(('AWS4' + secret_key).encode('utf-8'), date_stamp)
k_region = sign(k_date, region_name)
k_service = sign(k_region, service_name)
k_signing = sign(k_service, 'aws4_request')
return k_signing
# Normally you'd sign using your AWS secret key, but since you don't need it, skip it for Web Identity Token
# Prepare headers
headers = {
'x-amz-date': timestamp,
'Authorization': '', # No need to sign this request as the web identity token is the signature
}
# Construct the URL
url = f'https://{HOST}/?{canonical_querystring}'
# Send the HTTP request to AWS STS
request = urllib.request.Request(url, headers=headers)
# Make the HTTP request and parse the response
try:
with urllib.request.urlopen(request) as response:
response_data = response.read()
credentials = json.loads(response_data)
# Output the temporary credentials
print("Temporary Credentials:", json.dumps(credentials, indent=4))
except urllib.error.HTTPError as e:
print(f"Error: {e.code}, {e.read().decode('utf-8')}")
Metadata
Metadata
Assignees
Labels
No labels