基于AzureDevOps实现账号工厂

更新时间:

方案概述

当企业开通「资源目录」,将已有阿里云账号邀请进来,或者通过新建成员账号的方式开展新的业务,那么不同账号之间的统一权限管理就会显得尤为重要,如果是在这些账号内手工创建 RAM 角色,则无法保证权限统一,后续修改维护困难,本文档则介绍了一种通过Azure DevOps + Docker + Terraform 自动化为所有成员账号创建RAM 角色、权限及VPC等统一基线的方法。

方案优势

账号统一基线

账号工厂通过同一工作流模板生产成员账号,能够确保新账号都包含流水线中定义的统一基线,根据基线内容保障新账号权限安全。

基础设施代码化

基于IaC思想,将资源目录中成员账号的配置过程使用Terraform规范化,每次创建成员账号时使用同一份Terraform代码,保证所有成员账号权限统一,减轻运维管理负担。

灵活可扩展

Terraform及工作流代码可拓展,用户可根据需求拓展功能,提供更多的基线配置。Azure DevOps为功能丰富的DevOps产品,便于集成。

客户场景

上云阶段批量生产成员账号

场景描述

企业上云阶段构建多账号体系,多成员账号权限配置繁琐、效率低下,无法保证账号权限、资源配置等基线统一,后续修改维护困难。

适用客户

上云阶段需要批量生成统一基线账号并希望使用Azure DevOps的企业客户。

业务扩展新建成员账号

场景描述

企业业务扩展需开设新账号,企业手动创建账号时无法快速创建拥有统一身份权限、资源配置基线的成员账号。

适用客户

企业业务扩展阶段需要生成统一基线账号并希望使用Azure DevOps的企业客户。

方案架构

本方案使用Terraform自动化执行,整合Azure DevOps + Docker搭建Terraform的执行环境,实现了TerraformCI/CD集成。方案中使用ECS安装Self-hosted AgentDocker,AgentDevOps Server进行通信,在Docker中运行Terraform等账号基线Pipeline步骤,TerraformState文件使用OSS + OTS作为服务远端存储(Backend)并支持加锁,保证State文件安全。

以下的流程图描述了该方案的执行步骤,首先使用企业管理主账号下的RAM用户(子用户)AK信息,通过Terraform脚本登录到企业管理主账号,并在指定的资源夹下创建新的「成员账号」。之后扮演成员账号下的ResourceDirectoryAccountAccessRole角色,该角色会在成员账号加入RD时自动创建,并拥有云管理员(AdministratorAccess)权限。登录到成员账号后,会在成员账号下进行权限配置——创建IDP和相关RAM角色、创建一个用于执行Tarraform脚本的RAM用户并为上述角色和用户绑定权限策略。最后会在成员账号下进行网络配置——根据用户指定数据创建VPC和交换机。

产品费用及名词

产品费用

产品名称

产品说明

产品费用

资源目录RD

资源目录RD(Resource Directory)是阿里云面向企业客户提供的一套多级账号和资源关系管理服务。

免费,详情参见产品计费

访问控制RAM

访问控制(RAM)使您能够安全地集中管理对阿里云服务和资源的访问。您可以使用RAM创建和管理用户和组,并使用各种权限来运行或访问他们对云资源的访问。

免费,详情参见产品计费

专有网络VPC

专有网络VPC(Virtual Private Cloud)帮助您基于阿里云构建出一个隔离的网络环境,并可以自定义IP地址范围、网段、路由表和网关等;此外,也可以通过专线/VPN/GRE等连接方式实现云上VPC与传统IDC的互联,构建混合云业务。

免费,但在专有网络上创建的资源收费,详情参见产品计费

对象存储OSS

对象存储OSS(Object Storage Service)是阿里云提供的海量、安全、低成本、高持久的云存储服务。

收费,详情参见产品计费

表格存储OTS

表格存储(Tablestore)是阿里云自研的多模型结构化数据存储,提供海量结构化数据存储以及快速的查询和分析服务。

收费,详情参见产品定价

容器镜像服务ACR

容器镜像服务ACR提供安全地镜像托管能力,稳定的国内外镜像构建服务,便捷的镜像授权功能,方便用户进行镜像全生命周期管理。

企业版收费,详情见产品计费

Azure DevOps

Azure DevOpsAzure提供的DevOps产品。Azure PipelinesAzure DevOps中的流水线产品。

详情参见定价

Docker

Docker容器化技术,用于支持创建和使用容器,实现对容器的高效创建、部署及复制,并能将其从一个环境顺利迁移至另一个环境,从而有助于针对云优化应用。

高级版收费,详情参见Pricing

名词解释

名称

说明

企业管理主账号

在企业拥有多个阿里云账号时,特指拥有管理其他账号资源权限的管理员账号。用于管理多账号,统一配置多账号身份权限,统一查看各云账号账单,统一配置审计规则并下发到各成员账号。

RAM用户

RAM用户是RAM的一种实体身份类型,有确定的身份ID和身份凭证,它通常与某个确定的人或应用程序一一对应。因安全原因不推荐直接使用云账号的AK/SK。因此在账号下创建一个RAM用户,授予RAM用户最小权限,使用该RAM用户的AK/SK。

成员账号

在资源目录中受「企业管理主账号」邀请或被创建的其他账号,每一个成员账号均为一个独立的账号,拥有自己的云资源,企业可根据职责划分为不同的账号,由企业管理主账号统一管理。

State文件

Terraform中用于描述当前资源配置的文件,详情参见State。本文使用OSS + OTS作为State文件的远端存储,详情参见OSS Backend

安全性

资源目录权限

资源目录服务关联角色(AliyunServiceRoleForResourceDirectory)为资源目录集成服务提供可信访问通道,详情参见资源目录服务关联角色

Azure DevOps安全性

Azure DevOps安全详情参考官方文档

Terraform State文件安全

使用OSS作为Backend保存Terraform State文件,使用OTS支持State文件加锁及一致性检查,详情参见OSS Backend

Docker安全性

Docker安全性详情参见官方文档Security

AccessKey使用

需要使用企业管理主账号下RAM用户的AccessKey,用于创建账号及操作阿里云资源。该RAM用户拥有 AliyunResourceDirectoryFullAccessAliyunSTSAssumeRoleAccess两个权限。

实施步骤

实施准备

  • 已拥有一台可连通公网的ECS(本方案使用操作系统CentOS 7.9),ECS中已安装Docker

  • 确保已在「企业管理主账号」(也可使用其他账号)OSS下创建用于存储Terraform state文件的Bucket,并且在OTS中创建一张主键名为LockID,类型为String的数据表,用于作为Terraform state文件的锁。记录下Bucket和数据表的名称endpoint

  • 确保在「企业管理主账号」中,存在一个「RAM用户」AK,且该用户拥有 AliyunResourceDirectoryFullAccessAliyunSTSAssumeRoleAccess两个权限;在后续的步骤中,我们将使用该RAM用户及其AK。

  • 已拥有Git仓库,用于上传及下载相关代码。

  • 确定工作流及Terraform输入参数,输入参数分为两部分:第一部分为全局参数,需写入附件代码包中的settings.tfvars文件,每次流水线执行时均保持一致;第二部分为执行参数,执行流水线时动态填写,不会保存。

    • 全局参数

      • encodedsaml_metadata_document:企业IDP的元文件,用于在阿里云上创建IDP

      • sso_provider_name:创建的IDP的名称

      • ram_roles:需要创建的ram角色列表,示例中包括只读和管理员角色

      • user_name:用于执行TF脚本的角色名称

      • policy_name:自定义权限策略的名称

      • policy_document:自定义权限策略内容

      • attach_roles:自定义权限策略绑定的角色列表

      • attach_users:自定义权限策略绑定的用户列表

      • reader_name:需要绑定权限策略的只读角色名称

      • reader_policy_type:为只读角色绑定的权限策略的类型

      • reader_policy_name:为只读角色绑定的权限策略的名称

      • vpc_name:创建的vpc的名称

      • vswitch_name:vpc下交换机的名称

    • 执行参数

      • account_name:新创建账号的显示名称

      • account_name_prefix:新创建账号的账号标识

      • uid: 「企业管理主账号」uid

      • access_key:「企业管理主账号」下RAM用户的AK

      • secret_key:「企业管理主账号」下RAM用户的SK

      • folder_id:新创建的成员账号所属资源夹ID

      • vpc_cidr_block:VPC的网段

      • switch_cidr_block:交换机的网段

      • region:区域信息,如cn-hangzhou

      • zone_id:可用区ID,如cn-hangzhou-b

  • 已使用Azure DevOps,本文在Default pool下安装Agent,使用Default pools,需确保Default下已有可用的Agents(也可直接使用Azure提供的Agent),以容器方式运行Terraform代码。使用容器镜像服务中的 registry.cn-hangzhou.aliyuncs.com/terraform/terraform-docker-azure:v1 镜像运行,该镜像Dockerfile如下所示。

    FROM node:14-alpine
    
    ENV TERRAFORM_PLUGIN_DIR=/srv/terraform-plugins
    ENV TF_PLUGIN_CACHE_DIR=${TERRAFORM_PLUGIN_DIR}
    ENV TERRAFORM_VERSION=1.0.2
    ENV TERRAFORM_PROVIDER_ALICLOUD_VERSION=1.127.0
    ENV TERRAFORM_PROVIDER_LOCAL_VERSION=2.1.0
    ENV TERRAFORM_PROVIDER_EXTERNAL_VERSION=2.1.0
    ENV PATH="/opt/venv/bin:$PATH"
    
    RUN apk add bash sudo shadow \
        && apk add wget unzip git \
        && wget https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
        && unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/local/bin/ \
        && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/aliyun/alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/linux_amd64 \
        && wget https://releases.hashicorp.com/terraform-provider-alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/terraform-provider-alicloud_${TERRAFORM_PROVIDER_ALICLOUD_VERSION}_linux_amd64.zip \
        && unzip terraform-provider-alicloud_${TERRAFORM_PROVIDER_ALICLOUD_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/aliyun/alicloud/${TERRAFORM_PROVIDER_ALICLOUD_VERSION}/linux_amd64 \
        && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/linux_amd64 \
        && wget https://releases.hashicorp.com/terraform-provider-local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/terraform-provider-local_${TERRAFORM_PROVIDER_LOCAL_VERSION}_linux_amd64.zip \
        && unzip terraform-provider-local_${TERRAFORM_PROVIDER_LOCAL_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/local/${TERRAFORM_PROVIDER_LOCAL_VERSION}/linux_amd64 \
        && mkdir -p ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/external/${TERRAFORM_PROVIDER_EXTERNAL_VERSION}/linux_amd64 \
        && wget https://releases.hashicorp.com/terraform-provider-external/${TERRAFORM_PROVIDER_EXTERNAL_VERSION}/terraform-provider-external_${TERRAFORM_PROVIDER_EXTERNAL_VERSION}_linux_amd64.zip \
        && unzip terraform-provider-external_${TERRAFORM_PROVIDER_EXTERNAL_VERSION}_linux_amd64.zip -d ${TERRAFORM_PLUGIN_DIR}/registry.terraform.io/hashicorp/external/${TERRAFORM_PROVIDER_EXTERNAL_VERSION}/linux_amd64 \
        && rm -rf *.zip 
    
    LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"
    
    CMD [ "node" ]

实施时长

在实施准备工作完成的情况下,本方案实施预计时长:45分钟。

操作步骤

配置参数

  1. 下载本文源代码章节中的账号工厂代码,目录结构参考相应说明。

  2. 使用编辑器打开 backend.tfvars文件,修改该文件内的配置项:

    1. bucket:实施准备中在OSS中创建的Bucket名称。

    2. prefix:OSSState文件存储路径,可以根据实际情况修改。

    3. region:OSS存储地区,注意和实施准备中的地域一致。

    4. tablestore_endpoint:OTS的访问入口,可在OTS实例页面上查到。根据网络情况选择入口地址。

    5. tablestore_table:实施准备中创建的OTS数据表实例名称。

    6. access_key:OSS/OTS在企业管理主账号时不需要填写,不在企业管理主账号时需要填写相应账号RAM用户的AccessKey,该用户需要拥有OSS/OTS的读写权限。

    7. secret_key:OSS/OTS在企业管理主账号时不需要填写,不在企业管理主账号时需要填写相应账号RAM用户的SecretKey。

    8. endpoint:OSS访问入口,注意和实施准备中的地域一致。

  3. 用编辑器打开settings.tfvars文件,根据配置文件注释和实施准备中的全局参数填写。

部署Agent

  1. 本文中使用Azure Self-hosted Linux agentsECS中运行Job,详情参考链接

  2. 在阿里云上创建ECS(CentOS 7.9)并安装Azure agents,该ECS上已安装Git(2.30.1)和Docker(20.10.8)。将该Agents放置于Default Pool下,创建完成后如下图所示。也可以根据自身需求使用其他Agent(如Microsoft-hosted agents),需要修改下述yaml文件中 pool 一栏。

创建并运行Pipeline

  1. 将已修改的代码上传到自己的Git仓库中。

  2. 创建Pipeline,按页面提示选择已上传代码的代码库,在 Configure 步骤中使用以下 azure-piplines.yml 文件:

    parameters:
    - name: access_key
      displayName: AccessKey
      type: string
    - name: secret_key
      displayName: SecretKey
      type: string
    - name: region
      displayName: Region
      type: string
    - name: uid
      displayName: Uid
      type: string
    - name: account_name
      displayName: Account Name
      type: string
    - name: account_name_prefix
      displayName: Account Name Prefix
      type: string
    - name: folder_id
      displayName: Folder ID
      type: string
    - name: vpc_cidr_block
      displayName: VPC CIDR Block
      type: string
    - name: switch_cidr_block
      displayName: Switch CIDR Block
      type: string
    - name: zone_id
      displayName: Zone ID
    
    trigger: none
    
    # 使用Default中的Agent,也可以使用Azure Agent
    pool: Default
    # pool: 
    #   vmImage: ubuntu-latest
    
    variables:
      ALICLOUD_ACCESS_KEY: ${{ parameters.access_key }}
      ALICLOUD_SECRET_KEY: ${{ parameters.secret_key }}
      ALICLOUD_REGION: ${{ parameters.region }}
    
    container: 
      image: registry.cn-hangzhou.aliyuncs.com/terraform/terraform-docker-azure:v1
    
    steps:
    
    - bash: |
        terraform -chdir=step/account-create init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-account-create" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/account-create apply --auto-approve -var folder_id=${{ parameters.folder_id }} -var account_name=${{ parameters.account_name }} -var account_name_prefix=${{ parameters.account_name_prefix }}
      displayName: 创建账号
    - bash: |
        terraform -chdir=step/auth-create-idp init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-auth-create-idp" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/auth-create-idp apply --auto-approve -var-file=../../settings.tfvars -compact-warnings
      displayName: 权限配置-创建IDP
    - bash: |
        terraform -chdir=step/auth-create-role init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-auth-create-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/auth-create-role apply --auto-approve -var-file=../../settings.tfvars -compact-warnings
      displayName: 权限配置-创建角色
    - bash: |
        terraform -chdir=step/auth-create-user init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-auth-create-user" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/auth-create-user apply --auto-approve -var-file=../../settings.tfvars -compact-warnings
      displayName: 权限配置-创建TF用户
    - bash: |
        terraform -chdir=step/auth-authorize-role init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-auth-authorize-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/auth-authorize-role apply --auto-approve -var-file=../../settings.tfvars -compact-warnings
      displayName: 权限配置-角色授权
    - bash: |
        terraform -chdir=step/network-create-vpc-vsw init -backend-config="key=${{ parameters.uid }}-${{ parameters.account_name }}-auth-authorize-role" -backend-config=../../backend.tfvars -reconfigure -plugin-dir=/srv/terraform-plugins
        terraform -chdir=step/network-create-vpc-vsw apply --auto-approve -var vpc_cidr_block=${{ parameters.vpc_cidr_block }} -var switch_cidr_block=${{ parameters.switch_cidr_block }} -var zone_id=${{ parameters.zone_id }} -var-file=../../settings.tfvars -compact-warnings
      displayName: 网络配置
  3. 该文件使用Default Pool中的Agent,并使用实施准备中的Docker运行Terraform代码。在手动运行流水线时填入执行参数。

  4. 运行该流水线,并按照实施准备填入指定参数:

  5. 运行完成后,可查看每一步的执行结果和执行日志。

  6. 当在资源目录中新增成员账号、或者修改了配置项中的内容时,上传到Git仓库后重新运行流水线即可。

故障排除

Azure DevOps

AzureDevOps问题处理参见官方文档

资源目录

资源目录常见问题处理详情参见常见问题

表格存储

表格存储常见问题处理详情参见常见问题

OSS

OSS常见问题详情参见常见问题

相关内容