I need to access some credentials on lambda functions and one way to do that is to put them in environment variables.
However, the values of these credentials are visible in the lambda console. I am thinking to put them in secret manager or parameter store and put the key as env in lambda. Then load the value in lambda at runtime.
However, this approach is secure but give some latency. I am not sure how much latency it gives. Is there a better solution for that?
The Lambda variables are actually encrypted already, the decrypted values are shown from the console but if the user does not have permission for the key they will not be able to see them.
As you suggested you have the solutions of:
Secrets Manager
Systems Manager Parameter Store (use a SecureString).
The benefits that you will get by using either of these solutions is that you can change them outside of the version you're using as well as across a number of Lambda functions simultaneously.
You will also have an increased latency from trying to reach these service endpoints which would lead to a slight increase in time. You could reduce this latency by having your Lambda within a VPC and use VPC endpoints to the service (which will allow direct private communication over using the public internet) but it will still be longer than environment variables.
Ultimately this choice is for you, if you do need to reuse the variables and can put up with the slight latency then use secrets manager or systems manager parameter store. Otherwise manage the KMS permissions so that not every user can access the get to decrypt.
Related
We are developing a serverless application. The application has "users" that get added, "groups" that have "permissions" on different "resources". To check if a user has permission to do an action on a resource, there would be some calculations we will need to do. (We are using DynamoDB)
Basically, before every action, we will need to check if the user has permission to do that particular action on the given resource. I was thinking we could have a lambda function that checks that from a cache and If not in the cache, hits the DB, does the calculation, writes in the cache, and returns.
What kind of cache would be best to use here? We are going to be calling this internally from the backend itself.
Is API gateway the way to go still?
How about elastic cache for this purpose? Can we use it without having to configure a VPC? We are trying not to have to use a VPC in our application.
Any better ways?
They are all good options!
Elasticache is designed for caching data. API Gateway can also cache results.
An alternative is to keep the data "inside" the AWS Lambda function by using global variables. The values will remain present the next time the Lambda function is invoked, so you could cache results and an expiry time. Note, however, that Lambda might launch multiple containers if the function is frequently run (even in parallel), or not run for some time. Therefore, you might end up with multiple caches.
I'd say the simplest option would be API Gateway's cache.
Where are those permissions map (user <-> resource) is stored?
This aws's blog post might be interesting (it's about caching in lambda execution environment's memory.), because you could use dynamodb's table for that.
I am trying to set up an event trigger lambda#Edge function from cloudFront.
This function needs to access the database and replace the url's metadata before distributing out to users.
Issues I am facing:
My DocumentDB is placed in a VPC private subnet. Can't be accessed outside the VPC.
My Lambda edge function can't connect to my VPC since they are both in different region.
The method I had in mind is to create an API in my web server(public subnet) for my lambda function to call, but this seems like not a very efficient method
Appreciate If you can give me some advice or an alternative way for implementation.
Thanks in Advance
Lambda#Edge has a few limitations you can read about here.
Among them is:
You can’t configure your Lambda function to access resources inside your VPC.
That means the VPC being in another region is not your problem, you just can't place a Lambda # Edge function in any VPC.
The only solution I can think of is making your DocumentDB available publicly on the internet, which doesn't seem like a great idea. You might be able to create a security group that only allows access from the CloudFront IP-Ranges although I couldn't find out if Lambda#Edge actually uses the same ranges :/
Generally I'd avoid putting too much business logic in Lambda#Edge functions - keep in mind they're run on every request (or at the very least every request to the origin) and increase the latency for these requests. Particularly network requests are expensive in terms of time, more so if you communicate across continents to your primary region with the database.
If the information you need to update the URLs metadata is fairly static, I'd try to serialize it and distribute it in the lambda package - reading from local storage is considerably cheaper and faster.
Encountered a few speicific use cases that I'm somewhat confused to use which:
A large number of free, public API keys. Using lambda environment variable with encyption, other developer/admin can still expose their plaintext value right in the lambds console. Should Parameter Store be used instead?
Login credentials to a third party platform. I assume that Secrets Manager is the only option?
DB Connection strings. Secrets Manager? At $0.40/secret/month, the bill would add up for hundreds of DBs for simply storing credentials.
For storing any credentials you have three AWS managed choices:
Lambda Environment Variables
These will be passed into the Lambda function directly via the Lambda Service. You can prevent others accessing the string values by controlling their permissions to KMS via IAM. This will provide the best performance out of any options (there's no additional lookup in the code runtime).
By using this option be aware of the following pitfalls:
If you use versioning for your Lambda function the values are fixed, you would need to deploy a new version of the Lambda function to make changes.
Values are attached to an individual Lambda function, if the keys are used by multiple you will need to pass to each function individually.
Systems Manager Parameter Store
Using this option you would use the SDK to retrieve any key/values that you want. It can store both plain text values as well encrypted strings (the SecureString type). It provides basic functionality but if that is all you need then it will work great. It costs nothing to store the values, but the price is $0.05 per 10,000 Parameter Store API interactions. Unlike environment variables you can use the value across multiple Lambda functions.
By using this option you would need to be aware of the following:
There will be a hit to performance for retrieving the value everytime, to reduce this call the function in the global context so that it can be reused between invocations.
You will need an individual parameter per each key/value. For a database this would mean either creating individual parameters or storing the entire credential set as JSON object and decoding after you retrieve it.
Secrets Manager
Using this option a lot of the management is built into the service, a secret can contain either a string or a single line JSON object. The SDK will handle the retrieval of these values but you must be aware just like SSM you will take a performance hit so you'll want to take a look at a similar solution as the parameter store. The biggest advantage to secrets manager over SSM parameter store is its integrations with other AWS services allowing features such as secret rotation.
However if you don't need the features of secrets manager you may be paying for more than you actually require, this is the most expensive option of all three.
A large number of free, public API keys. Using lambda environment variable with encyption, other developer/admin can still expose their plaintext value right in the lambds console.
For the issue of developers being able to see the environment variables in the console, you can use a non-default KMS CMK, and configure permissions on that key so that the other developers can't use it (doc). They will still be able to see the rest of the Lambda configuration.
A bigger issue is how you will configure these environment variables. If you're using Terraform, for example, the configuration is written to the state file, and you will need to use external state (stored in S3 or on HashiCorp's servers) to secure it. If you're using CloudFormation, you can configure them using a dynamic reference to a Secrets Manager secret, but not to a Parameter Store secure string.
One other choice is to use the environment variables to reference parameter store keys, and then programmatically retrieve the values. For example, you have an environment variable named DATABASE_PASSWORD, and its value is /dev/database/password; the actual database password is a SecureString in Parameter Store, accessed via that path.
Login credentials to a third party platform. I assume that Secrets Manager is the only option?
Parameter store also provides a SecureString.
DB Connection strings. Secrets Manager? At $0.40/secret/month, the bill would add up for hundreds of DBs for simply storing credentials.
Does your application actually connect to hundreds of DBs? If yes, is $40/month (for 100 connections) really a financial hardship for your company?
If yes, then Parameter Store might be the best choice, but beware that there are a limited number of "free" parameters per account.
Does AWS provides any service for storing all the configs and we can get this config by just making a call to it? Here the config can be version controlled or available with less latency and so on?
Eg. I want to use some configs from the lambda function which I can easily change without changing the lambda function.
You can use AWS Systems Manager Parameter Store. It provides a centralized store to manage configuration data such as database strings, secrets or credentials.
https://aws.amazon.com/systems-manager/features/#Parameter_Store
DynamoDB is typically used for that purpose. The latency for a single GetItem request is typically around 5ms, and you can cache the results client-side to reduce the latency even further and to avoid a read io ever time.
Using AWS Step Functions to string together Lambdas is interesting, but is there a way to disable/hide logging on the execution details screen? Private information being handed from one lambda to another needs to be able to be done in secret, and adding a KMS encrypt/decrypt to each step is a ton of overhead, and impossible for lambdas that live in a VPC without internet access.
We've talked with Amazon and it looks like that there's no way to hide this information from the console. The alternative is to limit what gets sent to the Lambda functions at each step.
So you can ensure that only non-PII subsets of the input data are seen by certain functions. The usual workaround is to not passing PII data in at all and instead of that, place the PII data in an encrypted data stores, such as an S3 bucket or encrypted RDS database table, and pass a reference to that object through the state machine.
Another option is to use SSM parameter store with the SecureString type using KMS encryption. You would pass the name of the SSM parameter between steps. The lambda functions would use the API to retrieve and decrypt the value in a single request. See the link below for documentation on how to work with SSM parameter store using boto3 in Python.
http://boto3.readthedocs.io/en/latest/reference/services/ssm.html#SSM.Client.get_parameter
You will have to ensure that the roles to your lambda functions provide access to the SSM parameters AND access to same KMS key that was used to encrypt the value.