Lambda承担具有细粒度权限的AWS IAM角色



我正试图基于附加到Amazon Cognito用户的信息来假设细粒度的DynamoDB访问。

当前架构如下:

  1. React Native应用程序调用http-get,将JWT作为Authorization标头传递,以通过AWS Api网关
  2. 接收端的lambda函数对JWT进行解码,并取出附加到用户所属的Cognito组的Role Arn
  3. 然后,lambda函数使用上面提到的RoleArn调用sts.assumeRole,使用各种用户信息的RoleSessionName,以及基于附加到所述Cognito用户的自定义属性限制数据库访问的内联策略

在这组事件之后,我希望我对数据库调用的扫描会因为缺乏访问某些元素的权限而失败(稍后将使用查询而不是扫描,我只想确保权限正常工作(。

但是,扫描将继续从数据库中获取所有项目。

我一定错过了一些简单的东西,这就是我读过的做这种动作的方法。

这就是我们在Lambda函数中扮演的角色:

CognitoGroupRole:
Type: AWS::IAM::Role
Properties:
Description: Cognito Assets Group Role
AssumeRolePolicyDocument: 
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS:
- !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: Database1AccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "dynamodb:Scan"
- "dynamodb:PutItem"
- "dynamodb:UpdateItem"
- "dynamodb:Query"
Resource: !GetAtt Database1.Arn
- PolicyName: Database2AccessPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- "dynamodb:Query"
Resource: !GetAtt Database2.Arn

这是Lambda内部的函数,它承担角色并编写联机策略:

const assumeGroupRole = () => {
/* Get JWT from event.headers.Authorization */
const {
headers: { Authorization },
} = event;
/* Get the function name from context.functionName */
const { functionName } = context;
/* Decode the JWT */
const decodedToken = jwt_decode(Authorization);
const Policy = JSON.stringify({
Version: '2012-10-17',
Statement: {
Effect: 'Allow',
Action: ['dynamodb:Query', 'dynamodb:Scan'] /* Scan only for testing */,
Resource /* Device table ARN from environment variables */,
Condition: {
/* This condition *should* mean they can only access any row where the leading key is the AccountUniqueId */
'ForAllValues:StringEquals': {
'dynamodb:LeadingKeys': [decodedToken['custom:AccountUniqueId']],
},
},
},
});
console.info('Inline Policy', Policy);
/* ARN of the role attached to the cognito group */
const [RoleArn] = decodedToken['cognito:roles'];
/* Create session name from the email and function name */
const RoleSessionName = `${decodedToken.email}+${
functionName.split('-')[2]
}`;
return new Promise((resolve, reject) => {
sts.assumeRole({ RoleArn, RoleSessionName, Policy }, function (
err,
data,
) {
if (err) reject(console.error('Assume role error', err, err.stack));
else resolve(data);
});
});
};

在我实际运行扫描(在我完成这项工作后进行查询(以从DynamoDB:获取数据的地方

/* Create new DynamoDB Document client with Credentials from 
assumeRole */
const docClient = new AWS.DynamoDB.DocumentClient({
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken,
});
const params = {
TableName,
};
try {
/* Query the database with the above parameters to fetch only the 
items that match the conditions */
const { Items } = await docClient.scan(params).promise();
console.info('Queried Items', Items);
const statusCode = 200;
const body = JSON.stringify(Items);
logEvents(statusCode, body);
return {
statusCode,
body,
};
} catch (e) {
console.info('Error', e);
const statusCode = 400;
const body = JSON.stringify(e.message);
logEvents(statusCode, body);
return {
statusCode,
body,
};
}

感谢您的回复。我最终通过与一位同事的随意交谈弄明白了这一点。

事实证明;扫描";调用会忽略那些类型的细粒度权限。我认为这是因为扫描不是在寻找数据的子集,而是在寻找所有的数据。

对于上面公布的具有不匹配CCD_ 1的相同代码;未经授权";错误当我使用正确的AccountUniqueId时,我会得到我期望的数据。

最新更新