Guardrails to Prevent Privilege Escalation in AWS IAM
did someone say the principle of least privilege
hello avatars, today we are going to talk about IAM permissions. IAM permissions can be a pain to deal with, as we’ve covered, just saying follow least privilege doesnt always solve the problem. Least privilege is easy to say, but hard to actually figure out what that means for your team, company, or group. The one permission set that should never be in your IAM permissions is the ability to create/add to your own IAM permissions.
Required fundamental reading:
Least Privilege AWS IAM
Privilege escalation
what many people commonly refer to as priv-esc is when a hacker can increase their permissions to gain access to other systems or more restricted data. this is a fairly common risk vector that can be easily exploited if you do not know what you are doing in your IAM permissions.
From my earlier post, you know not to use the account root user, as their permissions cannot be restricted unless this its to an account in an AWS Organization, in which case SCPs would apply to that user.
Most of the time the two most common attack vectors are these two implementations:
IAM principals altering their own boundaries to access restricted services or data.
Creating a user with a higher permission set than themselves
If you are looking to implement this with IAM policy here is an example policy from aws:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowAdminAccess",
"Effect": "Allow",
"Action": "*",
"Resource": "*"
},
{
"Sid": "DenyAccessToCostAndBilling",
"Effect": "Deny",
"Action": [
"account:*",
"aws-portal:*",
"savingsplans:*",
"cur:*",
"ce:*"
],
"Resource": "*"
},
{
"Sid": "DenyPermBoundaryIAMPolicyAlteration",
"Effect": "Deny",
"Action": [
"iam:DeletePolicy",
"iam:DeletePolicyVersion",
"iam:CreatePolicyVersion",
"iam:SetDefaultPolicyVersion"
],
"Resource": [
"arn:aws:iam::YourAccount_ID:policy/ScopePermissions"
]
},
{
"Sid": "DenyRemovalOfPermBoundaryFromAnyUserOrRole",
"Effect": "Deny",
"Action": [
"iam:DeleteUserPermissionsBoundary",
"iam:DeleteRolePermissionsBoundary"
],
"Resource": [
"arn:aws:iam::YourAccount_ID:user/*",
"arn:aws:iam::YourAccount_ID:role/*"
],
"Condition": {
"StringEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::YourAccount_ID:policy/ScopePermissions"
}
}
},
{
"Sid": "DenyAccessIfRequiredPermBoundaryIsNotBeingApplied",
"Effect": "Deny",
"Action": [
"iam:PutUserPermissionsBoundary",
"iam:PutRolePermissionsBoundary"
],
"Resource": [
"arn:aws:iam::YourAccount_ID:user/*",
"arn:aws:iam::YourAccount_ID:role/*"
],
"Condition": {
"StringNotEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::YourAccount_ID:policy/ScopePermissions"
}
}
},
{
"Sid": "DenyUserAndRoleCreationWithOutPermBoundary",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:CreateRole"
],
"Resource": [
"arn:aws:iam::YourAccount_ID:user/*",
"arn:aws:iam::YourAccount_ID:role/*"
],
"Condition": {
"StringNotEquals": {
"iam:PermissionsBoundary": "arn:aws:iam::YourAccount_ID:policy/ScopePermissions"
}
}
},
{
"Sid": "DenyIAMActions",
"Effect": "Deny",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::YourAccount_ID:role/*"
}
]
}
If you know how IAM policy works you know that explicit deny always takes precedent over an allow. So in this case even though there is a wildcard allow, the deny would take priority.
AWS was looking to place some guardrails on these scenarios:
Any IAM principal created by IAM admins can have full access to AWS resources. The full access to AWS resources depends upon the identity-based policies because permissions boundaries don't provide permissions on their own.
The policy restricts IAM principals from accessing AWS billing and cost management related services.
IAM principals can't alter the permissions boundary to allow their own permissions to access restricted services.
IAM admins can't create IAM principals with more privileges than they already have.
The IAM principals created by IAM admins can't create IAM principals with more permissions than IAM admins.
AWS goes beyond regular priv-esc and also denies access to billing and cost services. This doesn’t necessarily need to be on your permission boundary / guardrail policy like this one. It could be in a DenyCostandBilling policy. It can be better to keep them separate as some analysts may need access to certain billing or cost services.
Attacking Service Roles
Another attack vector is exploiting service roles, or IAM roles scoped for services. One example would be if your org has default roles for compute services like EC2 or Lambda. Compute services generally need access to databases or S3 buckets/objects. One way to escalate privileges in this scenario is to get the credentials for a developer or similar persona, and then get onto an EC2 instance (SSH or SSM Session Manager or edit the code of a Lambda to read or get data from a database or S3.
This vector is a little bit more complicated and annoying to mitigate. Generally you want to make sure your service roles are scoped correctly. But that is not enough, right you cannot just remove the EC2s ability to connect to the database, then your app wont work.
For example, an EC2 instance that hosts a developer tool doesnt need access to an S3 bucket that hold customer data. Another thing you want to look at is eliminating these patterns entirely in production, or having some kind of time bound approval process in which access is granted via ephemeral token or similar process. On top of that, you want to make sure your lifecycles are segmented at the network level or prevent privilege escalation in this exact scenario, where one could compromise a service role in a development environment, and then look for backdoors into production systems.
Conclusion
Mitigating these types of attacks can be difficult and require serious thought. Another reason why cloud architects and cloud engineers with understandings of security patterns and controls will be compensated handsomely. These types of things are usually only learned from experience, so study up frens.
See you in the clouds
-Celt.
BONUS:
first person to comment on this post or DM me on twitter, will get a free trial for the stack.