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
2 changes: 1 addition & 1 deletion cmd/api/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ go_library(
deps = [
"//pkg/cli",
"//pkg/clock",
"//pkg/config",
"//pkg/tls",
"//pkg/uid",
"//svc/api",
],
)
187 changes: 14 additions & 173 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package api

import (
"context"
"time"

"github.com/unkeyed/unkey/pkg/cli"
"github.com/unkeyed/unkey/pkg/clock"
"github.com/unkeyed/unkey/pkg/config"
"github.com/unkeyed/unkey/pkg/tls"
"github.com/unkeyed/unkey/pkg/uid"
"github.com/unkeyed/unkey/svc/api"
)

Expand All @@ -22,187 +21,29 @@ var Cmd = &cli.Command{
Usage: "Run the Unkey API server for validating and managing API keys",

Flags: []cli.Flag{
// Server Configuration
cli.Int("http-port", "HTTP port for the API server to listen on. Default: 7070",
cli.Default(7070), cli.EnvVar("UNKEY_HTTP_PORT")),
cli.Bool("color", "Enable colored log output. Default: true",
cli.Default(true), cli.EnvVar("UNKEY_LOGS_COLOR")),
cli.Bool("test-mode", "Enable test mode. WARNING: Potentially unsafe, may trust client inputs blindly. Default: false",
cli.Default(false), cli.EnvVar("UNKEY_TEST_MODE")),

// Instance Identification
cli.String("platform", "Cloud platform identifier for this node. Used for logging and metrics.",
cli.EnvVar("UNKEY_PLATFORM")),
cli.String("image", "Container image identifier. Used for logging and metrics.",
cli.EnvVar("UNKEY_IMAGE")),
cli.String("region", "Geographic region identifier. Used for logging and routing. Default: unknown",
cli.Default("unknown"), cli.EnvVar("UNKEY_REGION"), cli.EnvVar("AWS_REGION")),
cli.String("instance-id", "Unique identifier for this instance. Auto-generated if not provided.",
cli.Default(uid.New(uid.InstancePrefix, 4)), cli.EnvVar("UNKEY_INSTANCE_ID")),

// Database Configuration
cli.String("database-primary", "MySQL connection string for primary database. Required for all deployments. Example: user:pass@host:3306/unkey?parseTime=true",
cli.Required(), cli.EnvVar("UNKEY_DATABASE_PRIMARY")),
cli.String("database-replica", "MySQL connection string for read-replica. Reduces load on primary database. Format same as database-primary.",
cli.EnvVar("UNKEY_DATABASE_REPLICA")),

// Caching and Storage
cli.String("redis-url", "Redis connection string for rate-limiting and distributed counters. Example: redis://localhost:6379",
cli.EnvVar("UNKEY_REDIS_URL")),
cli.String("clickhouse-url", "ClickHouse connection string for analytics. Recommended for production. Example: clickhouse://user:pass@host:9000/unkey",
cli.EnvVar("UNKEY_CLICKHOUSE_URL")),
cli.String("clickhouse-analytics-url", "ClickHouse base URL for workspace-specific analytics connections. Workspace credentials are injected programmatically. Example: http://clickhouse:8123/default",
cli.EnvVar("UNKEY_CLICKHOUSE_ANALYTICS_URL")),

// Observability
cli.Bool("otel", "Enable OpenTelemetry tracing and metrics",
cli.EnvVar("UNKEY_OTEL")),
cli.Float("otel-trace-sampling-rate", "Sampling rate for OpenTelemetry traces (0.0-1.0). Only used when --otel is provided. Default: 0.25",
cli.Default(0.25), cli.EnvVar("UNKEY_OTEL_TRACE_SAMPLING_RATE")),
cli.Int("prometheus-port", "Enable Prometheus /metrics endpoint on specified port. Set to 0 to disable.", cli.EnvVar("UNKEY_PROMETHEUS_PORT")),

// TLS Configuration
cli.String("tls-cert-file", "Path to TLS certificate file for HTTPS. Both cert and key must be provided to enable HTTPS.",
cli.EnvVar("UNKEY_TLS_CERT_FILE")),
cli.String("tls-key-file", "Path to TLS key file for HTTPS. Both cert and key must be provided to enable HTTPS.",
cli.EnvVar("UNKEY_TLS_KEY_FILE")),

// Vault Configuration
cli.String("vault-url", "URL of the remote vault service for encryption/decryption",
cli.EnvVar("UNKEY_VAULT_URL")),
cli.String("vault-token", "Bearer token for vault service authentication",
cli.EnvVar("UNKEY_VAULT_TOKEN")),

// Kafka Configuration
cli.StringSlice("kafka-brokers", "Comma-separated list of Kafka broker addresses for distributed cache invalidation",
cli.EnvVar("UNKEY_KAFKA_BROKERS")),

// ClickHouse Proxy Service Configuration
cli.String(
"chproxy-auth-token",
"Authentication token for ClickHouse proxy endpoints. Required when proxy is enabled.",
cli.EnvVar("UNKEY_CHPROXY_AUTH_TOKEN"),
),

// Profiling Configuration
cli.Bool(
"pprof-enabled",
"Enable pprof profiling endpoints at /debug/pprof/*. Default: false",
cli.Default(false),
cli.EnvVar("UNKEY_PPROF_ENABLED"),
),
cli.String(
"pprof-username",
"Username for pprof Basic Auth. Optional - if username and password are not set, pprof will be accessible without authentication.",
cli.EnvVar("UNKEY_PPROF_USERNAME"),
),
cli.String(
"pprof-password",
"Password for pprof Basic Auth. Optional - if username and password are not set, pprof will be accessible without authentication.",
cli.EnvVar("UNKEY_PPROF_PASSWORD"),
),

// Request Body Configuration
cli.Int64("max-request-body-size", "Maximum allowed request body size in bytes. Set to 0 or negative to disable limit. Default: 10485760 (10MB)",
cli.Default(int64(10485760)), cli.EnvVar("UNKEY_MAX_REQUEST_BODY_SIZE")),

// Logging Sampler Configuration
cli.Float("log-sample-rate", "Baseline probability (0.0-1.0) of emitting log events. Default: 1.0",
cli.Default(1.0), cli.EnvVar("UNKEY_LOG_SAMPLE_RATE")),
cli.Duration("log-slow-threshold", "Duration threshold for slow event sampling. Default: 1s",
cli.Default(time.Second), cli.EnvVar("UNKEY_LOG_SLOW_THRESHOLD")),

// CTRL Service Configuration
cli.String("ctrl-url", "CTRL service connection URL for deployment management. Example: http://ctrl:7091",
cli.EnvVar("UNKEY_CTRL_URL")),
cli.String("ctrl-token", "Bearer token for CTRL service authentication",
cli.EnvVar("UNKEY_CTRL_TOKEN")),
cli.String("config", "Path to a TOML config file",
cli.Default("unkey.toml"), cli.EnvVar("UNKEY_CONFIG")),
},

Action: action,
}

func action(ctx context.Context, cmd *cli.Command) error {
// Check if TLS flags are properly set (both or none)
tlsCertFile := cmd.String("tls-cert-file")
tlsKeyFile := cmd.String("tls-key-file")
if (tlsCertFile == "" && tlsKeyFile != "") || (tlsCertFile != "" && tlsKeyFile == "") {
return cli.Exit("Both --tls-cert-file and --tls-key-file must be provided to enable HTTPS", 1)
cfg, err := config.Load[api.Config](cmd.String("config"))
if err != nil {
return cli.Exit("Failed to load config: "+err.Error(), 1)
}

// Initialize TLS config if TLS flags are provided
var tlsConfig *tls.Config
if tlsCertFile != "" && tlsKeyFile != "" {
var err error
tlsConfig, err = tls.NewFromFiles(tlsCertFile, tlsKeyFile)
if err != nil {
return cli.Exit("Failed to load TLS configuration: "+err.Error(), 1)
// Resolve TLS config from file paths
if cfg.TLS.CertFile != "" {
tlsCfg, tlsErr := tls.NewFromFiles(cfg.TLS.CertFile, cfg.TLS.KeyFile)
if tlsErr != nil {
return cli.Exit("Failed to load TLS configuration: "+tlsErr.Error(), 1)
}
cfg.TLSConfig = tlsCfg
}

config := api.Config{
// Basic configuration
CacheInvalidationTopic: "",
Platform: cmd.String("platform"),
Image: cmd.String("image"),
Region: cmd.String("region"),

// Database configuration
DatabasePrimary: cmd.String("database-primary"),
DatabaseReadonlyReplica: cmd.String("database-replica"),

// ClickHouse
ClickhouseURL: cmd.String("clickhouse-url"),
ClickhouseAnalyticsURL: cmd.String("clickhouse-analytics-url"),

// OpenTelemetry configuration
OtelEnabled: cmd.Bool("otel"),
OtelTraceSamplingRate: cmd.Float("otel-trace-sampling-rate"),

// TLS Configuration
TLSConfig: tlsConfig,

InstanceID: cmd.String("instance-id"),
RedisUrl: cmd.String("redis-url"),
PrometheusPort: cmd.Int("prometheus-port"),
Clock: clock.New(),
TestMode: cmd.Bool("test-mode"),

// HTTP configuration
HttpPort: cmd.Int("http-port"),
Listener: nil, // Production uses HttpPort

// Vault configuration
VaultURL: cmd.String("vault-url"),
VaultToken: cmd.String("vault-token"),

// Kafka configuration
KafkaBrokers: cmd.StringSlice("kafka-brokers"),

// ClickHouse proxy configuration
ChproxyToken: cmd.String("chproxy-auth-token"),

// CTRL service configuration
CtrlURL: cmd.String("ctrl-url"),
CtrlToken: cmd.String("ctrl-token"),

// Profiling configuration
PprofEnabled: cmd.Bool("pprof-enabled"),
PprofUsername: cmd.String("pprof-username"),
PprofPassword: cmd.String("pprof-password"),

// Request body configuration
MaxRequestBodySize: cmd.Int64("max-request-body-size"),

// Logging sampler configuration
LogSampleRate: cmd.Float("log-sample-rate"),
LogSlowThreshold: cmd.Duration("log-slow-threshold"),
}

err := config.Validate()
if err != nil {
return err
}
cfg.Clock = clock.New()

return api.Run(ctx, config)
return api.Run(ctx, cfg)
}
2 changes: 1 addition & 1 deletion cmd/ctrl/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ go_library(
deps = [
"//pkg/cli",
"//pkg/clock",
"//pkg/config",
"//pkg/tls",
"//pkg/uid",
"//svc/ctrl/api",
"//svc/ctrl/worker",
],
Expand Down
Loading