Skip to content

Instantly share code, notes, and snippets.

@kalihman
Last active November 2, 2023 05:15
Show Gist options
  • Save kalihman/eb8c8148b4aa2312343383eac3651f23 to your computer and use it in GitHub Desktop.
Save kalihman/eb8c8148b4aa2312343383eac3651f23 to your computer and use it in GitHub Desktop.
Powershell AWS4 Signer for STS GetCallerIdentity Action
# Define Helper Functions
function Get-Sha256Hash ($StringToHash) {
$hasher = [System.Security.Cryptography.SHA256]::Create()
$Hash = ([BitConverter]::ToString($hasher.ComputeHash([Text.Encoding]::UTF8.GetBytes($StringToHash))) -replace '-','').ToLower()
Write-Output $Hash
}
function ConvertTo-SortedDictionary($HashTable) {
$SortedDictionary = New-Object 'System.Collections.Generic.SortedDictionary[string, string]'
foreach ($Key in $HashTable.Keys) {
$SortedDictionary[$Key]=$HashTable[$Key]
}
Write-Output $SortedDictionary
}
function Sign($Key, $Message) {
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.Key = $Key
$hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($Message))
}
function Get-SignatureKey($Key, $Date, $Region, $Service) {
$SignedDate = Sign ([Text.Encoding]::UTF8.GetBytes(('AWS4' + $Key).toCharArray())) $Date
$SignedRegion = Sign $SignedDate $Region
$SignedService = Sign $SignedRegion $Service
Sign $SignedService "aws4_request"
}
# Define Credentials
$Credentials = Invoke-RestMethod http://169.254.169.254/latest/meta-data/iam/security-credentials/BroservEc2InstanceRole
$AccessKey = $Credentials.AccessKeyId
$SecretAccessKey = $Credentials.SecretAccessKey
$Token = $Credentials.Token
# Define Keywords
$Action = 'Action=GetCallerIdentity&Version=2011-06-15'
$EndpointUrl = "sts.amazonaws.com"
$HTTPRequestMethod = "POST"
$CanonicalURI = "/"
$CanonicalQueryString = ""
$DateTime = [DateTime]::UtcNow.ToString("yyyyMMdd'T'HHmmss'Z'")
$DateString = [DateTime]::UtcNow.ToString('yyyyMMdd')
$RequestPayloadHash = Get-Sha256Hash($Action)
$Region = "us-east-1"
$Service = "sts"
$Headers = @{}
$ContentType = "application/x-www-form-urlencoded"
# 1. Create a Canonical Request for Signature Version 4
if (!$Headers["Host"]) { $Headers["Host"] = $EndpointUrl }
if (!$Headers["X-Amz-Date"]) { $Headers["X-Amz-Date"] = $DateTime }
if (!$Headers["Content-Type"] -and $ContentType) { $Headers["Content-Type"] = $ContentType }
if (!$Headers["X-Amz-Security-Token"]) { $Headers["X-Amz-Security-Token"] = $Token }
if (!$Headers["X-Amz-Content-Sha256"]) { $Headers["X-Amz-Content-Sha256"] = $RequestPayloadHash }
$SortedHeaders = ConvertTo-SortedDictionary $Headers
$CanonicalHeaders = (($SortedHeaders.GetEnumerator() | ForEach-Object { "$($($_.Key).ToLower()):$($_.Value)" }) -join "`n") + "`n"
$SignedHeaders = ($SortedHeaders.Keys -join ";").ToLower()
$CanonicalRequest = "$HTTPRequestMethod`n$CanonicalURI`n$CanonicalQueryString`n$CanonicalHeaders`n$SignedHeaders`n$RequestPayloadHash"
$hasher = [System.Security.Cryptography.SHA256]::Create()
$CanonicalRequestHash = ([BitConverter]::ToString($hasher.ComputeHash([Text.Encoding]::UTF8.GetBytes($CanonicalRequest))) -replace '-','').ToLower()
# 2. Create a String to Sign for Signature Version 4
$AlgorithmDesignation = "AWS4-HMAC-SHA256"
$CredentialScope = "$DateString/$Region/$Service/aws4_request"
$StringToSign = "$AlgorithmDesignation`n$DateTime`n$CredentialScope`n$CanonicalRequestHash"
# 3. Calculate the Signature for AWS Signature Version 4
$SigningKey = Get-SignatureKey $SecretAccessKey $DateString $Region $Service
$Signature = ([BitConverter]::ToString((sign $SigningKey $StringToSign)) -replace '-','').ToLower()
# 4. Add the Signing Information to the Request
$Headers["Authorization"]="AWS4-HMAC-SHA256 Credential=$AccessKey/$DateString/$Region/$Service/aws4_request, SignedHeaders=$SignedHeaders, Signature=$Signature"
$Protocol = "https://"
$Url = $Protocol + $EndpointUrl + $CanonicalURI
# 5.Optional): Test Request by Sending to Service
# $Res = Invoke-RestMethod -Method 'POST' -Uri $Url -Headers $Headers -Body $Action
# Write-Output $res.OuterXml
@kalihman
Copy link
Author

kalihman commented Nov 2, 2023

@kalihman Thanks for posting this code! The company I work for iterated off of what you posted here to create a Powershell module for this so that we could more easily maintain it internally. Since this was open sourced to begin with, we are throwing around the idea of open sourcing our version as well. If we decide to to that, would you be opposed to this? We would of course give you credit for the original work and would provide a link back to this page.

Hi @charltonstanley ! I'm glad to hear that my small contribution long time ago was meaningful to you 😄. Thank you for let me know and I do appreciate you want to contribute to open source too. I'm more than happy that you want to refer my code and credit me for your contribution. Looking forward to see your module being open sourced!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment