avatarTeri Radichel

Summarize

Attempting* to Use A Service Control Policy to Limit Users to Changing Their Own Credentials

ACM.402 Attempting to restrict users to managing their own credentials with conditions in Service Control Policies

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

⚙️ Check out my series on Automating Cybersecurity Metrics | Code.

🔒 Related Stories: AWS Security | Secure Code | IAM

💻 Free Content on Jobs in Cybersecurity | ✉️ Sign up for the Email List

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In the last post, I attempted to lockdown an SCP to only be modified from the root management account of an AWS Organization. I still need to create a new user to test it out.

But before I create a new user in a child account, I want to implement an AWS Organizations Service Control Policy that restricts users from modifying other people’s credentials, if possible.

I’ve written about the issues that arise from an IAM administrator who has permission to access new user credentials before. That is not the topic of this post, but you can read more about that in other posts and the potential for privilege escalation.

What I want to do in this post is disallow users from changing other users’ credentials. For example, a user with IAM privileges cannot attach a new set of developer credentials and use them to obtain permissions that are assigned to that user. The user cannot change the other user’s passwords and then login with the new credentials. The user cannot change the other user’s MFA device.

I’ve written about how to do this in IAM policies here.

One way to restrict the policies assigned to new users and accounts is by way of permission boundary assigned to the user. I explored IAM boundaries vs. SCPs for this purpose here:

One of the issues with permission boundaries is that they are account specific. You will have to add a permission boundary to every account where you want to use one. Permission boundaries are essentially account-specific service control policies attached to a user instead of a policy applied to accounts or OUs. It would be easier and less to manage if we globally set this restriction one time across the organization.

Can we simply copy over our IAM policy to the SCP? Let’s take a look.

Here’s the policy from my prior post and that post details what all these things are and why they are in this policy.

{
 "Version": "2012-10-17",
 "Statement": [
  {
   "Sid": "DenyMFAandCredentialActionsNotMatchingUserName",
   "Effect": "Deny",
   "Action": [
    "iam:CreateVirtualMFADevice",
    "iam:DeactivateMFADevice",
    "iam:EnableMFADevice",
    "iam:ResyncMFADevice",
    "iam:DeleteSSHPublicKey",
    "iam:UpdateSSHPublicKey",
    "iam:UploadSSHPublicKey",
    "iam:CreateAccessKey",
    "iam:DeleteAccessKey",
    "iam:UpdateAccessKey",
    "iam:ChangePassword",
    "iam:UpdateLoginProfile"
   ],
   "NotResource": [
    "arn:aws:iam::xxxxxxxxxxxx:mfa/${aws:username}",
    "arn:aws:iam::xxxxxxxxxxxx:user/${aws:username}"
   ]
  },
  {
   "Sid": "AllowWithoutMFA",
   "Effect": "Allow",
   "Action": [
    "iam:EnableMFADevice",
    "iam:ListMfaDevices",
    "iam:GetUser",
    "iam:GetAccountPasswordPolicy"
   ],
   "Resource": "arn:aws:iam::xxxxxxxxxxxx:user/${aws:username}"
  },
  {
   "Sid": "AllowAnyActionWithMFAExceptIAM",
   "Effect": "Allow",
   "NotAction": [
    "iam:*"
   ],
   "Resource": "*",
   "Condition": {
    "Bool": {
     "aws:MultiFactorAuthPresent": "true"
    },
    "StringEquals": {
     "aws:PrincipalAccount": [
      "xxxxxxxxxxxx"
     ]
    }
   }
  },
  {
   "Sid": "AllowIAMActionsOnAllButCurrentUser",
   "Effect": "Allow",
   "Action": [
    "iam:AttachUserPolicy",
    "iam:CreateUser",
    "iam:DetachUserPolicy",
    "iam:DeleteUserPermissionsBoundary",
    "iam:GenerateServiceLastAccessedDetails",
    "iam:PutUserPermissionsBoundary",
    "iam:PutUserPolicy",
    "iam:SimulatePrincipalPolicy",
    "iam:Tag*",
    "iam:Untag*",
    "iam:UpdateUser"
   ],
   "NotResource": "arn:aws:iam::xxxxxxxxxxxx:user/${aws:username}",
   "Condition": {
    "Bool": {
     "aws:MultiFactorAuthPresent": "true"
    },
    "StringEquals": {
     "aws:PrincipalAccount": [
      "xxxxxxxxxxxx"
     ]
    }
   }
  },
  {
   "Sid": "AllowAllReadIAMActionsandCreateConsoleLogin",
   "Effect": "Allow",
   "Action": [
    "iam:Get*",
    "iam:List*",
    "iam:CreateLoginProfile"
   ],
   "Resource": "*",
   "Condition": {
    "Bool": {
     "aws:MultiFactorAuthPresent": "true"
    },
    "StringEquals": {
     "aws:PrincipalAccount": [
      "xxxxxxxxxxx"
     ]
    }
   }
  },
  {
   "Sid": "DenyUpdateAndDeleteLoginProfile",
   "Effect": "Deny",
   "Action": [
    "iam:UpdateLoginProfile",
    "iam:DeleteLoginProfile"
   ],
   "Resource": "*"
  }
 ]
}

Recall that NotResource is one of the options not supported in an SCP:

If you try this you will get the dreaded error:

The provided policy document does not meet the requirements of the specified policy type.

That error message can mean any number of things and its non-specific nature makes troubleshooting SCPs very difficult so hoping AWS will fix that soon.

I saw a different approach using a condition. Let’s see if we can make that work. A condition has this format:

Condition: { "ConditionOperator": {"ContextKey" : ["Value"] } }

What conditions can we use?

Which one should we use? We could use StringNotEquals. The example I saw used ArnNotEquals. Let’s see which one might look better.

Condition: { "ArnNotEquals": {"ContextKey" : ["Value"] } }
Condition: { "StringNotEquals": {"ContextKey" : ["Value"] } }

Which Context Key should we use? Here are our options:

We can compare the username making the request with the Value we specify the condition below.

Condition: { "StringNotEquals": {"aws:username" : ["Value"] } }

What value should we set? We want to match the value of the username in the resource the user is trying to edit. How do we get that value?

What if we use ${aws:username}?

That variable refers to the principal taking the action, not the resource that the principal is trying to edit.

It doesn’t appear the global context keys are going to help us.

What about service-specific context keys? Here are the IAM and STS condition context keys.

How about iam:AssociatedResourceArn? Sounds promising right? Maybe the associated resource ARN is the user the ChangePassword is acting on. Per the documentation this seems to be related to assume role actions only, so this condition will not work with the actions we’re using in this policy.

If you drill down into the service specific context keys you basically get the same list.

Why this documentation is duplicated, I don’t know. Makes it more confusing to me.

I could be missing it, but I don’t see a way to get a handle on the resource so we can compare it to the principal taking the action. If it is possible it’s not easy to figure out from the above documentation and there’s only so much time in a day to try to reverse engineer this further and test to determine what is possible.

If I understand the available options correctly, aws:username=aws:username is always going to be true and that doesn’t help us.

So what problem does this pose for us? We can apply a policy to the administrator in the OrgAdmin account, but we cannot use the permission boundary in one account in another account. If we want to require creation of users with a permission boundary, we have to add that boundary to every single account where we want to use it. I’d rather not deal with that.

At this point, I’m going to say the orgadmin is a very powerful user and we’re going to use it to set up the initial organization and then lock it down. I may revisit this more later but for now…moving on.

Maybe some new options will be introduced in the above options or the documentation will get updated to further clarify how to achieve this objective.

To reiterate what I was trying to do:

I want a single Service Control Policy at the root to limit users to only change their own credentials. Exceptions can be added if needed but in general, users should only edit their own credentials. That is a critical aspect of non-repudiation, a topic I covered on other posts like this one:

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2023

About Teri Radichel:
~~~~~~~~~~~~~~~~~~~~
⭐️ Author: Cybersecurity Books
⭐️ Presentations: Presentations by Teri Radichel
⭐️ Recognition: SANS Award, AWS Security Hero, IANS Faculty
⭐️ Certifications: SANS ~ GSE 240
⭐️ Education: BA Business, Master of Software Engineering, Master of Infosec
⭐️ Company: Penetration Tests, Assessments, Phone Consulting ~ 2nd Sight Lab
Need Help With Cybersecurity, Cloud, or Application Security?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
🔒 Request a penetration test or security assessment
🔒 Schedule a consulting call
🔒 Cybersecurity Speaker for Presentation
Follow for more stories like this:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
❤️ Sign Up my Medium Email List
❤️ Twitter: @teriradichel
❤️ LinkedIn: https://www.linkedin.com/in/teriradichel
❤️ Mastodon: @teriradichel@infosec.exchange
❤️ Facebook: 2nd Sight Lab
❤️ YouTube: @2ndsightlab
Service Control Policy
Cloud
Security
Iam
Credentials
Recommended from ReadMedium