diff --git a/README.md b/README.md index 794b670..0bc8d41 100644 --- a/README.md +++ b/README.md @@ -94,12 +94,15 @@ This python script can be run locally or deployed as an AWS Lambda function. | Name | Description | Example | |-------------------|----------------------------------------------------------------|-----------------------------------------------------| -| s3_bucket | Name of the S3 bucket to export to. | `awsconfigs-bucket` | -| assume_role_name | Name of role used to assume into Management Accounts | `AccountSwitcherLambdaRole` | -| role_names | Role names to generate configs for | `OrganizationAccountAccessRole,ManagedOrg/ReadOnly` | -| session_name | Session name when assuming the role in the management acccount | `RoleSwitcherLambdav2` | -| payer_account_ids | List of AWS account IDs | `0123456789012,1234567890123` | +| S3_BUCKET | The name of the S3 bucket where the configurations will be stored (if not running locally). | `awsconfigs-bucket` | +| ASSUME_ROLE | The role name to be assumed in each payer account. | `AccountSwitcherLambdaRole` | +| ROLE_NAMES | Comma-separated role names for which the configurations will be generated. | `Admin,Developer,ReadOnly` | +| SESSION_NAME | The session name to use when assuming roles. | `RoleSwitcherLambdav2` | +| PAYER_ACCOUNT_IDS | Comma-separated AWS payer account IDs. | `123456789012,210987654321` | +| OU_OVERRIDES | JSON string of organizational unit (OU) ID to name mappings for overrides. | `{"ou-xyz1-abcdefgh":"Engineering","ou-xyz2-abcdefgh":"Marketing"}` | | running_locally | Set true for Local execution, false for Lambda. | `true` | +| AWS_REGION | The AWS region to use for the Lambda function. | `us-west-2` | +| AWS_PROFILE | The AWS profile to use for the Lambda function. | `default` | #### Local Execution diff --git a/lambda_handler.py b/lambda_handler.py index 216cb7d..2b8a5fd 100644 --- a/lambda_handler.py +++ b/lambda_handler.py @@ -1,4 +1,3 @@ -import json from library import util, aws, storage from library.conf_gen import ConfigGenerator diff --git a/testlambda.py b/testlambda.py deleted file mode 100644 index ca6084a..0000000 --- a/testlambda.py +++ /dev/null @@ -1,147 +0,0 @@ -import boto3 -import os -from moto import mock_aws -from unittest.mock import patch -from lambda_handler import main_handler -import shutil - - -@mock_aws -def test_main_function(): - """ - Test the main function of the lambda function script. - """ - # Set up the mocked AWS environment - aws_credentials() - mock_organizations() - mock_sts() - - # Mock environment variables - # os.environ['S3_BUCKET'] = 'org-account-switcher-bucket' - # os.environ['ASSUME_ROLE'] = 'AccountSwitcherLambdaRole' - # os.environ['ROLE_NAMES'] = 'MyOrg-Administrator,MyOrg-ReadOnly,MyOrg-Finance' - # os.environ['SESSION_NAME'] = 'testSession' - # os.environ['PAYER_ACCOUNT_IDS'] = '123456789012,234567890123' - # os.environ['RUNNING_LOCALLY'] = 'true' - - # Create a mock S3 resource and bucket - s3 = boto3.resource('s3', region_name='us-east-1') - s3.create_bucket(Bucket=os.environ['S3_BUCKET']) - - # Create a mock STS client - sts = boto3.client('sts', region_name='us-east-1') - # Create a mock Organizations client - org = boto3.client('organizations', region_name='us-east-1') - # Create a mock organization - org.create_organization(FeatureSet='ALL') - - # Define OUs and accounts structure - ou_structure = [ - {"Name": "OU1", "Accounts": ["AccountA", "AccountB"]}, - {"Name": "OU2", "Accounts": ["AccountC"]}, - ] - - # Create OUs and accounts - root_id = org.list_roots()['Roots'][0]['Id'] # Get the root ID dynamically - for ou in ou_structure: - ou_response = org.create_organizational_unit( - ParentId=root_id, - Name=ou["Name"] - ) - ou_id = ou_response['OrganizationalUnit']['Id'] - for account_name in ou["Accounts"]: - account_response = org.create_account( - AccountName=account_name, - Email=f"{account_name.lower()}@example.com" - ) - # Mock account creation and moving account to the OU logic would go here - - # Call the main function of the lambda script - event = {"Update": "True"} - context = {} - main_handler(event, context) # Ensure this matches your lambda function's name - - # Check if the expected files were created and uploaded to the mock S3 bucket or local directory - check_expected_files(s3) - - # Cleanup after test if necessary - # cleanup_temp_files() - - -def mock_organizations(): - org_client = boto3.client('organizations', region_name='us-east-1') - # Create an organization - org_client.create_organization(FeatureSet='ALL') - # Get the root ID - root_id = org_client.list_roots()['Roots'][0]['Id'] - - # Define the OUs and accounts structure - ou_structure = { - "OU1": ["AccountA", "AccountB"], - "OU2": ["AccountC"], - # Add more OUs and accounts as needed - } - - # Create OUs and accounts - for ou_name, accounts in ou_structure.items(): - # Create an OU - ou_id = org_client.create_organizational_unit(ParentId=root_id, Name=ou_name)['OrganizationalUnit']['Id'] - for account_name in accounts: - # Create an account - account_email = f"{account_name.lower()}@example.com" - account_id = org_client.create_account(AccountName=account_name, Email=account_email)['CreateAccountStatus']['AccountId'] - # Wait for account creation to complete (in real scenarios, you would check the status) - # Move the account to the OU - org_client.move_account(AccountId=account_id, SourceParentId=root_id, DestinationParentId=ou_id) - - -def mock_sts(): - sts_client = boto3.client('sts', region_name='us-east-1') - # You can add any specific mocking behavior for STS here if needed - -def aws_credentials(): - """Mocked AWS Credentials for moto.""" - os.environ["AWS_ACCESS_KEY_ID"] = "testing" - os.environ["AWS_SECRET_ACCESS_KEY"] = "testing" - os.environ["AWS_SECURITY_TOKEN"] = "testing" - os.environ["AWS_SESSION_TOKEN"] = "testing" - os.environ["AWS_DEFAULT_REGION"] = "us-east-1" - -def check_expected_files(s3): - # Adjusted to match the simplified path structure - expected_roles = os.environ['ROLE_NAMES'].split(',') - for role in expected_roles: - sanitized_role_name = role.replace("/", "-") - expected_files = [ - f"{sanitized_role_name}-browser-plugin-config.txt", - f"{sanitized_role_name}-awscli-config.txt", - f"{sanitized_role_name}-awscli-config-prefixed.txt", - ] - for expected_file in expected_files: - local_path = os.path.join('.', 'configs', expected_file) - assert os.path.exists(local_path), f"File {local_path} was not created locally as expected." - - -def cleanup_temp_files(): - """ - Removes output files and directories created by the test in the local filesystem. - """ - # Define the path to the configs directory where files are stored - configs_path = os.path.join('.', 'configs') - - # Check if the configs directory exists and remove it if it does - if os.path.exists(configs_path): - shutil.rmtree(configs_path) - print("Cleaned up temporary files and directories.") - else: - print("No temporary files found to clean up.") - -if __name__ == "__main__": - try: - test_main_function() - print("Test completed successfully.") - finally: - print("Cleaning up temporary files.") - # cleanup_temp_files() - -