diff --git a/core/src/main/java/io/temporal/samples/ssl/README.md b/core/src/main/java/io/temporal/samples/ssl/README.md index 187b5cc4..a48d7aed 100644 --- a/core/src/main/java/io/temporal/samples/ssl/README.md +++ b/core/src/main/java/io/temporal/samples/ssl/README.md @@ -1,11 +1,11 @@ # 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`. @@ -13,10 +13,48 @@ Before running the example you need to export the following env variables: - 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="" +export TEMPORAL_CLIENT_KEY="" +export TEMPORAL_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 +``` diff --git a/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java new file mode 100644 index 00000000..165737ff --- /dev/null +++ b/core/src/main/java/io/temporal/samples/ssl/SslEnabledWorkerCustomCA.java @@ -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); + } +}