AWS:将 Cognito 授权用户限制为特定 Lambda 函数

Phi*_*ipp 2 amazon-web-services amazon-cognito aws-lambda aws-api-gateway

我正在使用 AWS,并且有以下设置:UserPool; API网关、Lambda函数

API 网关使用 UserPool 授权者来保护 lambda 函数。到目前为止,这是有效的。现在我想将每个 lambda 函数限制为特定的用户组。因此,我在 CognitoPool 中创建了两个用户组(useradmin),并使用策略为每个组分配了特定角色。之后,我在 UserPool 中创建了一个用户并将其添加到该user组中。该用户仍然能够向每个路由/lambda 函数提交请求。

我如何提交请求?

  • 邮差
  • 在标头中设置IdToken(经过身份验证的用户)Authorization
  • 没有Authorization标头,响应是 401(如预期)
  • 使用Authorization标头,每个 lambda 函数都可以被触发(不是预期的)

用户池组的配置:

  • 团体用户:

    • 阿恩:Role ARN: arn:aws:iam::xxxxxx:role/User
    • 用户角色指定为

      {
        "Version": "2012-10-17",
        "Statement": [
          "Action": [
            "lambda:InvokeFunction",
            "lambda:InvokeAsync"
          ],
         "Resource": [
           "arn:aws:lambda:region:xxxxxx:function:api-dev-getItems
          ],
          "Effect": "Allow"
        ]
      }
      
      Run Code Online (Sandbox Code Playgroud)
  • 群组管理员:

    • 阿恩:Role ARN: arn:aws:iam::xxxxxx:role/Admin
    • AdminRole 指定为

      {
        "Version": "2012-10-17",
        "Statement": [
            "Action": [
            "lambda:InvokeFunction",
            "lambda:InvokeAsync"
          ],
          "Resource": [
             "arn:aws:lambda:region:xxxxxx:function:api-dev-getItems
             "arn:aws:lambda:region:xxxxxx:function:api-dev-getUsers
          ],
          "Effect": "Allow"
        ]
      }
      
      Run Code Online (Sandbox Code Playgroud)

id 令牌的有效负载还包含: 'cognito:roles': [ 'arn:aws:iam::xxxxxx:role/User' ]

Phi*_*ipp 5

所以我找到了解决我的问题的方法。以下是我的经验总结:

  • Cognito Authorizer 更像是/否授权者(是否经过身份验证;不评估用户组)
  • 因此,我在 API Gateway 中使用了 AWS IAM Authorizer,它将评估用户组角色
  • 必须传递 AWS 签名 v4 授权,而不是 JWT(npm 上有一个 postman 插件和几个包)
  • 由于我使用的是 API 网关,我必须将角色策略资源更改为execute-api:Invoke

详细地:

用户角色:

{
  "Version": "2012-10-17",
  "Statement": [
    "Action": [
      "lambda:InvokeFunction",
      "lambda:InvokeAsync"
    ],
   "Resource": [
     "arn:aws:execute-api:region:accountid:api-id/stage/GET/items
    ],
    "Effect": "Allow"
  ]
}
Run Code Online (Sandbox Code Playgroud)

管理员角色:

{
  "Version": "2012-10-17",
  "Statement": [
    "Action": [
      "lambda:InvokeFunction",
      "lambda:InvokeAsync"
    ],
   "Resource": [
     "arn:aws:execute-api:region:accountid:api-id/stage/GET/items
     "arn:aws:execute-api:region:accountid:api-id/stage/*/users
    ],
    "Effect": "Allow"
  ]
}
Run Code Online (Sandbox Code Playgroud)

我必须使用 Postman AWS Signature,而不是将 ID 令牌传递到标头中Authorization,这至少需要一个AccessKey和一个SecretKey. 当我使用 aws-sdk 登录我的用户时,可以检索这两个。aws-sdk-js 以 TypeScript 为例:

import { CognitoUserPool, CognitoUser, AuthenticationDetails } from 'amazon-cognito-identity-js';

const userPool = new CognitoUserPool({
  UserPoolId: 'my pool id',
  ClientId: 'my client id'
});

function signIn(username: string, password: string) {
  const authData = {
    Username: username,
    Password: password,
  };

  const authDetails = new AuthenticationDetails(authData);
  const userData = {
    Username: username,
    Pool: userPool,
  };

  const cognitoUser = new CognitoUser(userData);
  cognitoUser.authenticateUser(authDetails, {
    onSuccess: (result) => {
      const cognitoIdpKey = `cognito-idp.${region}.amazonaws.com/${userPool.getUserPoolId()}`;

      const credentials = new AWS.CognitoIdentityCredentials({
        IdentityPoolId: 'identity pool id,
        Logins: {
          [cognitoIdpKey]: result.getIdToken().getJwtToken(),
        }
      });
      AWS.config.update({
        credentials,
      });

      credentials.refreshPromise()
        .then(() => {
          console.log('Success refresh. Required data:', (credentials as any).data.Credentials);
        })
        .catch(err => console.error('credentials refresh', err));
    }
  });
}
Run Code Online (Sandbox Code Playgroud)