Skip to content

Security: dandavison/temporalio-documentation

Security

docs/security.md

id title sidebar_label sidebar_position description toc_max_heading_level keywords tags
security
Temporal Platform security features
Security
6
This guide is an overview of the Temporal Platform security features.
4
guide-context
security
term
guide-context
security
term

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

:::info Work in progress

This guide is a work in progress. Some sections may be incomplete. Information may change at any time.

:::

:::info General company security

For information about the general security habits of Temporal Technologies see our company security page.

:::

The Temporal Plaform is designed with security in mind, and there are many features that you can use to keep both the Platform itself and your user's data secure.

A secured Temporal Server has its network communication encrypted and has authentication and authorization protocols set up for API calls made to it. Without these, your server could be accessed by unwanted entities.

What is documented on this page are the built-in opt-in security measures that come with Temporal. However users may also choose to design their own security architecture with reverse proxies or run unsecured instances inside of a VPC environment.

Server Samples

The https://github.com/temporalio/samples-server repo offers two examples, which are further explained below:

  • TLS: how to configure Transport Layer Security (TLS) to secure network communication with and within a Temporal cluster.
  • Authorizer: how to inject a low-level authorizer component that can control access to all API calls.

Encryption in transit with mTLS

Temporal supports Mutual Transport Layer Security (mTLS) as a way of encrypting network traffic between the services of a cluster and also between application processes and a Cluster. Self-signed or properly minted certificates can be used for mTLS. mTLS is set in Temporal's TLS configuration. The configuration includes two sections such that intra-Cluster and external traffic can be encrypted with different sets of certificates and settings:

  • internode: Configuration for encrypting communication between nodes in the cluster.
  • frontend: Configuration for encrypting the Frontend's public endpoints.

A customized configuration can be passed using either the WithConfigLink preview iconTemporal Server options

You can run the Temporal Server as a Go application by including the server package go.temporal.io/server/temporal and using it to create and start a Temporal Server.

Learn more or WithConfigLoaderLink preview iconTemporal Server options

You can run the Temporal Server as a Go application by including the server package go.temporal.io/server/temporal and using it to create and start a Temporal Server.

Learn more Server options.

See TLS configuration reference for more details.

Authentication

There are a few authentication protocols available to prevent unwanted access such as authentication of servers, clients, and users.

Servers

To prevent spoofing and MITM attacks you can specify the serverName in the client section of your respective mTLS configuration. This enables established connections to authenticate the endpoint, ensuring that the server certificate presented to any connecting Client has the appropriate server name in its CN property. It can be used for both internode and frontend endpoints.

More guidance on mTLS setup can be found in the samples-server repo and you can reach out to us for further guidance.

Client connections

To restrict a client's network access to cluster endpoints you can limit it to clients with certificates issued by a specific Certificate Authority (CA). Use the clientCAFiles/ clientCAData and requireClientAuth properties in both the internode and frontend sections of the mTLS configuration.

Users

To restrict access to specific users, authentication and authorization is performed through extensibility points and plugins as described in the Authorization section below.

Authorization

:::note Information regarding AuthorizerLink preview iconWhat is an Authorizer Plugin?

undefined

Learn more and ClaimMapperLink preview iconWhat is a ClaimMapper Plugin?

The Claim Mapper component is a pluggable component that extracts Claims from JSON Web Tokens (JWTs).

Learn more has been moved to another location. :::

Temporal offers two plugin interfaces for implementing API call authorization:

The authorization and claim mapping logic is customizable, making it available to a variety of use cases and identity schemes. When these are provided the frontend invokes the implementation of these interfaces before executing the requested operation.

See https://github.com/temporalio/samples-server/blob/main/extensibility/authorizer for a sample implementation.

Single sign-on integration

Temporal can be integrated with a single sign-on (SSO) experience by utilizing the ClaimMapper and Authorizer plugins. The default JWT ClaimMapper implementation can be used as is or as a base for a custom implementation of a similar plugin.

Temporal Web

To enable SSO for the Temporal Web UI edit the web service's configuration per the Temporal Web README.

Temporal Cluster plugins {#plugins}

Temporal Clusters support some pluggable components.

What is a ClaimMapper Plugin? {#claim-mapper}

The Claim Mapper component is a pluggable component that extracts Claims from JSON Web Tokens (JWTs).

This process is achieved with the method GetClaims, which translates AuthInfo structs from the caller into Claims about the caller's roles within Temporal.

A Role (within Temporal) is a bit mask that combines one or more of the role constants. In the following example, the role is assigned constants that allow the caller to read and write information.

role := authorization.RoleReader | authorization.RoleWriter

GetClaims is customizable and can be modified with the temporal.WithClaimMapper server option. Temporal also offers a default JWT ClaimMapper for your use.

A typical approach is for ClaimMapper to interpret custom Claims from a caller's JWT, such as membership in groups, and map them to Temporal roles for the user. The subject information from the caller's mTLS certificate can also be a parameter in determining roles.

AuthInfo

AuthInfo is a struct that is passed to GetClaims. AuthInfo contains an authorization token extracted from the authorization header of the gRPC request.

AuthInfo includes a pointer to the pkix.Name struct. This struct contains an x.509 Distinguished Name from the caller's mTLS certificate.

Claims

Claims is a struct that contains information about permission claims granted to the caller.

Authorizer assumes that the caller has been properly authenticated, and trusts the Claims when making an authorization decision.

Default JWT ClaimMapper

Temporal offers a default JWT ClaimMapper that extracts the information needed to form Temporal Claims. This plugin requires a public key to validate digital signatures.

To get an instance of the default JWT ClaimMapper, call NewDefaultJWTClaimMapper and provide it with the following:

  • a TokenKeyProvider instance
  • a config.Authorization pointer
  • a logger

The code for the default ClaimMapper can also be used to build a custom ClaimMapper.

Token key provider

A TokenKeyProvider obtains public keys from specified issuers' URIs that adhere to a specific format. The default JWT ClaimMapper uses this component to obtain and refresh public keys over time.

Temporal provides an rsaTokenKeyProvider. This component dynamically obtains public keys that follow the JWKS format. rsaTokenKeyProvider uses only the RSAKey and Close methods.

provider := authorization.NewRSAKeyProvider(cfg)

:::note

KeySourceURIs are the HTTP endpoints that return public keys of token issuers in the JWKS format. RefreshInterval defines how frequently keys should be refreshed. For example, Auth0 exposes endpoints such as https://YOUR_DOMAIN/.well-known/jwks.json.

:::

By default, "permissions" is used to name the permissionsClaimName value.

Configure the plugin with config.Config.Global.Authorization.JWTKeyProvider.

JSON Web Token format

The default JWT ClaimMapper expects authorization tokens to be formatted as follows:

Bearer <token>

The Permissions Claim in the JWT Token is expected to be a collection of Individual Permission Claims. Each Individual Permission Claim must be formatted as follows:

<namespace> : <permission>

These permissions are then converted into Temporal roles for the caller. This can be one of Temporal's four values:

  • read
  • write
  • worker
  • admin

Multiple permissions for the same Namespace are overridden by the ClaimMapper.

Example of a payload for the default JWT ClaimMapper
{
   "permissions":[
      "system:read",
      "namespace1:write"
   ],
   "aud":[
      "audience"
   ],
   "exp":1630295722,
   "iss":"Issuer"
}

What is an Authorizer Plugin? {#authorizer-plugin}

The Authorizer plugin contains a single Authorize method, which is invoked for each incoming API call. Authorize receives information about the API call, along with the role and permission claims of the caller.

Authorizer allows for a wide range of authorization logic, including call target, role/permissions claims, and other data available to the system.

Configuration

The following arguments must be passed to Authorizer:

  • context.Context: General context of the call.
  • authorization.Claims: Claims about the roles assigned to the caller. Its intended use is described in the Claims section earlier on this page.
  • authorization.CallTarget: Target of the API call.

Authorizer then returns one of two decisions:

  • DecisionDeny: the requested API call is not invoked and an error is returned to the caller.
  • DecisionAllow: the requested API call is invoked.

:::warning

Authorizer allows all API calls pass by default. Disable the nopAuthority authorizer and configure your own to prevent this behavior.

:::

Configure your Authorizer when you start the server via the temporal.WithAuthorizerLink preview iconTemporal Server options

You can run the Temporal Server as a Go application by including the server package go.temporal.io/server/temporal and using it to create and start a Temporal Server.

Learn more server option.

If an Authorizer is not set in the server options, Temporal uses the nopAuthority authorizer that unconditionally allows all API calls to pass through.

a := authorization.NewDefaultAuthorizer()

How to authorize SDK API calls {#authorize-api-calls}

When authentication is enabled, you can authorize API calls made to the Frontend Service.

<Tabs defaultValue="go" queryString="lang" values={[{label: 'Go', value: 'go'},{label: 'Java', value: 'java'},{label: 'PHP', value: 'php'},{label: 'Python', value: 'python'},{label: 'TypeScript', value: 'typescript'},]}>

Content is planned but not yet available.

The Temporal Server expects an authorization gRPC header with an authorization token to be passed with API calls if requests authorization is configured.

Authorization Tokens may be provided to the Temporal Java SDK by implementing a io.temporal.authorization.AuthorizationTokenSupplier interface. The implementation should be used to create io.temporal.authorization.AuthorizationGrpcMetadataProvider that may be configured on ServiceStub gRPC interceptors list.

The implementation is called for each SDK gRPC request and may supply dynamic tokens.

JWT

One of the token types that may be passed this way are JWT tokens. Temporal Server provides a default implementation of JWT authentication.

Example

AuthorizationTokenSupplier tokenSupplier =
  //your implementation of token supplier
  () -> "Bearer <Base64 url-encoded value of the token for default JWT ClaimMapper>";
WorkflowServiceStubsOptions serviceStubOptions =
  WorkflowServiceStubsOptions.newBuilder()
    //other service stub options
    .addGrpcMetadataProvider(new AuthorizationGrpcMetadataProvider(tokenSupplier))
    .build();
WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(serviceStubOptions);
WorkflowClient client = WorkflowClient.newInstance(service);

Related read:

Content is planned but not yet available.

Content is planned but not yet available.

Content is planned but not yet available.

Data Converter {#data-converter}

Each Temporal SDK provides a Data ConverterLink preview iconWhat is a Data Converter?

A Data Converter is a Temporal SDK component that serializes and encodes data entering and exiting a Temporal Cluster.

Learn more that can be customized with a custom Payload CodecLink preview iconWhat is a Payload Codec?

A Payload Codec transforms an array of Payloads into another array of Payloads.

Learn more to encode and secure your data.

For details on what data can be encoded, how to secure it, and what to consider when using encryption, see Data encryption.

Codec Server

You can use a Codec ServerLink preview iconWhat is a Codec Server?

A Codec Server is an HTTP server that uses your custom Payload Codec to encode and decode your data remotely through endpoints.

Learn more with your custom Payload Codec to decode the data you see on your Web UI and CLI locally through remote endpoints. However, ensure that you consider all security implications of remote data encodingLink preview iconWhat is remote data encoding?

Remote data encding is using your custom Data Converter to decode (and encode) your Payloads remotely through endpoints.

Learn more before using a Codec Server.

For details on how to set up a Codec Server, see Codec Server setup.

There aren’t any published security advisories