阿里云账号分为主账号(用户) 和子账号(用户)两类,主账号为注册阿里云时的账号,其权限为root,出于安全考虑,建议实际操作时采用子账号。而操作员工的职责不同,不同子账号需要的权限也不同。此时,子账号权限策略的有效管理就很重要。本文将介绍下,当某员工通过子账号,使用运维编排服务(OOS)执行某模版,来完成一些例行运维任务时,如何既使子账号顺利完成相应操作,又最大程度保障账号的安全。

场景介绍

某公司账号下购买了若干台ECS实例,其中2台被打上标签TagKey:TagValue进行了分组,某员工甲被分配的子账号为subUser1ForOOS,甲定期通过该账号在OOS中执行一个模版T,模版执行的任务是对标签TagKey:TagValue分组下的ECS实例批量执行shell指令。即该员工具有对模版T的只读和执行权限,以及有模版任务涉及API(如RunCommand)的操作权限,且可操作的API仅对标签TagKey:TagValue分组下的实例有效。

解决方案

为满足上述场景,权限管理要分两方面,即OOS资源操作和ECS资源操作。

OOS方面 权限策略包括对模版的只读权限、对模版T的执行权限、对执行的查询权限。

ECS方面权限策略为对标签TagKey:TagValue下实例的操作权限,且操作权限仅限于模版中涉及的API。

以上的权限策略成功创建后,将其授权给员工甲使用的RAM子用户即可(或具有员工甲相同职责的用户组)。

操作步骤

步骤如下

  • ECS实例的分组
  • 创建OOS模版
  • 创建子账号(用户)
  • 创建自定义权限策略
  • 为子账号授权
  • 子账号执行OOS模版
  • 权限策略的补充验证

ECS实例的分组

  1. 登录 运维编排管理控制台
  2. 选择2台实例,在操作菜单下选择更多>实例设置>编辑标签
  3. 单击新建标签,输入标签键标签值,单击确定

    本文中标签键设为TagKey,标签值设为TagValue。

  4. 单击确定
  5. 打开实例列表栏,在搜索框中输入TagKey:TagValue,单击放大镜图标。
  6. 确认搜索结果为刚刚打标签TagKey:TagValue的实例。

创建OOS模版

  1. 登录运维编排管理控制台
  2. 单击我的模版,单击创建模版,选取空白模版,单击YAML

    本文中模版格式选择YAML。

  3. 将附件中YAML的模版内容复制到空白模版中(若您对实例分组的标签键值不是TagKey:TagValue,请根据实际情况对模版中TagKey和TagValue进行修改)。

  4. 模版任务如下,请确认模版将执行的任务。

    1. 验证指定标签下是否存在实例。
    2. 根据标签下是否存在停止的实例选择后续任务。
    3. 如果标签下存在停止的实例,则启动这些实例。
    4. 为标签下所有实例安装云助手。
    5. 在标签下所有实例中运行Shell命令。
  5. 填写模板名称,单击创建模版

    本文中,模版名称设为TestOperatingByGroups。

  6. 我的模版栏,可查看成功创建的模版TestOperatingByGroups。

创建子账号(用户)

  1. 使用阿里云主账号(或管理员账号)登录RAM控制台
  2. 在左侧导航栏的人员管理菜单下,单击用户>新建用户
  3. 输入登录名称显示名称

    本文中的登录名称及显示名称均设为subUser1ForOOS。

  4. 勾选控制台密码登录,单击自定义登录密码并填写要设置的子账号密码。
  5. 单击确定
  6. 用户栏中可查看成功创建的新账号。

创建自定义权限策略

  1. 使用阿里云主账号登录RAM控制台
  2. 在左侧导航栏的权限管理菜单下,单击权限策略管理
  3. 单击新建权限策略

    创建第一条策略用来管理OOS资源操作。

  4. 填写策略名称备注

    本文中策略名称设置为OOSResourceManage。

  5. 配置模式选择脚本配置,并将下述的第一段JSON策略样例拷贝到策略内容区域,并根据实际情况进行修改(将JSON中所有以$为前缀的变量名替换掉)。

    将第一段JSON中的$AliyunMasterAccountID、$RegionID、$TemplateName1修改为您所使用的阿里云主账号ID、OOS及ECS资源所在地域ID(本文中为cn-hangzhou)、允许子账号可执行的模版名称(本文中为TestOperatingByGroups。))。

    操作OOS的策略

    该段策略表示:被授权RAM用户具有对$RegionID地域下模版的只读权限、对模版$TemplateName1的执行权限、对$RegionID地域下OOS执行的查询权限。

    { 
    "Statement": [
    
        {
            "Action": [
                "oos:StartExecution",
                "oos:List*",
                "oos:Get*"
            ],
            "Resource": [
                "acs:oos:$RegionID:$AliyunMasterAccountID:template/$TemplateName1",
                "acs:oos:$RegionID:$AliyunMasterAccountID:execution/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "oos:List*",
                "oos:Get*"
            ],
            "Resource": [
                "acs:oos:$RegionID:$AliyunMasterAccountID:template/*"
            ],
            "Effect": "Allow"
        }
    ],
    "Version": "1"
    }            
  6. 单击确定

  7. 单击新建权限策略,创建第二条策略用来管理ECS资源操作。
  8. 填写策略名称备注
  9. 配置模式选择脚本配置,将下述的第二段JSON策略样例拷贝到策略内容区域,并根据实际情况进行修改(将JSON中所有以$为前缀的变量名替换掉)。将第二段JSON中的$AliyunMasterAccountID、$TagKey、$TagValue、$RegionID修改为您所使用的阿里云主账号ID、实例所属标签键和标签值(本文中根据ECS实例的分组,键及值应设为TagKey和TagValue)、OOS及ECS资源所在地域ID。(本文中为cn-hangzhou)。

    操作ECS的策略

    该段策略表示:被授权RAM用户具有对标签$TagKey:$TagValue下实例的操作权限,且仅可操作模版中涉及的API。

    {
    "Statement": [
    
        {
            "Effect": "Allow",
            "Action": [
                "ecs:DescribeInstances",
                "ecs:RebootInstance"
            ],
            "Resource": "acs:ecs:$RegionID:$AliyunMasterAccountID:instance/*",
            "Condition": {
                "StringEquals": {
                    "ecs:tag/$TagKey": [
                        "$TagValue"
                    ]
                }
            }
        },
    
        {
            "Effect": "Allow",
            "Action": [
                "ecs:DescribeCloudAssistantStatus",
                "ecs:InstallCloudAssistant"
            ],
            "Resource": "acs:ecs:*:$AliyunMasterAccountID:instance/*",
            "Condition": {
                "StringEquals": {
                    "ecs:tag/$TagKey": [
                        "$TagValue"
                    ]
                }
            }
        },
        {
            "Action": "ecs:DescribeTagKeys",
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Action": "ecs:DescribeTags",
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Effect": "Deny",
            "Action": [
                "ecs:DeleteTags",
                "ecs:UntagResources",
                "ecs:CreateTags",
                "ecs:TagResources"
            ],
            "Resource": "*"
        },
    
         {
            "Effect": "Allow",
            "Action": [
                "ecs:RunCommand"
            ],
            "Resource": "acs:ecs:*:$AliyunMasterAccountID:instance/*",
            "Condition": {
                "StringEquals": {
                    "ecs:tag/$TagKey": [
                        "$TagValue"
                    ]
                }
            }
        },
        {
            "Action": [
                "ecs:RunCommand"
            ],
            "Resource": [
                "acs:ecs:*:$AliyunMasterAccountID:command/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "ecs:DescribeInvocations",
                "ecs:DescribeInvocationResults"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        }
    ],
    "Version": "1"
    }            
  10. 单击确定

为子账号(或用户组)授权

  1. 使用阿里云主账号(或管理员账号)登录RAM控制台
  2. 在左侧导航栏的权限管理菜单下,单击授权
  3. 单击新增授权
  4. 被授权主体中输入子账号名称(或用户组名称)并选中,在选择权限中选择自定义权限策略,在左侧权限策略名称列表下,单击选择需要授予给子账号(或用户组)的权限策略。
    • 本文输入的子账号名称为subUser1ForOOS。
    • 本文选择的权限策略名称为OOSResourceManage和ECSResourceManage。
    • 在右侧区域框,若撤销对某策略的选择,可单击某条策略的×。
  5. 单击确定
  6. 单击完成

执行OOS模版

  1. 使用主账号(或管理员账号)登录RAM控制台,在右侧获取子账号登录地址。
  2. 退出主账号(或管理员账号)的登录,访问刚获取的子账号登录地址,登录子账号。

    本文中登录的子账号为subUser1ForOOS。

  3. 登录成功后,进入运维编排控制台
  4. 单击我的模版,找到TestOperatingByGroups模版,单击创建执行
  5. 单击下一步,设置参数
  6. 设置参数。
    • commandContent将要执行的shell命令。
    • rateControl模版执行时任务循环的并发速率及最大失败任务数。
  7. 单击下一步,确认,单击创建执行
  8. 执行管理中可查看刚刚创建的执行。

    若创建执行成功,且执行状态处于运行中,则表示命令已开始执行。

  9. 当执行状态转换为成功时,则表示命令执行成功。
  10. 如需了解执行细节,单击该执行的详情,查看执行日志

权限策略的补充验证

OOS模版执行成功后,表示子账号subUser1ForOOS的权限策略支持模版TestOperatingByGroups执行需要的权限,也可在OOS控制台验证子账号无法执行未授权的模版。另外,若想验证子账号无法对标签以外实例的操作,可在登录子账号subUser1ForOOS后,通过OpenAPI调试台对可操作API权限进行验证。

附件:OOS模版在某标签下的所有ECS实例中执行命令

  • 模板内容(YAML格式)
FormatVersion: OOS-2019-06-01
Description:
  en: Run a specific command in specified ECS instances.
  zh-cn: 对某些实例执行具体命令。
  name-en: RunSpecificCommandInSpecifiedInstances
  name-zh-cn: 指定的实例上执行具体命令。
Parameters:
  commandContent:
    Description:
      en: commandContent.
      zh-ch: shell指令内容。
    Type: String
    Default: echo hello
  rateControl:
    Description:
      en: Concurrency rate of task execution.
      zh-cn: 任务执行的并发比率。
    Type: Json
    AssociationProperty: RateControl
    Default:
      Mode: Concurrency
      MaxErrors: 0
      Concurrency: 100%
Tasks:
  - Name: CheckInstancesExistInTag
    Action: 'ACS::CheckFor'
    Description:
      en: Check for whether instances exist in specified tag.
      zh-cn: 验证指定标签下是否存在实例。
    Properties:
      Service: ECS
      API: DescribeInstances
      Parameters:
        Tags:
          - Key: TagKey
            Value: TagValue
      NotDesiredValues:
        - []
      PropertySelector: Instances.Instance|map(.InstanceId)
    Outputs:
      instanceIds:
        Type: List
        ValueSelector: 'Instances.Instance[].InstanceId'
      stoppedInstanceIdsExist:
        Type: String
        ValueSelector: >-
          Instances.Instance[]|select(.Status=="Stopped")|.InstanceId|[.]|all|tostring
      stoppedInstanceIds:
        Type: List
        ValueSelector: 'Instances.Instance[]|select(.Status=="Stopped")|.InstanceId'
  - Name: whetherStoppedInstancesExist
    Action: 'ACS::Choice'
    Description:
      en: Choose next task by stopped instances exist.
      zh-cn: 根据标签下是否存在停止的实例选择后续任务。
    Properties:
      DefaultTask: installCloudAssistant
      Choices:
        - When:
            'Fn::Equals':
              - 'true'
              - '{{ CheckInstancesExistInTag.stoppedInstanceIdsExist }}'
          NextTask: startInstances
  - Name: startInstances
    Action: 'ACS::ECS::StartInstance'
    Description:
      en: Start Instance.
      zh-cn: 启动标签下停止的实例。
    Properties:
      instanceId: '{{ ACS::TaskLoopItem }}'
    Loop:
      Items: '{{ CheckInstancesExistInTag.stoppedInstanceIds }}'
      RateControl: '{{ rateControl }}'
  - Name: installCloudAssistant
    Action: 'ACS::ECS::InstallCloudAssistant'
    Description:
      en: Install cloud assostant for ECS instances in tag.
      zh-cn: 给标签下所有实例安装云助手。
    Properties:
      instanceId: '{{ ACS::TaskLoopItem }}'
    Loop:
      Items: '{{ CheckInstancesExistInTag.instanceIds }}'
      RateControl: '{{ rateControl }}'
  - Name: runCommand
    Action: 'ACS::ECS::RunCommand'
    Description:
      en: Run cloud assostant command on ECS instances in tag.
      zh-cn: 在标签下所有实例中运行云助手命令。
    Properties:
      commandContent: '{{ commandContent }}'
      commandType: RunShellScript
      instanceId: '{{ ACS::TaskLoopItem }}'
    Loop:
      Items: '{{ CheckInstancesExistInTag.instanceIds }}'
      RateControl: '{{ rateControl }}'
      Outputs:
        invocationOutputs:
          AggregateType: 'Fn::ListJoin'
          AggregateField: invocationOutput
    Outputs:
      invocationOutput:
        Type: String
        ValueSelector: .invocationOutput
Outputs:
  invocationOutput:
    Type: List
    Value: '{{ runCommand.invocationOutputs }}'
  • 模板内容(JSON格式)
{
  "FormatVersion": "OOS-2019-06-01",
  "Description": {
    "en": "Run a specific command in specified ECS instances.",
    "zh-cn": "对某些实例执行具体命令。",
    "name-en": "RunSpecificCommandInSpecifiedInstances",
    "name-zh-cn": "指定的实例上执行具体命令。"
  },
  "Parameters": {
    "commandContent": {
      "Description": {
        "en": "commandContent.",
        "zh-ch": "shell指令内容。"
      },
      "Type": "String",
      "Default": "echo hello"
    },
    "rateControl": {
      "Description": {
        "en": "Concurrency rate of task execution.",
        "zh-cn": "任务执行的并发比率。"
      },
      "Type": "Json",
      "AssociationProperty": "RateControl",
      "Default": {
        "Mode": "Concurrency",
        "MaxErrors": 0,
        "Concurrency": "100%"
      }
    }
  },
  "Tasks": [
    {
      "Name": "CheckInstancesExistInTag",
      "Action": "ACS::CheckFor",
      "Description": {
        "en": "Check for whether instances exist in specified tag.",
        "zh-cn": "验证指定标签下是否存在实例。"
      },
      "Properties": {
        "Service": "ECS",
        "API": "DescribeInstances",
        "Parameters": {
          "Tags": [
            {
              "Key": "TagKey",
              "Value": "TagValue"
            }
          ]
        },
        "NotDesiredValues": [
          []
        ],
        "PropertySelector": "Instances.Instance|map(.InstanceId)"
      },
      "Outputs": {
        "instanceIds": {
          "Type": "List",
          "ValueSelector": "Instances.Instance[].InstanceId"
        },
        "stoppedInstanceIdsExist": {
          "Type": "String",
          "ValueSelector": "Instances.Instance[]|select(.Status==\"Stopped\")|.InstanceId|[.]|all|tostring"
        },
        "stoppedInstanceIds": {
          "Type": "List",
          "ValueSelector": "Instances.Instance[]|select(.Status==\"Stopped\")|.InstanceId"
        }
      }
    },
    {
      "Name": "whetherStoppedInstancesExist",
      "Action": "ACS::Choice",
      "Description": {
        "en": "Choose next task by stopped instances exist.",
        "zh-cn": "根据标签下是否存在停止的实例选择后续任务。"
      },
      "Properties": {
        "DefaultTask": "installCloudAssistant",
        "Choices": [
          {
            "When": {
              "Fn::Equals": [
                "true",
                "{{ CheckInstancesExistInTag.stoppedInstanceIdsExist }}"
              ]
            },
            "NextTask": "startInstances"
          }
        ]
      }
    },
    {
      "Name": "startInstances",
      "Action": "ACS::ECS::StartInstance",
      "Description": {
        "en": "Start Instance.",
        "zh-cn": "启动标签下停止的实例。"
      },
      "Properties": {
        "instanceId": "{{ ACS::TaskLoopItem }}"
      },
      "Loop": {
        "Items": "{{ CheckInstancesExistInTag.stoppedInstanceIds }}",
        "RateControl": "{{ rateControl }}"
      }
    },
    {
      "Name": "installCloudAssistant",
      "Action": "ACS::ECS::InstallCloudAssistant",
      "Description": {
        "en": "Install cloud assostant for ECS instances in tag.",
        "zh-cn": "给标签下所有实例安装云助手。"
      },
      "Properties": {
        "instanceId": "{{ ACS::TaskLoopItem }}"
      },
      "Loop": {
        "Items": "{{ CheckInstancesExistInTag.instanceIds }}",
        "RateControl": "{{ rateControl }}"
      }
    },
    {
      "Name": "runCommand",
      "Action": "ACS::ECS::RunCommand",
      "Description": {
        "en": "Run cloud assostant command on ECS instances in tag.",
        "zh-cn": "在标签下所有实例中运行云助手命令。"
      },
      "Properties": {
        "commandContent": "{{ commandContent }}",
        "commandType": "RunShellScript",
        "instanceId": "{{ ACS::TaskLoopItem }}"
      },
      "Loop": {
        "Items": "{{ CheckInstancesExistInTag.instanceIds }}",
        "RateControl": "{{ rateControl }}",
        "Outputs": {
          "invocationOutputs": {
            "AggregateType": "Fn::ListJoin",
            "AggregateField": "invocationOutput"
          }
        }
      },
      "Outputs": {
        "invocationOutput": {
          "Type": "String",
          "ValueSelector": ".invocationOutput"
        }
      }
    }
  ],
  "Outputs": {
    "invocationOutput": {
      "Type": "List",
      "Value": "{{ runCommand.invocationOutputs }}"
    }
  }
}