前言
服务配置参数的托管一直是开发和运维过程中比较重要的一环,对配置数据进行统一托管、安全存储、安全分发对于业务的安全稳定运行有极大的帮助。
这里我们提及的配置数据,通常指的是对于某项服务的启动加载必不可少的参数,常见的比如:
- 存储组件数据库(Mysql、Mongo、ES 等)的连接信息
- 消息中间件 (Redis、Kafka等)的配置信息
- 对业务而言必不可少的规格参数,比如连接池大小、内存缓冲区大小、连接超时时间、服务监听端口等
- 与业务息息相关的特性参数,比如业务的商品种类、价格配置等等 ......
这些数据都有如下的一些特点:
- 可结构化,比如可以通过 JSON、YAML 等数据格式进行结构化表示
- 可灵活配置,比如在不同环境下相同配置项的值会不一样
- 版本管理,比如在公有云环境、私有化环境、混合云环境下,配置文件分别有不同的版本,需要以版本或环境作为配置区分的依据
- 数据大小可控,比如一般来说这些数据不会超过 2K 或 4K 字节,在实际的业务场景中,对于比较庞大的配置数据(比如 4K 字节以上),一般建议按照使用场景、作用进行配置拆分,这样可以更加清晰的管理数据 ......
当然,还有一点不可忽视的特点就是,上述数据可能包含业务生产环境的关键信息,因此对这些数据进行安全加固是必不可少的,比如使用安全的加密手段对这些数据进行加密存储以及安全分发(https 信道传输)。
除了上面这些特点外,对配置数据进行全生命周期管理比如启用、禁用、新增、删除等也是增加业务运维效率不可缺少的能力。
这篇文章将会基于 SSM凭据管理系统 ,围绕配置数据管理的常见场景进行使用说明。
走近 SSM
总体架构概述
腾讯云 SSM 凭据管理系统最核心的能力是能对用户的凭据数据做安全加密托管,它的底层依赖于腾讯云KMS密钥管理系统对数据进行加解密。
SSM 在整个腾讯云云平台上的架构如下:
整个架构可以拆解为:
- 用户访问 SSM 可以通过两种方式,一种是使用 SDK,通过 API 接口进行数据的读取;另一种是用户自己登录控制台,通过 Web 界面的方式进行交互操作。
- 无论用户通过哪种方式进行操作,最终用户的请求都会被腾讯云云 API 接收,并且云 API 最终会将请求转发送到 SSM 系统, SSM 系统返回给客户端的数据,也是以腾讯云云 API作为统一出口 ,这里客户端与云 API交互链路默认都是 HTTPS 信道进行加密传输。
- 在 SSM 系统接收真正的请求之前,腾讯云的 CAM 需要对请求做鉴权操作,这里的鉴权包括对云平台密钥 AKSK 进行鉴权,对用户账号能否访问特定资源的鉴权等。
- SSM 系统在对凭据数据做生命周期的管理时,依赖 KMS 系统提供的加解密能力对数据进行加解密保护和存储。
通过控制台访问 SSM(示例)
以自定义凭据为例,通过云控制台访问 SSM 的形式如下:
通过 SDK 访问 SSM(示例)
通过 SDK 的方式访问 SSM会涉及到编码,这里我们可以 以 通过 python sdk 访问云 API 的方式来举例,展示拉取 SSM 凭据列表的操作:
import os
from tencentcloud.common import credential
from tencentcloud.common.credential import Credential
from tencentcloud.common.exception import TencentCloudSDKException
from tencentcloud.ssm.v20190923 import models as ssm_models, ssm_client
if name == 'main':
# 通过环境变量的方式获取腾讯云 AKSK(即 secretID、secretKey)
# 这里的环境变量的名称用户可以自定义
# 设置环境变量:
# export TENCENT_CLOUD_SECRET_ID="AKIDxxxxxxx"
# export TENCENT_CLOUD_SECRET_KEY="mX3Ixxxxxx"
# 如果希望环境变量长期生效,根据用户使用的 shell 环境,可以将环境变量写到对应的配置文件中
# 比如用户使用的 bash,则写入 ~/.bash_profile并source/.bash_profile/.zshrc 并 source ~/.zshrc
# 如果使用的是 zsh,则写入
SECRET_ID_ENV_NAME: str = "TENCENT_CLOUD_SECRET_ID"
SECRET_KEY_ENV_NAME: str = "TENCENT_CLOUD_SECRET_KEY"
secret_id: str = os.environ.get(SECRET_ID_ENV_NAME)
secret_key: str = os.environ.get(SECRET_KEY_ENV_NAME)
region: str = 'ap-guangzhou'
try:
cred: Credential = credential.Credential(secret_id, secret_key)
demo_client = ssm_client.SsmClient(cred, region)
req = ssm_models.ListSecretsRequest()
req.Limit = 10
rsp = demo_client.ListSecrets(req)
print(rsp.to_json_string(indent = ' '))
except TencentCloudSDKException as e:
print(e)
raise e
执行这段代码后将会输出:
SSM使用入门
自定义凭据
自定义凭据的概念
SSM 最简单的使用方式,同时在配置管理中也是最常见的使用方式,就是使用自定义凭据。
自定义凭据,最大的特点就是自定义,这里的自定义,指的是,用户可以自定义凭据的数据内容格式,当然这里所说的数据仅限于文本数据。
无论是结构化的数据如 JSON、YAML,TOML 等,还是非结构化的数据,比如"hello,world"这种常见字符串,都可以托管到自定义凭据中。
对于非文本类数据比如图片,如果确实有必要进行托管,则可以先将数据进行 base64 或其他形式的编码,转化成纯文本数据。
在 SSM 系统中,以用户为纬度(如同一个 APPID 下的账号),凭据名是唯一存在的,即同一个 APPID 下(无论是主账号 UIN 还是子账号 UIN),凭据名在创建时必须保持唯一。
手动创建自定义凭据
最简单的使用方式,就是,配置的管理员登录到 SSM 的控制台,设置好凭据内容,然后,业务进程通过集成 SSM SDK,拉取凭据内容并做内容解析。
比如现在在系统中创建好如下内容的凭据数据:
{
"username": "hello",
"password": "world",
"token": "1234567890"
}
将凭据名命名为demo_test
,其有且仅有一个版本:demo_01
点击确定后,即可生成凭据:
此时,凭据即创建完成。
通过 SDK 读取自定义凭据
在常见的服务配置管理场景中,对于配置的读取,往往都是通过API 接口的形式进行读取的。
SSM 系统提供了标准的腾讯云 SDK,这里我们以 Python SDK 为例演示凭据读取的过程。
import json
import osfrom tencentcloud.common import credential
from tencentcloud.common.credential import Credential
from tencentcloud.common.exception import TencentCloudSDKException
from tencentcloud.ssm.v20190923 import models as ssm_models, ssm_clientif name == 'main':
# 获取 SecretId 和 SecretKey
secret_id: str = os.environ.get("TENCENT_CLOUD_SECRET_ID")
secret_key: str = os.environ.get("TENCENT_CLOUD_SECRET_KEY")
try:
# 生成 credential 对象
cred: Credential = credential.Credential(secret_id, secret_key)# 指定需要调用的 SSM 的地域 region: str = 'ap-guangzhou' demo_client = ssm_client.SsmClient(cred, region) # 生成请求并填充参数 req = ssm_models.GetSecretValueRequest() req.SecretName = "demo_test" req.VersionId = "demo_01" # 发送请求,并获取响应 rsp = demo_client.GetSecretValue(req) # 解析响应数据,如将凭据明文进行结构化 data = json.loads(rsp.SecretString) # 使用凭据数据,这里仅仅作打印动作,实际业务场景中根据需要进行自定义 print(rsp.SecretName, rsp.VersionId, data) except TencentCloudSDKException as e: print(e) raise e</code></pre></div></div><p>无论使用 Python 语言的 SDK亦或是 Golang、Java、CPP 等等其他语言的 SDK,在通过 SDK 调用 SSM 的云 API 接口前都需要先获取云平台的 AKSK,这个步骤在上述示例代码中对应的语句为:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0"> secret_id: str = os.environ.get("TENCENT_CLOUD_SECRET_ID") secret_key: str = os.environ.get("TENCENT_CLOUD_SECRET_KEY")</code></pre></div></div><p>获取完 AKSK 后,需要先生成 Credential对象,用于客户端的创建:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>txt</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-txt"><code class="language-txt" style="margin-left:0"> cred: Credential = credential.Credential(secret_id, secret_key)</code></pre></div></div><p>由于 SSM 系统本身是分地域的,因此在查询某个凭据前,需要先确定凭据所处的地域,并生成对应的客户端:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0"> region: str = 'ap-guangzhou' demo_client = ssm_client.SsmClient(cred, region)</code></pre></div></div><p>作为业务方,我们只需要拉取凭据接口,因为我们只需要调用查询接口,读取凭据明文,在发起查询请求前需要先构造请求包:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0"> req = ssm_models.GetSecretValueRequest() req.SecretName = "demo_test" req.VersionId = "demo_01"</code></pre></div></div><p>SSM 系统查询凭据明文统一使用 <strong>GetSecretValue 接口</strong>进行查询。</p><p><strong>使用这个接口时,我们需要填充好 VersionId 字段,以明确需要查询的凭据版本,如前文所说,SSM 的自定义凭据是允许用户进行多版本管理的。</strong></p><p>关于更多 SSM 的 API 接口可以点击查阅。</p><p>构造好请求包之后,发送请求即可:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0">rsp = demo_client.GetSecretValue(req)</code></pre></div></div><p>对获取的响应做解析:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0">data = json.loads(rsp.SecretString)
print(rsp.SecretName, rsp.VersionId, data)
自定义凭据的多版本管理
自定义凭据允许用户设置多个版本,以应对不同场景下的差异化配置需求。
自定义凭据的多版本添加很简单:
点击确定后,当前凭据就有了两个版本:
对于业务进程来说,在明确当前应该使用哪个版本的凭据后,只需要在请求包的参数中,将版本号替换为对应的版本即可:
# 生成请求并填充参数
req = ssm_models.GetSecretValueRequest()
req.SecretName = "demo_test"
req.VersionId = "demo_special_01"
最终得到响应:
demo_test demo_special_01 {'special': 'this is a special config data'}
如前面的截图所示,多版本既可以新增,也可以更改和删除,通过 Web 界面交互操作时,用户在控制台点击操作即可。
通过 SSM 云 API 构建凭据管理服务
对于大部分服务来说,创建凭据的过程如果只能通过 Web 页面进行手动操作,会导致效率低下,且无法自动化,会限制很多场景。
SSM 云 API 提供了凭据生命周期管理的所有接口,业务方可以通过这些接口,构建自己的凭据管理服务,按照自己的使用场景,灵活的进行配置运维。
以下接口是自定义凭据生命周期管理常用的接口:
创建凭据 CreateSecret
查询凭据明文 GetSecretValue
更新指定凭据版本内容 UpdateSecret
新增指定凭据版本 PutSecretValue
删除指定凭据版本 DeleteSecretVersion
查询指定凭据的版本列表 ListSecretVersionIds
查询凭据列表 ListSecrets
禁用凭据 DisableSecret
启用凭据 EnableSecret
删除凭据 DeleteSecret
二进制数据的托管示例
在使用 API 进行凭据的创建和凭据版本的更新时,可以支持对于非文本类数据的托管,比如对于二进制数据的托管:
# 生成请求并填充参数
req = ssm_models.CreateSecretRequest()
req.SecretName = "binary_secret"
req.VersionId = "test_01"# 生成二进制数据,示例中为 256 个元素的ascii 码 binary_data = [x for x in range(0, 256)] print("origin binary_data:", binary_data) # 对二进制数据进行编码 req.SecretBinary = base64.standard_b64encode(bytes(binary_data)).decode(encoding = 'utf-8') # 发送请求,并获取响应 rsp = demo_client.CreateSecret(req) # 使用凭据数据,这里仅仅作打印动作,实际业务场景中根据需要进行自定义 print(rsp.SecretName, rsp.VersionId)</code></pre></div></div><p>此时数据明文为:</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:78.83%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723302572518957555.png" /></div><div class="figure-desc">二进制数据明文</div></div></div></figure><p>查询二进制凭据明文:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0"> # 构造查询请求包 query_req = ssm_models.GetSecretValueRequest() query_req.SecretName = "binary_secret" query_req.VersionId = "test_01" # 发送请求并获取响应 query_rsp = demo_client.GetSecretValue(query_req) print(query_rsp.to_json_string(indent = ' ')) # 对二进制数据先做 base64 解码操作进而获取真实明文 plain_bytes = base64.standard_b64decode(query_rsp.SecretBinary) print("secret plain data:", list(plain_bytes))</code></pre></div></div><p>得到的响应:</p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:78.83%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723302572885323942.png" /></div><div class="figure-desc">查询二进制凭据数据</div></div></div></figure><h3 id="eq1ou" name="%E5%9F%BA%E4%BA%8E%E4%BA%91-API-%E6%9E%84%E9%80%A0%E5%A4%9A%E5%9C%B0%E5%9F%9F%E5%87%AD%E6%8D%AE%E5%A4%87%E4%BB%BD%E8%83%BD%E5%8A%9B">基于云 API 构造多地域凭据备份能力</h3><p>在通过云 API 实现了凭据管理的自动化流程后,出于容灾考虑,业务方可以自己新增凭据容灾备份能力。</p><p>业务方可以通过接口:查询 SSM 地域列表 GetRegions 查询当前 SSM 所支持的地域,然后根据自己业务部署的地域,选择一个或多个作为容灾地域。</p><p>举个例子,假设用户的配置主要从 SSM 广州地域拉取,为了防止广州地域 SSM 不可访问(比如广州地域主干网络不可达等等异常情况发生)导致业务配置拉取不了,可以在访问广州失败时,将地域切换为北京和上海,进行配置的读取。</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0"> # 默认指定广州即可 region: str = 'ap-guangzhou' demo_client = ssm_client.SsmClient(cred, region) # 生成请求并填充参数 req = ssm_models.GetRegionsRequest() # 发送请求,并获取响应 rsp = demo_client.GetRegions(req) # 解析响应数据,如将凭据明文进行结构化 print(rsp.to_json_string(indent = ' '))</code></pre></div></div><p>得到的 SSM 地域列表:</p><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>python</div><div class="rno-markdown-code-toolbar-item is-num"><i class="icon-code"></i><span class="is-m-hidden">代码</span>运行次数:<!-- -->0</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div><button class="rno-markdown-code-toolbar-run"><i class="icon-run"></i><span class="is-m-hidden">Cloud Studio</span> 代码运行</button></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-python"><code class="language-python" style="margin-left:0">{ "Regions": [ "ap-guangzhou", "ap-beijing", "ap-shanghai", "ap-singapore", "ap-tokyo" ], "RequestId": "5f08ef56-9288-4d7b-be63-7a70b84c8555"
}
在构造多地域备份能力时,需要业务方首先在多个地域创建好内容相同的凭据,同时后续的凭据更新操作,也需要保证多地域的数据一致性。
业务方在代码实现时,对于凭据的写操作,建议增加超时操作,避免因为偶尔的超时或者网络抖动,导致更新失败,进而影响数据一致性。
SSM 凭据资源的权限管理
SSM 基于腾讯云CAM服务进行用户的资源访问控制。
当业务的复杂度逐步增大时,其凭据数量必然会逐步变多,这个时候,业务势必需要对凭据的访问进行权限划分。
腾讯云允许主账号生成子账号,并通过对子账号设置 CAM 策略语法,对子账号进行细粒度的权限划分。
比较典型的场景如:
某账号分别有两个子账号 A 和 B,其中 A 对应子业务 A,B 对应子业务 B,
那么业务 A 应该只能通过子账号 A 访问 A 对应的凭据资源,同样业务 B 也应该只能访问 B 对应的凭据资源。
此类场景可以归纳为:
- 每个子账号只可以对自己创建的凭据做创建删除等任何操作,但是不能看到以及不能对其他子账号/主账号创建的凭据做任何操作。
- 所有的业务子账号,只能对SSM 产品下自己的资源拥有操作权限,不能拥有其他如新增子账号、删除子账号、删除 CVM 等等权限。
实现上述的效果可以参考如下的 CAM 策略配置:
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": [
"ssm:DescribeAsyncRequestInfo",
"ssm:DescribeSupportedProducts",
"ssm:GetServiceStatus",
"ssm:GetRegions",
"ssm:CreateAccessKeySecret",
"ssm:CreateProductSecret",
"ssm:CreateSSHKeyPairSecret",
"ssm:CreateSecret",
"ssm:DescribeResourceIds"
],
"resource": [
""
]
},
{
"effect": "allow",
"action": [
"ssm:ListSecrets",
"ssm:GetSecretValue",
"ssm:UpdateRotationStatus",
"ssm:ListSecretVersionIds",
"ssm:RestoreSecret",
"ssm:PutSecretValue",
"ssm:DeleteSecret",
"ssm:DeleteSecretVersion",
"ssm:DescribeSecret",
"ssm:DisableSecret",
"ssm:EnableSecret",
"ssm:UpdateDescription",
"ssm:UpdateSecret",
"ssm:GetSSHKeyPairValue",
"ssm:RotateProductSecret",
"ssm:DescribeRotationDetail",
"ssm:DescribeRotationHistory"
],
"resource": [
"qcs::ssm::uin/{主账号UIN}:secret/creatorUin/{子账号UIN}/"
]
},
{
"effect": "allow",
"action": [
"kms:GetServiceStatus"
],
"resource": [
""
]
},
{
"effect": "allow",
"action": [
"cam:GetRole"
],
"resource": [
""
]
},
{
"effect": "allow",
"action": [
"tag:DescribeResourceTagsByResourceIds",
"tag:DescribeResourceTags"
],
"resource": [
""
]
}
]
}
注意,需要将 {主账号UIN}和 {子账号UIN} 替换为用户自己的UIN。
策略模板的说明
查询角色授权的权限
由于在开通SSM(首次使用SSM)时,需要对当前开通SSM的主账号进行角色授权操作,以保证此主账号(APPID和主账号UIN)具备相关产品的角色以及对应角色下的预设策略权限。
当使用子账号在控制台打开SSM页面时,首先要做的就是去查询当前账号是否授予了相关角色。
{
"effect": "allow",
"action": [
"cam:GetRole"
],
"resource": [
""
]
},
查询 KMS 是否开通的权限
由于SSM服务依赖于KMS服务,想要使用SSM就必须要检查KMS是否已经开通。
授予此策略是为了让子账号在控制台打开SSM页面时,有权限去查询当前是否已经开通了KMS。
{
"effect": "allow",
"action": [
"kms:GetServiceStatus"
],
"resource": [
""
]
},
针对 SSM 产品的接口级授权
由于调用这些接口时不需要指定任何凭据名,故设置为接口级授权,每个子账号都可以通过上述接口进行相关操作。
{
"effect": "allow",
"action": [
"ssm:DescribeAsyncRequestInfo",
"ssm:DescribeSupportedProducts",
"ssm:GetServiceStatus",
"ssm:GetRegions",
"ssm:CreateAccessKeySecret",
"ssm:CreateProductSecret",
"ssm:CreateSSHKeyPairSecret",
"ssm:CreateSecret",
"ssm:DescribeResourceIds"
],
"resource": [
""
]
},
针对 SSM 产品的资源级授权
由于调用这些接口时必须要指定凭据名,故将其设置为资源级授权,资源范围为当前子账号有权限的所有资源。
当主账号新建一个子账号后,将此策略,且仅将此策略授予子账号,则这个子账号只能查看、修改、删除他自己创建的的凭据资源。
{
"effect": "allow",
"action": [
"ssm:ListSecrets",
"ssm:GetSecretValue",
"ssm:UpdateRotationStatus",
"ssm:ListSecretVersionIds",
"ssm:RestoreSecret",
"ssm:PutSecretValue",
"ssm:DeleteSecret",
"ssm:DeleteSecretVersion",
"ssm:DescribeSecret",
"ssm:DisableSecret",
"ssm:EnableSecret",
"ssm:UpdateDescription",
"ssm:UpdateSecret",
"ssm:GetSSHKeyPairValue",
"ssm:RotateProductSecret",
"ssm:DescribeRotationDetail",
"ssm:DescribeRotationHistory"
],
"resource": [
"qcs::ssm::uin/{主账号UIN}:secret/creatorUin/{子账号UIN}/"
]
},
查询资源绑定的 TAG 的权限
在控制台拉取SSM的凭据时,可能也需要拉取每个凭据绑定了哪些TAG,因此需要相关读权限。
{
"effect": "allow",
"action": [
"tag:DescribeResourceTagsByResourceIds",
"tag:DescribeResourceTags"
],
"resource": [
""
]
}
如果业务侧需要更加定制化的策略,也可以根据自己的场景自行创建相关策略。
关于 CAM 策略语法的使用,请参考 CAM 侧相关的文档。
SSM 凭据类型的拓展
SSM 除了支持自定义凭据外,还支持特定产品类型的凭据,目前已有的类型包括:
- 数据库凭据
支持的数据库
- SSH 密钥对凭据
SSH 密钥对凭据
上述的几种凭据,主要针对的是腾讯云平台上,云原生的数据库以及 SSH 密钥对资源的安全托管。
SSM 对于云上数据库的凭据托管,可以支持自动轮换,SSM 会根据用户预先设定的轮转周期,对凭据中保存的账号密码信息进行更新。客户端通过调用 获取凭据明文 可以获取到最新的有效账号和密码信息。同一个凭据的账号和密码信息会发生变化,但对应的数据库的访问权限是相同的,SSM 会负责在数据库中同步创建或更新具有相同权限的账号或密码。
数据库凭据的轮换,对于云上数据库的安全运维有很大的帮助,可以大大减少数据库凭据泄露带来的数据库安全风险。
SSM 数据库凭据的使用这里不具体展开,请参考:数据库凭据的使用。
SSM 团队在集成腾讯云云原生资源上还在进一步拓展,比如后续会支持 Redis、Kafka、MongoDB、ES 等等云上资源凭据的托管。
基于 SSM 的云上密钥 AKSK 的安全保护
不知道大家注意到没,本篇文章中,所有示例代码里面,在获取 SecretId 和 SecretKey 时,都是使用环境变量从本地读取的方式来做的,其实这是一种不太安全的做法。
AKSK 作为云平台的入口凭据,其重要程度不言而喻,但是对于 AKSK 的保护是一个很复杂的话题,其不仅仅涉及到 SDK 集成和编码,还对内部数据安全治理体系提出了更高的要求,因为篇幅限制,这部分内容这里不具体展开,感兴趣的同学可以先看看作者之前的文章:
《关于AKSK安全保护的一点思考》
如果有疑问欢迎在评论区留言!