Handling sessions with Firestore


Many apps need session management for authentication and user preferences. ASP.NET core comes with middleware to store sessions in a distributed cache.

ASP.NET's default distributed cache is actually not distributed at all. It stores session data in the memory of the web server. When only one web server is serving a web site, this strategy is fine. But when many web servers are serving a web site, the web site's users can experience errors and lost data.

To avoid errors and lost data, an ASP.NET app must use a distributed cache that stores data in a persistent data store. This tutorial shows how to manage sessions on Cloud Run by storing them in Firestore and encrypting cookies with Cloud Key Management Service.

Objectives

  • Deploy the app on Cloud Run.

Costs

In this document, you use the following billable components of Google Cloud:

To generate a cost estimate based on your projected usage, use the pricing calculator. New Google Cloud users might be eligible for a free trial.

When you finish the tasks that are described in this document, you can avoid continued billing by deleting the resources that you created. For more information, see Clean up.

Before you begin

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Firestore, Cloud Run, Cloud Key Management Service, and Cloud Storage APIs.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  6. Make sure that billing is enabled for your Google Cloud project.

  7. Enable the Firestore, Cloud Run, Cloud Key Management Service, and Cloud Storage APIs.

    Enable the APIs

  8. To create a Firestore database in Native mode, complete the following steps:
    1. In the Google Cloud console, go to the Firestore viewer page.
      Go to the Firestore viewer
    2. From the Select a Firestore mode screen, click Select Native Mode.
    3. Select a location for your Firestore database. This location setting is the default Google Cloud resource location for your Google Cloud project . This location is used for Google Cloud services in your Google Cloud project that require a location setting, specifically, your default Cloud Storage bucket and your App Engine app.
    4. Click Create Database.
  9. In Cloud Shell, open the app's source code.
    Go to Cloud Shell

    Cloud Shell provides command-line access to your Google Cloud resources directly from the browser.

  10. To download the sample code and change into the app directory, click Proceed.
  11. In Cloud Shell, configure the gcloud CLI to use your new Google Cloud project:

    # Configure gcloud for your project
    gcloud config set project PROJECT_ID
    

    Replace PROJECT_ID with the Google Cloud project ID that you created using the Google Cloud console.

    The Google Cloud CLI is the primary way you interact with your Google Cloud resources from the command line. In this tutorial, you use the gcloud CLI to deploy and monitor your app.

Examining the source code

The following diagram illustrates how Firestore handles sessions for the Cloud Run app.

Diagram of architecture: user, Cloud Run, Firestore.

The ConfigureServices method in the Startup.cs file sets up the app to use Cloud KMS for encryption and Cloud Storage to store encrypted keys.

  1. In Cloud Shell, click launch editor to launch the editor and examine the Startup.cs file.

    public void ConfigureServices(IServiceCollection services)
    {
        // Antiforgery tokens require data protection.
        services.AddDataProtection()
            // Store keys in Cloud Storage so that multiple instances
            // of the web application see the same keys.
            .PersistKeysToGoogleCloudStorage(
                Configuration["DataProtection:Bucket"],
                Configuration["DataProtection:Object"])
            // Protect the keys with Google KMS for encryption and fine-
            // grained access control.
            .ProtectKeysWithGoogleKms(
                Configuration["DataProtection:KmsKeyName"]);
        services.AddFirestoreDistributedCache(
                Configuration["FIRESTORE_PROJECT_ID"])
            .AddFirestoreDistributedCacheGarbageCollector();
        services.AddSession();
    }
    

Setting up the Google Cloud project

  1. In the Cloud Shell editor, edit the appsettings.json file and replace the two instances of YOUR-PROJECT-ID with your Google Cloud project ID. Save the file.

    {
      "Logging": {
        "LogLevel": {
          "Default": "Warning"
        }
      },
      "AllowedHosts": "*",
      "DataProtection": {
        "Bucket": "YOUR-PROJECT-ID-bucket",
        "Object": "DataProtectionProviderKeys.xml",
        "KmsKeyName": "projects/YOUR-PROJECT-ID/locations/global/keyRings/dataprotectionprovider/cryptoKeys/masterkey"
      }
    }
    
  2. Create a new Cloud Key Management Service key ring named dataprotectionprovider:

    gcloud kms keyrings create dataprotectionprovider --location global

  3. Create a new Cloud Key Management Service key named masterkey:

    gcloud kms keys create masterkey --location global --keyring dataprotectionprovider --purpose=encryption

  4. Create a Cloud Storage bucket to store the encrypted keys:

    gsutil mb gs://PROJECT_ID-bucket

Deploying and running on Cloud Run

You can use the Cloud Run to build and deploy an app that runs reliably under heavy load and with large amounts of data.

This tutorial uses the Cloud Run to deploy the server.

  1. In your Cloud Shell, publish your app:

    dotnet publish -c Release
    
  2. Use Cloud Build to build a Docker container and publish to Container Registry:

    gcloud builds submit --tag gcr.io/PROJECT_ID/sessions bin/Release/netcoreapp2.1/publish

  3. Run the container with Cloud Run:

    gcloud beta run deploy sessions --region us-central1 --platform managed --image gcr.io/PROJECT_ID/sessions --allow-unauthenticated

    Make a note of the URL in the output:

    Service [sessions] revision [sessions-00003-xiz] has been deployed and is serving
    100 percent of traffic at https://sessions-r3f3em7nuq-uc.a.run.app
  4. To view the live app, go to the URL that you copied from the previous step.

Deleting sessions

You can delete session data in the Google Cloud console or implement an automated deletion strategy. If you use storage solutions for sessions such as Memcache or Redis, expired sessions are automatically deleted.

Debugging the app

If you cannot connect to your Cloud Run app, check the following:

  1. Check that the gcloud deploy commands successfully completed and didn't output any errors. If there were errors (for example, message=Build failed), fix them, and try deploying the Cloud Run app again.
  2. See the Cloud Run guide to viewing logs.

Clean up

Delete the project

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

What's next