Simple Python Code to get all VM Names, IPs, and FQDN's in the AWS Organization
Tags: aws, python, cloud, security
Published: 2022-10-06 11:27:53

Getting your AWS VM Name, IP address and FQDN from your AWS Organization should be simple. But...

AWS has made it ridiculously hard to get a consolidated list of all Virtual Machine Names, IP's and Fully-Qualified Domain Names across your AWS Organization. There is no single command to do it. You must iterate through all accounts individually, making API calls within each account. It can be tricky.

Using Python, I've made it simple. Keep reading to learn how I did it.

Background: The AWS Organization must be setup to allow users to assume roles from the Management Account to the individual Member Accounts. Start [here](https://aws.amazon.com/premiumsupport/knowledge-center/organizations-member-account-access/) with more information on this.

Program Logic:
1) Input the Management Account ID into the program. We'll use it later
```
print("******************************************************************")
print("Welcome to the AWS Organization EC2 Name, IP and FQDN Report")
print("To get started, please enter the AWS Organization Main Account ID: ")
orgMainAccountID = input()
```
2) Get the list of all the accounts in the AWS Organization
```
orgClient = boto3.client('organizations')
response = orgClient.list_accounts()
```
3) We'll iterate over all the accounts found in the "response" variable. For each of the accounts, we'll use the AWS Security Token Service (STS) to create temporary tokens to access the Member accounts from the Management account. Except, we won't create a temporary token for the Management account since we are accessing it directly. 
```
for account in response['Accounts']:
```
4) Using AWS STS, create the token and the session
```
stsClient = boto3.client('sts')
roleArn = "arn:aws:iam::" + account['Id'] + ":role/OrganizationAccountAccessRole"
stsresponse = stsClient.assume_role(RoleArn=roleArn, RoleSessionName='newsession')
# Save the details from assumed role into vars
newsession_id = stsresponse["Credentials"]["AccessKeyId"]
newsession_key = stsresponse["Credentials"]["SecretAccessKey"]
newsession_token = stsresponse["Credentials"]["SessionToken"]
```
5) Using the assume_role variables, create an ec2client to get information from our virtual machines and store in the "response" variable
```
# Use the assumed session vars to create a new boto3 client with the assumed role creds
ec2Client = boto3.client('ec2', 
  region_name=region['RegionName'],
  aws_access_key_id=newsession_id, 
  aws_secret_access_key=newsession_key, 
  aws_session_token=newsession_token)
response = ec2Client.describe_instances()
```
6) Loop through all responses and get the VM Name, IP, and FDQN.
```
for reservation in response["Reservations"]:
  for instance in reservation["Instances"]:
    try:
      if instance["State"]["Name"] == "running":
        print("Account Name:",account['Name']+",", "Region: 
        {}, Name: {}, Private IP: {}, Public IP: {}, FQDN: 
        {}".format( region['RegionName'],
        # get instance name from Tag Name
        [tag['Value'] for tag in instance['Tags'] if tag['Key'] == 'Name'][0], instance["PrivateIpAddress"],instance["PublicIpAddress"], instance["PublicDnsName"]))
     except KeyError as missing_key:
     # Used as missing_key for readability purposes only
       print(f"Trying to access a <dict> with a missing key {missing_key}") 
```
7) Back to the Management account ID we input in step 1. The code contains a condition to make sure we **don't** try to "assume_role" into the Management account, since we are accessing it directly.

A final note. The complete code can be found [here](https://github.com/jhowerin/AWS_Python_Scripts/tree/main/VM_IP_FQDN). Feel free to improve with better error handling, readability or execution speed.