New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fixed added deny iam policy when user opt disable log for a function #8561
fixed added deny iam policy when user opt disable log for a function #8561
Conversation
Codecov Report
@@ Coverage Diff @@
## master #8561 +/- ##
==========================================
+ Coverage 87.27% 87.28% +0.01%
==========================================
Files 256 256
Lines 9516 9524 +8
==========================================
+ Hits 8305 8313 +8
Misses 1211 1211
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as19ish Thank you! Please see my comment
this.serverless.service.provider.compiledCloudFormationTemplate.Resources[ | ||
this.provider.naming.getRoleLogicalId() | ||
].Properties.Policies[0].PolicyDocument.Statement.push({ | ||
Effect: 'Deny', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be good enough to just not add 'Allow'
policy? I believe that's all needed (by default access is denied)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@medikoo As serverless by default allow logs, so I think if we make by default access is denied so this makes more complicate the scenario. Let me know what u think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as19ish What I meant that we should disable access simply by removing "Allow" rules, and not by by replacing them with "Deny" rules (they're effect-less, as they do no override anything)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is some misunderstanding, I m explaining the whole problem.
By default, we are allowing lambda execution role to this permission
- logs:CreateLogStream
- logs:CreateLogGroup
- logs:PutLogEvents
Note: BY USING WILDCARD CHARACTER
"Statement": [
{
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": [
"arn:aws:logs:us-east-1:188267231256:log-group:/aws/lambda/serverless-dev*:*"
],
"Effect": "Allow"
},
{
"Action": [
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-1:188267231256:log-group:/aws/lambda/serverless-dev*:*:*"
],
"Effect": "Allow"
}
]
Now the main problem here how can we deny to specific lambda to do not put logs and also by default all lambda has the same lambda execution role.
So here what i'm doing is adding a new statement that denies for put logs for a specific function (full ARN not using a wildcard) as per the Principle of Least Privilege
{
"Action": "logs:PutLogEvents",
"Resource": [
"arn:aws:logs:us-east-1:188267231256:log-group:/aws/lambda/serverless-dev-hello:*"
],
"Effect": "Deny"
}
I m a little confused here. Can we do it in a better way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as19ish ah, indeed, thanks for explanations. I forgot that in common cases we use wildcards, and indeed for this, we'd need to deny the assigned rights.
Still it'll be good to integrate it better with logic which generates "Allow" rights, e.g. we should not create "Deny" rule, for functions not expressed by canonical naming (we should just prevent generation of "Allow" rights for them)
Therefore I would cover this in this part of logic:
serverless/lib/plugins/aws/package/lib/mergeIamTemplates.js
Lines 92 to 129 in 6dd9a31
this.serverless.service.getAllFunctions().forEach(functionName => { | |
const { name: resolvedFunctionName } = this.serverless.service.getFunction(functionName); | |
if (!resolvedFunctionName || resolvedFunctionName.startsWith(canonicalFunctionNamePrefix)) { | |
hasOneOrMoreCanonicallyNamedFunctions = true; | |
return; | |
} | |
const customFunctionNamelogGroupsPrefix = this.provider.naming.getLogGroupName( | |
resolvedFunctionName | |
); | |
policyDocumentStatements[0].Resource.push({ | |
'Fn::Sub': | |
'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + | |
`:log-group:${customFunctionNamelogGroupsPrefix}:*`, | |
}); | |
policyDocumentStatements[1].Resource.push({ | |
'Fn::Sub': | |
'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + | |
`:log-group:${customFunctionNamelogGroupsPrefix}:*:*`, | |
}); | |
}); | |
if (hasOneOrMoreCanonicallyNamedFunctions) { | |
// Ensure general policies for functions with default name resolution | |
policyDocumentStatements[0].Resource.push({ | |
'Fn::Sub': | |
'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + | |
`:log-group:${logGroupsPrefix}*:*`, | |
}); | |
policyDocumentStatements[1].Resource.push({ | |
'Fn::Sub': | |
'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + | |
`:log-group:${logGroupsPrefix}*:*:*`, | |
}); | |
} |
- For non canonical named functions, do not create "Allow" rights
- Group names of all disabled canonically named functions, and generate "Deny" rights in scope of this condition:
serverless/lib/plugins/aws/package/lib/mergeIamTemplates.js
Lines 116 to 129 in 6dd9a31
if (hasOneOrMoreCanonicallyNamedFunctions) { // Ensure general policies for functions with default name resolution policyDocumentStatements[0].Resource.push({ 'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + `:log-group:${logGroupsPrefix}*:*`, }); policyDocumentStatements[1].Resource.push({ 'Fn::Sub': 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}' + `:log-group:${logGroupsPrefix}*:*:*`, }); }
@medikoo Have a look. I just tried to incorporate your comment. Let me know if anything I missed. |
e1d8b48
to
b87b10e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@as19ish Thank you! It look really good. I've proposed one final improvement we can do
const { name: resolvedFunctionName } = this.serverless.service.getFunction(functionName); | ||
const { | ||
name: resolvedFunctionName, | ||
disableLogs: isDisableLogsOpt, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's name this var areLogsDisabled
if (!resolvedFunctionName || resolvedFunctionName.startsWith(canonicalFunctionNamePrefix)) { | ||
if (isDisableLogsOpt) { | ||
disableLogsCanonicallyNamedFunctions.push(resolvedFunctionName); | ||
} | ||
hasOneOrMoreCanonicallyNamedFunctions = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put it in else
clause (e.g. if all functions named canonically we should just stay at not creating "Allow" policies
@medikoo ^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @as19ish !
There is no way to disable the CloudWatch logs for a lambda function. One workaround is you can add the policy to your role to disable the CloudWatch logs.
I have added deny policy for that specific lamda so as per now by default all function have logs:PutLogEvents permission when there is disableLogs opt to true we are adding deny policy statement for that function
Closes: #8554