Terraform 助力 ECS 实例借助 RAM 管理阿里云产品

众所周知,不论以怎样的方式访问阿里云产品的 API,拥有账号完整权限的密钥AK(Access Key ID 和 Access Key Secret,简称 AK)是必不可少的参数。因此,对 AK 的有效管理是每个调用阿里云 API 的应用程序首先需要解决的问题。

对于部署在 ECS 实例上的应用程序而言,为了方便对 AK 的管理,通常需要将 AK 保存在应用程序的配置文件中或 ECS 实例的环境变量中,如此一来,无疑增加了 AK 管理的复杂性,降低了 AK 的安全性和灵活性。除此之外,对于多 Region 一致性部署应用的场景而言,AK 往往会随着镜像以及基于镜像创建的实例扩散出去,此时,将不得不更新镜像和逐台重新部署实例,从而应用部署的复杂度也将随之增加。

面对以上困境,我们可借助于 RAM 角色功能,将 RAM 角色 和 ECS 实例关联起来,使得实例内部的应用程序可以通过 STS 临时凭证(由系统自动生成和更新,详见 RAM And STS)访问其他云产品的 API。应用程序无需管理 STS 临时凭证,直接通过实例元数据 URL 即可获取。同时,通过对 RAM 角色和授权策略的管理,可以达到不同实例对不同云产品或相同云产品具有各自访问权限的目的。

值得注意的是,每个 RAM 角色可同时被授权多个策略,通常我们的做法是为某一角色逐个授权相应的策略,同时,对于已有的 ECS 实例,我们需要逐台绑定某一角色,如何实现对 RAM 角色的自动化管理,授权策略的灵活设置以及为角色批量绑定 ECS 实例呢?本文将借助于自动化运维工具 Terraform 给出最佳的实践方案。

Terraform 助力 ECS 实例借助 RAM 管理阿里云产品

正如上图所示,基于 Terraform 实现了 RAM Role,Policy以及 ECS 实例的创建,为 Role 配置 Policy,并将配置后的 Role 挂载到 ECS 实例上,进而帮助实例上的应用程序访问阿里云的其他云服务。

本文将以 ECS 实例借助于 RAM 角色访问 OSS 服务为例,向大家展示如何基于 Terraform 实现从 RAM 角色的创建,授权策略的设置到ECS 实例的绑定以及如何在绑定了 RAM 角色的 ECS 实例上利用 Python 访问 OSS 服务的。

定义 RAM 角色

首先编写 Terraform 模板,定义 RAM Role:

resource "alicloud_ram_role" "role" {
    name = "EcsRamRoleTest"
    services = ["ecs.aliyuncs.com"]
    description = "Test role for ECS and access to OSS."
    force = true
}

模板定义了一个 RAM Role:EcsRamRoleTest,并为该角色配置了一个受信云服务 ECS,表示该角色为一个服务角色,受信云服务 ECS 可以扮演该角色。其中,设置 force = true 表示在通过 Terraform 释放该 Role 时会强制解除与该 Role 相关联的所有关系。

定义 RAM 授权策略

接下来在模板中定义 RAM Policy:

resource "alicloud_ram_policy" "policy" {
      name = "EcsRamRolePolicyTest"
      statement = [
          {
           effect = "Allow"
           action = ["oss:Get*", "oss:List*"]
           resource = [ "*" ]
         }
     ]
      description = "Test role policy for ECS and access to OSS."
      force = true
}

模板定义了一个自定义的授权策略 EcsRamRoleTest,并为该 Policy 中声明了 OSS 只读权限的策略。和 RAM Role 类似,设置 force = true 表示在通过 Terraform 释放该 Policy 时会强制解除与该 Policy 相关联的所有关系。

为 RAM 角色授权策略

在定义好 RAM Role 和 Policy 之后,接下来需要将 Policy 跟 Role 进行绑定,为 Role 进行策略授权:

resource "alicloud_ram_role_policy_attachment" "role-policy" {
    policy_name = "${alicloud_ram_policy.policy.name}"
    role_name = "${alicloud_ram_role.role.name}"
    policy_type = "${alicloud_ram_policy.policy.type}"
}

模板利用将创建好的 Policy 绑定到 Role 上,使得 Role 具有访问某种云产品服务的权限。

定义 ECS 实例

接下来基于 Terraform 创建一个 ECS 实例,用来绑定 Role 和部署应用:

resource "alicloud_vpc" "vpc" {
     name = "vpc_for_ecs_role"
     cidr_block = "172.16.0.0/12"
}

resource "alicloud_vswitch" "vswitch" {
    name = "subnet_for_ecs_role"
     vpc_id = "${alicloud_vpc.vpc.id}"
     cidr_block = "172.16.0.0/21"
     availability_zone = "cn-beijing-a"
}

resource "alicloud_security_group" "sg" {
    name = "sg_for_ecs_role"
    vpc_id = "${alicloud_vpc.vpc.id}"
}

resource "alicloud_security_group_rule" "22_rule" {
    security_group_id = "${alicloud_security_group.sg.id}"
    type = "ingress"
    policy = "accept"
    port_range = "22/22"
    ip_protocol = "tcp"
    nic_type = "intranet"
    priority = 1
    cidr_ip = "0.0.0.0/0"
}

resource "alicloud_instance" "instance" {
    # cn-beijing
    vswitch_id = "${alicloud_vswitch.vswitch.id}"
    image_id = "ubuntu_140405_32_40G_cloudinit_20161115.vhd"
    availability_zone = "cn-beijing-a"

    # series III
    instance_type = "ecs.n4.large"
    system_disk_category = "cloud_efficiency"

    internet_charge_type = "PayByTraffic"
    internet_max_bandwidth_out = 20
    allocate_public_ip = true
    security_groups = ["${alicloud_security_group.sg.id}"]
    instance_name = "instance_for_role"
    password = "Test12345"
}

因为 ECS 实例 RAM 角色目前只支持 VPC 网络的实例,所以模板创建了一个 VPC 环境下的 ECS Instance,实例的镜像是 ubuntu_140405_32_40G_cloudinit_20161115.vhd, 规格是ecs.n4.large,通过allocate_public_ip = true为该实例分配了公网 IP,并为其设置了 20M 的带宽。 在创建 instance 的同时,还新建了 VPC, VSwitch 和安全组资源。为了可以远程连接 ECS 实例,为安全组创建了入方向的安全组规则,打开了 SSH 协议需要的 22 端口。

为 ECS 实例配置 RAM 角色

在完成 ECS 实例的创建和 RAM Role 的配置之后,接下来需要将 RAM Role 和 ECS 实例进行绑定,以帮助实例上的应用可以直接访问其他云资源:

resource "alicloud_ram_role_attachment" "attach" {
    role_name = "${alicloud_ram_role.role.name}"
    instance_ids = ["${alicloud_instance.instance.*.id}"]
}

定义 OSS Bucket

为了更好的测试结果,我们可通过 Terraform 新建一个 OSS Bucket,并为该 Bucket 上传两个 Object:

resource "alicloud_oss_bucket" "bucket" {
    bucket = "my-bucket-for-ram-role-test"
    acl = "public-read"
}

resource "alicloud_oss_bucket_object" "content-1" {
    bucket = "${alicloud_oss_bucket.bucket.bucket}"
    key = "object-content-key-1"
    content = "some words for test oss object content 1."
}

resource "alicloud_oss_bucket_object" "content-2" {
    bucket = "${alicloud_oss_bucket.bucket.bucket}"
    key = "object-content-key-2"
    content = "some words for test oss object content 2."
}

如上所示,模板定义了一个 OSS Bucket:"my-bucket-for-ram-role-test" 和两个 OSS Object,分别为:"object-content-key-1" 和 "object-content-key-2".

访问 ECS 实例并测试

接下来,我们登录到 ECS 实例上借助于 Python 访问 OSS 服务来测试 Role 以及 Policy 生效。具体步骤如下:

  1. 远程连接 ECS 实例
  2. 获取 STS 临时凭证
    访问 http://100.100.100.200/latest/meta-data/ram/security-credentials/<RAM-Role-Name> 即可获取 STS 临时凭证,其中 <RAM-Role-Name> 表示 RAM 角色名称,在这里我们将其设置为 “EcsRamRoleTest”。
    运行结果如下:

    root@iZ2XXXXXXXXX:~# curl http://100.100.100.200/latest/meta-data/ram/security-credentials/EcsRamRoleTest
     {
      "AccessKeyId" : "STS.LS6XXXXXXXXXXXXXXXXuW",
      "AccessKeySecret" : "HCXXXXXXXXXXXXXXXXXXXXXXXXXXXXXeAm",
      "Expiration" : "2017-08-18T13:17:39Z",
      "SecurityToken" : "CAIXXXXXXXXXXXXXXXXqq/etTxxxxxxxxxxxx6Mv/lXXXXXXXXXGW1",
      "LastUpdated" : "2017-08-18T07:17:39Z",
      "Code" : "Success"
    }
    

    结果显示,我们使用了 curl 命令成功地获取到了 STS 凭证,由此表明 RAM Role 已经与 ECS 实例绑定成功。

  3. 基于临时凭证,使用 Python SDK 访问 OSS
    本示例中,我们基于 STS 临时凭证使用 Python SDK 列举实例所在地域的 OSS Bucket 里的 2 个对象。具体测试步骤如下:

    • 执行如下命令,安装 OSS Python SDK

      $ sudo pip install oss2
    • 执行下述命令进行测试,其中:

      • oss2.StsAuth 中的 3 个参数分别对应于上述 STS 里的 AccessKeyId、AccessKeySecret 和 SecurityToken。
      • oss2.Bucket 中后 2 个参数是 Bucket 的名称和 Endpoint。本示例中,Bucket 名称为 my-bucket-for-ram-role-test,Endpoint 为 oss-cn-beijing.aliyuncs.com

      示例输出结果如下:

          
      root@iZ2XXXXXXXXX:~# python
      Python 2.7.6 (default, Oct 26 2016, 20:32:47) 
      [GCC 4.8.4] on linux2
      Type "help", "copyright", "credits" or "license" for more information.
      >>> import oss2
      >>> from itertools import islice
      >>> auth = oss2.StsAuth("STS.LS6XXXXXXXXXXXXXXXXuW", "HCXXXXXXXXXXXXXXXXXXXXXXXXXXXXXeAm", "CAIXXXXXXXXXXXXXXXXqq/etTxxxxxxxxxxxx6Mv/lXXXXXXXXXGW1")
      >>> bucket = oss2.Bucket(auth, "oss-cn-beijing.aliyuncs.com", "my-bucket-for-ram-role-test")
      >>> for b in islice(oss2.ObjectIterator(bucket), 2):
      ...     print(b.key)
      ... 
      object-content-key-1
      object-content-key-2
      >>> 
      

以上的运行结果显示,将 RAM Role 与 ECS 实例成功绑定后,ECS 实例可利用 STS 临时凭证成功地实现对 OSS 服务的访问,由此验证了整个运行流程的正确性。

写在最后

本文借助 RAM 角色访问云服务的功能,基于 Terraform 向大家展示了如何快速的实现 RAM 角色的创建,授权策略的设置,ECS 实例的创建以及绑定 RAM Role 等一系列操作,并通过测试验证了整个流程的有效性。

作为一个自动化运维工具,Terraform 的出现大大降低了资源编排的复杂度,简化了基础设施资源及其环境的搭建流程,同时对资源模板的版本化管理更是为基础设施资源的持续管理提供了方案,正如本文所展示的,当我们需要使用 OSS 的其他权限,或者访问其他云产品,或者让更多的 ECS 实例具有同样的权限的时候,只需要对如上的模板做一些适当的变更,如为 Policy 设置更多更丰富的 "statement",在 alicloud_instance 中设置 "count" 参数实现对 ECS 实例的平滑扩容等,然后只需运行一条简单的命令terraform apply 即可实现对原资源的快速升级和变更,省时又省力。

目前,面向阿里云的 Terraform Provider 仍在不断的发展和完善中,欢迎大家使用和提供宝贵的意见和建议。以下是相关参考资料,欢迎大家查阅。

Terraform Provider Github 地址https://github.com/alibaba/terraform-provider
Terraform Provider Document:Github: https://github.com/alibaba/terraform-provider-docs
Terraform Provider Packagehttps://github.com/alibaba/terraform-provider/releases
ECS 实例元数据获取 STS 临时凭证指南: https://www.alibabacloud.com/help/zh/doc-detail/49122.htm?spm=a3c0i.o54579zh.a3.7.4131bb5bwgOONE

备注:本文所涉及到的模板,可通过附件下载和使用,或者可直接访问ecs-ram-role-examplehttps://github.com/alibaba/terraform-provider/tree/master/terraform/examples/alicloud-ecs-ram-role 进行查看。

上一篇:(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序


下一篇:lucene .doc里存储的skiplist跳表