AWS API 网关的访问权限

Access permissions on AWS API Gateway

我正在构建一个应用程序,用户可以通过 Rest 访问 DynamoDb 中的某些数据 API。

我想到的是:

  1. 用户访问 API 网关,由 Cognito 用户池验证;
  2. API网关调用Lambda函数(写在Python);
  3. Lambda 函数访问 DynamoDB 和 returns 数据。

我希望能够根据用户限制对 DynamoDb 的访问级别。最初我以为Lambda函数可以从用户那里继承它的权限,但是这不行,因为它需要一个执行角色。

实现此目标的最佳方法是什么?例如,我是否可以将用户信息传递给 Lambda 函数,而 Lambda 函数又可以在访问 DynamoDb 之前担任此角色?如果是这样,将不胜感激。

看看SpaceFinder - Serverless Auth Reference App and Use API Gateway Lambda Authorizers

借助 Cognito,您可以使用 RBAC:

Amazon Cognito identity pools assign your authenticated users a set of temporary, limited privilege credentials to access your AWS resources. The permissions for each user are controlled through IAM roles that you create. You can define rules to choose the role for each user based on claims in the user's ID token. You can define a default role for authenticated users. You can also define a separate IAM role with limited permissions for guest users who are not authenticated.

因此您可以为每个用户创建特定的角色,尽管使用群组会更好

对于 Lambda 授权人,您可以创建自己的策略。 awslabs.

中有一个示例

除了 blueCat 的回答之外,我还简要地尝试了授予我的 Lambda 函数 sts:AssumeRole 权限,然后允许它承担通过 API 调用它的 Cognito 用户的角色。然后,我可以使用它来获取一组新的凭据,并使用 Cognito 用户的权限执行一些 activity。 lambda 中的代码大致是:

def lambda_handler(event, context):
    sts_client = boto3.client('sts')
    role = event['requestContext']['authorizer']['claims']['cognito:roles']
    cognito_role = sts_client.assume_role(
        RoleArn=role,
        RoleSessionName='lambda-session',
        DurationSeconds=3600
    )
    credentials = cognito_role['Credentials']
    sess = boto3.session.Session(
        aws_access_key_id=credentials['AccessKeyId'], 
        aws_secret_access_key=credentials['SecretAccessKey'],
        aws_session_token=credentials['SessionToken']
    )
    # Do something as the assumed user, e.g. access S3
    s3_client = sess.client('s3')
    # Do stuff here...

虽然这有效,但我发现承担角色和获取 S3 客户端大约需要 0.5 秒的开销,而且我无法在函数调用之间重复使用此会话,因为它是特定于用户的。因此这种方法不太适合我的应用。

我决定让我的 Lambda 完全访问相关的 DynamoDb 表,并使用 Cognito 用户组和 Lambda 授权方来限制个人用户能够调用的 API 部分.

我也处理过这个问题,但我用 Node.js 实现了我的解决方案,我想虽然你的问题是 Python 实现,但也许有人会偶然发现这个问题来寻找用 JS 回答,我认为这可以帮助下一个出现的人。

听起来您正试图在用户使用自定义属性针对您的 Cognito 用户池获得 Authenticated 凭据后想出一个有效的 Authorization 策略。

我创建了一个库,用于导出一些函数,这些函数允许我为 已验证 用户捕获 UserPoolIdUsername 所以我可以在我的 lambda 中捕获我需要的 custom:<attribute>,这样我实现的条件就可以将 API 消耗到我需要为每个用户提供授权的剩余 AWS 服务 由我的应用程序验证

这是我的图书馆:

import AWS from "aws-sdk";
// ensure correct AWS region is set
AWS.config.update({
    region: "us-east-2"
});

// function will parse the user pool id from a string
export function parseUserPoolId(str) {
    let regex = /[^[/]+(?=,)/g;
    let match = regex.exec(str)[0].toString();

    console.log("Here is the user pool id: ", match);

    return match.toString();
}

// function will parse the username from a string
export function parseUserName(str) {
    let regex = /[a-z,A-Z,0-9,-]+(?![^:]*:)/g;
    let match = regex.exec(str)[0].toString();

    console.log("Here is the username: ", match);

    return match.toString();
}

// function retries UserAttributes array from cognito
export function getCustomUserAttributes(upid, un) {
    // instantiate the cognito IdP
    const cognito = new AWS.CognitoIdentityServiceProvider({
        apiVersion: "2016-04-18"
    });

    const params = {
        UserPoolId: upid,
        Username: un
    };

    console.log("UserPoolId....: ", params.UserPoolId);
    console.log("Username....: ", params.Username);

    try {
        const getUser = cognito.adminGetUser(params).promise();
        console.log("GET USER....: ", getUser);
        // return all of the attributes from cognito
        return getUser;
    } catch (err) {
        console.log("ERROR in getCustomUserAttributes....: ", err.message);
        return err;
    }
}

实施此库后,您需要为其创建授权策略的任何 lambda 都可以使用它。

在你的 lambda 内部,你需要导入上面的库(我省略了下面的导入语句,你需要添加它们以便你可以访问导出的函数),你可以这样实现它们的使用::

export async function main(event, context) {
  const upId = parseUserPoolId(
    event.requestContext.identity.cognitoAuthenticationProvider
  );
  // Step 2 --> Get the UserName from the requestContext
  const usrnm = parseUserName(
    event.requestContext.identity.cognitoAuthenticationProvider
  );
  // Request body is passed to a json encoded string in
  // the 'event.body'
  const data = JSON.parse(event.body);

  try {
    // TODO: Make separate lambda for AUTHORIZATION
    let res = await getCustomUserAttributes(upId, usrnm);

    console.log("THIS IS THE custom:primaryAccountId: ", res.UserAttributes[4].Value);
    console.log("THIS IS THE custom:ROLE: ", res.UserAttributes[3].Value);
    console.log("THIS IS THE custom:userName: ", res.UserAttributes[1].Value);

    const primaryAccountId = res.UserAttributes[4].Value;

  } catch (err) {
    // eslint-disable-next-line
    console.log("This call failed to getattributes");
    return failure({
      status: false
    });
  }
}


Cognito 的响应将提供一个包含您需要的自定义属性的数组。 Console.log Cognito 的响应 console.log("THIS IS THE Cognito response: ", res.UserAttributes); 并检查 CloudWatch 日志中所需属性的索引号,并调整所需的索引:

res.UserAttributes[n]

现在你有了一个 authorization 机制,你可以在你的 lambda 中使用不同的条件来允许用户 POST 到 DynamoDB,或者从你的应用程序使用正确的任何其他 AWS 服务每个经过身份验证的用户的授权。