Re: S3 endpoint
Thanks for your feedback!
Btw, why do you need to change the hostname?
Btw, why do you need to change the hostname?
# To get the full iam-role access_key and secret_key the below powershell code works:
# Step 1: Get IMDSv2 token
$token = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/api/token" -Method PUT -Headers @{ "X-aws-ec2-metadata-token-ttl-seconds" = "21600" }).Content
# Step 2: Get IAM role name
$roleName = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/iam/security-credentials/" -Headers @{ "X-aws-ec2-metadata-token" = $token }).Content
# Step 3: Get temporary credentials
$credentials = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/iam/security-credentials/$roleName" -Headers @{ "X-aws-ec2-metadata-token" = $token }).Content | ConvertFrom-Json
# Output
$credentials.AccessKeyId
$credentials.SecretAccessKey
$credentials.Token
$credentials.Expiration
aws
seems to be doing.
object MetadataVersionGroup: TGroupBox
Caption = 'AWS Metadata Service Version'
TabOrder = ... // Adjust based on existing layout
object IMDSv1Radio: TRadioButton
Caption = 'IMDSv1'
Checked = True
OnClick = MetadataVersionChange
end
object IMDSv2Radio: TRadioButton
Caption = 'IMDSv2'
OnClick = MetadataVersionChange
end
end
TLoginDialog
class.
private:
TRadioButton *IMDSv1Radio;
TRadioButton *IMDSv2Radio;
TGroupBox *MetadataVersionGroup;
enum TMetadataVersion { mv1, mv2 };
TMetadataVersion FMetadataVersion;
void __fastcall MetadataVersionChange(TObject *Sender);
__fastcall TLoginDialog::TLoginDialog(TComponent* AOwner)
: TForm(AOwner)
{
// Existing code
FMetadataVersion = mv1; // Default to IMDSv1
}
void __fastcall TLoginDialog::MetadataVersionChange(TObject *Sender)
{
FMetadataVersion = IMDSv1Radio->Checked ? mv1 : mv2;
}
UnicodeString GetEC2InstanceMetadata()
{
UnicodeString Token;
if (FMetadataVersion == mv2)
{
THTTPClient *Client = new THTTPClient();
TStringStream *Response = new TStringStream();
try
{
Client->Request->Method = L"PUT";
Client->Request->CustomHeaders->AddValue(L"X-aws-ec2-metadata-token-ttl-seconds", L"21600");
Client->Put(L"http://169.254.169.254/latest/api/token", Response);
Token = Response->DataString.Trim();
}
__finally
{
delete Response;
delete Client;
}
}
THTTPClient *Client = new THTTPClient();
try
{
if (FMetadataVersion == mv2)
{
Client->Request->CustomHeaders->AddValue(L"X-aws-ec2-metadata-token", Token);
}
// Proceed with existing metadata requests (e.g., /latest/meta-data/...)
TStringStream *Response = new TStringStream();
Client->Get(L"http://169.254.169.254/latest/meta-data/...", Response);
return Response->DataString;
}
__finally
{
delete Client;
}
}
What changes need to be made to the winscp source code to add support for IMDSv2?
The source code is at: https://github.com/winscp/winscp/tree/master/source/forms
The source code files of interest are:
source/forms/Login.cpp
source/forms/Login.dfm
source/forms/Login.h
object MetadataVersionGroup: TGroupBox
Caption = 'AWS Metadata Service Version'
object IMDSv1Radio: TRadioButton
Caption = 'IMDSv1'
Checked = True
OnClick = MetadataVersionChange
end
object IMDSv2Radio: TRadioButton
Caption = 'IMDSv2'
OnClick = MetadataVersionChange
end
end
private:
TRadioButton *IMDSv1Radio;
TRadioButton *IMDSv2Radio;
void __fastcall MetadataVersionChange(TObject *Sender);
enum TMetadataVersion { mv1, mv2 };
TMetadataVersion FMetadataVersion;
FMetadataVersion = mv1;
void __fastcall TLoginDialog::MetadataVersionChange(TObject *Sender)
{
if (IMDSv1Radio->Checked)
FMetadataVersion = mv1;
else
FMetadataVersion = mv2;
}
UnicodeString token;
if (FMetadataVersion == mv2) {
// Make PUT request to get token
THTTPClient client;
client.Request->Method = "PUT";
client.Request->CustomHeaders->Add("X-aws-ec2-metadata-token-ttl-seconds: 21600");
UnicodeString tokenUrl = "http://169.254.169.254/latest/api/token";
TStringStream *response = new TStringStream;
try {
client.Put(tokenUrl, response);
token = response->DataString.Trim();
}
__finally {
delete response;
}
}
// Now, for each metadata request, include the token if using v2
THTTPClient client;
if (FMetadataVersion == mv2) {
client.Request->CustomHeaders->Add(UnicodeString().sprintf(L"X-aws-ec2-metadata-token: %s", token));
}
// Then proceed with GET requests as before
With IMDSv2, every request is now protected by session authentication. A session begins and ends a series of requests that software running on an EC2 instance uses to access the locally-stored EC2 instance metadata and credentials. The software starts a session with a simple HTTP PUT request to IMDSv2. IMDSv2 returns a secret token to the software running on the EC2 instance, which will use the token as a password to make requests to IMDSv2 for metadata and credentials. Unlike traditional passwords, you don’t need to worry about getting the token to the software, because the software gets it for itself with the PUT request. The token is never stored by IMDSv2 and can never be retrieved by subsequent calls, so a session and its token are effectively destroyed when the process using the token terminates. There’s no limit on the number of requests within a single session, and there’s no limit on the number of IMDSv2 sessions. Sessions can last up to six hours and, for added security, a session token can only be used directly from the EC2 instance where that session began.
curl http://169.254.169.254/
Invoke-RestMethod -uri http://169.254.169.254/
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/
[string]$token = Invoke-RestMethod -Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} -Method PUT -Uri http://169.254.169.254/latest/api/token
# the below command will show the last 4 characters of the access_key and secret_key for the iam-role. It also includes profile (if set), and AWS region.
aws configure list
# To get the full iam-role access_key and secret_key the below powershell code works:
# Step 1: Get IMDSv2 token
$token = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/api/token" -Method PUT -Headers @{ "X-aws-ec2-metadata-token-ttl-seconds" = "21600" }).Content
# Step 2: Get IAM role name
$roleName = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/iam/security-credentials/" -Headers @{ "X-aws-ec2-metadata-token" = $token }).Content
# Step 3: Get temporary credentials
$credentials = (Invoke-WebRequest -Uri "http://169.254.169.254/latest/meta-data/iam/security-credentials/$roleName" -Headers @{ "X-aws-ec2-metadata-token" = $token }).Content | ConvertFrom-Json
# Output
$credentials
# In which $credentials will contain like below (creds redacted of course)
$credentials | gm
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
AccessKeyId NoteProperty string AccessKeyId=*****
ToString Method string ToString()
Code NoteProperty string Code=Success
Expiration NoteProperty string Expiration=2025-01-23T00:30:21Z
LastUpdated NoteProperty string LastUpdated=2025-01-22T18:19:59Z
SecretAccessKey NoteProperty string SecretAccessKey=*****
Token NoteProperty string Token=*****
Type NoteProperty string Type=AWS-HMAC
# I haven't tested below, but it looks like it may work in powershell by setting $credentials to the below environmental variables. Also could set a profile, etc.
$env:AWS_ACCESS_KEY_ID = $credentials.AccessKeyId
$env:AWS_SECRET_ACCESS_KEY = $credentials.SecretAccessKey
$env:AWS_SESSION_TOKEN = $credentials.Token
# Verify
aws sts get-caller-identity