avatarTeri Radichel

Summarize

A Recursive Function to Obtain Organizational Unit IDs

ACM.409 A beautiful construct, when appropriate — recursion

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

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

🔒 Related Stories: AWS Organizations | IAM | Deploying a Static Website

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

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

In the last post I wrote one of my favorite posts to date. I showed how to deploy resources in parallel using micro-templates.

The one thing I mentioned I didn’t like was my code for obtaining the OU ID. Because I was in a hurry I was sort of trying to brute force my way through it. That’s because I have other client projects to complete.

In this post I’m going to fix that ugly code with a concept called recursion. If you’re not familiar, recursion is calling a function from itself repeatedly until you get an answer. It can cause an issue if not written properly because you can end up in an infinite loop if you are not careful. It is also not alway the best choice for performance. But I don’t think we will have an issue here.

And when it works — it is an elegant solution. A small amount of code can process a lot of data and I love that. Additionally, you can write code that doesn’t require hard coded values such as I had in the last post to parse tree type structures where you have parent-child relationships like the structure of our OUs.

So here’s how it works roughly:

get_root_id(){
  returns root id for AWS Organization
}

get_ou_id_from_name(){
  ou_name="$1"
  parent_id="$2"
  
  #parent_id is optional now because if not provided
  #the search will start from the root

 #the parent id is not set so start at the root  
  if [ "$parent_id" == "" ]; then parent_id=$(get_root_id)
    #if the ou_name passed in equals "root" then we can
    #just return the root id
    if [ "$ou_name" == "root" ]; then echo $parent_id; exit; fi
  fi

  #otherwise we search all the child nodes for the parent to see
  #if we can find a matching name
  for n in $(aws organizations list-organizational-units-for-parent --parent-id $parent_id \
      --query 'OrganizationalUnits[*].Name' --output text --profile $profile); do
      #check to see if the name of the current child matches
      #the ou name passed into the function
      if [ "$n" == "$ou_name" ]; then
        #if the current ou name matches the target ou name, return the ou id      
        #and exit the function - we're done
        id=$(aws organizations list-organizational-units-for-parent --parent-id $parent_id \
          --query 'OrganizationalUnits[?Name == `'$ou_name'`].Id' --output text --profile $profile)
        echo $id; exit
      fi
  done

  #If we haven't exited yet, we don't have an id yet
  #Loop through the child OU Ids and use each id as a parent id to recursively 
  #call the function again with the new parent id
  for pid in $(aws organizations list-organizational-units-for-parent --parent-id $parent_id \
     --query 'OrganizationalUnits[*].Id' --output text --profile $profile); do
    get_ou_id_recursive $ou_name $pid
  done
}

Note that I had to test the following to make sure my function works:

  • OU Name passed in equals root > this invokes the code that returns the root id
  • OU with root as parent > this invokes the code that loops through the names of the child nodes looking for a name match
  • OU with orgadmin as parent > this invokes the code that recursively calls the function if a match is not found.
  • OU with nonprod as parent > this was just a sanity check that tests multiple recursive executions

Here’s the function to get the root id (which calls my common validation code I wrote about in other posts):

Here’s the function to recursively get the ou_id based on an OU name:

This function is a bit slow and I wish AWS would simply write this function for us on the back end and give us an action that allows us to look up the OU ID based on a name. That would probably execute pretty quickly compared to what I have to do here because it wouldn’t need to make so many network calls potentially if they have this in some kind of database they can query directly. But until that happens, this works.

Now that I have a function that can get any OU ID based on the name without looking up the parent id I can more easily deploy resources that require OU Ids, like AWS accounts which I will deploy next.

I also can remove some of my hard coded and extraneous calls to look up parent IDs in the code in my prior post.

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
AWS
Organizational Unit
Name
Id
Recursion
Recommended from ReadMedium