注意:

使用 OCI 函数和 OCI 队列授权用户功能,而不向审批人公开管理权限

简介

对于许多企业来说,更新用户功能是关键需求,特别是当授权给用户的权限像控制台功能或 API 密钥一样敏感时。但是,就我们在 Oracle Cloud Infrastructure (OCI) 文档中发现的情况而言,即使存在明确允许用户的 Oracle Cloud Infrastructure Identity and Access Management (OCI IAM) 策略,管理员组中只有用户才能授权用户功能。有关更多信息,请参见管理用户

本教程演示了针对以下场景的解决方案:用户不在 OCI IAM 域的管理员组中,但仍需要通过利用 OCI Connector Hub 新发布的功能来集成 OCI 队列和 OCI 函数来授权用户功能。

解决方案体系结构

插图 SolutionArchitecture.png 的说明

目标

任务 1:创建从 OCI 队列到 OCI 函数的消息传送渠道

解决方案的关键部分是通过更改用户功能与审批人批准请求所需的权限分离所需的权限。

  1. 为传入请求创建 OCI 队列。有关详细信息,请参阅创建队列

  2. 创建用于授权用户的 OCI 函数。有关详细信息,请参阅创建函数

  3. 通过 OCI Connector Hub 配置 OCI 队列和 OCI 函数集成。确保在创建 OCI 队列时指定源,并且目标应为 OCI 函数。在本教程中,我们将可选任务留空。有关详细信息,请参阅宣布 OCI 队列在 OCI Connector Hub 中作为源的可用性

任务 2:配置 OCI IAM 策略和动态组

在将审批人的角色拆分为 OCI 队列以接收请求和 OCI 函数以运行请求后,我们需要配置严格的 OCI IAM 策略以确保权限不会被滥用。由于我们构建此解决方案是为了支持坚持使用根区间进行实施的客户,因此我们将演示 OCI IAM 部分的根区间中的所有配置。

  1. 仅允许审批人将队列消息推送到目标 OCI 队列。

    Allow group 'testApprover' to use queues in tenancy
    

    通过添加此策略,我们允许 testApprover 组中的用户使用该队列接收控制台访问请求。通过仅指定对队列推送资源类型的权限,我们可以对组施加更多限制,如下例所示。

    use queue-push in compartment <compartment> where target.queue.id = '<queue_ocid>'
    
  2. 通过指定以下匹配规则,将动态组配置为包括 OCI 函数。

    ALL{resource.type='fnfunc',resource.id='ocid.fnfunc.oc1.....'}
    

    然后,此动态组将获得 Oracle Identity Cloud Service 角色的授权以管理域中的用户。

  3. 配置动态组 Oracle Identity Cloud Service 角色。

    IDCS 域角色

    插图 DomainRole.png 的说明

  4. 将 OCI 函数配置为只能由 OCI 队列调用。以下示例仅将调用的源限制为队列,我们实际上可以通过对资源使用标记来使其更严格。有关更多信息,请参阅使用标记管理访问

    Allow service faas to use functions-family in tenancy where request.principal.type='queues'
    

任务 3:编写 OCI 函数代码

我们需要为 OCI Functions 编写一段 Python 代码,以实际运行从 OCI 队列中获取的请求。

  1. OCI 队列消息将传递到 data 对象中的函数。

    def handler(ctx, data: bytes = None) -> response.Response:
        try:
        # Parse the message from the OCI Queue
            if data:
            message = json.loads(data.getvalue().decode('utf-8'))
            else:
            message = "no useremail received"
    
  2. 使用资源主用户进行验证。

    注:以下代码行可能在 IDE 中不起作用。

    identity = IdentityClient({}, signer=oci.auth.signers.get_resource_principals_signer(), region=region)
    
  3. 转换传递到用户 Oracle Cloud 标识符 (OCID) 的用户电子邮件。

    def get_user_ocid_by_email(identity_client,email,tenancy_id):
        # List all users in the tenancy
        users = oci.pagination.list_call_get_all_results(identity_client.list_users,tenancy_id).data
    
        # Find the user with the matching email address
        for user in users:
            if user.email.lower() == email.lower():
                return user.id
    
        return None
    
  4. 使用 IdentityClient 函数使用资源主体更新用户功能。

    # Get the user by email address
    user_ocid = get_user_ocid_by_email(identity,user_email,tenancy)
    
    # Update user capabilities (example: enable API keys)
    update_details = oci.identity.models.UpdateUserCapabilitiesDetails(
        can_use_api_keys=True,
        can_use_auth_tokens=True,
        can_use_console_password=True,
        can_use_customer_secret_keys=True,
        can_use_db_credentials=True,
        can_use_o_auth2_client_credentials=True,
        can_use_smtp_credentials=True
    )
    
    # Update the user
    identity.update_user_capabilities(user_ocid, update_details)
    
  5. 将函数代码部署到我们刚刚创建的 OCI 函数中。有关部署 OCI 函数的详细步骤,请参阅 OCI 函数的配置说明

任务 4:测试更改

通过向目标队列发送消息来测试更改。我们可以使用 OCI 控制台或使用任何 SDK,包括 OCI Cloud Shell。

发送邮件

插图 send-message.png 的说明

检查

插图 examine.png 的说明

疑难解答

配置 OCI 函数以使用 OCIR

如果您使用 OCIR 作为 OCI 功能的存储库,则可能会遇到一些问题,因此找到解决方案并不容易,因为目前没有明确指南专门证明可以避免此类问题。

  1. 为 OCIR 存储库和 OCI 功能配置特定区间作为函数上下文。默认情况下,OCIR 资料档案库的上下文指向根区间,即使您按照控制台上的说明页在 Cloud shell 命令下运行也是如此。

    fn update context oracle.compartment-id ocid1.tenancy.oc1.....
    

    注:oracle.compartment-id 一样,此部分非常具有误导性,这使得人们认为此属性适用于函数和 OCIR,但是,对于 OCIR,我们有一个单独的属性,即 image-compartment-id。因此,如果您使用命名区间来运行函数并存储映像,请确保使用以下 OCI Cloud Shell 命令显式设置两个区间 ID。此外,还必须配置适当的 OCI IAM 策略,以允许 OCIR 与函数之间的操作(如果它们来自不同的命名区间)。

    fn update context oracle.image-compartment-id <compartment-ocid>
    fn update context oracle.compartment-id <compartment-ocid>
    

    如果无法正确执行此操作,您将遇到有线 403 错误,并且由于您可能甚至不知道 image-compartment-id,因此很难找到线索。

  2. 在 OCI Cloud Shell 从可访问 docker.io 的网络环境启动时,将函数配置为使用 OCIR,因为我们必须应用 docker API 来处理映像,通常 OCI 服务网络不允许您访问。如果您使用 OCI Cloud Shell,建议您使用公共网络进行容器部署。

    有关详细信息,请参阅函数:使用 Cloud Shell 入门

  3. 此处的另一个潜在阻塞器是尝试将队列消息传递给函数输入时。在其他关于如何传递变量的文章中可以找到多个引用,但它实际上就像在 Python 代码的 data 对象中输入 json 和接收一样简单。

    注:避免使用带有单引号或不带引号的 Javascript 类型的 json,因为目前只有严格的语法可以由 OCI 队列识别。

    {"name":"John"}
    

确认

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者访问 Oracle Learning YouTube 渠道上的更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心