avatarTeri Radichel

Summarize

Creating an AppSec Group to Administer Secrets Manager Secrets

ACM.85. Creating an AppSec User, Group, Role and eliminating over 500 lines of code and 8 files with abstraction

Part of my series on Automating Cybersecurity Metrics. The Code.

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

In the last post we looked at granting an IAM Group access to use a KMS key in a KMS Key Policy. This solution overcomes AWS policy limitations which don’t allow you to assign permissions directly to groups.

In a prior post I explained why you might want to segregate duties between IAM policies and resource policies. In addition, I showed why you might want to segregate KMS key policies from resource policies in order to ensure a secret can only be accessed by the assigned user.

Initially I had the IAM user deploy the resource policies and secrets. In this post we will consider using the framework we created in this series to create an AppSec role to implement the segregation of duties I’ve described.

  • The AppSec role will be responsible for creating Secrets Manager secrets and their associated resource policies.
  • The KMS role will still manage encryption keys and the associated resource policies.
  • The IAM role will manage IAM user roles and policies and deploy the Lambda policies which could be created by a development team, but deployed by the IAM team.

Create the AppSec Group

First we can create an AppSec group. We would want the AppSec administrators to be separate from developers, because the AppSec group sets permissions on access to developer-specific secrets. If we allow developers to control these permissions then a developer could give himself or herself access to other people’s secrets, barring some other control to prevent that.

Ideally you have a separate AppSec team but in a small company you might not have that. You might instead limit access to use the AppSec role in some other way such as requiring authorization to change policies and carefully auditing those changes. You might have restrictions that require development, QA, and production deployment to affect such policies. The goal is to ensure you achieve non-repudiation when it comes to use credentials and authentication however you end up architecting your identities, roles, credentials, and processes.

Create an AppSec User

Add a line to our script to deploy an AppSec user via the framework we developed earlier. As a reminder these would typically be user names, not the generic names we have here but I’m naming them this way to make it clear who is responsible for what.

Recall that we added the boolean at the end of the user name to indicate whether or not to deploy an SSH key for the user.

Deploy that user. Verify that your user got created.

Add MFA for your new user. The user would do this themselves in an actual organization as you would not have MFA if you add it for them. We’ll look at that option potentially more later but AWS offers sample policies to create their own credentials.

Create credentials and create an AWS CLI user profile. We’ll add the role profile after creating the role.

Create an AppSec group and add the new user

Add a line to create the new AppSec Group.

Add three lines to add the AppSec user to the AppSec group.

Modifying our framework to create a generic group policy template

It is at this point where I have created a specific group policy in the past. I kept these separate initially thinking that there would be some variation. However, after reviewing all the policies I have created so far it appears as though once again we can apply the principle of abstraction and consolidate these policies into one script and reduce the amount of code we need to maintain without introducing more risk.

I made a copy of one of our group-specific templates and made a few modifications as shown below to reference the group name where values were previously hard-coded.

Now let’s see what happens when we change our generic group deployment function in group_functions.sh to deploy groups using this new template:

Run the deploy.sh file in the root of our IAM groups directory.

I have an issue with the export name.

What is the name supposed to be?

Looks like I need to change the name passed into the template to the group name only in the deploy_group function. I can comment out the policy name and pass in the group name instead. I also noticed that I had previously named the policy GroupPolicy to make it easier to identify the policies in the list of policies in the AWS console or queries.

I changed the policy name to match the previous name below. In addition to matching the old name, we won’t end up with extraneous unused policies.

One other change I’m going to make right now is to move GroupPolicy.yaml to the cfn directory.

mv cfn/Policy/GroupPolicy.yaml cfn/

The reason for that change is that I can delete all the other policies and this would be the only policy in that directory. If I end up creating group specific policies later, I can reinstate the policy folder, but I expect that group users will always be associated with a role that has custom permissions instead. So I think this one change based on abstraction will allow us to eliminate all these files:

Change the path to the policy and delete the extraneous lines of code I commented out above in group_functions.sh:

Let’s test the deploy.sh script again.

One more error to resolve:

Value of property Groups must be of type List of String

Add a dash to indicate a Yaml list for groups and indent our Fn::Import statement:

And …I have to delete the stack in a rolled back state because it will not update for some reason. I wish AWS would fix this. #awswishlist

Stack:arn:aws:cloudformation:xxx:xxxx:stack/IAM-Policy-KMSAdmins/xxx is in ROLLBACK_COMPLETE state and can not be updated.

Now it appears that our syntax errors are all resolved and our CloudFormation stacks for all groups and policies deploy successfully.

AWS IDE and syntax checkers

I’m not sure if the AWS Cloud9 IDE would help with syntax issues for CloudFormation or not, but I don’t like writing my code in a Cloud IDE. I would rather have a secure tunnel to an EC2 instance than all the additional attack surface that comes with a browser, but if you are just starting out this may help:

Additionally theres a tool you can add on the command line that adds some color and syntax checking for CLI commands but for now at least, I’m not using it. I don’t remember the name of the tool off the top of my head but it is in my class slides if you ever take an AWS security class from me.

A note on programmer efficiency and security

There was a time when some people wanted to calculate how good a programmer is based on how many lines of code they can write in a certain amount of time. Hopefully you can gather from the example above how faulty that logic is.

By creating a generic template to handle my group policies, I have just eliminated approximately 560 lines of code, not including my verbose comments and copyright notice. In addition, I will likely need to create more groups in the future so I have simplified the creation of groups with a generic group policy and it takes less lines of code to deploy future groups.

Of course the astute software professional will also note that I’m not just creating generic code to save time that causes permissions to be more broad than they need to be. I’m still creating a group-specific policy in each case where members of each group can only assume an authorized role.

We are achieving the objectives of security and efficiency at the same time rather than trading one for the other.

Create an AppSec Role

Add a line to create the AppSec group in the role deploy.sh script.

Here we will need to add a custom role policy. Recall that we want this role to be able to manage resource policies for parameters and secrets. We can create the resource policy for a secret separately from the secret itself:

Recall that an AWS SSM Parameter has resource policies but they do not address permission to access the value stored in the parameter:

We’ll figure out if and how the AppSec user will interact with AWS Parameter store later, if at all. AWS Secrets Manager will be our primary repository for any non-dynamic session-oriented credentials due to the limitations of AWS Parameter Store. We’ll continue to evaluate these two services and their pros and cons as we progress.

For now we need to give the AppSec user permission to create a Secrets Manager secret policy.

Whether or not you want to name this role AppSec or something else makes not difference. What matters is the segregation of duties between IAM Policies, KMS policies, and Secret Policies. We could have named this role SecretsAdministrator instead.

Policy for our Secrets Administrator or AppSec role. If we take a look at the actions that a user can take related to Secrets Manager we might want our administrator to be able to do all of these except get a secret.

If AppSec or Secrets Manager admins need to get a secret this user could also have a developer account in their own name for testing developer access to a developer-specific secret, or an application for testing access to an application specific secret, rather than use an almighty administrator role that might have a substantial blast radius, if compromised. I explain blast radius in my book at the bottom of this post.

We can use the way precedence works in IAM policies to allow all secrets manager permissions but deny the GetSecretValue permission as shown below. The deny statement takes priority. I explained the importance of understanding precedence when dealing with multi-cloud environments at recent IANS Cybersecurity Forums in LA and Dallas. In this case, precedence works in our favor when using this design.

Now try to deploy our new group using the deploy.sh file in the Group folder of our framework. Unfortunately, we get the dreaded and not very helpful MalformedPolicyDocument error. Do you see the problem above?

Code: 400; Error Code: MalformedPolicyDocument

This is a problem that CloudFormation or an IAM component processing this code could evaluate pretty easily and report a more user-friendly error message (#awswishlist). I forgot to add the resource to the statement.

And, of course, we need to delete the stack to re-deploy. I wish we didn’t have to do that (#awswishlist).

Success!

Now we have an AppSec Group, User, and Role. In the next post we will consider how we need to refactor our code to deploy secrets via the AppSec admins instead of the IAM user and remove secrets permissions from IAM Admins.

Follow for updates.

Teri Radichel | © 2nd Sight Lab 2022

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
Appsec
Secrets
Secrets Manager
Appilcation Security
Cloud Security
Recommended from ReadMedium