Aws-lambda-dotnet: deploy-function and deploy-serverless override the environment variables

Created on 16 Jan 2018  路  9Comments  路  Source: aws/aws-lambda-dotnet

Hey.

I'm a bit confused on how to configure environment variables in Lambda. My attempt was basically to deploy my stack using dotnet lambda deploy-serverless, which worked great. Then I went to the Lambda function within the AWS Management Console, and I manually configured my secrets, such as the DB password, which again worked great.

Now, the next time I deployed my Lambda using dotnet lambda deploy-serverless it removed those environment variables, so then I tried dotnet lambda deploy-function ... and the same thing happened.

What is the correct way to set secret environment variables? I would rather not store any secrets in my git repo, but then how would I deploy them, if the above doesn't work?

Thanks.

guidance

Most helpful comment

@raRaRa I recommend you use EC2 SSM Parameter Store to securely manage your key/value pair configurations. It supports value encryption with AWS KMS Key, defined as type SecureString. KMS and parameter store key/value (except SecureString which can be created via AWS console) objects can be provisioned via CloudFormation and then referenced within your C# lambda code.

CodeBuild also supports EC2 SSM Paramater Store (including SecureString) natively allowing you to refer to a parameter in a project buildspec.yml file under the parameter-store section. The variable can then be used in the buildspec.yml to override the dotnet lambda --template-parameters key1=value1 or other build time scripts.

We use a combination of the lambda environment variables and SSM Parameter variables. Instead of passing in the defined value in the environment variable, we pass in a reference to the SSM parameter name e.g. \dev\ConnectionString.

This way we can:
1) change the value in a centralized location via SSM parameter store;
2) during an emergency/testing/debugging change the environment value in the AWS Lambda console to reference a different SSM key all together (e.g. \temp1\ConnectionString) ; and
3) programatically inject parameter store names as environment variables during CICD deployment. For instance use CodeBuild to refer to a parameter store that includes an environment name. Inject variables as \staging\ConnectionString or \testing\ConnectionString depending on if we are building for Staging or Testing.

References for you to consider:
BurningMonk: You should use SSM Parameter Store over Lambda env variables
https://hackernoon.com/you-should-use-ssm-parameter-store-over-lambda-env-variables-5197fc6ea45b

Organize Parameters by Hierarchy, Tags, or Amazon CloudWatch Events with Amazon EC2 Systems Manager Parameter Store
https://aws.amazon.com/blogs/mt/organize-parameters-by-hierarchy-tags-or-amazon-cloudwatch-events-with-amazon-ec2-systems-manager-parameter-store/

AWS SDK For .NET REFERENCE: check out the GetParameterAsync and PutParameterSync
https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SSM/TSSMClient.html

Cheers!
Panod

All 9 comments

Hi, I have done using template parameters and reference in environment variables in template, i.e.

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Transform": "AWS::Serverless-2016-10-31",
    "Parameters": {
        "CustomersDB": {
            "Description": "CustomersDB",
            "Type": "String"
        }
    },
    "Resources": {
        "Function": {
            "Type": "AWS::Serverless::Function",
            "Properties": {
                "Handler": "LambdaEntryPoint::FunctionHandlerAsync",
                "Runtime": "dotnetcore1.0",
                "CodeUri": "",
                "MemorySize": 256,
                "Timeout": 20,
                "Role": null,
                "Policies": [
                    "AWSLambdaFullAccess"
                ],
                "Environment": {
                    "Variables": {
                        "CUSTOMER_DB": {
                            "Ref": "CustomersDB"
                        }
                    }
                },
                "Events": {
                    "PutResource": {
                        "Type": "Api",
                        "Properties": {
                            "Path": "/{proxy+}",
                            "Method": "ANY"
                        }
                    }
                }
            }
        }
    }
}

@christianavila do you specify the CustomersDB in the CI? Or can you do that once in the Management Console?

When deploy the function, you can pass the parameters as arguments

 $ dotnet lambda help deploy-serverless

Command to deploy an AWS Serverless application

   dotnet lambda deploy-serverless [arguments] [options]

 -tp    | --template-parameters          CloudFormation template parameters. Format is <key1>=<value1>;<key2>=<value2>

Or after deploy, can management in console

@ChristianAvila I'm afraid this solution doesn't help me, because the next time I deploy, the deployment will override the environment variables with whatever is in the CloudFormation template (assuming I change the environment variables in the Management Console).

I don't want to store secrets in my template. However I could probably pass the parameters like you explained with a CI.

Is CodeBuild good enough for the job? Any alternative solutions? Anyone? :)

@raRaRa I recommend you use EC2 SSM Parameter Store to securely manage your key/value pair configurations. It supports value encryption with AWS KMS Key, defined as type SecureString. KMS and parameter store key/value (except SecureString which can be created via AWS console) objects can be provisioned via CloudFormation and then referenced within your C# lambda code.

CodeBuild also supports EC2 SSM Paramater Store (including SecureString) natively allowing you to refer to a parameter in a project buildspec.yml file under the parameter-store section. The variable can then be used in the buildspec.yml to override the dotnet lambda --template-parameters key1=value1 or other build time scripts.

We use a combination of the lambda environment variables and SSM Parameter variables. Instead of passing in the defined value in the environment variable, we pass in a reference to the SSM parameter name e.g. \dev\ConnectionString.

This way we can:
1) change the value in a centralized location via SSM parameter store;
2) during an emergency/testing/debugging change the environment value in the AWS Lambda console to reference a different SSM key all together (e.g. \temp1\ConnectionString) ; and
3) programatically inject parameter store names as environment variables during CICD deployment. For instance use CodeBuild to refer to a parameter store that includes an environment name. Inject variables as \staging\ConnectionString or \testing\ConnectionString depending on if we are building for Staging or Testing.

References for you to consider:
BurningMonk: You should use SSM Parameter Store over Lambda env variables
https://hackernoon.com/you-should-use-ssm-parameter-store-over-lambda-env-variables-5197fc6ea45b

Organize Parameters by Hierarchy, Tags, or Amazon CloudWatch Events with Amazon EC2 Systems Manager Parameter Store
https://aws.amazon.com/blogs/mt/organize-parameters-by-hierarchy-tags-or-amazon-cloudwatch-events-with-amazon-ec2-systems-manager-parameter-store/

AWS SDK For .NET REFERENCE: check out the GetParameterAsync and PutParameterSync
https://docs.aws.amazon.com/sdkfornet/v3/apidocs/items/SSM/TSSMClient.html

Cheers!
Panod

Thank you for the quick and detailed answer @panodk. Much appreciated! 鉂わ笍

No problem - happy to save you and others some time. :)

I ended up using what @panodk described above. But here's a bit more detail:

  1. You need to install the AWSSDK.SimpleSystemsManagement NuGet package in order to use AmazonSimpleSystemsManagementClient.
  2. You can use the AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_SESSION_TOKEN environment variables within your Lambda to authenticate the AmazonSimpleSystemsManagementClient client. Just make sure that the role for the Lambda has the proper access to read from Amazon SSM. I simply gave my Lambda access to AmazonSSMReadOnlyAccess.
  3. You can use GetParametersAsync to get many parameters at once.

Closing as it looks like the question was answered. You can pass environment variables as part of the serverless template and also parameterize the template to pass them in as part of deployment. Using SSM is also a great option to use.

Was this page helpful?
0 / 5 - 0 ratings