官方文檔:
https://docs.amazonaws.cn/IAM/latest/UserGuide/id_credentials_temp_request.html
描述一下這篇文章的背景:
1 背景
使用cognito 控制app接入:
APP 通過cognito服務的開發者授權驗證方式接入到的cognito服務身份池。通過userid 作爲開發人員標識換到cognito indentity pool 的唯一標識 indentityid。 而每一個通過驗證的用戶都可以用身份映射到一個AWS IAM Role(角色)。而角色可以分配一些策略。這些策略可以使用一些通配規則,拿到對應的indentityid。
比如分配到某身份上的S3訪問策略(policy)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": [
"arn:aws-cn:s3:::test",
"arn:aws-cn:s3:::test/users/${cognito-identity.amazonaws.com:sub}",
"arn:aws-cn:s3:::test/users/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
該策略使用後即可訪問 test S3存儲桶下的 users 目錄,且以身份池命名的文件夾的讀取權限。
比如用5aa0d55246c14813a2313c18換到的indentityID爲 cn-north-1:e1fb5311-asdfsad-sadfasdfa-ecfadb
如果僅僅使用S3這樣看起來沒有問題。 但近期引入了KVS 服務。而KVS的資源創建不允許有: 。所以這裏就給權限訪問帶來了困擾。而且通配的情況也讓授權訪問不夠靈活。
2 使用AWS STS頒發臨時身份憑證
https://docs.amazonaws.cn/IAM/latest/UserGuide/id_credentials_temp_request.html
這是IAM的關於臨時身份授權的文檔。提供了幾種方式如下:
AWS STS API | 誰能調用 | 憑證生命週期(最小值 /最大值 / 默認值) | MFA 支持¹ | 會話策略支持² | 對生成的臨時憑證的限制 |
---|---|---|---|---|---|
AssumeRole | 具有現有臨時安全憑證的 IAM 用戶或 IAM 角色 | 15 分鐘 | 最大會話持續時間設置³ | 1 小時 | 是 | 是 | 無法調用 GetFederationToken 或 GetSessionToken 。 |
AssumeRoleWithSAML | 任何用戶;發起人必須傳遞 SAML 身份驗證響應,指示身份驗證來自已知的身份提供商 | 15 分鐘 | 最大會話持續時間設置³ | 1 小時 | 否 | 是 | 無法調用 GetFederationToken 或 GetSessionToken 。 |
AssumeRoleWithWebIdentity | 任何用戶;發起人必須傳遞 Web 身份令牌,指示身份驗證來自已知的身份提供商 | 15 分鐘 | 最大會話持續時間設置³ | 1 小時 | 否 | 是 | 無法調用 GetFederationToken 或 GetSessionToken 。 |
GetFederationToken | IAM 用戶或 AWS 賬戶根用戶 | IAM 用戶:15 分鐘 / 36 小時 / 12 小時 根用戶:15 分鐘 / 1 小時 / 1 小時 |
否 | 是 | 無法使用 AWS CLI 或 AWS API 調用 IAM 操作。 無法調用除 GetCallerIdentity 之外的 AWS STS 操作。⁴允許通過 SSO 登錄到控制檯。⁵ |
GetSessionToken | IAM 用戶或 AWS 賬戶根用戶 | IAM 用戶:15 分鐘 / 36 小時 / 12 小時 根用戶:15 分鐘 / 1 小時 / 1 小時 |
是 | 否 | 除非請求附帶了 MFA 信息,否則無法調用 IAM API 操作。 無法調用除 AssumeRole 或 GetCallerIdentity 之外的 AWS STS API 操作。不允許通過 SSO 登錄到控制檯。⁶ |
提供了以上5中方式。
如果使用身份池的方式實質上應該是使用了AssumeRoleWithWebIdentity 該方式。
這裏我們想要更靈活的授予訪問權限這裏就提供兩種方式:
- GetFederationToken—通過自定義身份代理進行聯合
- GetSessionToken—不受信任的環境中用戶的臨時憑證
針對應用場景,是想要給APP臨時授權,所以選擇的爲GetFederationToken。
關於GetFederationToken的有效期:GetFederationToken
API 操作爲聯合身份用戶返回一組臨時安全憑證。該 API 不同於 AssumeRole
,其默認有效期大大增加 (12 小時而不是 1 小時)。此外,您還可以使用 DurationSeconds
參數指定臨時安全憑證保持有效的持續時間。生成的憑證在指定的持續時間內有效,即,900 秒 (15 分鐘) 到 129,600 秒 (36 小時) 之間。較長的有效期有助於減少對 AWS 的調用次數,因爲您不需要頻繁獲取新憑證。
關於GetFederationToken的權限範圍:
您在發出此請求時使用特定 IAM 用戶的憑證。臨時安全憑證的權限是由調用 GetFederationToken
時傳遞的會話策略決定的。生成的會話權限是 IAM 用戶策略與您傳遞的會話策略的交集。使用會話策略授予的權限不能超過請求聯合的 IAM 用戶的基於身份的策略允許的權限。有關角色會話權限的更多信息,請參閱會話策略。
測試代碼(nodejs)
代碼通過STS GetFederationToken 獲取credentials 並用該credentials初始化S3獲取S3中數據。
實際使用中獲取credentials 由服務端完成
使用credentials初始化S3獲取S3中文件由APP完成
const AWS = require('aws-sdk');
const sts = new AWS.STS({
accessKeyId: 'AKIAXXXXXXXXXXXXX',
secretAccessKey: 'NeUXXXXXXXXXXXXXXXXXXXXXXXXXX',
region: 'cn-northwest-1',
});
let str1 = {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": [
"arn:aws-cn:s3:::testbucket",
"arn:aws-cn:s3:::testbucket/test/",
"arn:aws-cn:s3:::testbucket/test/*"
]
}
]
}
function getFederationToken(){
return new Promise((resolve, reject) => {
var params = {
Policy:JSON.stringify(str1), //"{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"Stmt1\",\"Effect\":\"Allow\",\"Action\":\"s3:ListAllMyBuckets\",\"Resource\":\"*\"}]}",
Name: "test" //假定角色會話的標識符。 userid
};
sts.getFederationToken(params, function (err, data) {
if (err){
console.log(err, err.stack); // an error occurred
return reject(err);
}
else{
console.log(data);
return resolve(data.Credentials);
}
});
})
}
async function run(){
const credentials = await getFederationToken();
let s3 = new AWS.S3({ accessKeyId: credentials.AccessKeyId, secretAccessKey: credentials.SecretAccessKey, sessionToken: credentials.SessionToken, region:'cn-northwest-1'});
console.log(credentials);
let getParams = {
Bucket: "testbucket",
Key: 'kedaya1.jfif'
};
s3.getObject(getParams, function(err, data) {
if (err){
console.error("get object error");
console.error(err);
}
console.info('-------GET object------');
console.info(data);
});
}
run();
返回值
{
AccessKeyId: 'ASXXXXXXXXXXXXXX',
SecretAccessKey: 'qKFBNTXXXXXXXXXXXXX',
SessionToken: 'IQoJb3XXXXXXXXXXXXX',
Expiration: 2020-06-16T18:18:20.000Z
}