AWS Lambda Python function, to enable / disable access to a VPC environment
A recommendation that I give with most of my reviews, and which is relevant here, is a perusal of PEP 8, the official style guide for Python. Many of my comments below will reference that document.



import boto3, os


PEP 8 has a few things to say about this (in the section entitled Imports). First, generally you shouldn't put multiple modules on the same line. Next, third-party modules should be distinguished from built-ins, preferably with a blank line (and local application modules after). In addition, I like to alphabetize my imports within each group. It can prevent duplicates. So I would do it like this:

import os

import boto3




region = os.environ['PFregion']
security_group_id = os.environ['PFSG']
bastion_iid = os.environ['PFbastion_iid']
aws_profile = 'profile_name'


I have several problems with this. For one thing, os has a shortcut function for accessing environment variables: os.getenv. I would also pass these as arguments to lambda_handler instead of using global variables. This gives the option of calling the function from another module or calling it multiple times without the need of setting environment variables.

The if __name__ == '__main__': block should be where those variables are gotten. As a nice touch, you could use argparse to add commandline arguments as an alternative to environment variables. I would probably do it something like this:

# At the top with your other imports
from argparse import ArgumentParser

# In `if __name == '__main__':`
parser = ArgumentParser(description="Your program description")
parser.add_argument('-r', '--region', description='PF region')
 # (Repeat for other arguments)

args = parser.parse_args()


Then you can pass something like args.region or os.getenv('PFregion') to your function. That gives the command line option as the decision-maker, but it falls back on the environment variable.



def lambda_handler(event, context):
    if (__name__ == "__main__"):


This is a worker function; it shouldn't care what is calling it. I would move the block outside the function and pass the relevant variables as arguments. You could even use something like:

# Though because of my previous recommendation, this function would have more arguments.
def lambda_handler(event, context, session=boto3):
    ec2_client = session.client('ec2', region_name=region)
    ec2_resx = session.resource('ec2', region_name=region)


Then your if __name__ == '__main__': block could simply pass the session as an argument, but the default without a session still works.



event = { "up" : "true", "desc" : "this is a description field", "dry_run" : "false" }


I would add these options to the environment variable and command line options.

Python has its own booleans. Use them: "up": True.

Another styling comment: I wouldn't put spaces on both sides of the braces. PEP 8 comments on this.

I also noticed that you never use event['desc'] or event['dry_run']. Why then are they ever defined?