{"id":15840255,"url":"https://github.com/davealdon/barebones-aws-lambda-with-mfa","last_synced_at":"2026-04-24T22:33:06.265Z","repository":{"id":105658527,"uuid":"547973103","full_name":"DaveAldon/Barebones-AWS-Lambda-with-MFA","owner":"DaveAldon","description":"☠️ A barebones example of how to deploy to AWS Lambda using MFA and SAM CLI, with the Least Privilege IAM policy","archived":false,"fork":false,"pushed_at":"2022-10-10T01:15:13.000Z","size":2300,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-19T17:57:17.746Z","etag":null,"topics":["aws","aws-auth","aws-authentication","aws-lambda","aws-lambda-node","aws-sdk","lambda","sam","sam-cli","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DaveAldon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-08T17:18:57.000Z","updated_at":"2023-04-01T05:05:49.000Z","dependencies_parsed_at":"2023-06-12T15:00:26.633Z","dependency_job_id":null,"html_url":"https://github.com/DaveAldon/Barebones-AWS-Lambda-with-MFA","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/DaveAldon/Barebones-AWS-Lambda-with-MFA","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DaveAldon%2FBarebones-AWS-Lambda-with-MFA","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DaveAldon%2FBarebones-AWS-Lambda-with-MFA/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DaveAldon%2FBarebones-AWS-Lambda-with-MFA/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DaveAldon%2FBarebones-AWS-Lambda-with-MFA/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DaveAldon","download_url":"https://codeload.github.com/DaveAldon/Barebones-AWS-Lambda-with-MFA/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DaveAldon%2FBarebones-AWS-Lambda-with-MFA/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261995472,"owners_count":23242202,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-auth","aws-authentication","aws-lambda","aws-lambda-node","aws-sdk","lambda","sam","sam-cli","typescript"],"created_at":"2024-10-05T16:42:26.170Z","updated_at":"2026-04-24T22:33:01.242Z","avatar_url":"https://github.com/DaveAldon.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp float=\"left\"\u003e\n\u003cimg src=\"./resources/lambda.png\" width=\"100%\"\u003e\n\u003c/p\u003e\n\nA barebones example of how to deploy to AWS Lambda using [MFA](https://aws.amazon.com/iam/features/mfa/) and [SAM CLI](https://aws.amazon.com/serverless/sam/), with the [Least Privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) IAM policy.\n\n#### Getting Started\n\nAssumptions:\n\n1. You're part of an AWS organization\n2. You don't have root access, and need to request \"least privilege\" access to your admin in order to deploy a new Lambda function\n3. Your organization requires MFA\n\n#### Step 1: Install Dependencies\n\n1. Install the [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)\n\n```\ncurl \"https://awscli.amazonaws.com/AWSCLIV2.pkg\" -o \"AWSCLIV2.pkg\"\nsudo installer -pkg AWSCLIV2.pkg -target /\n```\n\nand then run `aws --version` to verify that it's installed correctly.\n\n2. Install [Docker](https://docs.docker.com/engine/install/) - This is needed for local testing of AWS SAM projects\n\n3. Install [Homebrew](https://docs.brew.sh/) - This is needed to install the AWS SAM CLI\n\n```\n/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)\"\n```\n\nVerify that it's installed correctly by running `brew --version`\n\n4. Install the [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)\n\n```\nbrew tap aws/tap\nbrew install aws-sam-cli\n```\n\nVerify that it's installed correctly by running `sam --version`\n\n#### Step 2: Get the minimum roles needed for your AWS account\n\nYou'll need the following roles if you're part of an AWS organization that practices the \"least-privilege\" principle:\n\n- `iam:CreateRole`\n- `iam:AttachRolePolicy`\n- `iam:DetachRolePolicy`\n- `cloudformation:CreateChangeSet`\n- `apigateway:*` SAM needs to associate your Lambda function with an API gateway\n\n#### Step 3: Invoke the hello-world Lambda function\n\nRun `npm run invoke` to run the included sample lambda function locally. To verify that it's working, you should get a similar output to the following:\n\n```\n{\n    \"statusCode\": 200,\n    \"body\": \"{\\\"message\\\": \\\"hello world\\\"}\"\n}\n```\n\nThe `SAM-Project` folder is an example node v16 + typescript lambda function originally created via a `sam init` command. You can run `sam init` and follow the guided instructions to create your own SAM environment if you desire, based on a variety of languages like Python, Rust, C#, etc.\n\n#### Step 4: Deploy to AWS Lambda\n\nRun `npm run deploy` to build and deploy the Lambda function to a new AWS stack called `sam-barebones-aws-lambda-with-mfa`, and with the authentication configuration called `mfa`. This command runs you through the \"guided\" deployment, which will ask you a few clarifying questions. Here's an example of what this could look like:\n\n```\nLooking for config file [samconfig.toml] :  Found\nReading default arguments  :  Success\n\nSetting default arguments for 'sam deploy'\n=========================================\nStack Name [sam-barebones-aws-lambda-with-mfa]:\nAWS Region [us-east-1]:\n#Shows you resources changes to be deployed and require a 'Y' to initiate deploy\nConfirm changes before deploy [Y/n]: y\n#SAM needs permission to be able to create roles to connect to the resources in your template\nAllow SAM CLI IAM role creation [Y/n]: y\n#Preserves the state of previously provisioned resources when an operation fails\nDisable rollback [y/N]: n\nHelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y\nSave arguments to configuration file [Y/n]: y\nSAM configuration file [samconfig.toml]:\nSAM configuration environment [mfa]:\n```\n\nYou can take a look at the [samconfig.toml](./SAM-Project/samconfig.toml) file that we created to see where some of these values come from, and where the guided deployment may make updates.\n\nIf the deployment preparation is successful, you should see output like this:\n\n\u003cp float=\"left\"\u003e\n\u003cimg src=\"./resources/deployment_prep.png\" width=\"90%\"\u003e\n\u003c/p\u003e\n\nThen you'll be asked for a final confirmation to proceed, and if everything is successful, you should see output like this, depending on your region:\n\n```\nSuccessfully created/updated stack - sam-barebones-aws-lambda-with-mfa in us-east-1\n```\n\n#### Step 5: Try out the deployed Lambda function\n\nNow that your Lambda function has been deployed, you should try invoking it using its Function URL.\n\nYou can generate this url by going to `AWS Console -\u003e Lambda -\u003e find the sam-barebones-aws-lambda-with-mfa application -\u003e Configuration -\u003e Function URL -\u003e Create Function URL`.\n\nFor ease of testing purposes, set the auth type to `NONE`, making your function public. Otherwise you'll need authentication to invoke it.\n\n\u003cp float=\"left\"\u003e\n\u003cimg src=\"./resources/functionurl.png\" width=\"90%\"\u003e\n\u003c/p\u003e\n\nThen navigate to the url, and you should see this result in your browser:\n\n```\n{\"message\":\"hello world\"}\n```\n\n### Troubleshooting\n\nThere are a number of random things that can go wrong during this entire Lambda process. I've tried to include some of the most common issues, and how to resolve them.\n\n#### Deployment Errors\n\nIf you get an error like the following during a deployment:\n\n```\n\nError: Failed to create managed resources: An error occurred (ExpiredToken) when calling the CreateChangeSet operation: The security token included in the request is expired\n\n```\n\nYou need to rerun the mfa token generation command:\n\n1. `CODE=\u003cYOUR_CODE\u003e npm run mfa`\n   or\n2. `sh generate_mfa_tokens.sh \u003cYOUR_CODE\u003e`\n\n#### Post-Deployment Errors\n\nIf you try invoking the Lambda function via the Function URL and get an error like the following:\n\n```\n{\n    \"message\": \"Internal server error\"\n}\n```\n\nand an accompanying error in **CloudWatch** like this:\n\n```\nUnknown application error occurred Runtime.ImportModuleError\n\n{\n    \"errorType\": \"Runtime.ImportModuleError\",\n    \"errorMessage\": \"Error: Cannot find module 'app'\\nRequire stack:\\n- /var/runtime/index.mjs\",\n    \"stack\": [\n        \"Runtime.ImportModuleError: Error: Cannot find module 'app'\",\n        \"Require stack:\",\n        \"- /var/runtime/index.mjs\",\n        \"    at _loadUserApp (file:///var/runtime/index.mjs:951:17)\",\n        \"    at async Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:976:21)\",\n        \"    at async start (file:///var/runtime/index.mjs:1137:23)\",\n        \"    at async file:///var/runtime/index.mjs:1143:1\"\n    ]\n}\n```\n\nThis is because there's an issue with the handler. There are a couple things to try depending on your setup:\n\n1. Make sure that the handler in the [template.yaml](./SAM-Project/hello-world/../template.yaml) config is fully qualified, with its parent folder name included in the path, and that the functions are named correctly\n2. If you're uploading your file via zip, you'll need to use `index` instead of `app`\n\n#### Investigating Authentication Issues\n\n`aws configure list` - shows you the current configuration and if your profile is set correctly or not. Example output:\n\n```\nName        Value                       Type                        Location\n----        -----                       ----                        --------\n\nprofile     \u003cnot set\u003e                   None None\naccess_key  ********\\*\\*\\*\\*********    shared-credentials-file\nsecret_key  ********\\*\\*\\*\\*********    shared-credentials-file\nregion      us-east-1                   config-file                 ~/.aws/config\n\n```\n\n`nano ~/.aws/credentials` - You can use whatever editor you want for this. But this shows you the credentials file, separated by profiles, with the tokens/access key information. Example output:\n\n```\n[default]\naws_access_key_id = XXXXXXXXXXXXXXXXXXXX\naws_secret_access_key = XXXXXXXXXXXXXXXXXXXX\n[mfa]\naws_access_key_id = XXXXXXXXXXXXXXXXXXXX\naws_secret_access_key = XXXXXXXXXXXXXXXXXXXX\naws_session_token = XXXXXXXXXXXXXXXXXXXX\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavealdon%2Fbarebones-aws-lambda-with-mfa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavealdon%2Fbarebones-aws-lambda-with-mfa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavealdon%2Fbarebones-aws-lambda-with-mfa/lists"}