AWS and sign_aws4 request made with HTTP

I am trying to autenticate a request to my AWS endpoint using AWS Signature 4, I see there’s a function in AWS.jl called sign_aws4!, but I would appreciate a code example of how to use it, because I don’t really understand where to place it…

this is my request:

function call_endpoint(message)
    resp = HTTP.request(
        "POST",
        ENV["AWS_ENDPOINT"],
        headers,
        body = JSON.json(Dict("inputs" => message, 
        "parameters" => Dict( "max_new_tokens" => 200 )))
    )
    return resp
end

I could find any code snippets on google… any help more than welcome!

You could try using submit_request which will sign it and do some retries and such (but requires you pass a AWS.Request input). But why do you need to manually construct the request? Is there a service AWS.jl doesn’t cover already?

I am not following, sign_aws4 signature is (aws::AbstractAWSConfig, request::Request, time::DateTime), I understand this as in I have to pass a request…

Stepping back a little bit, what are you trying to do? What is the HTTP request for?

I am sending a POST request to an endpoint on sagemaker…

Do any of these do what you need?

For endpoint inference you want the SageMaker Runtime service.

2 Likes

yes, thank you!

I think this is the right one, still the question of signing the call remains, doesn’t it?

using JSON
using AWS
@service Sagemaker_Runtime
body = JSON.json(Dict("inputs" => "what is Python?", 
"parameters" => Dict( "max_new_tokens" => 200 )))
endpoint = "myurl"
Sagemaker_Runtime.invoke_endpoint(body, endpoint)

returns this error

AWS.AWSExceptions.AWSException: 404 -- AWSException

HTTP.Exceptions.StatusError(404, "POST", "/endpoints/myurl", HTTP.Messages.Response:
"""
HTTP/1.1 404 Not Found
x-amzn-RequestId: a4991672-a474-4882-8626-56e4e35a6206
Date: Sun, 10 Dec 2023 11:03:34 GMT
Content-Length: 29
connection: keep-alive

[Message Body was streamed]""")

<UnknownOperationException/>

That function will automatically sign the request, and if it wasn’t signed, you’d get a different error than a 404. So there’s some other issue, maybe your endpoint isn’t correct, or the region isn’t configured in your AWS config. Hard to say without more details.

1 Like

thank you Eric, I will investigate the issues you mentioned… is the AWS.jl expecting such values stored somewhere in particular? or will it check the AWS CLI values or ENV variables in .profile or .bashrc?

Yeah. It is hard to find in the docs, but here is the list of places it checks: https://github.com/JuliaCloud/AWS.jl/blob/100c30ec942e5e38d4a987dbef6b30c85dda9fbf/src/AWSCredentials.jl#L49-L57

1 Like

thanks for this, tbh with the credentials I have on .aws/credentials I can successfully connect to my endpoint using Postman.

I still have the same error with AWS.jl, I suspect it doesn’t pick them up… or should I explicitly do something?

Can you post the full error? Also, what AWS region are you using?

sure of course, I am on eu-west-1

AWS.AWSExceptions.AWSException: 404 -- AWSException

HTTP.Exceptions.StatusError(404, "POST", "/endpoints/jumpstart-dft-meta-textgeneration-llama-2-13b-f/invocations/invocations", HTTP.Messages.Response:
"""
HTTP/1.1 404 Not Found
x-amzn-RequestId: 7ec3853c-e55b-40cb-9486-f60c4b572940
Date: Sun, 10 Dec 2023 13:16:09 GMT
Content-Length: 29
connection: keep-alive

[Message Body was streamed]""")

<UnknownOperationException/>



Stacktrace:
  [1] (::HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}})(req::HTTP.Messages.Request; proxy::Nothing, socket_type::Type, socket_type_tls::Type, readtimeout::Int64, connect_timeout::Int64, logerrors::Bool, logtag::Nothing, kw::Base.Pairs{Symbol, Union{Nothing, Int64}, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:iofunction, :decompress, :verbose), Tuple{Nothing, Nothing, Int64}}})
    @ HTTP.ConnectionRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/ConnectionRequest.jl:144
  [2] (::HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}})(req::HTTP.Messages.Request; retry::Bool, retries::Int64, retry_delays::ExponentialBackOff, retry_check::Function, retry_non_idempotent::Bool, kw::Base.Pairs{Symbol, Union{Nothing, Int64}, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:iofunction, :decompress, :verbose), Tuple{Nothing, Nothing, Int64}}})
    @ HTTP.RetryRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/RetryRequest.jl:35
  [3] manageretries
    @ ~/.julia/packages/HTTP/bDoga/src/clientlayers/RetryRequest.jl:30 [inlined]
  [4] (::HTTP.CookieRequest.var"#managecookies#4"{HTTP.CookieRequest.var"#managecookies#1#5"{HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}})(req::HTTP.Messages.Request; cookies::Bool, cookiejar::HTTP.Cookies.CookieJar, kw::Base.Pairs{Symbol, Union{Nothing, Integer}, NTuple{4, Symbol}, NamedTuple{(:iofunction, :decompress, :verbose, :retry), Tuple{Nothing, Nothing, Int64, Bool}}})
    @ HTTP.CookieRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/CookieRequest.jl:42
  [5] managecookies
    @ ~/.julia/packages/HTTP/bDoga/src/clientlayers/CookieRequest.jl:19 [inlined]
  [6] (::HTTP.HeadersRequest.var"#defaultheaders#2"{HTTP.HeadersRequest.var"#defaultheaders#1#3"{HTTP.CookieRequest.var"#managecookies#4"{HTTP.CookieRequest.var"#managecookies#1#5"{HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}})(req::HTTP.Messages.Request; iofunction::Nothing, decompress::Nothing, basicauth::Bool, detect_content_type::Bool, canonicalize_headers::Bool, kw::Base.Pairs{Symbol, Integer, Tuple{Symbol, Symbol}, NamedTuple{(:verbose, :retry), Tuple{Int64, Bool}}})
    @ HTTP.HeadersRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/HeadersRequest.jl:71
  [7] defaultheaders
    @ ~/.julia/packages/HTTP/bDoga/src/clientlayers/HeadersRequest.jl:14 [inlined]
  [8] (::HTTP.RedirectRequest.var"#redirects#3"{HTTP.RedirectRequest.var"#redirects#1#4"{HTTP.HeadersRequest.var"#defaultheaders#2"{HTTP.HeadersRequest.var"#defaultheaders#1#3"{HTTP.CookieRequest.var"#managecookies#4"{HTTP.CookieRequest.var"#managecookies#1#5"{HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}})(req::HTTP.Messages.Request; redirect::Bool, redirect_limit::Int64, redirect_method::Nothing, forwardheaders::Bool, response_stream::Base.BufferStream, kw::Base.Pairs{Symbol, Integer, Tuple{Symbol, Symbol}, NamedTuple{(:verbose, :retry), Tuple{Int64, Bool}}})
    @ HTTP.RedirectRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/RedirectRequest.jl:17
  [9] redirects
    @ ~/.julia/packages/HTTP/bDoga/src/clientlayers/RedirectRequest.jl:14 [inlined]
 [10] (::HTTP.MessageRequest.var"#makerequest#3"{HTTP.MessageRequest.var"#makerequest#1#4"{HTTP.RedirectRequest.var"#redirects#3"{HTTP.RedirectRequest.var"#redirects#1#4"{HTTP.HeadersRequest.var"#defaultheaders#2"{HTTP.HeadersRequest.var"#defaultheaders#1#3"{HTTP.CookieRequest.var"#managecookies#4"{HTTP.CookieRequest.var"#managecookies#1#5"{HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}})(method::String, url::URIs.URI, headers::Vector{Pair{SubString{String}, SubString{String}}}, body::String; copyheaders::Bool, response_stream::Base.BufferStream, http_version::HTTP.Strings.HTTPVersion, verbose::Int64, kw::Base.Pairs{Symbol, Bool, Tuple{Symbol, Symbol}, NamedTuple{(:redirect, :retry), Tuple{Bool, Bool}}})
    @ HTTP.MessageRequest ~/.julia/packages/HTTP/bDoga/src/clientlayers/MessageRequest.jl:35
 [11] makerequest
    @ ~/.julia/packages/HTTP/bDoga/src/clientlayers/MessageRequest.jl:24 [inlined]
 [12] request(stack::HTTP.MessageRequest.var"#makerequest#3"{HTTP.MessageRequest.var"#makerequest#1#4"{HTTP.RedirectRequest.var"#redirects#3"{HTTP.RedirectRequest.var"#redirects#1#4"{HTTP.HeadersRequest.var"#defaultheaders#2"{HTTP.HeadersRequest.var"#defaultheaders#1#3"{HTTP.CookieRequest.var"#managecookies#4"{HTTP.CookieRequest.var"#managecookies#1#5"{HTTP.RetryRequest.var"#manageretries#3"{HTTP.RetryRequest.var"#manageretries#1#4"{HTTP.ConnectionRequest.var"#connections#4"{HTTP.ConnectionRequest.var"#connections#1#5"{HTTP.TimeoutRequest.var"#timeouts#3"{HTTP.TimeoutRequest.var"#timeouts#1#4"{HTTP.ExceptionRequest.var"#exceptions#2"{HTTP.ExceptionRequest.var"#exceptions#1#3"{typeof(HTTP.StreamRequest.streamlayer)}}}}}}}}}}}}}}}}, method::String, url::URIs.URI, h::Vector{Pair{SubString{String}, SubString{String}}}, b::String, q::Nothing; headers::Vector{Pair{SubString{String}, SubString{String}}}, body::String, query::Nothing, kw::Base.Pairs{Symbol, Any, Tuple{Symbol, Symbol, Symbol}, NamedTuple{(:redirect, :retry, :response_stream), Tuple{Bool, Bool, Base.BufferStream}}})
    @ HTTP ~/.julia/packages/HTTP/bDoga/src/HTTP.jl:457
 [13] #request#20
    @ ~/.julia/packages/HTTP/bDoga/src/HTTP.jl:315 [inlined]
 [14] macro expansion
    @ ~/.julia/packages/Mocking/Q17aB/src/mock.jl:29 [inlined]
 [15] (::AWS.var"#48#50"{AWS.Request, OrderedCollections.LittleDict{Symbol, Any, Vector{Symbol}, Vector{Any}}})()
    @ AWS ~/.julia/packages/AWS/SchLh/src/utilities/request.jl:225
 [16] (::Base.var"#90#92"{Base.var"#90#91#93"{AWS.AWSExponentialBackoff, AWS.var"#49#51", AWS.var"#48#50"{AWS.Request, OrderedCollections.LittleDict{Symbol, Any, Vector{Symbol}, Vector{Any}}}}})(; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Base ./error.jl:296
 [17] (::Base.var"#90#92"{Base.var"#90#91#93"{AWS.AWSExponentialBackoff, AWS.var"#49#51", AWS.var"#48#50"{AWS.Request, OrderedCollections.LittleDict{Symbol, Any, Vector{Symbol}, Vector{Any}}}}})()
    @ Base ./error.jl:291
 [18] _http_request(http_backend::AWS.HTTPBackend, request::AWS.Request, response_stream::IOBuffer)
    @ AWS ~/.julia/packages/AWS/SchLh/src/utilities/request.jl:250
 [19] macro expansion
    @ ~/.julia/packages/Mocking/Q17aB/src/mock.jl:29 [inlined]
 [20] (::AWS.var"#41#44"{AWS.AWSConfig, AWS.Request, IOBuffer, Vector{Int64}})()
    @ AWS ~/.julia/packages/AWS/SchLh/src/utilities/request.jl:134
 [21] (::AWS.var"#42#46"{AWS.var"#41#44"{AWS.AWSConfig, AWS.Request, IOBuffer, Vector{Int64}}, IOBuffer})()
    @ AWS ~/.julia/packages/AWS/SchLh/src/utilities/request.jl:149
 [22] (::Base.var"#90#92"{Base.var"#90#91#93"{AWS.AWSExponentialBackoff, AWS.var"#43#47"{AWS.AWSConfig, Vector{String}, Vector{String}, Int64}, AWS.var"#42#46"{AWS.var"#41#44"{AWS.AWSConfig, AWS.Request, IOBuffer, Vector{Int64}}, IOBuffer}}})(; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ Base ./error.jl:296
 [23] (::Base.var"#90#92"{Base.var"#90#91#93"{AWS.AWSExponentialBackoff, AWS.var"#43#47"{AWS.AWSConfig, Vector{String}, Vector{String}, Int64}, AWS.var"#42#46"{AWS.var"#41#44"{AWS.AWSConfig, AWS.Request, IOBuffer, Vector{Int64}}, IOBuffer}}})()
    @ Base ./error.jl:291
 [24] submit_request(aws::AWS.AWSConfig, request::AWS.Request; return_headers::Nothing)
    @ AWS ~/.julia/packages/AWS/SchLh/src/utilities/request.jl:200
 [25] (::AWS.RestJSONService)(request_method::String, request_uri::String, args::Dict{String, Any}; aws_config::AWS.AWSConfig, feature_set::AWS.FeatureSet)
    @ AWS ~/.julia/packages/AWS/SchLh/src/AWS.jl:431
 [26] RestJSONService
    @ ~/.julia/packages/AWS/SchLh/src/AWS.jl:402 [inlined]
 [27] invoke_endpoint(Body::String, EndpointName::String, params::Dict{String, String}; aws_config::AWS.AWSConfig)
    @ Main.Sagemaker_Runtime ~/.julia/packages/AWS/SchLh/src/services/sagemaker_runtime.jl:83
 [28] invoke_endpoint(Body::String, EndpointName::String, params::Dict{String, String})
    @ Main.Sagemaker_Runtime ~/.julia/packages/AWS/SchLh/src/services/sagemaker_runtime.jl:77
 [29] top-level scope
    @ /mnt/data/projects/GenieGiano/test.ipynb:1

If you do

julia> config = global_aws_config();

julia> config.region
"eu-central-1"

does it show your region? If not, try setting the ENV variable AWS_REGION.

Then see if you can access any other functions. Like

@service Sagemaker
Sagemaker.list_apps()

to see if you can find your app and if even that simple request errors. If so there is probably a configuration problem.

yes if I run those commands I get back my region, and I can get the Sagemaker service

Sagemaker.list_apps()

OrderedCollections.LittleDict{String, Any, Vector{String}, Vector{Any}} with 1 entry:
  "Apps" => Any[LittleDict{String, Any, Vector{String}, Vector{Any}}("AppName"=…
1 Like

Ok that’s great! Then the configuration is working. Looking again at your message:

This looks wrong to me. Try removing invocations from what you’re passing to the function.

1 Like

nice spot! still have JSON issue but it looks like it’s talking to the endpoint now!

ok great! I have never used sagemaker so I am not about that part. Maybe start a new topic about this issue, and try to include a minimal example (see also Please read: make it easier to help you).