-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ea23602
commit 9efbd3d
Showing
5 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
This sample shows how to connect a client to Temporal using mtls where the certificates are dynamically loaded. This allows the credentials to be replaced without restarting the worker. | ||
|
||
### Steps to run this sample: | ||
1) Configure a [Temporal Server](https://github.com/temporalio/samples-go/tree/main/#how-to-use) (such as Temporal Cloud) with mTLS. | ||
|
||
2) Run the following command to start the worker | ||
``` | ||
go run ./dynamicmtls/worker -target-host my.namespace.tmprl.cloud:7233 -namespace my.namespace -client-cert path/to/cert.pem -client-key path/to/key.pem | ||
``` | ||
3) Run the following command to start the example | ||
``` | ||
go run ./dynamicmtls/starter -target-host my.namespace.tmprl.cloud:7233 -namespace my.namespace -client-cert path/to/cert.pem -client-key path/to/key.pem | ||
``` | ||
|
||
Note: | ||
|
||
If the server uses self-signed certificates and does not have the SAN set to the actual host, pass one of the following two options when starting the worker or the example above: | ||
1. `-server-name` and provide the common name contained in the self-signed server certificate | ||
2. `-insecure-skip-verify` which disables certificate and host name validation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package dynamicmtls | ||
|
||
import ( | ||
"crypto/tls" | ||
"crypto/x509" | ||
"flag" | ||
"fmt" | ||
"os" | ||
|
||
"go.temporal.io/sdk/client" | ||
) | ||
|
||
// ParseClientOptionFlags parses the given arguments into client options. In | ||
// some cases a failure will be returned as an error, in others the process may | ||
// exit with help info. | ||
func ParseClientOptionFlags(args []string) (client.Options, error) { | ||
// Parse args | ||
set := flag.NewFlagSet("hello-world-mtls", flag.ExitOnError) | ||
targetHost := set.String("target-host", "localhost:7233", "Host:port for the server") | ||
namespace := set.String("namespace", "default", "Namespace for the server") | ||
serverRootCACert := set.String("server-root-ca-cert", "", "Optional path to root server CA cert") | ||
clientCert := set.String("client-cert", "", "Required path to client cert, will be dynamically loaded when server requests a certificate") | ||
clientKey := set.String("client-key", "", "Required path to client key, will be dynamically loaded when server requests a certificate") | ||
serverName := set.String("server-name", "", "Server name to use for verifying the server's certificate") | ||
insecureSkipVerify := set.Bool("insecure-skip-verify", false, "Skip verification of the server's certificate and host name") | ||
if err := set.Parse(args); err != nil { | ||
return client.Options{}, fmt.Errorf("failed parsing args: %w", err) | ||
} else if *clientCert == "" || *clientKey == "" { | ||
return client.Options{}, fmt.Errorf("-client-cert and -client-key are required") | ||
} | ||
|
||
// Load server CA if given | ||
var serverCAPool *x509.CertPool | ||
if *serverRootCACert != "" { | ||
serverCAPool = x509.NewCertPool() | ||
b, err := os.ReadFile(*serverRootCACert) | ||
if err != nil { | ||
return client.Options{}, fmt.Errorf("failed reading server CA: %w", err) | ||
} else if !serverCAPool.AppendCertsFromPEM(b) { | ||
return client.Options{}, fmt.Errorf("server CA PEM file invalid") | ||
} | ||
} | ||
|
||
return client.Options{ | ||
HostPort: *targetHost, | ||
Namespace: *namespace, | ||
ConnectionOptions: client.ConnectionOptions{ | ||
TLS: &tls.Config{ | ||
GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { | ||
cert, err := tls.LoadX509KeyPair(*clientCert, *clientKey) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed loading client cert and key: %w", err) | ||
} | ||
return &cert, nil | ||
|
||
}, | ||
RootCAs: serverCAPool, | ||
ServerName: *serverName, | ||
InsecureSkipVerify: *insecureSkipVerify, | ||
}, | ||
}, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"log" | ||
"os" | ||
|
||
"github.com/temporalio/samples-go/dynamicmtls" | ||
"github.com/temporalio/samples-go/helloworld" | ||
"go.temporal.io/sdk/client" | ||
) | ||
|
||
func main() { | ||
// The client is a heavyweight object that should be created once per process. | ||
clientOptions, err := dynamicmtls.ParseClientOptionFlags(os.Args[1:]) | ||
if err != nil { | ||
log.Fatalf("Invalid arguments: %v", err) | ||
} | ||
c, err := client.Dial(clientOptions) | ||
if err != nil { | ||
log.Fatalln("Unable to create client", err) | ||
} | ||
defer c.Close() | ||
|
||
workflowOptions := client.StartWorkflowOptions{ | ||
ID: "hello_world_workflowID", | ||
TaskQueue: "hello-world-mtls", | ||
} | ||
|
||
we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, helloworld.Workflow, "Temporal") | ||
if err != nil { | ||
log.Fatalln("Unable to execute workflow", err) | ||
} | ||
|
||
log.Println("Started workflow", "WorkflowID", we.GetID(), "RunID", we.GetRunID()) | ||
|
||
// Synchronously wait for the workflow completion. | ||
var result string | ||
err = we.Get(context.Background(), &result) | ||
if err != nil { | ||
log.Fatalln("Unable get workflow result", err) | ||
} | ||
log.Println("Workflow result:", result) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package main | ||
|
||
import ( | ||
"log" | ||
"os" | ||
|
||
"github.com/temporalio/samples-go/dynamicmtls" | ||
"github.com/temporalio/samples-go/helloworld" | ||
"go.temporal.io/sdk/client" | ||
"go.temporal.io/sdk/worker" | ||
) | ||
|
||
func main() { | ||
// The client and worker are heavyweight objects that should be created once per process. | ||
clientOptions, err := dynamicmtls.ParseClientOptionFlags(os.Args[1:]) | ||
if err != nil { | ||
log.Fatalf("Invalid arguments: %v", err) | ||
} | ||
c, err := client.Dial(clientOptions) | ||
if err != nil { | ||
log.Fatalln("Unable to create client", err) | ||
} | ||
defer c.Close() | ||
|
||
w := worker.New(c, "hello-world-mtls", worker.Options{}) | ||
|
||
w.RegisterWorkflow(helloworld.Workflow) | ||
w.RegisterActivity(helloworld.Activity) | ||
|
||
err = w.Run(worker.InterruptCh()) | ||
if err != nil { | ||
log.Fatalln("Unable to start worker", err) | ||
} | ||
} |