User-Specific Secrets on AWS: IAM Policies
ACM.82 IAM Policies to allow users to describe their own secrets
This is a continuation of my series of posts on Automating Cybersecurity Metrics.
In the last post, we created an SSH key for a user programatically. I created a policy for our Developer Group Role using the ${aws:username} parameter which I hoped would restrict each user to only access their own secret.
Creating and Storing an EC2 SSH Key in Secrets Manager
Looks like we can’t view the secret in the console. More on that later.
Create an AWS Secrets Manager secret
Problem accessing a user-specific secret with a role
If you recall, I have not given the Developer user console access at this point. I might address this later but for now let’s use the AWS CLI to see if the developer role can access the secret. I’ll need to set up an AWS CLI profile for the developer role:
Using an AWS CLI Profile with MFA
Now let’s see if we can get the secret using the AWS CLI and the developer profile. There’s one other thing we’ll need to fix. The describe-secret CLI command requires a secret ID which doesn’t exactly match our secret name. Some extra characters got added at the end.
We’ll need to adjust our Developer Group Role policy:
That is not a great solution. Someone might be able to manipulate a user name to add dashes to it and access our secret. What if someone could create a username “Developer-1” and then try to access our secret? This policy would grant them access.
We also have another problem. Using the AWS CLI with the assumed role, the name of the user is not our Developer user. It is the role name: DevelopersGroup.
Recall that we gave the user name access to the secret not the role or group because we want to enforce non-repudiation. (See prior posts.)
Applying the policy to a group
What if we apply the policy to a group instead of the role? Would the policy then apply to a user name correctly? It might, but we still have the problem above. The secret name does not match the developer name. If we use a * in the policy we might end up with unintended consequences as explained above.
Applying a user-specific policy
What if we try to access the secret with an AWS CLI profile specific to the user instead of the role?
DescribeSecret on resource: Developer-fnL9lq because no identity-based policy allows the secretsmanager:DescribeSecret action
We haven’t granted any permissions directly to the user specifically — we only granted permission to assume the DeveloperGroup role. We need to remove the permission from the role and apply them to the user instead.
Generally it is not a good practice to create user-specific policies in AWS. In fact, I might ding you for that on a security assessment in certain circumstances. However, in this case, each individual policy is unique and the policy should be deleted or deactivated with the user. The policy is very specific and for one purpose. We have a single template to apply the same policy to all users, so if you need to update it, you update it in once place and redeploy it to all users.
It would be a lot easier if AWS would just create the secret with the name we specified in the ARN (#awswishlist). That would also ensure that our secret names are unique we could simply reference the username in the template instead of looking up the secret name and creating a per-user policy.
There are pros and cons to this approach, but we can get a very specific policy that gives a user only access to their own secret. Due to the secret naming conventions I don’t see another way to do it as cleanly at the moment without adding a dangerous asterisk. Let’s try it.
If we need to deactivate or delete a user, we would need to remove the user-specific secret and SSH key, the same way you would delete a user name and password or disable it. You might want to create a service control policy that prevents deleting a user until their user-specific secret has been deleted or maybe inactivated somehow so you don’t have orphan secrets. I need to think that through a bit more.
Creating a Per-User Secret with CloudFormation
What if we create a user secret for a user with CloudFormation and pass our SSH key in as a parameter when creating the secret?
Where would that parameter end up? Recall that parameters appear read only in the AWS console:
We can’t create a secret with no value at all that we can update later either. So we’d have to pass something to our secret value. We don’t want to pass in any sensitive data because it will end up in the AWS console in plain text for anyone with access to read.
Creating the secret in CloudFormation help us protect a secret we are creating, but it allows us to get the secret id as an output. But as you recall we can get that secret ID when we create it with a CLI command as well in the prior post.
Which solution works better for us? Well, we have another problem we haven’t yet addressed: If the secret already exists, we can’t recreate it. If we use the CloudFormation deploy command that will handle whether the secret needs to be created or updated. We could do that with our own code, but why create more work for ourselves? We’ll use CloudFormation to create the secret.
Create a Secret With CloudFormation
We can change our script to create a secret with CloudFormation so it will create or update the secret as needed. We’ll set a default value for the secret and overwrite it with the SSH key in the a later step.
Note that as explained above, we can see that the parameter we used to set a default value for our secret is visible in clear text in the AWS console. Don’t pass secret values in as parameters to AWS Secrets Manager.
Even if using NoEcho…many warnings here:
If you check CloudTrail logs for the UpdateSecret entry, you’ll see that the secret value is not present. You would just need to consider where it might exist on the system where you are making the API call.
Here’s our updated function where we:
Check if the key already existsCreate or update the secretUpdate the secret with the value of the SSH keyUpdate the user policy to allow the user to access their own secret
Here’s the policy that allows the user to get the value of their own secret.
Remove the permissions we tried to add to the Developer Role Policy.
Now test to see if the developer can access his or her own secret:
aws secretsmanager describe-secret –secret-id Developer –profile developeruser
Yes!
There is one other thing we can and probably should add to this policy since it is not a role and we want to make sure that only the correct developer can access their own secret. Do you know what it is?
Adding an MFA condition to an IAM user policy
We can add an MFA condition. I’ve written about the MFA condition documentation before here:
Adding Conditions to AWS IAM, Resource, and Trust Policies
I think we can just check if MFA is present without the ifexists but let’s try this out:
Condition:
“Bool”:
“aws:MultiFactorAuthPresent” : “True”
That deploys, now let’s see if we can still access our secret. No:
An error occurred (AccessDeniedException) when calling the DescribeSecret operation: User: arn:aws:iam::xxxx:user/Developer is not authorized to perform: secretsmanager:DescribeSecret on resource: Developer because no identity-based policy allows the secretsmanager:DescribeSecret action
Once again, this error message is misleading. I wish it would specify that the condition is not met. In any case, let’s go see what the request looks like in CloudTrail.
To find the action that caused the error I had to search by UserName.
For some reason I did not find it when I searched by AWS Secrets Manager Secret as the resource.
I could also find it by searching for DescribeSecret:
Well, would you look at that. There’s no MFA value at all in this request, even though I have configured my user in the CLI to use MFA:
So this is where the “long term credentials” come into play with your MFA conditions that I wrote about in the prior post. Apparently there is no way to enforce MFA for this action for a single user using programmatic credential or they will not be able to programmatically get to the secret.
If we remove MFA, then if a Developer has credentials hard-coded on their local laptop then someone could use them without MFA to get to this user-specific secret programmatically. That is quite unfortunate.
What if we remove the MFA condition? We can once again access our secret, and interestingly enough, now the Resource Type correctly shows an AWS::SecretsManager:Secret
Keep the above in mind if you are trying to write alerts related to failure to access a Secrets Manager Secret and you’re searching on Resource type — always test your alerts with actual values.
OK let’s say we add “if exists” to our policy as recommended in the AWS documentation. Does that actually help us? As I’ve written about before — no. In this case, MFA doesn’t exist when someone is using long term credentials. So if we were to add if exists our condition simply wouldn’t be enforced when the condition doesn’t exist, as it does not in the above scenario. I feel that the AWS documentation is not exactly clear on this point and it makes it seem like the “if exists” option is OK when it is really not if you actually want to enforce MFA.
We’ll look at some of the other actions the user took and see if the MFA authentication shows up anywhere else in a later post. For now, I removed the MFA requirement until we can test other actions.
Follow for updates.
Teri Radichel
If you liked this story please clap and follow:
Medium: Teri Radichel or Email List: Teri Radichel
Twitter: @teriradichel or @2ndSightLab
Requests services via LinkedIn: Teri Radichel or IANS Research
© 2nd Sight Lab 2022
All the posts in this series:
Automating Cybersecurity Metrics (ACM)
____________________________________________
Author:
Cybersecurity for Executives in the Age of Cloud on Amazon
Need Cloud Security Training? 2nd Sight Lab Cloud Security Training
Is your cloud secure? Hire 2nd Sight Lab for a penetration test or security assessment.
Have a Cybersecurity or Cloud Security Question? Ask Teri Radichel by scheduling a call with IANS Research.
Cybersecurity & Cloud Security Resources by Teri Radichel: Cybersecurity and Cloud security classes, articles, white papers, presentations, and podcasts
Create a Per-User Secret in Secrets Manager: Part 1 was originally published in Cloud Security on Medium, where people are continuing the conversation by highlighting and responding to this story.