Reference

End to End Identity

CipherStash Proxy can associate the identity of an application user, as well as additional context about a database statement. This information is included in data access logs for improved visibility.

Overview

User identity and context information can be set using the SET CS_IDENTITY and SET CS_CONTEXT commands. These commands behave similarly to other PostgreSQL SET commands but are only available when connecting via CipherStash Proxy. The command arguments values are never passed on to the database itself.

Adding these commands to your application unlocks powerful new capabilities.

Available commands:

  • SET CS_IDENTITY { TO | = } 'jwt_token'
  • SET CS_CONTEXT { TO | = } 'json'
  • RESET {CS_IDENTITY | CS_CONTEXT}

Both Identity and Context data are tied to the current connection or transaction context. The application is responsible for ensuring that data is reset.

SET CS_IDENTITY takes a JWT as an argument. For example:

1-- full JWT not shown (it might be quite large)
2SET CS_IDENTITY TO 'eyJhbGciOiJSUzI1NiIsIn...';

You can run SET CS_IDENTITY at any time and all subsequent statements will be associated with the identity. The typical approach is to set the identity for every statement or transaction.

For example, the following will record data accesses to the user's table against the user specified by the JWT given to SET CS_IDENTITY.

1SET CS_IDENTITY TO 'eyJhbGciOiJSUzI1NiIsIn...';
2SELECT name, email FROM users;

Important

JWTs are credentials, which can grant access to resources. Be careful where you paste them!

SET CS_CONTEXT accepts arbitrary JSON data to be associated with the data access logs. The context data can be used to refine search and analysis in the dashboard.

For example, to associate the version of the application used when making the request:

1SET CS_CONTEXT TO '{"app_version": "2.7.3"}`;

Configuring an Identity Provider

Each JWT is issued by an identity provider. This might be your application or a 3rd party Identity Provider such as Auth0. A JWT can also include "claims" which provide information about its intended usage, the service that issued it and who it was generated for.

CipherStash proxy requires the following claims to be present on any JWT passed to SET CS_IDENTITY:

ClaimMeaningHow its used by CipherStash Proxy
issThe identity provider that issued this JWT. Usually a URL.Checked against an allow-list before the JWT is accepted
audThe intended service for this JWTChecked against an allow-list before the JWT is accepted. Record in data-access logs.
subIdentity of user (or machine) the JWT was issued toRecorded in data-access logs

See RFC: 7519 JSON Web Token for further details.

Add a trusted issuer

To add a trusted identity provider to CipherStash Proxy, you can specify an Issuer (iss claim) and Audience (aud claim) that must be present in a JWT using the Cipherstash CLI.

The following assumes you have the CLI configured.

Add an authorised issuer and audience to your account:

1stash identify provider trust \
2  --issuer auth.domain.com \
3  --audience api.domain.com

The issuer should be the domain that hosts the JSON Web Key issued by the Authorisation Server:

1https://{issuer}/.well-known/jwks.json

The audience should be the audience value in your JWT.

Multiple values can be provided for both issuer and audience as comma-delimited strings

1stash identify provider trust \
2  --issuer "auth.domain.com, auth.domain.org" \
3  --audience "api.domain.com, api.domain.org"

We expect fully qualified, valid URLs including the https:// scheme, but the CLI will try and normalize the url for you.

For example:

1auth.domain.com => https://auth.domain.com/

Both forms of the URL will be accepted.

If you're still not sure what values to use, you can inspect a JWT using JWT.io. For example, below is a JWT issued by the CipherStash Auth0 tenant:

CipherStash JWT Claims from jwt.io

You can see that the iss claim is set to https://auth.cipherstash.com/ and the aud is set to https://console.cipherstash.com. To trust JWTs with these claims the command would be as follows:

1stash identify provider trust \
2  --issuer "auth.cipherstash.com" \
3  --audience "console.cipherstash.com"

Revoke a trusted issuer

Revoke an issuer so that JWTs signed by it are no longer trusted.

1stash identify provider revoke --issuer

For example:

1stash identify provider revoke --issuer "auth.example.net"

See the Cipherstash CLI Reference for more details.

Set Identity

SQL Command to set a JWT token that will be verified and decoded.

Syntax

1SET CS_IDENTITY { TO | = } 'jwt_token'

Description

The SET CS_IDENTITY command changes the run-time identity.

The input parameter is expected to be a valid JWT token.

The token is validated against authorised issuers and audiences configured in the CipherStash Workspace.

If issuer and audience are valid, the JWT token is decoded and the issuer, audience and subscriber values are extracted and propagated with the Statement Audit Log.

Issuers and Audience

The JWT passed to SET CS_IDENTITY must contain trusted aud and iss claims for the workspace. See Configuring an Identity Provider

Example

1-- Set JWT Token
2SET CS_IDENTITY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2lkLmNvbXBhbnkuY29tIiwiYXVkIjoiaHR0cHM6Ly9hcHAuY29tcGFueS5jb20iLCJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.pPpSemUg7GM2eDOz193lBojDFqqR2Hu5M5ovItXcFOA'
1{
2  "iss": "https://id.company.com",
3  "aud": "https://app.company.com",
4  "sub": "1234567890",
5  "name": "John Doe",
6  "iat": 1516239022
7}

Statements executed after the above SET CS_IDENTITY command will include the subject and audience. For example, the following query will result in a statement log entry similar to the below:

1SELECT name FROM users LIMIT 1;
1{
2  "id": "d27341f8-dd3b-4498-bb4d-d9ccf7eb6bf9",
3  "workspace_id": "W9BODZQX2PQGD2DM",
4  "statement_id": "374d72c1-f09f-4eb4-ac69-c43de8f9c193",
5  // 'sub' claim from JWT passed to SET CS_IDENTITY
6  "identity": "1234567890",
7  // 'aud' claim JWT passed to SET CS_IDENTITY
8  "audience": "https://app.company.com",
9  "context": null,
10  "statement": "SELECT name FROM users LIMIT {REDACTED}",
11  "statement_fingerprint": "e529ebb63e482f0f",
12  "database": "postgres",
13  "database_pool_name": "postgres",
14  "database_host": "db",
15  "database_username": "postgres",
16  "created_at": "2024-06-25T09:11:21.292Z",
17  "type": "statement_received"
18}

Reset Identity

Immediately clear identity information.

Syntax

1RESET CS_IDENTITY

Description

The RESET CS_IDENTITY command clears the run-time identity data.

Set Context

Sets arbitrary JSON data to be with statement Audit log.

Syntax

1SET CS_CONTEXT { TO | = } '<json>';

Description

The SET CS_CONTEXT command changes the run-time context that is propagated with the Statement Audit Log.

The input parameter is expected to be a valid JSON string. The parameter will be checked to ensure it can be parsed as JSON, but no other restrictions or requirements apply.

If the input parameter is invalid, a parse error is returned.

Example

Setting context will result in the additional information being included in statement audit logs.

1SET CS_CONTEXT TO '{"extra": "data"}';
2SELECT name FROM users LIMIT 1;

Statement audit log:

1{
2  "id": "d27341f8-dd3b-4498-bb4d-d9ccf7eb6bf9",
3  "workspace_id": "W9BODZQX2PQGD2DM",
4  "statement_id": "374d72c1-f09f-4eb4-ac69-c43de8f9c193",
5  "identity": null,
6  "audience": null,
7  // Context information passed to SET CS_CONTEXT
8  "context": {
9    "extra": "data"
10  },
11  "statement": "SELECT name FROM users LIMIT {REDACTED}",
12  "statement_fingerprint": "e529ebb63e482f0f",
13  "database": "postgres",
14  "database_pool_name": "postgres",
15  "database_host": "db",
16  "database_username": "postgres",
17  "created_at": "2024-06-25T09:11:21.292Z",
18  "type": "statement_received"
19}

Reset Context

Immediately clear context information.

Syntax

1RESET CS_CONTEXT

Description

The RESET CS_CONTEXT command clears the run-time context.


Rails Example

In Rails, an around_action can SET and RESET the context or identity for all statements run inside the controller. Context data can be loaded or extracted from the session.

1class BaseController < ApplicationController
2  around_action :wrap_in_context
3
4  private
5    def wrap_in_context
6      begin
7        ActiveRecord::Base.connection.execute("SET CS_CONTEXT '{...}'")
8        yield
9      ensure
10        ActiveRecord::Base.connection.execute("RESET CS_CONTEXT")
11      end
12    end
13end

Lifecycle

Transaction Mode

In transaction mode, a client is connected for the duration of a transaction. The connection is returned to the pool once the transaction is complete.

This mode is enabled by default.

An application can start a transaction and execute multiple statements against the same underlying connection to the database.

As transactions complete, and connections returned to the pool, any set identity or context information is discarded.

Data can be changed at any time by executing SET {CS_IDENTITY | CS_CONTEXT} or RESET {CS_IDENTITY | CS_CONTEXT}.

Session Mode

Session mode is the normal behaviour of Postgres connections in the wild. In Session mode, the connection context lives until the client closes the connection.

The identity is retained until the next SET {CS_IDENTITY | CS_CONTEXT} statement or RESET {CS_IDENTITY | CS_CONTEXT} is called.

Example Session Mode Flow

In this example, the App has called SET CS_IDENTITY before executing multiple statements.

Both statements will be executed by the proxy with the same identity.

1App   -> Connect
2
3Proxy -> Database Connection
4
5App   -> SET CS_IDENTITY
6
7App   -> Statement
8
9Proxy -> Executes Statement [with CS_IDENTITY]
10
11App   -> Statement
12
13Proxy -> Executes Statement [with CS_IDENTITY]
14
15App   -> Close Connection
Previous
CipherStash Proxy operations & troubleshooting