Skip to content

Instantly share code, notes, and snippets.

@kalihman
Last active November 2, 2023 05:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • 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
@charltonstanley
Copy link

@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.

@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