我尝试通过发出 HTTPS 请求在 lua 中使用 AWS SES API 发送电子邮件,但我在响应对象正文中收到“NotAuthorizedException/”。有人可以帮助我了解为什么会出现此错误以及可能的解决方案。
为了创建 AWS 签名版本 4,我使用了 this 代码。
用于调用 API,
local aws_v4 = require ("kong.plugins.kong-rate-limit.ses.v4")
local http = require "resty.http"
local cjson = require "cjson.safe"
local meta = require "kong.meta"
local constants = require "kong.constants"
local resty_http = require 'resty.http'
local tostring = tostring
local tonumber = tonumber
local type = type
local fmt = string.format
local ngx_encode_base64 = ngx.encode_base64
local ngx_time = ngx.time
local string_match = string.match
local os_time = os.time
local concat = table.concat
local AWS_PORT = 443
local function iso8601_to_epoch(date_iso8601)
local inYear, inMonth, inDay, inHour, inMinute, inSecond, inZone = string_match(date_iso8601, '^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)(.-)$')
local zHours, zMinutes = string_match(inZone, '^(.-):(%d%d)$')
local returnTime = os_time({year=inYear, month=inMonth, day=inDay, hour=inHour, min=inMinute, sec=inSecond, isdst=false})
if zHours then
returnTime = returnTime - ((tonumber(zHours)*3600) + (tonumber(zMinutes)*60))
end
return returnTime
end
local function get_keys_from_metadata(iam_role,metadata_url)
local httpc = resty_http:new()
httpc:set_timeout(300) -- set timeout to 300ms
local res, err = httpc:request_uri(metadata_url .. iam_role, {
ssl_verify = false,
keepalive = false
})
if err then
kong.log.err("Could not get keys from meta-data endpoint")
end
if not res then
kong.log.err("Empty response from meta-data endpoint")
end
if res.status ~= 200 then
kong.log.err("Not OK (HTTP 200) response from meta-data endpoint")
end
local body = cjson.decode(res.body)
local expiration = iso8601_to_epoch(body.Expiration) - ngx_time() -- aws keys auto regenerates 5 min before expiration. Maybe have to change this.
return { ["AccessKeyId"] = body.AccessKeyId, ["SecretAccessKey"] = body.SecretAccessKey, ["Token"] = body.Token }, nil, expiration
end
local function get_keys_from_cache(iam_role,metadata_url,override_ttl,ttl)
if override_ttl then
local cred, err = kong.cache:get(iam_role .. "_cred", {ttl=ttl} , get_keys_from_metadata, iam_role, metadata_url)
else
local cred, err = kong.cache:get(iam_role .. "_cred", nil , get_keys_from_metadata, iam_role, metadata_url)
end
if err then
kong.log.err("Could not get/put ",err)
end
if cred then
return cred.AccessKeyId, cred.SecretAccessKey, cred.Token
end
return nil
end
local function publish_to_ses(client, request)
local res, err = client:request {
method = "GET",
path = request.url,
body = request.body,
headers = request.headers
}
return res
end
return {
publish = function(conf, body, email_body, notified_key)
local message_body=ngx.escape_uri("This is body")
local email_subject = ngx.escape_uri("This is subject")
local source = ngx.escape_uri("example@gmail.com")
local host = fmt("email.%s.amazonaws.com", conf.aws_region)
local path = "/"
local query = concat({'Version=2010-12-01&Action=SendEmail&Source=' , source, '&Destination.ToAddresses.member.1=', source ,'&Message.Subject.Data=', email_subject,'&Message.Body.Text.Data=' , message_body})
local port = conf.port or AWS_PORT
local aws_key, aws_secret, aws_token
if conf.aws_key == nil and conf.aws_secret == nil and conf.aws_iam_role ~= nil then
if conf.store_creds_in_cache then
aws_key, aws_secret, aws_token = get_keys_from_cache(conf.aws_iam_role, conf.aws_metadata_url, conf.override_cache_creds_ttl, conf.cache_creds_ttl)
else
local cred, e, ttl = get_keys_from_metadata(conf.aws_iam_role, conf.aws_metadata_url)
if cred and e == nil then
aws_key, aws_secret, aws_token = cred.AccessKeyId, cred.SecretAccessKey, cred.Token
end
end
else
aws_key = conf.aws_key
aws_secret = conf.aws_secret
end
local opts = {
region = conf.aws_region,
service = "ses",
method = "GET",
headers = {
["Content-Type"] = "text/plain",
},
path = path,
host = host,
port = port,
access_key = aws_key,
secret_key = aws_secret,
query = query
}
if aws_token then
opts["headers"]['X-Amz-Security-Token'] = aws_token
end
local request, err = aws_v4(opts)
if err then
kong.log.err("An unexpected error occurred while signing request according to AWS signature(V4)",err)
end
-- Trigger request
local client = http.new()
client:set_timeout(conf.timeout)
client:connect(host, port)
local ok, err = client:ssl_handshake()
if not ok then
kong.log.err("[SES]An unexpected error occurred while connecting: ",err)
end
local res = publish_to_ses(client, request)
if not res then
if conf.policy == "local" then
service_in_memory:delete(notified_key)
else
res = publish_to_ses(client, request)
end
end
local content = res:read_body()
local ok, err = client:close()
if not ok then
kong.log.err("[SES]Could not close connection :",err)
end
if res.status == 200 then
local MessageId=content:match("MessageId>(.*)</MessageId")
content=cjson.encode({
MessageId=MessageId,
})
end
kong.log.info("[SES]Message published: ", content)
end,
}
我正在尝试从 AWS EC2 元数据获取凭据
任何小帮助都会对我有很大帮助, 谢谢。