La autenticación AWS API con Rest API - AWS no pudo validar las credenciales de acceso proporcionadas

Estoy tratando de crear un simple programa C# o VB para conectarse a la API AWS y devolver una cadena JSON dando datos de instancia EC2. En lugar de eso, obtengo el error. "AWS no pudo validar las credenciales de acceso proporcionadas"

He intentado conectarme en ambos Postman y en un programa VB como sigue:

Imports System.Net
Imports System.IO

Module Main

    Sub Main()

        Dim result As String = RunQuery("", "https://ec2.amazonaws.com/?Action=DescribeInstances")

        Console.WriteLine(result)
        Console.ReadLine()

    End Sub


    Public Function RunQuery(creds As String, url As String, Optional data As String = Nothing) As String

        Dim request As HttpWebRequest = TryCast(WebRequest.Create(url), HttpWebRequest)
        request.ContentType = "application/json"
        request.Method = "GET"

        If data IsNot Nothing Then
            Using writer As StreamWriter = New StreamWriter(request.GetRequestStream())
                writer.Write(data)
            End Using
        End If

        Dim d As Date = Date.UtcNow
        Dim t As String = Format(d, "yyyyMMdd") & "T" & Format(d, "HHmmss") & "Z"

        request.Headers.Add("X-Amz-Date", t)
        request.Headers.Add("Authorization", "AWS4-HMAC-SHA256 Credential=***MYAPIKEY***/20201216/us-east-2/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=***MYAPISECRET***")

        Dim response As HttpWebResponse = TryCast(request.GetResponse(), HttpWebResponse)
        Dim result As String = String.Empty

        Using reader As StreamReader = New StreamReader(response.GetResponseStream())
            result = reader.ReadToEnd()
        End Using

        Return result

    End Function
End Module

La producción del cartero era

xml version="1.0" encoding="UTF-8"?
AuthFailureAWS was not able to validate the provided access credentials37153d9f-c042-4ae3-8a13-06dc3b052afc

Postman output

Escribí el vb basado en código postal:

var client = new RestClient("https://ec2.amazonaws.com/?Action=DescribeInstances");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("X-Amz-Date", "20201216T092737Z");
request.AddHeader("Authorization", "AWS4-HMAC-SHA256 Credential=MYAPIKEY/20201216/us-east-2/ec2/aws4_request, SignedHeaders=host;x-amz-date, Signature=MYAPISIGNATURE");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);

Preguntas similares se han hecho muchas veces antes, pero las únicas respuestas que puedo ver son que el reloj PC estaba equivocado, así que he corregido la mía tal que su dentro de 0,2 segundos del verdadero tiempo de Internet.

También no pude encontrar otro programa VB o C# similarmente simple que se conecta con éxito a EC2, por lo que este hilo puede ayudar a otros en el futuro.

Me pregunto si la firma tiene que ser codificada con base64 o algún otro algoritmo? De lo contrario, ¿cómo puedo conseguir que esto funcione ya sea en cartero o en vb/c#? TIA

Pregunta hecha hace 3 años, 5 meses, 0 días - Por scriptsculptor52b5


3 Respuestas:

  • Así que hubo un par de problemas

    1. URL incorrecta, la correcta era https://ec2.us-east-2.amazonaws.com/?Action=DescribeInstances&Version=2016-11-15

    2. Supuse que el secreto era la firma, no lo es.

    Aquí hay un VB completo. Aplicación de consola NET que conecta con éxito con AWS. Lo sentimos, pero el código es razonablemente obvio y no demasiado largo.

    
    Option Explicit On
    Option Compare Text
    Option Strict On
    
    Imports System.Net.Http
    Imports System.Security.Cryptography
    Imports System.Text
    
    Public Module Program
    
        Public Sub Main(ByVal args As String())
    
            If args.Length <> 5 Then
                Throw New Exception("AWS Integration requires 5 parameters: url accessKey secretKey awsRegion awsServiceName")
            End If
    
            Dim url As String = args(0)             '   "https://ec2.us-east-2.amazonaws.com/?Action=DescribeInstances&Version=2016-11-15"
            Dim accessKey As String = args(1)       ' api key
            Dim secretkey As String = args(2)       ' api secret
            Dim awsRegion As String = args(3)       ' = "us-east-2"
            Dim awsServiceName As String = args(4)  '= "ec2"
    
            Dim msg As HttpRequestMessage = New HttpRequestMessage(HttpMethod.[Get], url)
            msg.Headers.Host = msg.RequestUri.Host
            Dim utcNowSaved As DateTimeOffset = DateTimeOffset.UtcNow
            Dim amzLongDate As String = utcNowSaved.ToString("yyyyMMddTHHmmssZ")
            Dim amzShortDate As String = utcNowSaved.ToString("yyyyMMdd")
            msg.Headers.Add("x-amz-date", amzLongDate)
            Dim canonicalRequest As New StringBuilder
            canonicalRequest.Append(msg.Method.ToString & vbLf)
            canonicalRequest.Append(String.Join("/", msg.RequestUri.AbsolutePath.Split("/"c).Select(AddressOf Uri.EscapeDataString)) & vbLf)
            canonicalRequest.Append(GetCanonicalQueryParams(msg) & vbLf)
            Dim headersToBeSigned As New List(Of String)
    
            For Each header In msg.Headers.OrderBy(Function(a) a.Key.ToLowerInvariant, StringComparer.OrdinalIgnoreCase)
                canonicalRequest.Append(header.Key.ToLowerInvariant)
                canonicalRequest.Append(":")
                canonicalRequest.Append(String.Join(",", header.Value.[Select](Function(s) s.Trim)))
                canonicalRequest.Append(vbLf)
                headersToBeSigned.Add(header.Key.ToLowerInvariant)
            Next
    
            canonicalRequest.Append(vbLf)
            Dim signedHeaders As String = String.Join(";", headersToBeSigned)
            canonicalRequest.Append(signedHeaders & vbLf)
            canonicalRequest.Append("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
            Dim stringToSign As String = "AWS4-HMAC-SHA256" & vbLf & amzLongDate & vbLf & amzShortDate & "/" & awsRegion & "/" & awsServiceName & "/aws4_request" & vbLf & Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString))
            Dim dateKey() As Byte = HmacSha256(Encoding.UTF8.GetBytes("AWS4" & secretkey), amzShortDate)
            Dim dateRegionKey() As Byte = HmacSha256(dateKey, awsRegion)
            Dim dateRegionServiceKey() As Byte = HmacSha256(dateRegionKey, awsServiceName)
            Dim signingKey() As Byte = HmacSha256(dateRegionServiceKey, "aws4_request")
            Dim signature As String = ToHexString(HmacSha256(signingKey, stringToSign.ToString))
            Dim credentialScope As String = amzShortDate & "/" & awsRegion & "/" & awsServiceName & "/aws4_request"
            msg.Headers.TryAddWithoutValidation("Authorization", "AWS4-HMAC-SHA256 Credential=" & accessKey & "/" & credentialScope & ", SignedHeaders=" & signedHeaders & ", Signature=" & signature)
            Dim client As HttpClient = New HttpClient
            Dim result As HttpResponseMessage = client.SendAsync(msg).Result
    
            If result.IsSuccessStatusCode Then
                'Console.WriteLine(result.Headers)
                Dim s As String = result.Content.ReadAsStringAsync().Result
                Console.WriteLine(s)
            Else
                Console.WriteLine(result.StatusCode & vbCrLf & result.ToString.Replace(vbCr, "").Replace(vbLf, ""))
            End If
    
        End Sub
    
        Private Function GetCanonicalQueryParams(ByVal request As HttpRequestMessage) As String
            Dim values = New SortedDictionary(Of String, String)
            Dim querystring = System.Web.HttpUtility.ParseQueryString(request.RequestUri.Query)
    
            For Each key In querystring.AllKeys
    
                If key Is Nothing Then
                    values.Add(Uri.EscapeDataString(querystring(key)), $"{Uri.EscapeDataString(querystring(key))}=")
                Else
                    values.Add(Uri.EscapeDataString(key), $"{Uri.EscapeDataString(key)}={Uri.EscapeDataString(querystring(key))}")
                End If
            Next
    
            Dim queryParams = values.Select(Function(a) a.Value)
            Return String.Join("&", queryParams)
        End Function
    
        Public Function Hash(ByVal bytesToHash() As Byte) As String
            Return ToHexString(SHA256.Create.ComputeHash(bytesToHash))
        End Function
    
        Private Function ToHexString(ByVal array As IReadOnlyCollection(Of Byte)) As String
            Dim hex = New StringBuilder(array.Count * 2)
    
            For Each b In array
                hex.AppendFormat("{0:x2}", b)
            Next
    
            Return hex.ToString
        End Function
    
        Private Function HmacSha256(ByVal key() As Byte, ByVal data As String) As Byte()
            Return New HMACSHA256(key).ComputeHash(Encoding.UTF8.GetBytes(data))
        End Function
    End Module
    
    
    

    HTH someone :)

    Respondida el Dec 16, 2020 a las 10:40 - por javagiant

    Votos positivos: 0 | Votos negativos: 0

  • El error "AWS no pudo validar las credenciales de acceso proporcionadas" suele ocurrir cuando hay un problema con la autenticación de las credenciales de acceso a AWS. Parece que estás intentando realizar la autenticación manualmente en la solicitud HTTP, lo cual puede ser propenso a errores.

    En lugar de realizar la autenticación manualmente, te recomendaría utilizar las bibliotecas y SDK proporcionados por AWS para interactuar con sus servicios de forma segura y sin tener que lidiar con la autenticación a nivel de la solicitud HTTP.

    Para C

    , puedes utilizar el AWS SDK for .NET, que te facilitará la autenticación y el uso de servicios como EC2. Aquí tienes un ejemplo de cómo podrías modificar tu código en C# utilizando el SDK:

    csharp
    using Amazon;
    using Amazon.EC2;
    using Amazon.EC2.Model;
    
    class Program
    {
        static void Main()
        {
            var awsCreds = new Amazon.Runtime.BasicAWSCredentials("ACCESS_KEY", "SECRET_KEY");
            var region = RegionEndpoint.USEast2; // Cambia a la región correcta si es necesario
            var client = new AmazonEC2Client(awsCreds, region);
    
            DescribeInstancesRequest request = new DescribeInstancesRequest();
            DescribeInstancesResponse response = client.DescribeInstances(request);
    
            foreach (var reservation in response.Reservations)
            {
                foreach (var instance in reservation.Instances)
                {
                    Console.WriteLine($"Instance Id: {instance.InstanceId}");
                }
            }
        }
    }
    

    Este código usaría las credenciales de acceso que proporciones en lugar de ACCESS_KEY y SECRET_KEY, y luego se conectará a AWS EC2 para obtener información sobre las instancias en ejecución.

    Si aún prefieres realizar la autenticación manualmente, ten en cuenta que la firma debe generarse utilizando el algoritmo HMAC-SHA256 y los pasos requeridos por la documentación de AWS. Asegúrate de seguir correctamente todos los pasos necesarios para construir la firma y añadirla a la cabecera Authorization.

    Espero que esta información te sea útil y te ayude a solucionar tu problema de autenticación con AWS. ¡Déjame saber si tienes alguna otra pregunta!

    Respondida el Dec 17, 2020 a las 10:41 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Problema:

    La autenticación con las API de AWS utilizando las credenciales de acceso proporcionadas no es válida.

    Causas posibles:

    Credenciales de acceso incorrectas o inválidas. Reloj del sistema desincronizado con la hora de AWS. Firma de solicitud incorrecta. Encabezado Authorization mal formado.

    Soluciones:

    1. Verifica las credenciales de acceso:

    Asegúrate de estar utilizando las credenciales de acceso correctas para tu cuenta de AWS. Comprueba el ID y la clave de acceso secreta en la consola de administración de AWS o en tus variables de entorno.

    2. Sincroniza el reloj del sistema:

    El reloj del sistema debe estar sincronizado con la hora de AWS para generar firmas de solicitud válidas. Utiliza el comando ntpdate o un servicio NTP para sincronizar el reloj del sistema.

    3. Genera una firma de solicitud válida:

    Utiliza la biblioteca de firmas de AWS para generar la firma de solicitud. Sigue la documentación oficial de AWS para crear la cadena de firma y el encabezado Authorization.

    4. Comprueba el encabezado Authorization:

    El encabezado Authorization debe tener el formato correcto: AWS4-HMAC-SHA256 Credential=<access key ID>/<date>/<region>/<service>/aws4_request, SignedHeaders=<list of signed headers>, Signature=<signature> Asegúrate de que los encabezados firmados incluyan host y x-amz-date.

    Ejemplo para C

    :

    c

    using Amazon;

    using Amazon.EC2; using Amazon.Runtime; using System; namespace AwsEc2GetInstances { class Program { static void Main(string[] args) { // Define the AWS credentials var accessKeyId = "YOUR_ACCESS_KEY_ID"; var secretAccessKey = "YOUR_SECRET_ACCESS_KEY"; var credentials = new BasicAWSCredentials(accessKeyId, secretAccessKey); // Define the region var region = RegionEndpoint.USEast1; // Create the EC2 client var client = new AmazonEC2Client(credentials, region); // Create the request var request = new DescribeInstancesRequest { Filters = new List { new Filter("instance-type", new List { "t2.micro" }) } }; // Get the instances var response = client.DescribeInstances(request); // Print the instances foreach (var instance in response.Reservations) { Console.WriteLine(instance.Instances[0].InstanceId); } } } }

    Ejemplo para Postman:

    En la pestaña "Headers", agrega un nuevo encabezado con la clave x-amz-date y el valor de la fecha y hora actuales en formato ISO 8601 (por ejemplo, 2023-03-08T12:00:00Z). En la pestaña "Headers", agrega un nuevo encabezado con la clave Authorization y el valor generado por la biblioteca de firmas de AWS.

    Recursos adicionales:

    AWS Signature Version 4 AWS SDK for .NET AWS SDK for Python (Boto3)

    Respondida el Dec 17, 2020 a las 10:49 - por Gemini

    Votos positivos: 0 | Votos negativos: 0