当前位置:首页 > 技术 > 正文内容

阿里云 ECS 云助手敏感数据加密传输实践

访客 技术 2026年9月29日 11

核心痛点与场景分析

在运维自动化场景中,通过 RunCommand API 向 ECS 实例下发指令是常见操作。然而,该过程会在多个链路留下痕迹,包括 DescribeInvocation、ActionTrail 审计日志以及云服务网关和应用层日志。这意味着,拥有相应权限的 RAM 用户、实例内部用户甚至云平台运维人员,理论上均可追溯命令明文。

当命令中包含高敏感信息(如重置 Root 密码、注入 API Key)时,这种全链路可见性构成了安全风险。例如,直接执行 echo "root:SecretPass" | chpasswd 会导致 SecretPass 暴露在日志中。为解决此问题,可利用云助手 Agent 内置的临时密钥对机制,实现"密文传输、本地解密"的安全闭环。

实施步骤详解

1. 生成临时非对称密钥对

首先,需要在目标 ECS 实例上触发云助手 Agent 生成一对临时的 RSA 密钥。私钥仅驻留在实例内存或受保护的进程空间中,公钥则用于后续的数据加密。

执行以下命令获取公钥及密钥 ID:

aliyun-service data-encryption -g --json

参数说明:

  • -g: Generate,生成新密钥对。
  • --json: 以 JSON 格式输出结果,便于脚本解析。
  • 可选参数 -i <id> 自定义密钥标识,-t <seconds> 设置过期时间(默认 60 秒)。

返回示例:

{
    "id": "tmp-key-8f9a2b",
    "createdTimestamp": 1675309078,
    "expiredTimestamp": 1675309138,
    "publicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...[省略]...\n-----END PUBLIC KEY-----\n"
}

记录返回的 id 和 publicKey,这是后续流程的关键凭证。

2. 客户端加密敏感数据

在发送命令前,使用上一步获取的公钥对敏感字符串进行 RSA-OAEP (SHA-256) 加密,并将密文转换为 Base64 编码。以下是不同语言环境的实现逻辑重构:

Python 实现方案

利用 cryptography 库或 PyCrypto 模块完成加密。注意处理 PEM 格式的换行符兼容性问题。

import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Hash import SHA256

def encrypt_sensitive_data(pub_key_pem: str, plain_text: str) -> str:
    """
    使用 RSA OAEP-SHA256 对文本进行加密并返回 Base64 字符串
    """
    # 导入公钥
    key = RSA.import_key(pub_key_pem)
    
    # 初始化加密器
    cipher = PKCS1_OAEP.new(key, hashAlgo=SHA256)
    
    # 执行加密并编码
    encrypted_bytes = cipher.encrypt(plain_text.encode('utf-8'))
    return base64.b64encode(encrypted_bytes).decode('utf-8')

# 调用示例
public_key_content = """-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
-----END PUBLIC KEY-----"""
secret_value = "MySuperSecretPassword123!"
ciphertext = encrypt_sensitive_data(public_key_content, secret_value)
print(f"Encrypted Payload: {ciphertext}")

Node.js / TypeScript 实现方案

使用原生 crypto 模块。需确保 Node.js 版本支持 createPublicKey。

import * as crypto from 'crypto';

async function rsaEncryptWithOAEP(pemKey: string, data: string): Promise<string> {
    // 标准化 PEM 头尾,防止格式错误
    const normalizedPem = pemKey.replace(/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----/g, '').trim();
    const fullPem = `-----BEGIN PUBLIC KEY-----\n${normalizedPem}\n-----END PUBLIC KEY-----`;

    const publicKey = crypto.createPublicKey({
        key: fullPem,
        format: 'pem',
        type: 'spki'
    });

    const bufferData = Buffer.from(data, 'utf8');
    
    const encryptedBuffer = crypto.publicEncrypt({
        key: publicKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
    }, bufferData);

    return encryptedBuffer.toString('base64');
}

// 调用示例
const pubKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...\n-----END PUBLIC KEY-----";
rsaEncryptWithOAEP(pubKey, "SecureTokenXYZ").then(res => console.log(res));

浏览器端 JavaScript 实现方案

适用于 Web 控制台集成场景,使用 Web Crypto API。

function arrayBufferToBase64(buffer) {
    let binary = '';
    const bytes = new Uint8Array(buffer);
    for (let i = 0; i < bytes.byteLength; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return window.btoa(binary);
}

async function webEncryptSensitive(publicKeyPem, plaintext) {
    // 清理 PEM 格式中的换行和头部尾部,转为纯 Base64 DER
    const cleanPem = publicKeyPem
        .replace(/-----BEGIN PUBLIC KEY-----/, '')
        .replace(/-----END PUBLIC KEY-----/, '')
        .replace(/\s+/g, '');
    
    const binaryDerString = atob(cleanPem);
    const binaryDer = Uint8Array.from(binaryDerString, c => c.charCodeAt(0));

    const cryptoSubtle = window.crypto.subtle;
    
    // 导入 SPKI 格式的公钥
    const keyObject = await cryptoSubtle.importKey(
        'spki',
        binaryDer.buffer,
        { name: 'RSA-OAEP', hash: 'SHA-256' },
        true,
        ['encrypt']
    );

    // 执行加密
    const encodedText = new TextEncoder().encode(plaintext);
    const encryptedArrayBuffer = await cryptoSubtle.encrypt(
        { name: 'RSA-OAEP' },
        keyObject,
        encodedText
    );

    return arrayBufferToBase64(encryptedArrayBuffer);
}

3. 构建解密与执行的 Shell 脚本

将加密后的密文嵌入到最终的 RunCommand 脚本中。脚本逻辑分为三步:调用 Agent 解密、立即销毁临时密钥、执行原始业务命令。

假设变量定义如下:

  • KP_ID: 第一步生成的密钥 ID (t-hy03a65fmrd1zpc)
  • ENC_VAL: 第二步生成的 Base64 密文

最终下发的命令内容模板:

#!/bin/bash

# 配置变量
KEY_PAIR_ID="t-hy03a65fmrd1zpc"
ENCRYPTED_DATA="{{BASE64_ENCRYPTED_STRING}}"

# 1. 请求云助手 Agent 使用私钥解密
# 注意:此操作仅在实例本地内存中进行,不会上传明文到网络
DECRYPTED_SECRET=$(aliyun-service data-encryption -d -i "$KEY_PAIR_ID" -T "$ENCRYPTED_DATA")

if [ $? -ne 0 ] || [ -z "$DECRYPTED_SECRET" ]; then
    echo "Error: Decryption failed." >&2
    exit 1
fi

# 2. 安全加固:立即删除临时密钥对,防止重放攻击或后续泄露
aliyun-service data-encryption --remove-keypair -i "$KEY_PAIR_ID"

# 3. 执行实际业务逻辑(例如重置密码)
echo "root:${DECRYPTED_SECRET}" | chpasswd

# 可选:清除环境变量中的敏感信息
unset DECRYPTED_SECRET
unset ENCRYPTED_DATA

安全性评估与风险管控

该架构通过非对称加密实现了数据在传输链路中的机密性保护。

防护能力:

  • API 层隔离:外部监控者(包括管理员和其他 RAM 用户)在 ActionTrail 或 DescribeInvocation 中只能看到 Base64 密文,无法还原明文。
  • 日志脱敏:由于解密发生在实例内部进程间通信(IPC),云平台的管控日志和网关日志均不包含明文密码。

剩余风险与缓解措施:

  • 实例内窥视:若攻击者已登录该 ECS 实例,且在密钥过期前截获了正在执行的 Shell 进程,可能通过读取 /proc/<pid>/environ 或调试内存获取明文。
    缓解策略:严格限制 key_pair_timeout 为极短值(如 10-30 秒),并确保脚本执行完毕后立即调用 --remove-keypair。
  • 侧信道攻击:虽然概率极低,但理论上存在通过时序分析破解 RSA 的可能性。
    缓解策略:使用标准的 RSA-OAEP 填充模式而非简单的 PKCS#1 v1.5,并在生产环境中结合 IAM 最小权限原则,限制能查看实例内部日志的用户范围。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。