Last active
May 15, 2023 16:18
-
-
Save infamousjoeg/1123f44682737e2bd8239ccb1129d8a1 to your computer and use it in GitHub Desktop.
PowerShell AWS STS Signed Headers w/ Conjur's authn-iam
This file contains 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
# Please note that this script uses a C# helper class for HMAC-SHA256 calculations. | |
# This is because PowerShell does not natively support this kind of operations. | |
# Also, this script assumes that you are calling Get-SignedHeaders with the proper | |
# parameters to generate your signed headers. | |
# Create a C# class for HMACSHA256 Helper which is used to compute HMACSHA256 hash | |
Add-Type -TypeDefinition @" | |
using System; | |
using System.Text; | |
using System.Security.Cryptography; | |
public class HMACSHA256Helper | |
{ | |
// Compute HMACSHA256 hash and return the hash as a lowercase string | |
public static string ComputeHash(string key, string data) | |
{ | |
var secretKeyBytes = Encoding.UTF8.GetBytes(key); | |
using (var hmac = new HMACSHA256(secretKeyBytes)) | |
{ | |
var dataBytes = Encoding.UTF8.GetBytes(data); | |
var hashBytes = hmac.ComputeHash(dataBytes); | |
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower(); | |
} | |
} | |
// Compute HMACSHA256 hash and return the hash as a byte array | |
public static byte[] ComputeHashBytes(string key, string data) | |
{ | |
var secretKeyBytes = Encoding.UTF8.GetBytes(key); | |
using (var hmac = new HMACSHA256(secretKeyBytes)) | |
{ | |
var dataBytes = Encoding.UTF8.GetBytes(data); | |
return hmac.ComputeHash(dataBytes); | |
} | |
} | |
} | |
"@ -Language CSharpVersion3 | |
# Function to compute the signature key | |
function Get-SignatureKey { | |
param( | |
$key, # Secret key for signing | |
$dateStamp, # Date stamp | |
$regionName, # AWS region name | |
$serviceName # AWS service name | |
) | |
# Compute hashes for the date, region and service | |
$kDate = [HMACSHA256Helper]::ComputeHashBytes("AWS4$key", $dateStamp) | |
$kRegion = [HMACSHA256Helper]::ComputeHashBytes([System.Text.Encoding]::UTF8.GetString($kDate), $regionName) | |
$kService = [HMACSHA256Helper]::ComputeHashBytes([System.Text.Encoding]::UTF8.GetString($kRegion), $serviceName) | |
# Compute the final signing key | |
$kSigning = [HMACSHA256Helper]::ComputeHashBytes([System.Text.Encoding]::UTF8.GetString($kService), 'aws4_request') | |
return $kSigning | |
} | |
# Function to get signed headers | |
function Get-SignedHeaders { | |
param( | |
$access_key, # AWS access key | |
$secret_key, # AWS secret key | |
$session_token, # AWS session token | |
$region # AWS region | |
) | |
# Define the AWS host and request parameters | |
$aws_host = 'sts.amazonaws.com' | |
$request_parameters = 'Action=GetCallerIdentity&Version=2011-06-15' | |
$service = 'sts' | |
$method = 'GET' | |
# Get current date and time in the specific format | |
$t = Get-Date -Format "yyyyMMddTHHmmssZ" | |
$amzdate = $t | |
$datestamp = $t.Substring(0,8) | |
# Create canonical URI, query string, headers and signed headers | |
$canonical_uri = '/' | |
$canonical_querystring = $request_parameters | |
$canonical_headers = 'host:' + $aws_host + "`n" + 'x-amz-date:' + $amzdate + "`n" + 'x-amz-security-token:' + $session_token + "`n" | |
$signed_headers = 'host;x-amz-date;x-amz-security-token' | |
# Compute payload hash | |
$payload_hash = [HMACSHA256Helper]::ComputeHash("", "") | |
# Create canonical request | |
$canonical_request = $method + "`n" + $canonical_uri + "`n" + $canonical_querystring + "`n" + $canonical_headers + "`n" + $signed_headers + "`n" + $payload_hash | |
# Define the algorithm to be used | |
$algorithm = 'AWS4-HMAC-SHA256' | |
# Create the credential scope string | |
$credential_scope = $datestamp + '/' + $region + '/' + $service + '/' + 'aws4_request' | |
# Create the string to sign using the previously defined elements | |
$string_to_sign = $algorithm + "`n" + $amzdate + "`n" + $credential_scope + "`n" + [HMACSHA256Helper]::ComputeHash("", $canonical_request) | |
# Call the Get-SignatureKey function to get the signing key | |
$signing_key = Get-SignatureKey $secret_key $datestamp $region $service | |
# Compute the signature by signing the string_to_sign using the signing_key | |
$signature = [HMACSHA256Helper]::ComputeHash([System.Text.Encoding]::UTF8.GetString($signing_key), $string_to_sign) | |
# Create the authorization header | |
$authorization_header = $algorithm + ' ' + 'Credential=' + $access_key + '/' + $credential_scope + ', ' + 'SignedHeaders=' + $signed_headers + ', ' + 'Signature=' + $signature | |
# Create a hashtable for headers | |
$headers = @{ | |
'host' = $aws_host | |
'x-amz-date' = $amzdate | |
'x-amz-security-token' = $session_token | |
'Authorization' = $authorization_header | |
} | |
# Return the headers in JSON format | |
return $headers | ConvertTo-Json -Compress | |
} |
This file contains 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
. "$PSScriptRoot\Get-SignedHeaders.ps1" | |
# Make a request to the IMDS to get the role name | |
$roleName = Invoke-RestMethod -Uri http://169.254.169.254/latest/meta-data/iam/security-credentials | |
# Make a second request to get the security credentials for the role | |
$credentials = Invoke-RestMethod -Uri http://169.254.169.254/latest/meta-data/iam/security-credentials/$roleName | |
# Extract the access key, secret key, and session token from the response | |
$access_key = $credentials.AccessKeyId | |
$secret_key = $credentials.SecretAccessKey | |
$session_token = $credentials.Token | |
# Conjur is hard-coded to always validate AWS signed headers against sts.amazonaws.com (us-east-1) | |
$region = "us-east-1" | |
# You can now use these values with the Get-SignedHeaders function | |
$headers = Get-SignedHeaders -access_key $access_key -secret_key $secret_key -session_token $session_token -region $region | |
Write-Host $headers | |
$conjurApplianceURL = "https://conjur.joegarcia.dev" | |
$conjurServiceID = "prod" | |
$conjurAccount = "cyberarkdemo" | |
$conjurHostID = "host%2Fcloud%2Faws%2Fec2%2F735280068473%2FConjurAWSRoleEC2" | |
$conjurAuthnURL = "${conjurApplianceURL}/api/authn-iam/${conjurServiceID}/${conjurAccount}/${conjurHostID}/authenticate" | |
$accessToken = Invoke-RestMethod -Uri $conjurAuthnURL -Method "POST" -Body $headers | |
write-host "" | |
write-host "Results..." | |
write-host $accessToken | |
write-host "...end." | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment