如何生成AWS的会话令牌

huangapple go评论65阅读模式
英文:

How to generate the session token for AWS

问题

根据您在此帖子的已接受答案下面的评论:

https://stackoverflow.com/questions/41305553/error-message-when-calling-api-gateway-with-signature

我无法弄清楚如何在C#中获取会话令牌。

我已经按照这个教程进行了操作 - https://docs.aws.amazon.com/pinpoint/latest/developerguide/tutorials-using-postman-configuration.html
在Postman中它运行得很完美。但是SO问题上的已接受答案由于身份验证而失败。

不知何故,Postman为我生成了会话令牌供我使用。我无法在文档和SO已接受答案中找到它是如何完成的。

如果有人能向我展示如何通过C#获取令牌并成功调用API,我将不胜感激。

提前感谢。

英文:

As per my comment under the Accepted Answer on this post:

https://stackoverflow.com/questions/41305553/error-message-when-calling-api-gateway-with-signature

I cannot figure out how to get the Session Token to use in C#.

I've gone through this tutorial - https://docs.aws.amazon.com/pinpoint/latest/developerguide/tutorials-using-postman-configuration.html
And it works perfectly in Postman. But the accepted answer on the SO Question fails due to authentication.

Somehow Postman is generating the session token for me to use. And I can't see how it's done in both the documentation and in the SO Accepted Answer.

Is someone could show me how to get the token via C# and do a successful call to the API, that would be greatly appreciated.

Thanks in advance

答案1

得分: 1

好的,我懂了。以下是翻译的部分:

Ok,我明白了。我能够使用 PostMan 生成的 RestSharp 代码片段使其正常工作,但我需要传递 Signature,这在 @VonC 提供的代码中已完成:

private string CreateSignature(string stringToSign, string dateStamp)
{
    byte[] kDate = HmacSha256(dateStamp, Encoding.UTF8.GetBytes("AWS4" + secretKey));
    byte[] kRegion = HmacSha256(region, kDate);
    byte[] kService = HmacSha256("execute-api", kRegion);
    byte[] kSigning = HmacSha256("aws4_request", kService);

    return BitConverter.ToString(new HMACSHA256(kSigning).ComputeHash(Encoding.UTF8.GetBytes(stringToSign))).Replace("-", "").ToLower();
}

将所有内容组合在一起就可以了:

var options = new RestClientOptions("https://email.us-east-1.amazonaws.com")
{
    MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("/v1/email/identities/someone@awebsite.com", Method.Get);

var date = DateTime.UtcNow;
var dateTimeStamp = date.ToString("yyyyMMddTHHmmssZ");
request.AddHeader("X-Amz-Date", dateTimeStamp);

request.AddHeader("Authorization", "AWS4-HMAC-SHA256 Credential=putyourcredentialhere/20230527/us-east-1/mobiletargeting/aws4_request, SignedHeaders=host;x-amz-date, Signature=" + signatureFromVonC);
RestResponse response = await client.ExecuteAsync(request);
Debug.WriteLine(response.Content);
英文:

Ok, I got it working. I was able to use the RestSharp code snippet that PostMan generates, but I needed to pass in the Signature which was done in the code provided by @VonC:

    private string CreateSignature(string stringToSign, string dateStamp)
    {
        byte[] kDate = HmacSha256(dateStamp, Encoding.UTF8.GetBytes("AWS4" + secretKey));
        byte[] kRegion = HmacSha256(region, kDate);
        byte[] kService = HmacSha256("execute-api", kRegion);
        byte[] kSigning = HmacSha256("aws4_request", kService);

        return BitConverter.ToString(new HMACSHA256(kSigning).ComputeHash(Encoding.UTF8.GetBytes(stringToSign))).Replace("-", "").ToLower();
    }

Put it all together and it works:

var options = new RestClientOptions("https://email.us-east-1.amazonaws.com")
{
    MaxTimeout = -1,
};
var client = new RestClient(options);
var request = new RestRequest("/v1/email/identities/someone@awebsite.com", Method.Get);

var date = DateTime.UtcNow;
var dateTimeStamp = date.ToString("yyyyMMddTHHmmssZ");
request.AddHeader("X-Amz-Date", dateTimeStamp);

request.AddHeader("Authorization", "AWS4-HMAC-SHA256 Credential=putyourcredentialhere/20230527/us-east-1/mobiletargeting/aws4_request, SignedHeaders=host;x-amz-date, Signature=" + signatureFromVonC);
RestResponse response = await client.ExecuteAsync(request);

Debug.WriteLine(response.Content);

答案2

得分: 0

以下是翻译好的部分:

这个过程通过Postman集合进行解释时不使用会话令牌。在消耗这些端点时,它会使用Access和Secret密钥对请求进行签名。

这个应该能帮助您通过HTTP API消耗AWS服务。

NuGet: Aws4RequestSigner

如果您不想使用第三方库,您可以根据这个参考文档定义自己的实现。

英文:

The process explained through the Postman collections does not use a session token. It signs the request with the Access and Secret keys when consuming the endpoints.

This library should assist you in consuming the AWS services through HTTP APIs.

NuGet: Aws4RequestSigner

In case you do not want to use a 3rd party library, you can define your own implementation with this reference documentation.

答案3

得分: 0

为了使用 Pinpoint APIs 进行身份验证,您需要传递包含您在 Postman 中设置的 accesssKeyregionserviceName 变量的 Authorization 标头。如果您检查您导入的 Postman 集合并导航到“Headers”,您可以单击以显示隐藏的标头 - 在那里,您可以找到实际传递给请求的 HTTP 标头,因此您可以在您的 C# 实现中模拟它。
在 C# 中如何实现这一点?有各种方法。您只需创建带有 Authorization 标头的 HTTP 客户端,并传递与您在 Postman 中看到的相同值即可。

英文:

In order to authenticate your request with Pinpoint APIs you need to pass Authorization header which contains accesssKey, region, and serviceName variables you have set in Postman. If you inspect the Postman collections you have imported and navigate to "Headers" you can click to reveal hidden headers - there you can find which HTTP headers you actually pass with your request, so you can mimic that with your C# implementation.
How to do this in C#? Various ways. You simply need to create HTTP Client with Authorization header and pass the same value you see in Postman

答案4

得分: 0

以下是代码部分,不需要翻译:

using Amazon;
using Amazon.Runtime;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using System;
using System.Net.Http;
using System.Threading.Tasks;

public class AWSSignatureExample
{
    private const string AccessKey = "Your AWS Access Key";
    private const string SecretKey = "Your AWS Secret Key";
    private const string Region = "us-west-2"; // Or your preferred region

    public async Task CallAWSService()
    {
        // Step 1: Get temporary security credentials from STS
        var creds = new BasicAWSCredentials(AccessKey, SecretKey);
        var stsClient = new AmazonSecurityTokenServiceClient(creds, RegionEndpoint.GetBySystemName(Region));
        var getSessionTokenRequest = new GetSessionTokenRequest
        {
            DurationSeconds = 3600 // 1 hour
        };
        var sessionTokenResponse = await stsClient.GetSessionTokenAsync(getSessionTokenRequest);
        var temporaryCredentials = sessionTokenResponse.Credentials;

        // Steps 2-4: Create a canonical request, create a string to sign, and calculate the signature
        var signer = new AWS4Signer();
        signer.Initialize(temporaryCredentials.AccessKeyId, temporaryCredentials.SecretAccessKey, Region);
        var request = new HttpRequestMessage(HttpMethod.Get, "https://my-service-url"); // Replace with your service URL
        signer.Sign(request, temporaryCredentials.SessionToken);

        // Step 5: Send the request
        var httpClient = new HttpClient();
        var response = await httpClient.SendAsync(request);
    }
}

public class AWS4Signer
{
    public void Initialize(string accessKey, string secretKey, string region)
    {
        // Initialize your signer with the access key, secret key, and region
    }

    public void Sign(HttpRequestMessage request, string sessionToken)
    {
        // Sign the request here using the AWS Signature Version 4 process
        // You would generate the canonical request, create the string to sign, calculate the signature,
        // and then add the 'Authorization' and 'X-Amz-Security-Token' headers to the request
    }
}

在实际使用时,请将"Your AWS Access Key"和"Your AWS Secret Key"替换为您的实际AWS访问密钥和密钥,将"https://my-service-url"替换为您要调用的AWS服务的URL。

英文:

When you consider Signing AWS API requests, the process becomes much more elaborate: AWS uses temporary security credentials, consisting of an access key ID, a secret access key, and a security token, to enable applications to send authenticated requests on your behalf without sharing your long-term AWS security credentials. A session token is part of these temporary security credentials.

Session tokens are issued by the AWS Security Token Service (STS).
AWS STS is a web service that enables you to request temporary, limited-privilege credentials for AWS Identity and Access Management (IAM) users or for users that you authenticate (federated users).

When you make a call to AWS STS to assume a role or a federated user, AWS STS returns the temporary security credentials, which consist of the access key, secret key, and session token. These temporary security credentials are then used to sign the AWS API requests.

For instance, if you want to use temporary security credentials to sign an AWS API request:

  1. You or your application calls the AssumeRole (for IAM users) or GetFederationToken (for federated users) operation of AWS STS. You include an IAM role ARN or federated user credentials in the API call.

  2. AWS STS verifies the role or user credentials and returns temporary security credentials, which include an access key ID, a secret access key, and a session token.

  3. You use these temporary security credentials (access key ID, secret access key, and session token) to sign subsequent AWS API requests.

  4. AWS verifies the signature on the incoming request. If the signature is valid, and the session token is valid and has not expired, AWS allows the API call.

  5. The API call is processed, and the result is returned to you or your application.

The AWS SDKs handle these steps automatically. When you use an AWS SDK to make requests, you specify the temporary security credentials (access key ID, secret access key, and session token), and the SDK uses them to sign the requests for you.

In the context of AWS Signature Version 4, the session token is included in the X-Amz-Security-Token header of the HTTP request. Note that the session token itself is not included in the signature calculation.

  • When you are making a call to AWS STS to get a session token, you do not need to include the X-Amz-Security-Token parameter because you do not have a session token yet.
  • When you have a session token (obtained from AWS STS) and are using it to sign requests to other AWS services, you include the session token value in the X-Amz-Security-Token header as part of the HTTP request. This allows AWS to verify the temporary security credentials that you are using to make the request.

While using temporary security credentials is optional, in your case AWS session tokens are generated by making a request to the AWS Security Token Service (STS). This is typically done when you want to use temporary security credentials instead of the long-term credentials associated with an IAM user.

The steps to create a canonical request, create a string to sign, and calculate the signature are part of the process of signing the request to AWS services. These steps are generally performed after obtaining the temporary security credentials (including the session token) from AWS STS. Here is a general sequence of the steps:

  1. Call AWS STS to get temporary security credentials. This will give you an access key ID, a secret access key, and a session token.
  2. Use the access key ID and secret access key from the previous step to create a canonical request for the AWS service API operation you want to call.
  3. Create a string to sign based on the canonical request.
  4. Calculate the signature using the string to sign and your secret access key.
  5. Include the calculated signature and session token in the headers of your HTTP request when you call the AWS service API operation.

This sequence ensures that your request to the AWS service is both authenticated (proves who you are) and authorized (proves you have permission to perform the requested operation).

  1. Create a Canonical Request: This includes all the information that you want to send in your request, including the HTTP method, the URL path, the query string parameters, the headers, and the payload (or body) of the request. This information is represented in a specific format defined by AWS.

  2. Create a String to Sign: This includes the hashed canonical request along with additional metadata, such as the algorithm you are using for signing (AWS4-HMAC-SHA256), the date and time of the request, and the service and region you are making the request to.

  3. Calculate the Signature: This involves using your AWS secret access key to create a signing key, and then using that signing key to create a signature from the string to sign. The signature proves that the request is authentic and has not been tampered with.

After generating the signature, you include it in the Authorization header of your HTTP request, along with other necessary information such as your AWS access key ID and the headers that you included in the canonical request. If you are using temporary security credentials, you also include the session token in the X-Amz-Security-Token header.

As a rough example:

using Amazon;
using Amazon.Runtime;
using Amazon.SecurityToken;
using Amazon.SecurityToken.Model;
using System;
using System.Net.Http;
using System.Threading.Tasks;

public class AWSSignatureExample
{
    private const string AccessKey = "Your AWS Access Key";
    private const string SecretKey = "Your AWS Secret Key";
    private const string Region = "us-west-2"; // Or your preferred region

    public async Task CallAWSService()
    {
        // Step 1: Get temporary security credentials from STS
        var creds = new BasicAWSCredentials(AccessKey, SecretKey);
        var stsClient = new AmazonSecurityTokenServiceClient(creds, RegionEndpoint.GetBySystemName(Region));
        var getSessionTokenRequest = new GetSessionTokenRequest
        {
            DurationSeconds = 3600 // 1 hour
        };
        var sessionTokenResponse = await stsClient.GetSessionTokenAsync(getSessionTokenRequest);
        var temporaryCredentials = sessionTokenResponse.Credentials;

        // Steps 2-4: Create a canonical request, create a string to sign, and calculate the signature
        var signer = new AWS4Signer();
        signer.Initialize(temporaryCredentials.AccessKeyId, temporaryCredentials.SecretAccessKey, Region);
        var request = new HttpRequestMessage(HttpMethod.Get, "https://my-service-url"); // Replace with your service URL
        signer.Sign(request, temporaryCredentials.SessionToken);

        // Step 5: Send the request
        var httpClient = new HttpClient();
        var response = await httpClient.SendAsync(request);
    }
}

public class AWS4Signer
{
    public void Initialize(string accessKey, string secretKey, string region)
    {
        // Initialize your signer with the access key, secret key, and region
    }

    public void Sign(HttpRequestMessage request, string sessionToken)
    {
        // Sign the request here using the AWS Signature Version 4 process
        // You would generate the canonical request, create the string to sign, calculate the signature,
        // and then add the 'Authorization' and 'X-Amz-Security-Token' headers to the request
    }
}

This example uses the AWS SDK for .NET (C#) and assumes that you have implemented the AWS Signature Version 4 process in the AWS4Signer class.

Also, this example uses your AWS root user access key and secret key to call AWS STS. In a production scenario, you should avoid using root user credentials. Instead, use the credentials of an IAM user that has the necessary permissions, or use AWS Identity and Access Management (IAM) roles if you are running your application on Amazon EC2, AWS Lambda, or other AWS service.

Do replace "Your AWS Access Key" and "Your AWS Secret Key" with your actual AWS access key and secret key, and replace "https://my-service-url" with the URL of the AWS service you want to call.

An example of AWS Signature Version 4 process implementation in the AWS4Signer class would be:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;

public class AWS4Signer
{
    private const string Algorithm = "AWS4-HMAC-SHA256";
    private string accessKey;
    private string secretKey;
    private string region;

    public void Initialize(string accessKey, string secretKey, string region)
    {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
        this.region = region;
    }

    public void Sign(HttpRequestMessage request, string sessionToken)
    {
        var date = DateTime.UtcNow;
        var dateStamp = date.ToString("yyyyMMdd");
        var dateTimeStamp = date.ToString("yyyyMMddTHHmmssZ");

        request.Headers.Add("x-amz-date", dateTimeStamp);
        request.Headers.Add("x-amz-security-token", sessionToken);

        string canonicalUri = request.RequestUri.AbsolutePath;
        string canonicalQueryString = request.RequestUri.Query.TrimStart('?');
        string canonicalHeaders = string.Join("\n", request.Headers.OrderBy(x => x.Key).Select(x => $"{x.Key}:{x.Value.First()}")) + "\n";
        string signedHeaders = string.Join(";", request.Headers.Select(x => x.Key));
        string payloadHash = HashAndHexEncode("");

        string canonicalRequest = $"{request.Method}\n{canonicalUri}\n{canonicalQueryString}\n{canonicalHeaders}\n{signedHeaders}\n{payloadHash}";

        string credentialScope = $"{dateStamp}/{region}/execute-api/aws4_request";
        string stringToSign = $"{Algorithm}\n{dateTimeStamp}\n{credentialScope}\n{HashAndHexEncode(canonicalRequest)}";

        string signature = CreateSignature(stringToSign, dateStamp);

        string authorizationHeader = $"{Algorithm} Credential={accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}";
        request.Headers.Add("Authorization", authorizationHeader);
    }

    private string HashAndHexEncode(string data)
    {
        using var sha256 = SHA256.Create();
        byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(data));
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }

    private string CreateSignature(string stringToSign, string dateStamp)
    {
        byte[] kDate = HmacSha256(dateStamp, Encoding.UTF8.GetBytes("AWS4" + secretKey));
        byte[] kRegion = HmacSha256(region, kDate);
        byte[] kService = HmacSha256("execute-api", kRegion);
        byte[] kSigning = HmacSha256("aws4_request", kService);

        return BitConverter.ToString(new HMACSHA256(kSigning).ComputeHash(Encoding.UTF8.GetBytes(stringToSign))).Replace("-", "").ToLower();
    }

    private byte[] HmacSha256(string data, byte[] key)
    {
        return new HMACSHA256(key).ComputeHash(Encoding.UTF8.GetBytes(data));
    }
}

huangapple
  • 本文由 发表于 2023年5月22日 11:59:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302956.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定