Determine if AWS EC2 Instance is in Test or Prod Account

It recently became apparent that I need a way to determine if I’m on an AWS TST (Test) EC2 instance, or a PRD (production) EC2 instance. The reason this is necessary is so that I can include a function to upload a file, or a folder, to an S3 bucket and ensure the portion of the bucket name that includes the environment, is included, and is correct. Therefore, I needed a function to be able to determine where it was running: in TST or PRD. Had I known I would need this information earlier, I would’ve had the CloudFormation template write this information to the Windows Registry or a flat file, so I could pick it up when needed. Had I considered an option such as this, I wouldn’t be wracking my brain now to try to determine a way to gather this information, when I didn’t leave it somewhere.

The computer names are the same in both environments (in both AWS accounts), so any comparison there doesn’t work. The TST servers and the PRD servers have the same name. After some thought, I came up with my three options:

1. Return the ARN from the metadata, and use that to determine whether I am on a TST or PRD EC2 instance, by extracting the AWS account number from the ARN and comparing it to two known values. This would allow me to determine which account I’m in—TST or PRD.

2. Look at the folders in C:\support\Logs. My functions, that are invoked inside the UserData section of a CloudFormation template, include logging that creates folders in this location named “TST” on a test EC2 instance and named “PRD” on a production EC2 instance.

3. Read in the UserScript.ps1 file (the UserData section in the CloudFormation template), and compare the number of the ‘tst’ and ‘prd’ strings in the file’s contents. Based on my UserData section, if there are more ‘tst’ strings, I’m on a TST EC2 instance, and if there are more ‘prd’ strings, I’m on a PRD EC2 instance.

Seriously Tommy, leave yourself some information on the system somewhere already. You never know when you might need it.

I decided I would use two of the three above options, providing myself a fallback if it were ever necessary. Who knows, I may not retire from my place of employment, and I’d like my code to continue to work as long as possible, even if I’m not around to fix it. I was worried about hard coding in those AWS account numbers, but less so, when I added a check against my UserScript.ps1 file (again, the UserData section of a CloudFormation document) for the count of ‘tst’ vs. ‘prd’ strings. Maybe it’ll never be used, but if needed, it’ll be there for me.

Here’s my first check in order to determine if my code is running on a TST or PRD EC2 instance. Feel free to look past my Write-Verbose statements. I used these for logging. So you have a touch of information, I’m creating the name of an S3 bucket, such as <projectname>-<environment>. Right now, we’re after the <environment> section, which I’m out to store in $Env. The <projectname> portion comes from parsing the EC2 instance’s assigned hostname.

#region Determine S3 Bucket using ARN and Account Number.
Write-Verbose -Message "$BlockLocation Determing the S3 Bucket Name using the ARN and account number."
$WebRequestResults = (Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/iam/info' -Verbose:$false).Content
$InstanceProfileArn = (ConvertFrom-Json -InputObject $WebRequestResults).InstanceProfileArn
$AccountNumber = ($InstanceProfileArn.Split(':'))[4]
Write-Verbose -Message "$BlockLocation ARN: $InstanceProfileArn."
Write-Verbose -Message "$BlockLocation Account Number: $AccountNumber."`

If ($AccountNumber -eq '615613892375') {
    $Env = 'tst'
} ElseIf ($AccountNumber -eq '368125857028') {
    $Env = 'prd'
} Else {
    $Env = 'unknown'
    Write-Verbose -Message "$BlockLocation Unable to determine S3 Bucket Name using the ARN and account number."
} # End If.
#endregion

The following region’s code is wrapped in an If statement that will only fire if the $Env variable is equal to the string “unknown”. Notice that in the above code, $Env will be set to this value if neither of the AWS account numbers matches my hard coded values. No, those aren’t real AWS account numbers—well, not mine at least, and yes, they could’ve come in via function parameters.

#region If necessary, determine using 'tst' vs. 'prd' in UserScript.ps1.
If ($Env -eq 'unknown') {
    Write-Verbose -Message "$BlockLocation Determing S3 Bucket Name by comparing specific strings in the UserScript.ps1 file."
    $FileContent = Get-Content -Path "$env:ProgramFiles\Amazon\EC2ConfigService\Scripts\UserScript.ps1"
    $MatchesTst = Select-String -InputObject $FileContent -Pattern 'tst' -AllMatches
    $MatchesPrd = Select-String -InputObject $FileContent -Pattern 'prd' -AllMatches
    Write-Verbose -Message "$BlockLocation Comparing ."

    If ($MatchesTst.Matches.Count -gt $MatchesPrd.Matches.Count) {
        $Env = 'tst'
    } ElseIf ($MatchesTst.Matches.Count -lt $MatchesPrd.Matches.Count)  {
        $Env = 'prd'
    } Else {
        Write-Warning -Message "Unable to determine account number by comparing specific strings in the UserScript.ps1 file."
        Write-Verbose -Message "$BlockLocation Unable to determine account number by comparing specific strings in the UserScript.ps1 file."
    }
} # End If.
#endregion

If the above code fires, it will read in the contents of my UserScript.ps1 file. Again, this script file contains exactly what’s in the UserData section of my instance’s CloudFormation template. Once we have the file’s contents in a variable, we’ll scan it two times. On the first check, we’ll record the matches for the string ‘tst’. On the second check, we’ll record the matches for the string ‘prd’. The way I’ve written my UserData section, if there are more ‘tst’ strings, I’m on a TST EC2 instance, and if there are more ‘prd’ strings, I’m on a PRD EC2 instance. There’s a nested If statement that does this comparison and tells me which it is by assigning the proper value to that $Env variable.

So, after all that, I think I’ll just try to predetermine what information might be needed in the future and drop that into a flat-file or put it into the registry… just in case, it’s ever needed. This task was obnoxious but worthy of sharing.

Leave a Reply

Your email address will not be published. Required fields are marked *