亚马逊AWS官方博客

亚马逊云科技标签策略中国区替代方案

背景

亚马逊云科技提供的多账户结构体系能够让用户安全且有效地扩展其云上业务。用户可以借助亚马逊云科技Organizations服务集中管理其组织中跨账号的资源。其中亚马逊Organization服务国际区提供的标签策略可以帮助用户在组织账户中规范标签的使用。在标签策略中,用户可以规范标签的键值以及标签策略作用的资源范围。

在本文撰写之时,亚马逊云科技 Organizations 的标签策略功能尚未在中国区(北京区和宁夏区)上线。为了方便已在亚马逊云科技国际区使用标签策略的用户将标签策略迁移到亚马逊科技中国区,本文利用亚马逊云科技 Identity and Access Management(IAM)策略中的显式拒绝(Explicit Deny)语句(Statement)和条件控制(Condition)来替代标签策略。另外,根据一般用户的使用习惯(用户往往需要在创建资源时强制添加指定的标签),也可以通过IAM策略来强制用户在创建资源时添加标签。

理解标签策略

首先,标签策略是用来规范标签键值的使用,具体来说标签策略可以规范标签键的大小写和标签值是否符合定义值范围。但是,当创建资源时,标签策略并不会强制资源必须添加标签策略定义的标签键值。如果需要在创建资源时强制添加定义标签,我们需要额外的IAM策略(后面的章节会有具体的讲解)。

以下是一个标签策略(标签策略语法)的例子:

{
  "tags": {
    "Name": {
      "tag_key": {
        "@@assign": "Name"
      },
      "enforced_for": {
        "@@assign": [
          "ec2:instance",
          "ec2:volume"
        ]
      }
    },
    "Owner": {
      "tag_key": {
        "@@assign": "Owner"
      },
      "tag_value": {
        "@@assign": [
          "*@company.com",
          "*@company.digital"
        ]
      },
      "enforced_for": {
        "@@assign": [
          "ec2:instance",
          "ec2:volume"
        ]
      }
    }
}

上述的标签策略可以解读为,如果在请求创建EC2或者EBS的过程中添加了标签“Name”或者“Owner”, “Name”/“Owner”键的大小写必须符合规范, 而“Owner”的值必须符合“*@company.com”或者“*@comapny.digital”,另外,如果请求中的标签集不包含“Name”和“Owner”则标签策略不会生效。除此之外,在标签策略的代码中,需要注意的是“tag_key”是用来定义标签键是否需要区分大小写;“tag_value”是用来定义键值范围;“enforced_for”是用来定义标签策略作用的资源。

改标签策略为IAM策略

了解了标签策略的实现原理后,就可以来进行标签策略改写。在上述例子中,标签策略规范了键“Name”的大小写和键“Owner”的大小写以及其值必须符合“*@company.com”或者“*@comapny.digital”;而这两个标签的作用范围都是ec2:instance和ec2:volume服务资源。针对这个例子,我们可以在IAM策略中针对“ec2:CreateTags”操作(Action),使用显示拒绝和条件控制来规范标签,另外也需要添加额外的条件控制来排除在请求中如果没有出现指定标签时,策略带来的影响。

下面就是根据上述的标签策略改写后的IAM策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CaseSensitiveName",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": [
                "arn:aws-cn:ec2:*:*:volume/*",
                "arn:aws-cn:ec2:*:*:instance/*"
            ],
            "Condition": {
                "ForAllValues:StringNotEquals": {
                    "aws:TagKeys": "Name"
                },
                "Null": {
                    "aws:RequestTag/Name": "false"
                }
            }
        },
        {
            "Sid": "RestrictionOwner",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": [
                "arn:aws-cn:ec2:*:*:volume/*",
                "arn:aws-cn:ec2:*:*:instance/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:RequestTag/Owner": [
                        "*@company.com",
                        "*@company.digital"
                    ]
                },
                "Null": {
                    "aws:RequestTag/Owner": "false"
                }
            }
        },
        {
            "Sid": "CaseSensitiveOwner",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": [
                "arn:aws-cn:ec2:*:*:volume/*",
                "arn:aws-cn:ec2:*:*:instance/*"
            ],
            "Condition": {
                "ForAllValues:StringNotEquals": {
                    "aws:TagKeys": "Owner"
                },
                "Null": {
                    "aws:RequestTag/Owner": "false"
                }
            }
        }
    ]      
}

接下来,我们来看一下以上IAM策略的分解内容的解读:

Line 6

"Effect": "Deny"

首先是针对于特定资源在创建标签操作(Action)时使用显示拒绝。

Line 14 -21

"Condition": {
    "ForAllValues:StringNotEquals": {
        "aws:TagKeys": "Name"
    },
    "Null": {
        "aws:RequestTag/Name": "false"
    }
}

根据IAM策略的判断逻辑,在多个条件的情况下,如果某一个或多个条件不满足,则返回false 。如果和显示拒绝一起使用,就是说只要不满足多条件中的一个条件,就不会命中这条策略,换句话说就是不会被拒绝。

从上面例子可以看出,第一个条件运算符为”ForAllValues:StringNotEquals”, 其中条件键值是{“aws:TagKeys”: “Name”}。这条条件的背后逻辑是,如果请求集中每一个标签的键都不等于“Name”,则返回true; 反过来讲,如果请求集中有一个标签的键等于“Name”,则返回false, 在这种情况下,这个请求就不会被显示拒绝。另外,为了符合标签策略的特点(不会强制要求资源加标签),需要加上第二个条件;运算符为“Null”,条件键值为{“aws:RequestTag/Name”: “false”},解释为如果请求中的标签键不是“Name”(不分大小写),该条件就会返回false,整条请求就不会被显示拒绝。从另外一方面来说,这条策略语句会对不符合“Name”大小写的标签进行拒绝;也就是说如果请求中的标签为“name/nAme…“就会同时命中上述的两条条件控制,从而被拒绝。

Line 33-43

"Condition": {
    "StringNotLike": {
        "aws:RequestTag/Owner": [
            "*@company.com",
            "*@company.digital"
        ]
    },
    "Null": {
        "aws:RequestTag/Owner": "false"
    }
}

33-43行的逻辑和14-21行的逻辑类似,请求中的标签键不等于”Owner”或者有标签等于Owner且标签值符合*@company.com或*@company.digital就不会被显示拒绝。总结来说,这条策略语句是标签值范围的控制。如果在请求中标签键等于Owner但值不符合*@company.com或*@company.digital就会被拒绝。

到这里,就实现了标准标签策略的逻辑;但在用户规范标签使用过程中,往往会在创建资源时,强制标签添加。这个话题会在下个章节讨论。

强制在创建资源时添加标签

强制添加标签的IAM策略和之前章节的IAM策略类似,还是可以使用IAM策略的显示拒绝和条件控制。比如需要将上章节提到的“Name”和“Owner”标签在创建EC2和EBS时(”ec2:CreateVolume”,”ec2:RunInstances”)强制添加到资源中,我们就可以使用显示拒绝和条件,其中条件运算符为“Null”,条件键值为{“aws:RequestTag/Name”: “true”}, 也就是说请求中如果标签键没有“Name”,条件则返回true, 从而整个请求会被显示拒绝。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TagsMustOwner",
      "Effect": "Deny",
      "Action": [
        "ec2:CreateVolume",
        "ec2:RunInstances"
      ],
      "Resource": [
        "arn:aws:ec2:*:*:instance/*",
        "arn:aws:ec2:*:*:volume/*"
      ],
      "Condition": {
        "Null": {
          "aws:RequestTag/Owner": "true"
        }
      }
    },
    {
      "Sid": "TagsMustName",
      "Effect": "Deny",
      "Action": [
        "ec2:CreateVolume",
        "ec2:RunInstances"
      ],
      "Resource": [
        "arn:aws:ec2:*:*:instance/*",
        "arn:aws:ec2:*:*:volume/*"
      ],
      "Condition": {
        "Null": {
          "aws:RequestTag/Name": "true"
        }
      }
    }
  ]
}

需要注意的是如果需要强制多个标签的添加,我们需要编写多个语句(Statements), 而不是将多个标签写在同一个Statement的条件控制列表里。

实施标签策略和强制标签策略

通过上面几个章节的讲解,大家掌握了如何将亚马逊云科技国际区的标签策略转换成IAM策略,以及如何利用IAM策略来强制添加标签。但我们如何像在国际区时,使用标签策略和服务控制策略 (Service Control Policies,SCP)在Organization或者OU级别来实施这些IAM策略呢?针对这个问题,首先,目前SCP 功能还未在中国区(北京区和宁夏区)上线,但用户可以结合中国区SCP的替代方案(基于 IAM 权限边界的 SCP 替代方案)来配置基于IAM策略的标签策略和强制标签策略。待SCP服务在中国区上线后,可以直接在SCP策略中配置基于IAM策略的标签策略和强制标签策略。

如下图,在国际区中,我们可以利用标签策略和SCP在Organization或者OU级别来规范和强制标签的使用(左图);而在中国区我们可以通过SCP替代方案利用IAM 权限边界(IAM Permission Boundary)和IAM策略来在Organization或者OU级别来规范和强制标签的使用。

注意:由于我们改写的IAM策略都是显式拒绝策略,所以IAM权限边界和IAM策略的实际效果是一样的。

标签策略转IAM策略工具

为了方便用户将亚马逊云科技国际区的标签策略转为IAM策略,我们提供了一个转化工具(代码下载链接)。用户可以简单地将标签策略转为IAM策略。注意,目前该工具只测试过EC2,EBS,VPC等资源,对于某些资源可能会出现问题。

该工具会自动地将用户的标签策略按照上述章节描述的方法转化为IAM策略,用户可以手动的将这些策略放入某些IAM实体(角色、用户)的IAM 权限边界中以规范这些IAM实体的标签;另外,用户也可以结合中国区SCP的替代方案(基于 IAM 权限边界的 SCP 替代方案)在Organization或者OU级别来实施这些IAM策略。

总结

本文通过对亚马逊云科技标签策略的分析,将亚马逊云科技标签策略转成中国区支持的IAM策略;并结合客户实际使用标签场景,增加了强制标签添加功能。另外,标签策略转换工具可以将用户已有的亚马逊云科技国际区标签策略直接转化为IAM策略,助力用户将标签策略迁移至亚马逊云科技中国区。

参考

标签策略

https://docs.aws.amazon.com/zh_cn/organizations/latest/userguide/orgs_manage_policies_tag-policies.html

了解标签策略的强制执行

https://docs.aws.amazon.com/zh_cn/organizations/latest/userguide/orgs_manage_policies_tag-policies-enforcement.html

服务控制策略 (SCP)

https://docs.aws.amazon.com/zh_cn/organizations/latest/userguide/orgs_manage_policies_scps.html

单个账户内部的访问控制逻辑

https://docs.amazonaws.cn/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow

本篇作者

谢丹

亚马逊云科技专业服务团队云架构顾问。专注于企业整体云上基础设施架构设计、迁移方案设计、最佳实践以及落地实施。

王枫楠

亚马逊云科技专业服务团队安全顾问。专注于企业整体云上安全架构设计、最佳实践以及落地实施。