Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions core/src/main/java/io/temporal/samples/ssl/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,60 @@
# Workflow execution with mTLS


This example shows how to secure your Temporal application with [mTLS](https://docs.temporal.io/security/#encryption-in-transit-with-mtls).
This is required to connect with Temporal Cloud or any production Temporal deployment.


## Export env variables

Before running the example you need to export the following env variables:

- TEMPORAL_ENDPOINT: grpc endpoint, for Temporal Cloud would like `${namespace}.tmprl.cloud:7233`.
- TEMPORAL_NAMESPACE: Namespace.
- TEMPORAL_CLIENT_CERT: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates).
- TEMPORAL_CLIENT_KEY: For Temporal Cloud see requirements [here](https://docs.temporal.io/cloud/how-to-manage-certificates-in-temporal-cloud#end-entity-certificates).



## Running this sample

```bash
./gradlew -q execute -PmainClass=io.temporal.samples.ssl.Starter
```

## Run SslEnabledWorkerCustomCA Sample

This sample shows how to start a worker that connects to a temporal cluster with mTLS enabled; created by ([tls-simple sample](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple));

SslEnabledWorkerCustomCA demonstrates:

- Passing a custom CA certificate file as parameter
- Overriding the authority name used for TLS handshakes (if needed)

1.Start a temporal cluster with tls

Please follow the temporal server-sample to start simple Temporal mTLS cluster locally: [tls-simple](https://github.com/temporalio/samples-server/tree/main/tls/tls-simple)

2.Set environment variables

```bash
# Environment variables
# paths to ca cert, client cert and client key come from the previous step
export TEMPORAL_CLIENT_CERT="</path/to/client.pem>"
export TEMPORAL_CLIENT_KEY="</path/to/client.key>"
export TEMPORAL_CA_CERT="</path/to/ca.cert>"
export TEMPORAL_ENDPOINT="localhost:7233" # Temporal grpc endpoint
export TEMPORAL_NAMESPACE="default" # Temporal namespace
export TEMPORAL_SERVER_HOSTNAME="tls-sample" # Temporal server host name
```

3.Start the Worker

```bash
./gradlew -q execute -PmainClass="io.temporal.samples.ssl.SslEnabledWorkerCustomCA"
```

4.Expected result

```text
[main] INFO i.t.s.WorkflowServiceStubsImpl - Created WorkflowServiceStubs for channel: ManagedChannelOrphanWrapper{delegate=ManagedChannelImpl{logId=1, target=localhost:7233}}
[main] INFO io.temporal.internal.worker.Poller - start: Poller{name=Workflow Poller taskQueue="MyTaskQueue", namespace="default"}
Workflow completed:done
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2020 Temporal Technologies, Inc. All Rights Reserved
*
* Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Modifications copyright (C) 2017 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not
* use this file except in compliance with the License. A copy of the License is
* located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

package io.temporal.samples.ssl;

import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder;
import io.temporal.client.WorkflowClient;
import io.temporal.client.WorkflowClientOptions;
import io.temporal.client.WorkflowOptions;
import io.temporal.serviceclient.WorkflowServiceStubs;
import io.temporal.serviceclient.WorkflowServiceStubsOptions;
import io.temporal.worker.Worker;
import io.temporal.worker.WorkerFactory;
import java.io.FileInputStream;
import java.io.InputStream;

public class SslEnabledWorkerCustomCA {

static final String TASK_QUEUE = "MyTaskQueue";

public static void main(String[] args) throws Exception {

// Load your client certificate, which should look like:
// -----BEGIN CERTIFICATE-----
// ...
// -----END CERTIFICATE-----
InputStream clientCert = new FileInputStream(System.getenv("TEMPORAL_CLIENT_CERT"));

// PKCS8 client key, which should look like:
// -----BEGIN PRIVATE KEY-----
// ...
// -----END PRIVATE KEY-----
InputStream clientKey = new FileInputStream(System.getenv("TEMPORAL_CLIENT_KEY"));

// Load your Certification Authority certificate, which should look like:
// -----BEGIN CERTIFICATE-----
// ...
// -----END CERTIFICATE-----
InputStream caCert = new FileInputStream(System.getenv("TEMPORAL_CA_CERT"));

// For temporal cloud this would likely be ${namespace}.tmprl.cloud:7233
String targetEndpoint = System.getenv("TEMPORAL_ENDPOINT");

// Your registered namespace.
String namespace = System.getenv("TEMPORAL_NAMESPACE");

// Create an SSL Context using the client certificate and key based on the implementation
// SimpleSslContextBuilder
// https://github.com/temporalio/sdk-java/blob/master/temporal-serviceclient/src/main/java/io/temporal/serviceclient/SimpleSslContextBuilder.java
SslContext sslContext =
GrpcSslContexts.configure(
SslContextBuilder.forClient()
.keyManager(clientCert, clientKey)
.trustManager(caCert))
.build();

// Create SSL enabled client by passing SslContext, created by
// SimpleSslContextBuilder.
WorkflowServiceStubs service =
WorkflowServiceStubs.newServiceStubs(
WorkflowServiceStubsOptions.newBuilder()
.setSslContext(sslContext)
.setTarget(targetEndpoint)
// Override the authority name used for TLS handshakes
.setChannelInitializer(
c -> c.overrideAuthority(System.getenv("TEMPORAL_SERVER_HOSTNAME")))
.build());

// Now setup and start workflow worker, which uses SSL enabled gRPC service to
// communicate with backend. client that can be used to start and signal workflows.
WorkflowClient client =
WorkflowClient.newInstance(
service, WorkflowClientOptions.newBuilder().setNamespace(namespace).build());

// worker factory that can be used to create workers for specific task queues
WorkerFactory factory = WorkerFactory.newInstance(client);

/*
* Define the workflow worker. Workflow workers listen to a defined task queue and process
* workflows and activities.
*/
Worker worker = factory.newWorker(TASK_QUEUE);

/*
* Register our workflow implementation with the worker.
* Workflow implementations must be known to the worker at runtime in
* order to dispatch workflow tasks.
*/
worker.registerWorkflowImplementationTypes(MyWorkflowImpl.class);

/*
* Start all the workers registered for a specific task queue.
* The started workers then start polling for workflows and activities.
*/
factory.start();

// Create the workflow client stub. It is used to start our workflow execution.
MyWorkflow workflow =
client.newWorkflowStub(
MyWorkflow.class,
WorkflowOptions.newBuilder()
.setWorkflowId("WORKFLOW_ID")
.setTaskQueue(TASK_QUEUE)
.build());

/*
* Execute our workflow and wait for it to complete. The call to our execute method is
* synchronous.
*/
String greeting = workflow.execute();

// Display workflow execution results
System.out.println("Workflow completed:" + greeting);
System.exit(0);
}
}