API网关跨帐户访问

时间:2018-12-30 10:52:23

标签: amazon-web-services api aws-api-gateway

我有两个AWS账户,例如考虑账户a和账户b。帐户a要访问帐户b中部署在API网关上的API。现在可以从帐户a访问帐户b中的API。我想为该API添加白名单,以仅允许帐户-a。当我添加资源策略时,仅将API的帐户a列入白名单时,它总是抛出错误“不允许用户匿名”。有人可以让我知道是否遵循正确的方法。请让我知道是否错过了任何事情。

我将auth添加为“ AWS_IAM”,并且具有以下资源策略。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::****:role/****"
            },
            "Action": "execute-api:Invoke",
            "Resource": "arn:aws:execute-api:ap-southeast-1:****:***/*/*/*"
        }
    ]
}

现在出现错误

  

“缺少身份验证令牌”

我的要求是使用aws帐户白名单或源vpc过滤来保护AWS API网关中部署的API。请在生成api请求(例如对请求进行签名)时帮助提供所需的信息以及是否进行任何特殊处理。一个简单的例子将不胜感激。

3 个答案:

答案 0 :(得分:0)

引起此错误的原因是,在客户端,您需要使用AWS身份验证标头对请求进行签名。 通常,对于AWS服务的调用,当您使用AWS sdk时,它将自动对请求进行签名。不幸的是,到目前为止,here尚无官方的亚马逊方式来签署此调用API的请求。 您可以通过以下方式使用aws-requests-auth之类的第三方库:

from aws_requests_auth.boto_utils import BotoAWSRequestsAuth
auth = BotoAWSRequestsAuth(aws_host='api.example.com',
                           aws_region='us-east-1',
                           aws_service='execute-api')

import requests
response = requests.post('https://api.example.com/test', json={"foo": "bar"}, auth=auth)

如果您希望在lambda函数中使用它,则可以将其安装为目标层,方法是将其安装到目标文件夹中,然后压缩该文件夹并将其用作lambda层。

答案 1 :(得分:0)

如@Sam所述,您需要生成一个签名并将其与您的http请求一起发送。您可以通过两种方式执行此操作。

  1. 您可以生成签名,并以http请求作为标头发送签名
  2. 您可以使用可以生成签名并发送请求的库

方法1-生成签名

### generate signature
const aws4  = require('aws4')
const signature = aws4.sign({
  host: 'https://apiId.execute-api.ap-southeast-2.amzonaws.com',
  method: 'GET',
  path: '/development/hello',
  headers: {

  },
  region: 'ap-southeast-2',
  service: 'execute-api'
}, {
  secretAccessKey: "your access key",
  accessKeyId: "your secret key",
  sessionToken: "your session token if you are using temporary credentials"

})

// output
{ "host":
   "something.execute-api.ap-southeast-2.amzonaws.com",
  "method": "GET",
  "path": "/development/hello",
  "headers": {
     "Host":
      "something.execute-api.ap-southeast-2.amzonaws.com",
     "X-Amz-Security-Token":
      "security token",
     "Authorization":
      "AWS4-HMAC-SHA256 Credential=ASIARNZFFFFFEGFG23JY/20191212/ap-southeast-2/execute-api/aws4_request, SignedHeaders=host;x-amz-date;x-amz-security-token;x-apigw-api-id, Signature=7fd8e51c2bf4faefaRRRRRf92c700799b78234d204"
  },
  "region": "ap-southeast-2",
  "service": "execute-api"
}

在您的http请求中包含AuthorizationX-Amz-DateX-Amz-Security-Token作为标头。

方法2-使用可以生成签名并发送请求的库

var apigClientFactory = require('aws-api-gateway-client').default;

var apigClient = apigClientFactory.newClient({
    invokeUrl:'https://apiId.execute-api.ap-southeast-2.amzonaws.com/development', // REQUIRED
    accessKey: 'your access key', // REQUIRED
    secretKey: 'your secret key', // REQUIRED
    sessionToken: 'your session token if you are using temporary credentials',
    region: 'ap-southeast-2', // REQUIRED: The region where the API is deployed.
    systemClockOffset: 0, // OPTIONAL: An offset value in milliseconds to apply to signing time
    retries: 4, // OPTIONAL: Number of times to retry before failing. Uses axon-retry plugin.
    retryCondition: (err) => { // OPTIONAL: Callback to further control if request should be retried.  Uses axon-retry plugin.
      return err.response && err.response.status === 500;
    }
});


(() => {
  apigClient.invokeApi(null, `/hello`, 'GET', {
    headers: {
    }
  })
  .then(function(result){
    console.log('result: ', result)
      //This is where you would put a success callback
  }).catch( function(result){
    console.log('result: ', result)
      //This is where you would put an error callback
  });
})()

希望这会有所帮助,祝你好运

答案 2 :(得分:0)

您必须生成一个签名的请求。下面是你可以在本地运行的 Python 代码

import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import requests

session = boto3.Session(profile_name="YOUR PROFILE NAME")
credentials = session.get_credentials()
creds = credentials.get_frozen_credentials()


def signed_request(method, url, data=None, params=None, headers=None):
    request = AWSRequest(method=method, url=url, data=data, params=params, headers=headers)
    SigV4Auth(creds, "YOUR API NAME", "us-east-1").add_auth(request)
    return requests.request(method=method, url=url, headers=dict(request.headers), data=data)


def main():
    url = f"YOUR API URL"
    data = '{"data":"John"}'
    headers = {'Content-Type': 'application/json'}
    response = signed_request(method='POST', url=url, data=data, headers=headers)
    print(response.text)


if __name__ == "__main__":
    main()