OOS操作ECS分组资源的权限策略管理
更新时间:2019-11-15 12:18:25
背景
阿里云账号分为主账号(用户)和子账号(用户)两类,主账号为注册阿里云时的账号,其权限为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实例的分组
- 使用阿里云主账号(或管理员账号)登录到ECS控制台 。
- 选择2台实例,在操作菜单下选择更多 > 实例设置 > 编辑标签。
- 单击新建标签,输入标签键 和标签值,单击确定。
本文中标签键设为TagKey,标签值设为TagValue。 - 单击确定。
- 打开实例列表栏,在搜索框中输入TagKey:TagValue,单击放大镜图标。
- 确认搜索结果为刚刚打标签TagKey:TagValue的实例。
创建OOS模版
- 使用阿里云主账号(或管理员账号)登录到运维编排控制台 。
- 单击我的模版,单击创建模版,选取空白模版,单击YAML。
本文中模版格式选择YAML。 将附件中YAML的模版内容复制到空白模版中(若您对实例分组的标签键值不是TagKey:TagValue,请根据实际情况对模版中TagKey和TagValue进行修改)。
模版任务如下,请确认模版将执行的任务。
- 验证指定标签下是否存在实例。
- 根据标签下是否存在停止的实例选择后续任务。
- 如果标签下存在停止的实例,则启动这些实例。
- 为标签下所有实例安装云助手。
- 在标签下所有实例中运行Shell命令。
填写模板名称,单击创建模版 。
本文中,模版名称设为TestOperatingByGroups。- 在我的模版栏,可查看成功创建的模版TestOperatingByGroups。
创建子账号(用户)
- 使用阿里云主账号(或管理员账号)登录RAM控制台
- 在左侧导航栏的人员管理菜单下,单击用户 > 新建用户。
- 输入登录名称及显示名称。
本文中的登录名称及显示名称均设为subUser1ForOOS。 - 勾选控制台密码登录,单击自定义登录密码并填写要设置的子账号密码。
- 单击确定。
- 在用户栏中可查看成功创建的新账号。
创建自定义权限策略
- 使用阿里云主账号登录RAM控制台
- 在左侧导航栏的权限管理菜单下,单击权限策略管理。
- 单击新建权限策略。
创建第一条策略用来管理OOS资源操作。 - 填写策略名称和备注。
本文中策略名称设置为OOSResourceManage。 配置模式选择脚本配置,并将下述的第一段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"
}
单击确定。
- 单击新建权限策略,创建第二条策略用来管理ECS资源操作。
- 填写策略名称和备注。
配置模式选择脚本配置,将下述的第二段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"
}
单击确定。
为子账号(或用户组)授权
- 使用阿里云主账号(或管理员账号)登录RAM控制台。
- 在左侧导航栏的权限管理菜单下,单击授权。
- 单击新增授权。
- 在被授权主体中输入子账号名称(或用户组名称)并选中,在选择权限中选择自定义权限策略,在左侧权限策略名称列表下,单击选择需要授予给子账号(或用户组)的权限策略。
- 本文输入的子账号名称为subUser1ForOOS。
- 本文选择的权限策略名称为OOSResourceManage和ECSResourceManage。
- 在右侧区域框,若撤销对某策略的选择,可单击某条策略的×。
- 单击确定。
- 单击完成。
执行OOS模版
- 使用主账号(或管理员账号)登录RAM概览,在右侧获取子账号登录地址。
- 退出主账号(或管理员账号)的登录,访问刚获取的子账号登录地址,登录子账号。
- 本文中登录的子账号为subUser1ForOOS。
- 本文中登录的子账号为subUser1ForOOS。
- 登录成功后,进入运维编排控制台 。
- 单击我的模版,找到TestOperatingByGroups模版,单击创建执行。
- 单击 下一步,设置参数。
- 设置参数。
- commandContent 将要执行的shell命令。
- rateControl 模版执行时任务循环的并发速率及最大失败任务数。
- 单击 下一步,确认,单击创建执行。
- 在执行管理中可查看刚刚创建的执行。
若创建执行成功,且执行状态处于运行中,则表示命令已开始执行。 - 当执行状态转换为成功时,则表示命令执行成功。
- 如需了解执行细节,单击该执行的详情,查看执行日志。
权限策略的补充验证
OOS模版执行成功后,表示子账号subUser1ForOOS的权限策略支持模版TestOperatingByGroups执行需要的权限,也可在OOS控制台验证子账号无法执行未授权的模版。另外,若想验证子账号无法对标签以外实例的操作,可在登录子账号subUser1ForOOS后,通过Open Api 调试台对可操作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 }}"
}
}
}