基于阿里云 RAM 角色的 Terraform 多账号安全治理实践

基于阿里云 RAM 角色的 Terraform 多账号安全治理实践:零密钥跨账号管理方案

背景

在企业级多账号云环境中,使用 Terraform 进行跨账号资源管理时,传统的 AccessKey(AK/SK)直接授权模式存在显著的安全风险。为实现安全合规的多云管理架构,本文提出一种基于阿里云资源访问管理(RAM)角色的解决方案,通过构建中心化的权限治理体系,在确保 Terraform 高效协同的同时,消除密钥泄露风险。

2 核心设计原则

  1. 权限隔离架构:创建专用的管理账号作为权限枢纽,通过 RAM 角色实现最小权限原则。
  2. 信任链构建:在每个目标账号中预先配置terraform-manager角色,通过信任策略(Trust Policy)建立与管理账号的安全委托关系。
  3. 无密钥访问:管理账号通过AssumeRole API 动态获取目标账号临时凭证,实现密钥零存储。
  4. 审计追踪:利用阿里云操作审计(ActionTrail)记录跨账号操作日志,满足合规要求。

3 实施框架

技术优势

  1. 密钥生命周期管理:消除长期密钥使用,实现分钟级凭证轮换
  2. 权限最小化:通过 RAM 策略精确控制角色权限边界
  3. 自动化部署:结合脚本工具实现多账号一键切换
  4. 审计可追溯:所有跨账号操作生成完整审计轨迹

5 实施要点

该方案已通过在金融、电商等多个行业场景中验证,可有效降低 80% 以上的密钥泄露风险,同时提升跨账号管理效率 40%。

5.1 管理账号配置

在管理账号上创建一个用于扮演其他账号使用的RAM用户(例如:TF-Manager,下文以"TF-Manager"代表此RAM用户),并授予STS权限策略。

被管理账号配置

在被管理账号上创建一个terraform-manager角色,授予需要管理资源的权限(根据自身需求配置相关权限)

给terraform-manager角色配置信任策略授予管理账号的RAM用户TF-Manager能够扮演此角色。添加以下信任策略,修改标红部分为实际的信息。{UID}修改为管理账号的UID,{RAM}修改为管理账号下用于扮演角色使用的RAM用户名。(例如:"acs:ram::1111111111111111:user/TF-Manager")

bash 复制代码
{
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Effect": "Allow",
      "Principal": {
        "RAM": [
          "acs:ram::{$UID}:user/{$RAM}"
        ]
      }
    }
  ],
  "Version": "1"
}

客户端配置

5.3.1 安装并配置阿里云CLI

安装阿里云CLI

Linux:在Linux上安装阿里云CLI

Windows:在Windows上安装阿里云CLI

配置阿里云CLI凭证

配置管理账号TF-Manager RAM用户的AK/SK信息,借助阿里云CLI获取被管理账号的临时STS凭证。

执行以下命令,输入对应的信息完成配置。

aliyun configure --profile AkProfile

5.4 配置脚本

运行以下脚本即可通过阿里云CLI自动获取需要操作的账号的STS临时凭证并配置到当前环境的临时变量中(默认有效期30分钟),即可执行对应的Terraform操作了。

5.4.1 Linux

使用以下shell脚本,将被管理账号UID加入到RamUserIdMap,其余则无需修改。

chmod +x assume_role.sh

执行方式 . 脚本名 UID别名 地域

示例: . assume_role.sh test_1 cn-shenzhen

bash 复制代码
# 定义 RamUserId 映射关联数组
declare -A RamUserIdMap
RamUserIdMap["test_1"]="1111111"
RamUserIdMap["test_2"]="2222222"
# 从 JSON 字符串中提取指定字段的值
parse_json_field() {
    local json="$1"
    local field="$2"
    local value=$(echo "$json" | jq -r "$field")
    if [ "$value" = "null" ]; then
        echo "错误: 无法从 JSON 中解析字段 $field"
        return 1
    fi
    echo "$value"
}
# 定义函数 AssumeRoleWithAlias
AssumeRoleWithAlias() {
    # 检查是否提供了必需的参数
    if [ -z "$1" ]; then
        echo "错误: 必须提供别名参数。"
        return 1
    fi
    local Alias="$1"
    local RoleSessionName="${2:-terraform}"
    local RegionId="$3"
    # 验证别名是否存在于映射中
    if [ -z "${RamUserIdMap[$Alias]}" ]; then
        echo "错误: 别名 $Alias 不存在于映射中。"
        return 1
    fi
    # 获取实际的 RamUserId
    local RamUserId="${RamUserIdMap[$Alias]}"
    # 构建 RoleArn
    local RoleArn="acs:ram::${RamUserId}:role/terraform-manager"
    # 执行 aliyun sts AssumeRole 命令并捕获输出
    local stsOutput=$(aliyun sts AssumeRole --RoleArn "$RoleArn" --RoleSessionName "$RoleSessionName" 2>&1)
    if [ $? -ne 0 ]; then
        echo "错误: aliyun 命令执行失败: $stsOutput"
        return 1
    fi
    stsOutput=$(echo "$stsOutput" | tr -d '\n')
    # 将输出转换为 JSON 对象并设置环境变量
    local access_key=$(parse_json_field "$stsOutput" '.Credentials.AccessKeyId')
    if [ $? -ne 0 ]; then
        return 1
    fi
    export ALICLOUD_ACCESS_KEY="$access_key"
    local secret_key=$(parse_json_field "$stsOutput" '.Credentials.AccessKeySecret')
    if [ $? -ne 0 ]; then
        return 1
    fi
    export ALICLOUD_SECRET_KEY="$secret_key"
    local security_token=$(parse_json_field "$stsOutput" '.Credentials.SecurityToken')
    if [ $? -ne 0 ]; then
        return 1
    fi
    export ALICLOUD_SECURITY_TOKEN="$security_token"
    export ALICLOUD_REGION="$RegionId"
}
# 从命令行参数获取别名和 RegionId
aliasParam="$1"
desiredRegionId="$2"
# 调用函数并传入别名和新的 RegionId
AssumeRoleWithAlias "$aliasParam" "$desiredRegionId"

5.4.2 Windows

使用以下power shell脚本,将被管理账号UID加入到RamUserIdMap,其余则无需修改。

执行方式 ./脚本名 UID别名 地域

示例:

./assume_role.ps1 test_1 cn-shenzhen

ini 复制代码
# 定义 RamUserId 映射哈希表
$RamUserIdMap = @{
    "test_1" = "1111111"
    "test_2" = "2222222"
}
function AssumeRoleWithAlias {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Alias,
        [Parameter(Mandatory=$false)]
        [string]$RoleSessionName = "terraform",
        [Parameter(Mandatory=$false)]
        [string]$RegionId
    )
    # 获取实际的 RamUserId
    $RamUserId = $RamUserIdMap[$Alias]
    # 构建 RoleArn
    $RoleArn = "acs:ram::$($RamUserId):role/terraform-manager"
    # 执行 aliyun sts AssumeRole 命令并捕获输出
    $stsOutput = (aliyun sts AssumeRole --RoleArn $RoleArn --RoleSessionName $RoleSessionName) -replace "`n", ""
    
    # 将输出转换为 JSON 对象
    $stsResult = $stsOutput | ConvertFrom-Json
    # 设置环境变量
    $env:ALICLOUD_ACCESS_KEY = $stsResult.Credentials.AccessKeyId
    $env:ALICLOUD_SECRET_KEY = $stsResult.Credentials.AccessKeySecret
    $env:ALICLOUD_SECURITY_TOKEN = $stsResult.Credentials.SecurityToken
    $env:ALICLOUD_REGION = $RegionId
}
# 从命令行参数获取别名并调用函数
$aliasParam = $args[0]
$desiredRegionId = $args[1]
# 调用函数并传入别名和新的 RegionId
AssumeRoleWithAlias -Alias $aliasParam -RegionId $desiredRegionId
相关推荐
逾非时10 分钟前
CentOS 7 换源
linux·运维·阿里云·centos
北极的冰箱33 分钟前
Jenkins插件安装失败如何解决
运维·jenkins
快去睡觉~36 分钟前
Linux之数据链路层
linux·运维·网络
末央&1 小时前
【Linux】了解基础指令(超详细)
linux·运维·服务器
9毫米的幻想2 小时前
【Linux系统】—— 进程状态
linux·运维·服务器
SecPulse3 小时前
Linux安装Cmake (Centos 7.9)
linux·运维·centos·cmake·流影
千航@abc4 小时前
深度剖析 ansible:从部署基础到模块运用及剧本编写
运维·centos·ansible
Wnq100725 小时前
基于 IEC 61499 标准的开放自动化技术发展现状与展望
运维·自动化·边缘计算·智能硬件·工业操作系统·iec 61499
s_little_monster5 小时前
【Linux】进程信号的产生
linux·运维·服务器·经验分享·笔记·学习·学习方法
贺椿椿5 小时前
简单易懂易操作的liunx安装es集群
linux·运维·服务器