当使用Cognito组角色时,AWS IAM SDK会获取特定角色的所有策略文档

如何解决当使用Cognito组角色时,AWS IAM SDK会获取特定角色的所有策略文档

我正在使用AWS Cognito用户池组来管理API Gateway API的权限。我相信这是网上论坛的有效用法,如文档所示:https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html#using-groups-to-control-permission-with-amazon-api-gateway

不幸的是,据我所知,该用例的文档基本上是不存在的(除了那段小段落)。我试图弄清楚它如何与自定义API网关授权者Lambda函数一起使用。我已经创建了一个测试角色,并将其分配给了Cognito中的一个测试组。该角色具有单个策略,但将来该角色将具有多个策略。

现在,在我的自定义授权者中,我已经在验证访问令牌等,并且一切正常。我现在正在尝试在使用组/角色/策略中添加此细粒度的访问控制。我已经安装了IAM SDK,并一直在挖掘以查看需要进行哪些呼叫。似乎没有简单的方法来获得角色及其所有策略。我想出的最好的方法如下:

public async Task<IEnumerable<string>> GetGroupPermissionsForUserAsync(Models.User user)
{
    if (!user.UserAttributes.TryGetValue(UserAttributeName.UserPoolId,out var userPoolId))
    {
        return null;
    }

    var groups = await GetUserGroups(user.Username,userPoolId);
    var groupRoleArn = groups.FirstOrDefault()?.RoleArn;
    var policies = new List<string>();
    if (!string.IsNullOrWhiteSpace(groupRoleArn))
    {
        var roleName = groupRoleArn.Substring(groupRoleArn.IndexOf('/') + 1);
        var rolePoliciesResponse = await _iamClient.ListAttachedRolePoliciesAsync(new ListAttachedRolePoliciesRequest { RoleName = roleName });
        
        foreach (var rolePolicy in rolePoliciesResponse.AttachedPolicies)
        {
            var policyVersionsResponse = await _iamClient.ListPolicyVersionsAsync(new ListPolicyVersionsRequest
            {
                PolicyArn = rolePolicy.PolicyArn
            });

            var latestPolicyVerson = policyVersionsResponse.Versions.OrderByDescending(x => x.CreateDate).LastOrDefault();
            var policyVersionResponse = await _iamClient.GetPolicyVersionAsync(new GetPolicyVersionRequest
            {
                PolicyArn = rolePolicy.PolicyArn,VersionId = latestPolicyVerson.VersionId
            });
            
            if (!string.IsNullOrWhiteSpace(policyVersionResponse?.PolicyVersion.Document))
            {
                policies.Add(HttpUtility.UrlDecode(policyVersionResponse.PolicyVersion.Document));
            }
        }
    }

    return policies;
}

private async Task<IEnumerable<GroupType>> GetUserGroups(string username,string userPoolId)
{
    string nextToken = null;
    var groups = new List<GroupType>();
    do
    {
        var response = await _cognitoClient.AdminListGroupsForUserAsync(new AdminListGroupsForUserRequest
        {
            Username = username,UserPoolId = userPoolId
        });

        groups.AddRange(response.Groups);

        nextToken = response.NextToken;
    } while (!string.IsNullOrWhiteSpace(nextToken));

    return groups.OrderBy(x => x.Precedence);
}

如您所见,我必须打很多电话才能获得角色策略。

  1. _cognitoClient.AdminListGroupsForUserAsync从Cognito获取用户组。
  2. _iamClient.ListAttachedRolePoliciesAsync获取与角色关联的策略。
  3. _iamClient.ListPolicyVersionsAsync获取每个策略的版本。
  4. _iamClient.GetPolicyVersionAsync以获取最终包含策略文档的单个策略版本。

ListPolicyVersionsAsync返回带有文档属性的响应,但由于某种原因它始终为null,因此需要额外的GetPolicyVersionAsync调用。

这不仅增加了延迟(这是授权函数的一个问题,在该函数中,每次对API的调用都将通过此代码运行),但它给我留下了一堆我需要某种方式的单独策略删除重复数据,然后再返回API网关。

真的没有更容易/更快的方法吗?是否可以通过较少的呼叫获得所有这些信息,并且是否可以在规则重叠的情况下展平策略?

解决方法

使用Cognito和API Gateway设置授权的方法有很多,很难在不知道您试图通过API Gateway方法访问哪些AWS资源的情况下说出最适合您的方法。例如,您的API Gateway方法是与访问数据库信息的lambda方法集成在一起,还是直接调用服务?

如果我理解正确,那么您希望合并用户可能所属的(可能)多个组的权限,以便提出用于该特定请求的一组权限。因此,user角色可以允许访问用户数据,而admin角色可以进一步扩展对其他管理端点的访问?

假设您有一个非常标准的方案,其中API网关方法与lambda方法集成在一起,然后该lambda方法访问诸如数据库之类的基础AWS资源,那么您可以按以下方式使用自定义授权程序:

如果自定义授权者仅返回执行请求的API方法所需的权限,则可以大大简化操作:

{
  "principalId": "sub-from-ID-token","policyDocument": {
    "Version": "2012-10-17","Statement": [
      {
        "Action": "execute-api:Invoke","Effect": "Allow","Resource": [
          "arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/address"
        ]
      }
    ]
  }
}

在标准情况下,成功授权的请求将执行包含api逻辑的lambda。此后备Lambda将具有 execution角色,该角色定义了访问受保护资源(例如DynamoDB表中的数据等)的所有权限。因此,每当后备Lambda访问其他AWS资源时,您都不会不必更新多个组角色的权限,而是在系统中的单个位置管理这些权限。

使用此设置,您可以为需要保护的api的每个区域提供一个相当简单的自定义授权器。

例如,为了保护您的/user/*端点,您可以有一个自定义授权者,该授权者仅检查传递给授权者的 ID令牌是否包含user组在其cognito:groups声明中。如果是这样,则您返回执行请求的api方法(execute-api:Invoke)所需的权限。然后,您可能会有另一个自定义授权者,通过检查/admin/*组是否在ID令牌的admin声明中,来保护cognito:groups路由,等等。

自定义授权者响应的缓存

每个自定义授权者都有一个可选的TTL设置,该设置确定其响应(对于特定的JWT令牌)将被缓存多长时间。这有助于减少任何lambda预热时间,或减少授权者中其他标注所花费的时间。

如果授权者采用多种方法,例如:

  • 获取/用户/地址
  • POST /用户/地址
  • 获取/ user / mobile

然后必须注意,将为所有这些方法缓存成功授权的响应,直到缓存超时为止。因此,自定义授权者返回的策略必须返回定义用户可以执行的所有方法的资源列表,或者使用通配符。

涵盖所有/user/*条路线的授权者的示例响应

{
  "principalId": "sub-from-ID-token","Resource": [
          "arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/address","arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:POST/user/address","arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:GET/user/mobile"
        ]
      }
    ]
  }
}

涵盖所有/user/*路由的授权者的示例响应(使用通配符)

{
  "principalId": "sub-from-ID-token","Resource": [
          "arn:aws:execute-api:eu-west-1:1234567890:qwerty:prod:*/user/*"
        ]
      }
    ]
  }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-