Skip to content

Commit

Permalink
feat: narrow-down idp roles scope (#1974)
Browse files Browse the repository at this point in the history
* fixes based on PR comments

* fix: fix async push

* feat: narrow-down idp roles scope

* narrow down IAM update plicies for the lambda execution role
  • Loading branch information
kaustavghosh06 committed Aug 8, 2019
1 parent caba157 commit ccfd508
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 17 deletions.
20 changes: 18 additions & 2 deletions packages/amplify-provider-awscloudformation/lib/push-resources.js
Expand Up @@ -401,15 +401,17 @@ function uploadTemplateToS3(context, resourceDir, cfnFile, category, resourceNam
function formNestedStack(context, projectDetails, categoryName, resourceName, serviceName, skipEnv) {
/* eslint-enable */
const nestedStack = context.amplify.readJsonFile(`${__dirname}/rootStackTemplate.json`);

const { amplifyMeta } = projectDetails;

let authResourceName;
let categories = Object.keys(amplifyMeta);
categories = categories.filter(category => category !== 'provider');
categories.forEach((category) => {
const resources = Object.keys(amplifyMeta[category]);
resources.forEach((resource) => {
const resourceDetails = amplifyMeta[category][resource];
if (category === 'auth') {
authResourceName = resource;
}
const resourceKey = category + resource;
let templateURL;
if (resourceDetails.providerPlugin) {
Expand Down Expand Up @@ -462,9 +464,23 @@ function formNestedStack(context, projectDetails, categoryName, resourceName, se
}
});
});

if (authResourceName) {
updateIdPRolesInNestedStack(context, nestedStack, authResourceName);
}
return nestedStack;
}

function updateIdPRolesInNestedStack(context, nestedStack, authResourceName) {
const authLogicalResourceName = `auth${authResourceName}`;
const idpUpdateRoleCfn = context.amplify.readJsonFile(`${__dirname}/update-idp-roles-cfn.json`);

idpUpdateRoleCfn.UpdateRolesWithIDPFunction.DependsOn.push(authLogicalResourceName);
idpUpdateRoleCfn.UpdateRolesWithIDPFunctionOutputs.Properties.idpId['Fn::GetAtt'].unshift(authLogicalResourceName);

Object.assign(nestedStack.Resources, idpUpdateRoleCfn);
}

module.exports = {
run,
updateStackForAPIMigration,
Expand Down
Expand Up @@ -33,16 +33,11 @@
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Effect": "Deny",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "authenticated"
}
}
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
Expand All @@ -57,16 +52,11 @@
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Effect": "Deny",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"ForAnyValue:StringLike": {
"cognito-identity.amazonaws.com:amr": "unauthenticated"
}
}
"Action": "sts:AssumeRoleWithWebIdentity"
}
]
}
Expand Down
@@ -0,0 +1,173 @@
{

"UpdateRolesWithIDPFunction": {
"DependsOn": [
"AuthRole",
"UnauthRole"
],
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": {
"Fn::Join": [
"\n",
[
"const response = require('cfn-response');",
"const aws = require('aws-sdk');",
"let responseData = {};",
"exports.handler = function(event, context) {",
" try {",
" let authRoleName = event.ResourceProperties.authRoleName;",
" let unauthRoleName = event.ResourceProperties.unauthRoleName;",
" let idpId = event.ResourceProperties.idpId;",
" let promises = [];",
" let authParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'authenticated'}}}]};",
" let unauthParamsJson = { 'Version': '2012-10-17','Statement': [{'Effect': 'Allow','Principal': {'Federated': 'cognito-identity.amazonaws.com'},'Action': 'sts:AssumeRoleWithWebIdentity','Condition': {'StringEquals': {'cognito-identity.amazonaws.com:aud': idpId},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'unauthenticated'}}}]};",
" if (event.RequestType == 'Delete') {",
" delete authParamsJson.Statement.Condition;",
" delete unauthParamsJson.Statement.Condition;",
" let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};",
" let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};",
" const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});",
" promises.push(iam.updateAssumeRolePolicy(authParams).promise());",
" promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());",
" Promise.all(promises)",
" .then((res) => {",
" console.log(\"delete\" + res);",
" console.log(\"response data\" + JSON.stringify(res));",
" response.send(event, context, response.SUCCESS, res);",
" });",
" }",
" if (event.RequestType == 'Update' || event.RequestType == 'Create') {",
" const iam = new aws.IAM({ apiVersion: '2010-05-08', region: event.ResourceProperties.region});",
" let authParams = { PolicyDocument: JSON.stringify(authParamsJson),RoleName: authRoleName};",
" let unauthParams = {PolicyDocument: JSON.stringify(unauthParamsJson),RoleName: unauthRoleName};",
" promises.push(iam.updateAssumeRolePolicy(authParams).promise());",
" promises.push(iam.updateAssumeRolePolicy(unauthParams).promise());",
" Promise.all(promises)",
" .then((res) => {",
" console.log(\"createORupdate\" + res);",
" console.log(\"response data\" + JSON.stringify(res));",
" response.send(event, context, response.SUCCESS, {});",
" });",
" }",
" } catch(err) {",
" console.log(err.stack);",
" responseData = {Error: err};",
" response.send(event, context, response.FAILED, responseData);",
" throw err;",
" }",
"};"
]
]
}
},
"Handler": "index.handler",
"Runtime": "nodejs8.10",
"Timeout": "300",
"Role": {
"Fn::GetAtt": [
"UpdateRolesWithIDPFunctionRole",
"Arn"
]
}
}
},
"UpdateRolesWithIDPFunctionOutputs": {
"Type": "Custom::LambdaCallout",
"Properties": {
"ServiceToken": {
"Fn::GetAtt": [
"UpdateRolesWithIDPFunction",
"Arn"
]
},
"region": {
"Ref": "AWS::Region"
},
"idpId": {
"Fn::GetAtt": [

"Outputs.IdentityPoolId"
]
},
"authRoleName": {
"Ref": "AuthRoleName"
},
"unauthRoleName": {
"Ref": "UnauthRoleName"
}
}
},
"UpdateRolesWithIDPFunctionRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"RoleName": {
"Fn::Join": [
"",
[
{
"Ref": "AuthRoleName"
},
"-idp"
]
]
},
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": [
"lambda.amazonaws.com"
]
},
"Action": [
"sts:AssumeRole"
]
}
]
},
"Policies": [
{
"PolicyName": "UpdateRolesWithIDPFunctionPolicy",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
},
{
"Effect": "Allow",
"Action": "iam:UpdateAssumeRolePolicy",
"Resource": {
"Fn::GetAtt": [
"AuthRole",
"Arn"
]
}
},
{
"Effect": "Allow",
"Action": "iam:UpdateAssumeRolePolicy",
"Resource": {
"Fn::GetAtt": [
"UnauthRole",
"Arn"
]
}
}
]
}
}
]
}
}
}
Expand Up @@ -310,7 +310,12 @@ class CloudFormation {
.then((result) => {
let resources = result.StackResources;
resources = resources.filter(resource =>
!['DeploymentBucket', 'AuthRole', 'UnauthRole'].includes(resource.LogicalResourceId));
!['DeploymentBucket',
'AuthRole',
'UnauthRole',
'UpdateRolesWithIDPFunction',
'UpdateRolesWithIDPFunctionOutputs',
'UpdateRolesWithIDPFunctionRole'].includes(resource.LogicalResourceId));

const promises = [];

Expand Down

0 comments on commit ccfd508

Please sign in to comment.