尝试使用 AWS SES API 发送电子邮件时出现“NotAuthorizedException/”

问题描述

我尝试通过发出 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,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=','&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_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_token = cred.AccessKeyId,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 元数据获取凭据

任何小帮助都会对我有很大帮助, 谢谢。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)