问题描述
我有以下设置:
REST API网关包含一个具有代理Lambda集成的端点,并使用AWS_IAM
授权者进行保护。最终用户从Cognito Identity Pool
检索临时AWS凭证,以换取从Cognito User Pool
检索的令牌,然后使用这些凭证调用API。
当用户调用API网关时,我希望被调用的lambda函数以与调用用户相同的权限运行。例如,如果用户仅具有从PK为CUSTOMER1234
的DynamoDB中读取项目的权限,那么我希望lambda函数也仅具有该权限。不同的用户将具有不同的权限,因此我无法将其“硬编码”到我的Lambda权限中。
这似乎是一个相当普遍的用例,但是我找不到任何有关如何实现这种目的的文档。
一种可能性是随每个请求一起发送用户的AWS凭证(即访问密钥和秘密密钥),然后在Lambda中使用这些凭证构建新会话,但这可能是一个糟糕的主意(它还会增加函数运行时间提高了5倍。
解决方法
在网络上发送AWS凭证似乎不是一个好主意,因为攻击者可能会截取它们并用它们来访问您的资源,直到它们过期为止。
有可能使用您的Cognito用户池中的JWT在lambda函数中获取AWS凭证 ,例如使用:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'IDENTITY_POOL_ID',Logins: {
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>': 'ID_TOKEN'
}
});
这意味着您的lambda的API调用将使用身份池中映射到的角色运行,并且您可以使用LeadingKeys条件来确保您的Web身份只能访问自己的数据:
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
但是,这会增加处理时间,因为您在每个请求中进行额外的API调用(CognitoIdentityCredentials()
在后台进行了2个API调用),以获取凭据。另外,您将无法在API网关方法上使用AWS_IAM授权,因为您尚未获得凭证。因此,您正在谈论具有两个授权设置。一种允许您的Web身份调用API网关方法,另一种允许您的Lambda函数以您的用户身份运行。
所以也许您的选择是:
直接从客户端进行API调用
您可以直接从客户端进行DynamoDB API调用,而不必通过API网关。这将与您的身份池设置很好地配合使用,因为您可以在用户登录以获取AWS凭证时仅进行一次CognitoIdentityCredentials()
调用。然后,将使用您的用户权限进行后续的DynamoDB调用,并且您可以使用LeadingKeys条件来确保您的用户仅访问自己的数据。
接受您的lambda函数将始终以相同的执行角色运行
如果您想使用Lambda支持的API网关,那么您可以接受,您将使用Lambda或Cognito授权者来授权您的用户有权执行API方法,然后再执行一些应用程序级在Lambda函数中的授权,以确保它们仅调用自己的分区空间。实际上,通过这种方式,您可能不需要身份池,而仅使用用户池JWT令牌中的sub
声明。毕竟,您将验证包含sub
的JWT未被篡改,并且它是由正确的用户池和应用程序客户端发出的,因此您可以信任其内容。
您可以直接将API Gateway与DynamoDB集成
取决于所需的逻辑,而不是通过lambda函数支持API方法,您可以将API Gateway方法直接与DynamoDB as shown in this amazon tutorial集成。同样,您将使用经过验证的JWT中的sub
作为分区键来强制进行正确的数据访问。