企业上云首当其冲的就是要考量安全性的问题。为了保证系统的安全,和数据的安全,公司必须制定访问控制策略。首先看看现在的云平台对于身份认证与访问控制的设计。
Microsoft Azure
Azure 资源的基于角色的访问控制 (RBAC)
Role-Based Access Control :其基本思想是,对系统操作的各种权限不是直接授予具体的用户,而是在用户集合与权限集合之间建立一个角色集合。每一种角色对应一组相应的权限。一旦用户被分配了适当的角色后,该用户就拥有此角色的所有操作权限。
Azure提到使用RBAC的最佳做法是授予用户完成工作所需的最低权限。
RBAC 的工作原理
RBAC 控制资源访问权限的方式是创建角色分配。
安全主体(Security Principal)
安全主体是一个对象,表示请求访问 Azure 资源的用户、组、服务主体或托管标识。
角色定义(Role Definition)
角色定义是权限的集合。角色定义列出可以执行的操作,例如读取、写入和删除。
范围(Scope)
角色分配是出于授予访问权限的目的,将角色定义附加到特定范围内的用户、组、服务主体或托管标识的过程。 通过创建角色分配来授予访问权限,通过删除角色分配来撤销访问权限。
RBAC 是一个加法模型
那么Azue RBAC是如何确定用户是否有权限访问资源
步骤:
- 用户(或服务主体)获取 Azure 资源管理器的令牌。令牌包含用户的组成员身份(包括可传递的组成员身份)。
- 用户使用附加的令牌对 Azure 资源管理器发出 REST API 调用。
- Azure 资源管理器检索适用于对其执行操作的资源的所有角色分配和拒绝分配。
- Azure 资源管理器缩小适用于此用户或其组的角色分配范围,并确定用户针对此资源拥有的角色。
- Azure 资源管理器确定 API 调用中的操作是否包含在用户针对此资源拥有的角色中。
- 如果用户在请求的范围内没有具有该操作的角色,则不授予访问权限。 否则,Azure 资源管理器会检查是否适用拒绝分配。
- 如果拒绝分配适用,则阻止访问。 否则授予访问权限。
阿里云
访问控制(RAM)
访问控制(Resource Access Management)是阿里云提供的管理用户身份与资源访问权限的服务。RAM也是按需为用户分配最小权限。
RAM 的工作原理
RAM用户
RAM用户是RAM中的一种身份,对应某一个操作实体。通过创建新的RAM用户并授权,RAM用户便可以访问相关资源。有确定的身份ID和身份凭证,它通常与某个确定的人或应用程序一一对应。
-
用户管理与分权
用户组
若云账号下有多个RAM用户,通过创建用户组对职责相同的RAM用户进行分类并授权,从而更好的管理用户及其权限。
RAM角色
RAM角色有确定的身份,可以被赋予一组权限策略,但没有确定的登录密码或访问密钥。RAM角色需要被一个受信的实体用户扮演,扮演成功后实体用户将获得RAM角色的安全令牌,使用这个安全令牌就能以角色身份访问被授权的资源。
-
权限策略(Policy)
一个角色可以绑定一组权限策略。没有绑定权限策略的角色也可以存在,但不能访问资源。
RAM中权限策略的语法和结构 可以自己查看
其中权限策略结构包括:版本号,授权语句列表。每条授权语句包括授权效力(Effect)、操作(Action)、资源(Resource)以及限制条件(Condition,可选项)。
可以看出Azure 与阿里云 实现访问控制的模型上大同小异
访问控制身份认证实现
阿里云
阿里云的访问控制:单点登录(SSO),开放授权管理(OAuth);
点击可以参考 SSO 和 OAuth 原理
无论哪种方式登录的API,RAM服务会对每个访问的请求进行身份验证,无论使用HTTP还是HTTPS协议提交请求,都需要在请求中包含签名信息。
RAM计算签名
RAM通过使用AccessKey ID和AccessKeySecret进行对称加密的方法来验证请求的发送者身份。AccessKey ID和AccessKeySecret由阿里云颁发给访问者,其中AccessKey ID用于标识访问者的身份,AccessKeySecret用于加密签名字符串和服务器端验证签名字符串的密钥,必须严格保密谨防泄露。API网关计算签名例子
计算签名可以
- 校验请求参数是否被篡改。
- 请求来源是否合法。
- 请求是否具有唯一性。
它要求调用方按照约定好的算法生成签名字符串,作为请求的一部分,接口提供方验算签名即可知是否合法。
那么如果一个系统也要实现计算签名该怎么做呢?
主要步骤:
- 接口提供方给出appKey和appSecret
- 调用方根据appId和appSecret以及请求参数,按照一定算法生成签名sign
- 接口提供方验证签名
生成签名的步骤如下:
1.将所有业务请求参数按字母先后顺序排序
2.参数名称和参数值链接成一个字符串A
3.在字符串A的首尾加上appSecret组成一个新字符串B
4.对字符串进行HmacSHA256得到签名sign
5.使用Base64生产签名字符串
看看阿里云API网关设置的签名的元素有哪些
系统级 Header
【必选】X-Ca-Key:AppKey。
【必选】X-Ca-Signature:签名字符串。
【可选】X-Ca-Timestamp:API 调用者传递时间戳,值为当前时间的毫秒数,也就是从1970年1月1日起至今的时间转换为毫秒,时间戳有效时间为15分钟。(保证请求的唯一性)
【可选】X-Ca-Nonce:API 调用者生成的 UUID,结合时间戳防重放。
【可选】Content-MD5 当请求 Body 非 Form 表单时,可以计算 Body 的 MD5 值传递给云网关进行 Body MD5 校验。(防止内容别篡改)
【可选】X-Ca-Stage请求 API 所属 Stage,目前仅支持 TEST 、PRE 和 RELEASE,默认RELEASE,若您调用的 API 不在线上环境,请一定要指定该参数的值,否则会报 URL 错误。
Example:
httpget
public static Response httpGet(String host, String path, int connectTimeout, Map<String, String> headers, Map<String, String> querys, List<String> signHeaderPrefixList, String appKey, String appSecret)
throws Exception {
headers = initialBasicHeader(HttpMethod.GET, path, headers, querys, null, signHeaderPrefixList, appKey, appSecret);
HttpClient httpClient = wrapClient(host);
httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, getTimeout(connectTimeout));
HttpGet get = new HttpGet(initUrl(host, path, querys));
for (Map.Entry<String, String> e : headers.entrySet()) {
get.addHeader(e.getKey(), MessageDigestUtil.utf8ToIso88591(e.getValue()));
}
return convert(httpClient.execute(get));
}
initialBasicHeader
private static Map<String, String> initialBasicHeader(String method, String path,
Map<String, String> headers,
Map<String, String> querys,
Map<String, String> bodys,
List<String> signHeaderPrefixList,
String appKey, String appSecret)
throws MalformedURLException {
if (headers == null) {
headers = new HashMap<String, String>();
}
headers.put(SystemHeader.X_CA_TIMESTAMP, String.valueOf(new Date().getTime()));
//headers.put(SystemHeader.X_CA_X_CA_TIMESTAMPNONCE, UUID.randomUUID().toString());
headers.put(SystemHeader.X_CA_KEY, appKey);
headers.put(SystemHeader.X_CA_SIGNATURE,
SignUtil.sign(appSecret, method, path, headers, querys, bodys, signHeaderPrefixList));
return headers;
}
sign
public static String sign(String secret, String method, String path,
Map<String, String> headers,
Map<String, String> querys,
Map<String, String> bodys,
List<String> signHeaderPrefixList) {
try {
Mac hmacSha256 = Mac.getInstance(Constants.HMAC_SHA256);
byte[] keyBytes = secret.getBytes(Constants.ENCODING);
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, Constants.HMAC_SHA256));
hmacSha256.
return new String(Base64.encodeBase64(
hmacSha256.doFinal(buildStringToSign(method, path, headers, querys, bodys, signHeaderPrefixList)
.getBytes(Constants.ENCODING))),
Constants.ENCODING);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
从而进行计算签名
那么后端如何校验签名呢?
主要步骤如下:
- 得到请求方携带的API签名。
- 将所有业务请求参数按字母先后顺序排序。
- 参数名称和参数值链接成一个字符串A。
- 在字符串A的首尾加上apiSecret接口密匙组成一个新字符串B。
- 对新字符串B进行HMAC_SHA256散列运算生成服务器端的API签名,将客户端的API签名进行Base64解码,然后开始验证签名。
- 如果服务器端生成的API签名与客户端请求的API签名是一致的,则请求是可信的,否则就是不可信的。
API鉴权
先看看阿里云的RAM鉴权
阿里云使用权限来描述用户、用户组、角色对具体资源的访问能力。
权限策略(Policy)
权限策略是用语法结构描述的一组权限的集合,可以精确地描述被授权的资源集、操作集以及授权条件。
通过为RAM用户、用户组或RAM角色绑定权限策略,可以获得权限策略中指定的访问权限。
-
- 效力(Effect):授权效力包括两种:允许(Allow)和拒绝(Deny)。
- 操作(Action):操作是指对具体资源的操作。
- 资源(Resource):资源是指被授权的具体对象。
- 限制条件(Condition): 限制条件是指授权生效的限制条件。
-
Example:
- 通过指定的IP地址访问阿里云
{
"Statement": [
{
"Action": "ecs:*",
"Effect": "Allow",
"Resource": "*",
"Condition": {
"IpAddress": {
"acs:SourceIp": "192.168.0.0/16"
}
}
}
],
"Version": "1"
}
- 在指定的时间段访问阿里云。
{
"Statement": [
{
"Action": "ecs:*",
"Effect": "Allow",
"Resource": "*",
"Condition": {
"DateLessThan": {
"acs:CurrentTime": "2019-08-12T17:00:00+08:00"
}
}
}
],
"Version": "1"
}
- 列出并读取一个存储空间中的资源。
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": "oss:ListObjects",
"Resource": "acs:oss:*:*:myphotos"
},
{
"Effect": "Allow",
"Action": "oss:GetObject",
"Resource": "acs:oss:*:*:myphotos/*"
}
]
}
RAM鉴权
规则
- 以主账号身份访问
- 以RAM用户身份访问
- 以RAM角色身份访问
主要讲一下RAM角色身份访问
访问令牌
阿里云临时安全令牌(Security Token Service,STS)是阿里云提供的一种临时访问权限管理服务。
接下来是,“阿里云让你模仿,但没有让你超越”
假如我们有一个菜单API如下:
- API1: http://localhost:8001/cargosmart/ssm2014/city/listCitys
- API2: http://localhost:8002/cargosmart/ssm2014/port/createPort
- API3: http://localhost:8003/cargosmart/ssm2014/carrier/deteleCarrier
我需要这个三个接口进行安全访问控制;
1.API保护,可以设计自己的计算签名
2.API鉴权
需要的元素:
-
身份类别
2.权限策略结构
json格式:
API1: http://localhost:8001/cargosmart/ssm2014/city/listCitys
{
"Statement": [
{
"Action": "ssm2014:listCitys",
"Effect": "Allow",
"Resource": [
"cs:ssm2014:123456:user/UserName",
"cs:ssm2014:123456:group/groupName" ,
"cs:ssm2014:123456:role/roleName"],
"Condition": {
"DateLessThan": {
"acs:CurrentTime": "2020-04-10T17:00:00+08:00"
}
}
}
],
}
API2: http://localhost:8002/cargosmart/ssm2014/port/createPort
{
"Statement": [
{
"Action": "ssm2014:createPort",
"Effect": "Deny",
"Resource": [
"cs:ssm2014:23456:user/UserName",
"cs:ssm2014:*:group/groupName" ,
"cs:ssm2014:23456:role/roleName"],
"Condition": {
"DateLessThan": {
"acs:CurrentTime": "2020-04-10T17:00:00+08:00"
}
}
}
],
}