Amazon web services 无法将lambda策略中的${cognito identity.amazonaws.com:sub}用于无服务器和DynamoDB/cognito/API网关

Amazon web services 无法将lambda策略中的${cognito identity.amazonaws.com:sub}用于无服务器和DynamoDB/cognito/API网关,amazon-web-services,amazon-dynamodb,aws-api-gateway,amazon-cognito,serverless-framework,Amazon Web Services,Amazon Dynamodb,Aws Api Gateway,Amazon Cognito,Serverless Framework,目标: { "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogStream", "logs:CreateLogGroup" ],

目标:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "logs:CreateLogStream",
                "logs:CreateLogGroup"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:xxx:log-group:/aws/lambda/exeampleservice*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:xxxx:log-group:/aws/lambda/exampleservice*:*:*"
            ],
            "Effect": "Allow"
        },
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:GetItem",
                "dynamodb:Query"
            ],
            "Resource": "*",
            "Condition": {
                "ForAllValues:StringEquals": {
                    "dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
                }
            }
        }
    ]
}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    },
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-east-1:<identity pool id>"
        }
      }
    }
  ]
}
  • 使用Cognito进行身份验证(使用下面的serverless.yml配置)
  • 点击经过身份验证的端点GET/users以触发lambda作业
  • 根据IAM策略,使用LeadingKey条件限制对基于cognito用户
    cognito identity.amazonaws.com:sub
    查询的DynamoDB表的访问
  • 问题: 我的策略似乎没有填充cognito变量
    ${cognito identity.amazonaws.com:sub}
    。如果我用一个值手动指定
    dynamodb:LeadingKeys
    ,它可以正常工作。看来我只需要Cognito来正确地填充子值,我到处都找过了,找不到解决方案

    我的lambda角色/策略(修改了从serverless生成的版本,使其具有带有Cognito和DynamoDB规则的信任策略):

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "logs:CreateLogStream",
                    "logs:CreateLogGroup"
                ],
                "Resource": [
                    "arn:aws:logs:us-east-1:xxx:log-group:/aws/lambda/exeampleservice*:*"
                ],
                "Effect": "Allow"
            },
            {
                "Action": [
                    "logs:PutLogEvents"
                ],
                "Resource": [
                    "arn:aws:logs:us-east-1:xxxx:log-group:/aws/lambda/exampleservice*:*:*"
                ],
                "Effect": "Allow"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "dynamodb:PutItem",
                    "dynamodb:GetItem",
                    "dynamodb:Query"
                ],
                "Resource": "*",
                "Condition": {
                    "ForAllValues:StringEquals": {
                        "dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
                    }
                }
            }
        ]
    }
    
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        },
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "cognito-identity.amazonaws.com"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "cognito-identity.amazonaws.com:aud": "us-east-1:<identity pool id>"
            }
          }
        }
      ]
    }
    
    具有信任关系:

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "logs:CreateLogStream",
                    "logs:CreateLogGroup"
                ],
                "Resource": [
                    "arn:aws:logs:us-east-1:xxx:log-group:/aws/lambda/exeampleservice*:*"
                ],
                "Effect": "Allow"
            },
            {
                "Action": [
                    "logs:PutLogEvents"
                ],
                "Resource": [
                    "arn:aws:logs:us-east-1:xxxx:log-group:/aws/lambda/exampleservice*:*:*"
                ],
                "Effect": "Allow"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "dynamodb:PutItem",
                    "dynamodb:GetItem",
                    "dynamodb:Query"
                ],
                "Resource": "*",
                "Condition": {
                    "ForAllValues:StringEquals": {
                        "dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
                    }
                }
            }
        ]
    }
    
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        },
        {
          "Effect": "Allow",
          "Principal": {
            "Federated": "cognito-identity.amazonaws.com"
          },
          "Action": "sts:AssumeRoleWithWebIdentity",
          "Condition": {
            "StringEquals": {
              "cognito-identity.amazonaws.com:aud": "us-east-1:<identity pool id>"
            }
          }
        }
      ]
    }
    
    我已经尽了一切努力在策略中获取变量
    ${cognito identity.amazonaws.com:sub}
    ,但似乎没有任何效果

    有人知道如何解决这个问题吗?或者我可能会错过什么。(如果我遗漏了任何关键信息,我将更新更多信息)

    谢谢

    编辑:(其他信息)

    我的登录函数(lambda+httpapi)如下所示,我通过用户/密码授权用户,然后调用CognitoIdentityCredentials“注册”我的身份并从池中获取我的身份ID。(我验证了我是在身份池向用户显示时注册的)

    然后,我的登录调用以accessToken、idToken、identityId响应

    我的所有其他API调用都在授权我的承载授权调用中使用idToken,但是似乎没有假定我的身份池的授权角色,而是使用我的lambda角色执行

    我错过了什么?我原以为Cognito会处理身份验证池的假定角色,但似乎整个身份验证池?感谢您的帮助

    我的请求上下文(从我的登录函数中,请注意标识对象中充满了空值):

    我的登录功能

    const AWS = require('aws-sdk');
    const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
    global.fetch = require('node-fetch').default; // .default for webpack.
    const USER_POOL_ID = process.env.USER_POOL_ID;
    const USER_POOL_CLIENT_ID = process.env.USER_POOL_CLIENT_ID;
    const USER_POOL_IDENTITY_ID = process.env.USER_POOL_IDENTITY_ID; 
    console.log('USER_POOL_ID', USER_POOL_ID);
    console.log('USER_POOL_CLIENT_ID', USER_POOL_CLIENT_ID);
    console.log('USER_POOL_CLIENT_ID', USER_POOL_IDENTITY_ID);
     
    const poolData = {
      UserPoolId: USER_POOL_ID, 
      ClientId: USER_POOL_CLIENT_ID,
    };
     
    const poolRegion = 'us-east-1';
    const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
     
    function login(Username, Password) {
      var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
        Username,
        Password,
      });
     
      var userData = {
        Username,
        Pool: userPool,
      };
      var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
     
      return new Promise((resolve, reject) => {
        cognitoUser.authenticateUser(authenticationDetails, {
          onSuccess: function (result) {
     
            AWS.config.credentials = new AWS.CognitoIdentityCredentials({
              IdentityPoolId: USER_POOL_IDENTITY_ID, // your identity pool id here
              Logins: {
                // Change the key below according to the specific region your user pool is in.
                [`cognito-idp.${poolRegion}.amazonaws.com/${USER_POOL_ID}`]: result
                  .getIdToken()
                  .getJwtToken(),
              },
            });
     
            //refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity()
            AWS.config.credentials.refresh((error) => {
              if (error) {
                console.error(error);
              } else {
                // Instantiate aws sdk service objects now that the credentials have been updated.
                // example: var s3 = new AWS.S3();
                console.log('Successfully Refreshed!');
                AWS.config.credentials.get(() => {
                  // return back all tokens and identityId in login call response body.
                  const identityId = AWS.config.credentials.identityId;
                  const tokens = {
                    accessToken: result.getAccessToken().getJwtToken(),
                    idToken: result.getIdToken().getJwtToken(),
                    refreshToken: result.getRefreshToken().getToken(),
                    identityId,
                  };
                  resolve(tokens);
                });
              }
            });
          },
          onFailure: (err) => {
            console.log(err);
            reject(err);
          },
        });
      });
    }
    module.exports = {
      login,
    };
    

    我不太清楚您是否使用了身份(将您的ID令牌从用户池交换为STS令牌)

    令人困惑的是,cognito identity.amazonaws.com:sub解析为ID池标识ID,而不是来自用户池的ID令牌中的主题ID。请参阅本页的“注释”部分:


    要获取身份凭证,请查看

    ,如果您将AWS网关与Lambda一起使用,则无法使用这些变量

    您必须直接从使用IAM auth(使用类似aws amplify的东西)注册身份的客户端应用程序访问DynamoDB


    我最终使用STS在lambda函数中扮演Cognito的组身份验证角色,并完全绕过身份池。

    @JDClark感谢您的响应。为了澄清,我正在获取标识的凭据,并在登录lambda函数中获取identityId。但我不确定下一步是什么。看起来我的IdToken和access token即使在之后仍然保持不变,而且最重要的是,cognito似乎没有承担由我的identity auth提供的角色,因为它似乎仍在使用我的lambda执行策略的假定角色。这里是我的登录功能,如果你有时间来看看。在上面的登录函数中,我登录并获得证书,但由于我是在邮递员中完成这项工作的,所以我只是在所有呼叫中使用承载人。如果我只是通过用户池传递从我的授权中提供的承载者,它会保持注册的身份吗?在将JWTs交换为凭据(作为GetCredentialsForIdentity API的一部分)时,您将收到回凭据(本质上是一个STS令牌,与您直接承担角色相同)。这些将与ID池确定的角色相关联(该角色的确定方式是可配置的)。然后,您可以使用此令牌使用sigv4对HTTP请求进行签名,并通过IAM授权人访问lambda,或创建AWS会话,以将服务用作令牌相关的角色等。如果您只使用默认会话,则它将与lambda的角色一起使用。