Add RavenDB to an Existing AWS Lambda Project (.NET C#)


Before We Get Started

You will need the following before continuing:

Starting from scratch?

For a brand new AWS Lambda function, we recommend using the RavenDB AWS Lambda .NET template which is set up with dependency injection, X.509/PEM certificate support, and AWS Secrets Manager integration.
You can also reference the template to see how the integration is set up.

Installing the RavenDB Client SDK

Get started by installing the RavenDB.Client Nuget package in your solution or project which provides the .NET client SDK.

Using the .NET CLI:

dotnet add package RavenDB.Client

Initializing the Document Store

Import the DocumentStore from Raven.Client.Documents namespace to create a new instance with the required configuration and initialize your connection to RavenDB by calling the Initialize method.

using Raven.Client.Documents;

var documentStore = new DocumentStore() {
  Urls = new [] { "https://a.free.mycompany.ravendb.cloud" },
  DatabaseName = "demo",
  // Other options
};
documentStore.Initialize();

For more on what options are available, see Creating a Document Store.

Set up dependency injection

For AWS Lambda functions, it's recommended to configure the document store and document sessions with .NET dependency injection.
The easiest way is to use the community Nuget package RavenDB.DependencyInjection:

dotnet add package RavenDB.DependencyInjection

The pattern to set up dependency injection to inject an IAsyncDocumentSession only works reliably with a ASP.NET Core Lambda function. If you are not using the AWS Lambda ASP.NET Core Hosting for .NET, you can still use a more traditional singleton DocumentStoreHolder pattern.

In your Program.cs, add a using statement for Raven.DependencyInjection which exposes two extension methods:

  • IServiceCollection.AddRavenDbDocStore
  • IServiceCollection.AddRavenDbAsyncSession

The resulting service configuration will look like this:

// Requires a using statement
using Raven.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Configure injection for IDocumentStore
services.AddRavenDbDocStore();

// Configure injection for IAsyncDocumentSession
services.AddRavenDbAsyncSession();

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Register Lambda to replace Kestrel as the web server for the ASP.NET Core application.
// If the application is not running in Lambda then this method will do nothing. 
builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

You can customize the options before they get passed down to the underlying DocumentStore with an overload:

services.AddRavenDbDocStore(options => {
    // ...
    // Customize `options`
    // ...

    options.Conventions.UseOptimisticConcurrency = true;
});

Warm vs. Cold Starts

In AWS Lambda, the instance will be shared across function invocations if the Lambda is warmed up, otherwise it will be constructed each time the function warms up. For more, see Deployment Considerations.

You can set options manually but it's more likely you'll want to configure support for app settings.

Adding Support for App Settings

You will need a way to pass options to the DocumentStore on your local machine and when deployed to AWS Lambda.

The RavenDB.DependencyInjection package supports reading settings from appsettings.json for ASP.NET applications.
The default ASP.NET Core hosting also supports environment variable configuration.

For more on the different configuration providers supported, see Configuration in ASP.NET Core.

Using JSON settings

An example appsettings.json file that connects to the RavenDB live test cluster might look like:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "RavenSettings": {
    "Urls": ["http://live-test.ravendb.net"],
    "DatabaseName": "(not set)"
  }
}

Using environment variables

Environment variables follow the .NET conventions with __ being the dot-notation separator (e.g. RavenSettings__DatabaseName).

You can pass environment variables in your terminal profile, OS settings, Docker env, on the command-line, or within AWS.

Configuring Support for Certificates

RavenDB uses client certificate authentication (mutual TLS) to secure your database connection.
The .NET Client SDK supports X509Certificate2 which is passed to the DocumentStore.Certificate option.
There are multiple ways to load a certificate:

  • Load from .pfx files
  • Load from PEM-encoded certificate
  • Load from AWS Secrets Manager

Load from .pfx Files

You can load PFX files with or without a password by providing the certificate path using RavenSettings:CertFilePath:

{
    "RavenSettings": {
        "Urls": ["https://a.free.company.ravendb.cloud"],
        "DatabaseName": "demo",
        "CertFilePath": "..\\shared\\certs\\company.client.certificate.pfx"
    }
}

The dependency injection logic will automatically load the certificate from this path without extra code.

If the .pfx file requires a password, provide it using the .NET secrets tool by setting RavenSettings:CertPassword:

dotnet user-secrets init
dotnet user-secrets set "RavenSettings:CertPassword" "<CertPassword>"

However, keep in mind that using an absolute physical file path or a user secret requires manual steps for every developer working on a project to configure.

Avoid uploading or deploying .pfx files

PFX files can be compromised, especially if they are not password-protected. Using a physical file also makes it hard to manage and rotate when they expire. They are only recommended for ease-of-use on your local machine.
For production, it is better to use the PEM certificate method or AWS Secrets Manager.

Load from PEM-encoded certificate

For AWS Lambda, it's recommended to use a PEM-encoded certificate that can be provided through an environment variable without deploying any files.

Unlike a .pfx file, a PEM-encoded certificate is plain-text encoded:

-----BEGIN CERTIFICATE-----
MIIFCzCCAvO...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAK...
-----END RSA PRIVATE KEY-----

AWS limits the size of an environment variable to 4KB with a 5KB limit for all variables.
To pass a PEM-encoded certificate, you will need to store the public key (.crt file) alongside your app files and pass the private key contents through an environment variable like RavenSettings__CertPrivateKey.
The private key will be about 3KB, leaving 2KB left for other environment variables.

On the client, you will have to assemble a PEM using the static X509Certificate2.CreateFromPem(publicKey, privateKey) method.

Here is an example Program.cs that adds support for assembling a PEM certificate by adding RavenSettings:CertPublicKeyFilePath and RavenSettings:CertPrivateKey configuration options:

using System.Security.Cryptography.X509Certificates;
using Raven.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRavenDbAsyncSession();
builder.Services.AddRavenDbDocStore(options =>
    {
      var certPrivateKey = builder.Configuration.GetSection("RavenSettings:CertPrivateKey");
      var certPublicKeyFilePath = builder.Configuration.GetSection("RavenSettings:CertPublicKeyFilePath");
      var usePemCert = certPrivateKey != null && certPublicKeyFilePath != null;

      if (usePemCert)
      {
        var certPem = File.ReadAllText(certPublicKeyFilePath);
        // Workaround ephemeral keys in Windows
        // See: https://github.com/dotnet/runtime/issues/66283
        var intermediateCert = X509Certificate2.CreateFromPem(certPem, certPrivateKey);
        var cert = new X509Certificate2(intermediateCert.Export(X509ContentType.Pfx));
        intermediateCert.Dispose();

        options.Certificate = cert;
      }
    });

builder.Services.AddControllers();
builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);

var app = builder.Build();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

This supports using .pfx files or a PEM-encoded certificate, if provided.
It works around a known issue in Windows with ephemeral keys.

For a full reference implementation, view the code on the template repository.

Load from AWS Secrets Manager

If you want to load your .NET configuration from AWS Secrets Manager, you can use the community package Kralizek.Extensions.Configuration.AWSSecretsManager to support securely loading certificates instead of relying on production environment variables.

Learn more about configuring AWS Secrets Manager

Configuring AWS

You will need to configure certificate authentication in AWS Lambda. Depending on the method you choose above, the steps vary.

Using Environment Variables

Under your Lambda function, go to Configuration > Environment to edit your environment variables.

AWS environment variable settings

AWS environment variable settings

Specifying Path to Certificate Files

If you are deploying a physical .pfx file, you can specify the RavenSettings__CertFilePath and RavenSettings__CertPassword environment variables.

If you are using a PEM-encoded certificate, using the example code above you would pass a RavenSettings__CertPublicKeyFilePath environment variable (if it differs from your appsettings.json value).

Specifying the PEM-encoded Private Key

The RavenSettings__CertPrivateKey environment variable should be set to the contents of the .key file from the RavenDB client certificate package.

Example value:

RavenSettings__CertPrivateKey=----- BEGIN RSA PRIVATE KEY ----- MIIJKA...

It will look like this in the AWS console:

AWS environment variable settings for PEM certificate private key

AWS environment variable settings for PEM certificate private key

When pasting into the AWS Console, line breaks will automatically be removed and this should still be parsed successfully with X509Certificate2.CreateFromPem without extra handling.

These values will override appsettings.json once saved.

Next Steps

AWS

RavenDB