Skip to content

Commit f872f42

Browse files
Add API key support
1 parent 9c4f647 commit f872f42

File tree

5 files changed

+72
-18
lines changed

5 files changed

+72
-18
lines changed

cmd/cmdoptions/client.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import (
1414
"go.temporal.io/sdk/client"
1515
"go.temporal.io/sdk/converter"
1616
"go.uber.org/zap"
17+
"google.golang.org/grpc"
18+
"google.golang.org/grpc/metadata"
1719
)
1820

1921
const AUTH_HEADER_ENV_VAR = "TEMPORAL_OMES_AUTH_HEADER"
@@ -46,6 +48,8 @@ type ClientOptions struct {
4648
AuthHeader string
4749
// Disable Host Verification
4850
DisableHostVerification bool
51+
// API Key
52+
APIKey string
4953
}
5054

5155
// loadTLSConfig inits a TLS config from the provided cert and key files.
@@ -95,6 +99,23 @@ func (c *ClientOptions) Dial(metrics *Metrics, logger *zap.SugaredLogger) (clien
9599
clientOptions.ConnectionOptions.TLS = tlsCfg
96100
clientOptions.Logger = NewZapAdapter(logger.Desugar())
97101
clientOptions.MetricsHandler = metrics.NewHandler()
102+
if c.APIKey != "" {
103+
clientOptions.Credentials = client.NewAPIKeyStaticCredentials(c.APIKey)
104+
clientOptions.ConnectionOptions.DialOptions = []grpc.DialOption{
105+
grpc.WithUnaryInterceptor(
106+
func(ctx context.Context, method string, req any, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
107+
return invoker(
108+
metadata.AppendToOutgoingContext(ctx, "temporal-namespace", c.Namespace),
109+
method,
110+
req,
111+
reply,
112+
cc,
113+
opts...,
114+
)
115+
},
116+
),
117+
}
118+
}
98119

99120
var authHeader string
100121
if c.AuthHeader == "" {
@@ -135,6 +156,7 @@ func (c *ClientOptions) AddCLIFlags(fs *pflag.FlagSet) {
135156
fs.StringVar(&c.ClientKeyPath, "tls-key-path", "", "Path to client private key")
136157
fs.BoolVar(&c.DisableHostVerification, "disable-tls-host-verification", false, "Disable TLS host verification")
137158
fs.StringVar(&c.TLSServerName, "tls-server-name", "", "TLS target server name")
159+
fs.StringVar(&c.APIKey, "api-key", "", "API key for authentication")
138160
fs.StringVar(&c.AuthHeader, "auth-header", "",
139161
fmt.Sprintf("Authorization header value (can also be set via %s env var)", AUTH_HEADER_ENV_VAR))
140162
}
@@ -162,6 +184,9 @@ func (c *ClientOptions) ToFlags() (flags []string) {
162184
if c.TLSServerName != "" {
163185
flags = append(flags, "--tls-server-name", c.TLSServerName)
164186
}
187+
if c.APIKey != "" {
188+
flags = append(flags, "--api-key", c.APIKey)
189+
}
165190
if c.AuthHeader != "" {
166191
flags = append(flags, "--auth-header", c.AuthHeader)
167192
}

workers/dotnet/App.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ public static class App
7373
name: "--tls-key-path",
7474
description: "Path to a client key for TLS");
7575

76+
private static readonly Option<FileInfo?> apiKeyOption = new(
77+
name: "--api-key",
78+
description: "API key for authentication");
79+
7680
private static readonly Option<string> promAddrOption = new Option<string>(
7781
name: "--prom-listen-address",
7882
description: "Prometheus listen address");
@@ -106,6 +110,7 @@ private static Command CreateCommand()
106110
cmd.Add(useTLSOption);
107111
cmd.Add(clientCertPathOption);
108112
cmd.Add(clientKeyPathOption);
113+
cmd.add(apiKeyOption);
109114
cmd.Add(promAddrOption);
110115
cmd.Add(promHandlerPathOption);
111116
cmd.SetHandler(RunCommandAsync);
@@ -156,7 +161,12 @@ private static async Task RunCommandAsync(InvocationContext ctx)
156161
Runtime = runtime,
157162
Namespace = ctx.ParseResult.GetValueForOption(namespaceOption)!,
158163
Tls = tls,
159-
LoggerFactory = loggerFactory
164+
LoggerFactory = loggerFactory,
165+
ApiKey = ctx.ParseResult.GetValueForOption(apiKeyOption),
166+
RpcMetadata = new Dictionary<string, string>()
167+
{
168+
["temporal-namespace"] = ctx.ParseResult.GetValueForOption(namespaceOption)!,
169+
}
160170
});
161171

162172
// Collect task queues to run workers for

workers/java/io/temporal/omes/Main.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import com.uber.m3.tally.RootScopeBuilder;
99
import com.uber.m3.tally.Scope;
1010
import com.uber.m3.tally.StatsReporter;
11+
import io.grpc.Metadata;
1112
import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext;
13+
import io.grpc.stub.MetadataUtils;
1214
import io.micrometer.core.instrument.util.StringUtils;
1315
import io.micrometer.prometheus.PrometheusConfig;
1416
import io.micrometer.prometheus.PrometheusMeterRegistry;
@@ -23,16 +25,17 @@
2325
import io.temporal.worker.WorkerFactory;
2426
import io.temporal.worker.WorkerFactoryOptions;
2527
import io.temporal.worker.WorkerOptions;
28+
import net.logstash.logback.encoder.LogstashEncoder;
29+
import picocli.CommandLine;
30+
31+
import javax.net.ssl.SSLException;
2632
import java.io.FileInputStream;
2733
import java.io.FileNotFoundException;
2834
import java.io.InputStream;
2935
import java.util.ArrayList;
3036
import java.util.Collections;
3137
import java.util.List;
3238
import java.util.concurrent.CountDownLatch;
33-
import javax.net.ssl.SSLException;
34-
import net.logstash.logback.encoder.LogstashEncoder;
35-
import picocli.CommandLine;
3639

3740
@CommandLine.Command(name = "features", description = "Runs Java features")
3841
public class Main implements Runnable {
@@ -86,6 +89,9 @@ public class Main implements Runnable {
8689
@CommandLine.Option(names = "--tls-key-path", description = "Path to a client key for TLS")
8790
private String clientKeyPath;
8891

92+
@CommandLine.Option(names = "--api-key", description = "API key for authentication")
93+
private String apiKey;
94+
8995
// Metric parameters
9096
@CommandLine.Option(
9197
names = "--prom-listen-address",
@@ -122,29 +128,36 @@ public class Main implements Runnable {
122128

123129
@Override
124130
public void run() {
131+
WorkflowServiceStubsOptions.Builder workflowServiceStubOptionsBuilder = WorkflowServiceStubsOptions.newBuilder();
125132
// Configure TLS
126-
SslContext sslContext = null;
127-
if (StringUtils.isNotEmpty(clientCertPath)) {
128-
if (StringUtils.isEmpty(clientKeyPath)) {
133+
if (StringUtils.isNotEmpty(clientCertPath) || StringUtils.isNotEmpty(clientKeyPath)) {
134+
if (StringUtils.isEmpty(clientKeyPath) || StringUtils.isEmpty(clientCertPath)) {
129135
throw new RuntimeException("Client key path must be specified since cert path is");
130136
}
131137

132138
try {
133139
InputStream clientCert = new FileInputStream(clientCertPath);
134140
InputStream clientKey = new FileInputStream(clientKeyPath);
135-
sslContext = SimpleSslContextBuilder.forPKCS8(clientCert, clientKey).build();
141+
SslContext sslContext = SimpleSslContextBuilder.forPKCS8(clientCert, clientKey).build();
142+
workflowServiceStubOptionsBuilder.setSslContext(sslContext);
136143
} catch (FileNotFoundException | SSLException e) {
137144
throw new RuntimeException("Error loading certs", e);
138145
}
139-
140-
} else if (StringUtils.isNotEmpty(clientKeyPath) && StringUtils.isEmpty(clientCertPath)) {
141-
throw new RuntimeException("Client cert path must be specified since key path is");
142146
} else if (isTlsEnabled) {
143-
try {
144-
sslContext = SimpleSslContextBuilder.noKeyOrCertChain().build();
145-
} catch (SSLException e) {
146-
throw new RuntimeException(e);
147-
}
147+
workflowServiceStubOptionsBuilder.setEnableHttps(true);
148+
}
149+
// Configure API key
150+
if (StringUtils.isNotEmpty(apiKey)) {
151+
workflowServiceStubOptionsBuilder.addApiKey(() -> apiKey);
152+
Metadata.Key<String> TEMPORAL_NAMESPACE_HEADER_KEY =
153+
Metadata.Key.of("temporal-namespace", Metadata.ASCII_STRING_MARSHALLER);
154+
Metadata metadata = new Metadata();
155+
metadata.put(TEMPORAL_NAMESPACE_HEADER_KEY, namespace);
156+
workflowServiceStubOptionsBuilder.setChannelInitializer(
157+
(channel) -> {
158+
channel.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata));
159+
});
160+
148161
}
149162

150163
// Configure logging
@@ -174,9 +187,8 @@ public void run() {
174187
// Configure client
175188
WorkflowServiceStubs service =
176189
WorkflowServiceStubs.newServiceStubs(
177-
WorkflowServiceStubsOptions.newBuilder()
190+
workflowServiceStubOptionsBuilder
178191
.setTarget(serverAddress)
179-
.setSslContext(sslContext)
180192
.setMetricsScope(scope)
181193
.build());
182194

workers/python/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ async def run():
8787
"--tls-cert-path", default="", help="Path to client TLS certificate"
8888
)
8989
parser.add_argument("--tls-key-path", default="", help="Path to client private key")
90+
parser.add_argument("--api-key", help="API key for authentication")
9091
# Prometheus metric arguments
9192
parser.add_argument("--prom-listen-address", help="Prometheus listen address")
9293
parser.add_argument(
@@ -144,6 +145,7 @@ async def run():
144145
namespace=args.namespace,
145146
tls=tls_config,
146147
runtime=new_runtime,
148+
api_key=args.api_key,
147149
)
148150

149151
# Collect task queues to run workers for (if there is a suffix end, we run

workers/typescript/src/omes.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ async function run() {
3939
.option('--tls', 'Enable TLS')
4040
.option('--tls-cert-path <clientCertPath>', 'Path to a client certificate for TLS')
4141
.option('--tls-key-path <clientKeyPath>', 'Path to a client key for TLS')
42+
.option('--api-key <apiKiey>', 'API key for authentication')
4243
.option('--prom-listen-address <promListenAddress>', 'Prometheus listen address')
4344
.option('--prom-handler-path <promHandlerPath>', 'Prometheus handler path', '/metrics');
4445

@@ -122,6 +123,10 @@ async function run() {
122123
const connection = await NativeConnection.connect({
123124
address: opts.serverAddress,
124125
tls: tlsConfig,
126+
apiKey: opts.apiKey,
127+
metadata: {
128+
'temporal-namespace': opts.namespace,
129+
},
125130
});
126131

127132
// Possibly create multiple workers if we are being asked to use multiple task queues

0 commit comments

Comments
 (0)