gotjava2012
gotjava2012

Reputation: 761

aws-sam-local environment variables

I am following the readme here: https://github.com/awslabs/aws-sam-local

I have a lambda written in python 3.6 and its similar to the helloworld example here : https://github.com/awslabs/aws-sam-local/tree/develop/samples/hello-world/python

template.yml looks as such:

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: MyFunction1 API
Resources:
  MyFunction1:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: MyFunction1
      Handler: lambda_module.lambda_handler
      Runtime: python3.6
      CodeUri: lambda.zip
      MemorySize: 128
      Timeout: 10
      Policies:
        -AWSLamdbaBasicExecutionRole
      Events:
        BingLambdaEndpoint:
          Type: Api
          Properties:
            Path: MyFunction1/search
            Method: get

I have environment variables within the lambda but not able to wire them up on start up. Documentation says I can create a environments.json file and append the following on the invoke command : Use --env-vars argument of invoke

My environment file looks like the example and I get an error: Unable to find environment variable: api_key

environment.json looks as such:

{
  "MyFunction1": {
    "api_key": "123456789",
    "BUCKET_NAME": "testBucket"
  }
}

command I run is as such:

sam local invoke MyFunction1 --env-vars environment_variables.json -e event.json

Can anyone provide additional insight?

Upvotes: 72

Views: 87284

Answers (9)

Cocuba
Cocuba

Reputation: 372

For those using

sam local invoke MyFunction1 --env-vars environment_variables.json -e event.json

and not getting the variables in your function, it’s because the options should go after the function name. It should be

sam local invoke --env-vars environment_variables.json -e event.json MyFunction1

Upvotes: 0

Erik Finnman
Erik Finnman

Reputation: 1677

If you're like me and want to set some environment variable only for local development purposes, I got this to work without an environment file by simply defining the environment variable in the template.yaml file (as shown in the other answers) and then just exporting the variable in the shell:

export MY_VARIABLE=some_value

If I then launch the local environment using:

sam local start-api

the variable is available to my lambda function.

Upvotes: 1

chucre
chucre

Reputation: 496

You can use the option -n, --env-vars PATH. This this is JSON file and you need to have an object that maps with your resource name in the template.

template.yaml:

...
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Environment:
        Variables:
          SOME_VAR: !Ref SomeVar
...

Let's assume your file name for the variables is .env.local.json. The content should match something like this:

.env.local.json:

{
  "HelloWorldFunction": {
     "SOME_VAR": "NEW_VALUE"
  }
}

Then you need to run the command:

sam local start-api --env-vars .env.local.json

Upvotes: 5

Michael Schmid
Michael Schmid

Reputation: 5005

Here’s a comprehensive solution to use environment-specific variables with AWS SAM. Do not use this approach for secrets!

In the Cloudformation template (template.yaml by default), define the variables and refer to them as needed, for example:

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'

Parameters:
  TargetEnv:
    Type: String
    Description: Target environment name
  DynamoDB:
    Type: String
    Description: ARN of the DynamoDB table
  SecurityGroups:
    Type: List<String>
    Description: List of VPC security groups
  Subnet:
    Type: String
    Description: VPC subnet identifier

Globals:
  Function:
    Environment:
      Variables:
        TargetEnv: !Ref TargetEnv
        DynamoDB: !Ref DynamoDB
  …

Resources:
  ServiceRole:
    Type: 'AWS::IAM::Role'
    Properties:
      Policies:
        - PolicyName: dynamodb
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - dynamodb:Query
                Resource: !Ref DynamoDB
      …

  MyFunction1:
    Type: AWS::Serverless::Function
    Properties:
      Role: !GetAtt ServiceRole.Arn
      VpcConfig: &vpc_props
        SecurityGroupIds: !Ref SecurityGroups
        SubnetIds:
          - !Ref Subnet
    …

The variables that are listed under Globals.Function.Environment.Variables are also available at runtime – in Node.js in this example as process.env.TargetEnv and process.env.DynamoDB

Then, set the parameters’ values in SAM’s configuration (samconfig.yaml by default, or use the TOML format if you prefer).

version: 0.1

default:
  build:
    parameters:
      cached: true
      parallel: true
  deploy:
    parameters: &default_deploy_parameters
      stack_name: my-service
      s3_prefix: my-service
      resolve_s3: true
      region: eu-central-1
      capabilities: CAPABILITY_IAM
      image_repositories: []

staging:
  deploy: &staging_deploy
    parameters:
      <<: *default_deploy_parameters
      parameter_overrides:
        - TargetEnv=staging
        - HandshakeTable=arn:aws:dynamodb:eu-central-1:07867760868:table/MyTable
        - SecurityGroups=sg-61f4470b87daef18c,sg-72a87ea4bf7f4b5d2
        - Subnet=subnet-16b4ca88aca7ab4b8

  local_start_api: *staging_deploy
  local_invoke: *staging_deploy

production:
  deploy:
    parameters:
      <<: *default_deploy_parameters
      parameter_overrides:
        - TargetEnv=production
        - HandshakeTable=arn:aws:dynamodb:eu-central-1:870517811788:table/MyTable
        - SecurityGroups=sg-9fa4b495c33d84a18,sg-fcb69e4ca84aa7e81
        - Subnet=subnet-daad36a5d2a700a8e

Finally, you can use the environments defined in the template (staging, production) with the respective commands.

sam deploy --config-env staging
sam local start-api --config-env staging
sam local invoke MyFunction1 --config-env staging
sam deploy --config-env production

For sam build, the environment must not be specified.

Upvotes: 1

Leopoldo Varela
Leopoldo Varela

Reputation: 364

Make sure that your template's parameters have NoEcho equals true, like in this example:

Parameters:
  # Build variables
  Stage:
    Type: String
  # Environment variables
  MssqlServer:
    Type: String
    NoEcho: true
  MssqlDatabase:
    Type: String
    NoEcho: true
  MssqlUser:
    Type: String
    NoEcho: true
  MssqlPassword:
    Type: String
    NoEcho: true

Then you can simply pass the environment variables with a command like this:

sam deploy --parameter-overrides "MssqlServer='$MSSQL_SERVER' MssqlDatabase='$MSSQL_DATABASE' MssqlUser='$MSSQL_USER' MssqlPassword='$MSSQL_PASSWORD' Stage=dev" --config-env dev

Upvotes: 1

JLarky
JLarky

Reputation: 10241

template file

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
  
Globals:

  Function:
    Timeout: 3

Parameters:

  SomeVar:
    Type: String
    Description: My SomeVar
    Default: default value

Resources:

  HelloWorldFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: app.lambdaHandler
      Runtime: nodejs12.x
      Environment:
        Variables:
          SOME_VAR: !Ref SomeVar
      Events:
        HelloWorld:
          Type: Api
          Properties:
            Path: /hello
            Method: get

Outputs:

  HelloWorldApi:
    Description: "API Gateway endpoint URL for Prod stage for Hello World function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"

  HelloWorldFunction:
    Description: "Hello World Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn

  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

from https://github.com/awslabs/aws-sam-cli/issues/1163#issuecomment-557874976

then in code

console.log(process.env.SOME_VAR);

when you run sam local start-api and it will print default value

when you run sam local start-api --parameter-overrides SomeVar=other_value and it will print other_value

then if you create file env.json with this content

{ "PreviewsFunction": { "SOME_VAR": "123" } }

when you run sam local start-api --env-vars env.json and it will print 123

p.s. it will work with start-api/start-lambda/invoke all in the same way, but it looks like sam deploy only works with --parameter-overrides SomeVar=other_value and no --env-vars

Upvotes: 52

Mike Patrick
Mike Patrick

Reputation: 11006

Any environment variables you want to use with SAM Local in this manner need to exist in your SAM template. From this GitHub issue:

... SAM Local only parses environment variables that are defined in the SAM template.

In the template, you can provide no value, an empty string, or choose a sensible default.

A portion of a template including environment variables:

Resources:
  MyFunction1:
    Type: 'AWS::Serverless::Function'
    Properties:
      .....
      Environment:
        Variables:
          api_key:
          BUCKET_NAME:

You can think of the environment variables file as a mechanism to override environment variables that the template "knows" about. It does not work as a mechanism to inject arbitrary environment variables into the local runtime.

Upvotes: 88

Abul Fayes
Abul Fayes

Reputation: 147

I had the same issue. When I ran

sam local start-api --env-vars  env.json 

The values in env.json where not being read. What fixed the issue for me was to use the following format in env.json

"Parameters": {
    "PARAM_NAME": "VALUE"
}

The other format did not work for me:

{ "function": { "PARAM_NAME": "VALUE" } }

Upvotes: 6

toonsend
toonsend

Reputation: 1352

Ensure that the variables are declared in template.yml. A config file overwrites the variables but does not create variables when they don't exist in the original template.

Upvotes: 13

Related Questions