繁体   English   中英

AWS Cloudfront(使用WAF)+ API网关:如何通过Cloudfront强制访问?

[英]AWS Cloudfront (with WAF) + API Gateway: how to force access through Cloudfront?

我想把WAF放在API网关的前面,并且我发现只有通过在APIG面前手动添加启用了WAF的额外Cloudfront发行版才能获得(小)信息 这有点遗憾,特别是因为APIG现在本身支持自定义域,但它应该有效。

现在为了使解决方案安全而不仅仅是模糊,我想强制要求只能通过Cloudfront发行版访问API。 这样做的最佳选择是什么?

  • 我希望能够使用类似于S3的'Origin Access Identities',但不知道如何做到这一点。
  • 如果我可以将一个IAM用户(或角色?)分配给Cloudfront发行版,我可以使用API​​G IAM功能,但我不知道如何做到这一点。
  • 我可能需要在APIG中使用API​​密钥,并将其作为来自Cloudfront的Origin Custom Header传递。 这可能有用,只要我们不想将API密钥用于其他目的,所以我对此并不完全满意。
  • 可以使用虚拟(!)自定义授权程序,令牌验证表达式实际检查从Cloudfront作为Origin自定义标头传递的秘密。 应该工作,它更灵活,但有点脏......或不?

有更好的想法吗? 或者也许“正确的方式”存在,但我忽略了它?

我来自API Gateway。

不幸的是,我们现在拥有的最佳解决方案是在CloudFront中注入原始自定义标头并在自定义授权器中验证(在您的问题中选项4)。

我们已经意识到这种局限性并没有那么好的解决方法。 我们希望将来提供更好的WAF集成,但我们没有ETA。

“正确”的方式是在其他人提到的API Gateway中使用自定义授权者。

“便宜”的方式是子弹3,一个api键。 如果你试图抵御ddos攻击,你可能只会提供waf - > cloudfront - > api网关。 因此,如果有人发现了你的api网关网址,并决定使用ddos而不是cloudfront,那么自定义授权者就意味着你现在正在首当其冲地攻击lambda。 Api网关每秒可处理超过10k个请求,默认lambda限制为每秒100个。 即使你有亚马逊增加你的限制你是否愿意支付每秒10k lambda的持续攻击?

AWS代表将告诉您,“API密钥用于标识,而不是用于身份验证。密钥不用于签署请求,不应用作安全机制” https://aws.amazon.com/blogs/aws/新用法,计划换亚马逊API网关/

但老实说,如果你不打算在你的lambda中做更好的事情而不是验证一些巨大的混乱字符串,为什么不把这个负担和成本留给别人。 (最大密钥长度为128个字符)

也许你可以有一个预定的lambda函数来发布一个新的api密钥并每6小时更新一次cloudfront的头文件?

如果你想将api密钥用于其他事情,那么只需要一个api网关源进行身份验证,另一个来源和api网关用于其他任何事情。 这种方式在ddos攻击中你可以每秒处理10k请求到你的auth api,而所有其他已经登录的客户每秒集合10k就可以使用你的api。 Cloudfront和waf每秒可处理100K,因此在这种情况下它们不会阻止您。

另外需要注意的是,如果你在api网关后面使用lambda,你可以使用lambda @ edge并且只是跳过api网关。 (这不适合大多数场景,因为lambda @ edge受到严重限制,但我想我会把它扔出去。)

但最终我们需要与API GATEWAY进行WAF集成! :)

您可以使用自定义域名并使用WAF将DNS指向分发。 直接请求原始API网关分发的请求将不起作用。

可以通过使用Lambda @ Edge函数SigV4签名原始请求,然后在API网关上启用IAM身份验证,强制通过CloudFront进行访问。 此策略可与CloudFront分配中的API密钥结合使用( CloudFront + API密钥指南 )。

假设您已将API网关设置为CloudFront分配的原点,则首先需要创建Lambda @ Edge功能( Lambda @ Edge设置指南 ),然后确保其执行角色可以访问您希望的API网关访问。 为简单起见,您可以在Lambda的执行角色中使用AmazonAPIGatewayInvokeFullAccess托管IAM策略,这使其可以调用您帐户中的任何API网关。

然后,如果您使用aws4作为签名客户端,这就是您的Lambda @ Edge代码的样子:

const aws4 = require("aws4");

const signCloudFrontOriginRequest = (request) => {
  const searchString = request.querystring === "" ? "" : `?${request.querystring}`;

  // Utilize a dummy request because the structure of the CloudFront origin request
  // is different than the signing client expects
  const dummyRequest = {
    host: request.origin.custom.domainName,
    method: request.method,
    path: `${request.origin.custom.path}${request.uri}${searchString}`,
  };

  // Include the body in the signature if present
  if (Object.hasOwnProperty.call(request, 'body')) {
    const { data, encoding } = request.body;
    const buffer = Buffer.from(data, encoding);
    const decodedBody = buffer.toString('utf8');

    if (decodedBody !== '') {
      dummyRequest.body = decodedBody;
      dummyRequest.headers = { 'content-type': request.headers['content-type'][0].value };
    }
  }

  // Use the Lambda's execution role credentials
  const credentials = {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    sessionToken: process.env.AWS_SESSION_TOKEN
  };

  aws4.sign(dummyRequest, credentials); // Signs the dummyRequest object

  // Sign a clone of the CloudFront origin request with appropriate headers from the signed dummyRequest
  const signedRequest = JSON.parse(JSON.stringify(request));
  signedRequest.headers.authorization = [ { key: "Authorization", value: dummyRequest.headers.Authorization } ];
  signedRequest.headers["x-amz-date"] = [ { key: "X-Amz-Date", value: dummyRequest.headers["X-Amz-Date"] } ];
  signedRequest.headers["x-amz-security-token"] = [ { key: "X-Amz-Security-Token", value: dummyRequest.headers["X-Amz-Security-Token"] } ];

  return signedRequest;
};

const handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const signedRequest = signCloudFrontOriginRequest(request);

  callback(null, signedRequest);
};

module.exports.handler = handler;

请注意,如果您在请求中包含正文,则必须手动配置Lambda @ Edge函数以通过控制台或SDK包含正文,或者设置CloudFormation自定义资源以调用SDK,因为CloudFormation不支持本机启用此功能

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM