Skip to main content

One Connection String, Any Platform: Connecting to Zaris

· 6 min read
Clustron Team
Distributed Systems Engineering

One connection string across .NET config, PowerShell, and the web console

Half of the "works in dev, breaks in prod" connection bugs come down to the same thing: the connection details were spelled three different ways in three different places. The appsettings.json had one host list, the ops runbook pasted another into a PowerShell session, and the string someone copied off a wiki had a stale token baked right into it.

Zaris takes that whole class of problem off the table with a single, platform-agnostic connection-string format. The exact same string works when your .NET app reads it from configuration, when an operator hands it to a PowerShell cmdlet, and when someone copies it straight out of the web console. One canonical spelling, everywhere.

This post breaks the string down part by part, shows all three ways to use it, and makes the case for the one rule that matters most in production: never put a raw token in the string.

The shape of the string​

A Zaris connection string is a URI. Here's a fully-loaded one:

zariss://zaris-a.example.com:7861,zaris-b.example.com:7861/?store=orders&token=env:ZARIS_TOKEN

Every part of that is doing a job:

  • Scheme → transport security. zaris:// is plaintext; zariss:// is TLS (the extra s, same convention as http/https). Choosing the scheme is how you turn transport encryption on — there's no separate flag to forget.
  • Comma-separated hosts → failover / seed list. You can list more than one host:port, and the client treats them as a seed list for failover. It connects through whichever seed answers and discovers the rest of the cluster from there, so a single node being down at startup doesn't lock you out.
  • A required store name. Every connection targets exactly one store, and the store name is required — there's no implicit default. That's deliberate: it means a string always says which store it's for, and you can't accidentally point a job at the wrong one because the target was left blank.
  • A safely-supplied token. Authentication tokens are secrets, so the format keeps them out of the literal string. Instead of pasting the token, you point at where to read it from — token=env:ZARIS_TOKEN reads it from an environment variable, and token=file:/path/to/token reads it from a file on disk. The secret never sits in the string itself, so it never lands in source control, a shell history, or a screenshot.

That last point is the one worth internalizing: the string carries a reference to the credential, not the credential.

Using it from .NET​

.NET apps read the string from standard ConnectionStrings configuration — the same appsettings.json / IConfiguration mechanism you already use for databases. Put it where every other connection string lives:

{
"ConnectionStrings": {
"Orders": "zariss://zaris-a.example.com:7861,zaris-b.example.com:7861/?store=orders&token=env:ZARIS_TOKEN"
}
}

Then read it through configuration like anything else:

var connectionString = builder.Configuration.GetConnectionString("Orders");
var store = await ZarisStore.ConnectAsync(connectionString);

Because the token is env:ZARIS_TOKEN, the committed appsettings.json is safe to check in — it names the environment variable rather than holding the secret. Each environment supplies its own ZARIS_TOKEN, and the string stays identical from a developer's laptop to the production pods.

Using it from PowerShell​

The admin cmdlets take the identical string. Connect-ZrStore accepts it directly with -ConnectionString:

$conn = "zariss://zaris-a.example.com:7861,zaris-b.example.com:7861/?store=orders&token=env:ZARIS_TOKEN"
Connect-ZrStore -ConnectionString $conn

Note that this is the same string that's sitting in appsettings.json. An operator debugging a production issue and a service running in production are pointed at the cluster in exactly the same way — no translation step where a subtle difference in host list or store name can creep in. The env: indirection works here too: set ZARIS_TOKEN in the shell's environment and the cmdlet resolves it at connect time.

Copy it straight from the console​

The third source is the web console. For any store, the console shows a copyable connection string — a correct one, already spelled the canonical way, with the right hosts and store name filled in. An operator who needs to connect doesn't hand-assemble a URI from memory; they copy the string the console generated and paste it into their app config or a Connect-ZrStore call.

That closes the loop. The console produces the canonical string, .NET config consumes it, and PowerShell consumes it — three surfaces, one format, no re-spelling.

The one rule for production​

Always use env: or file: token indirection in real deployments. Never paste a raw token into the string.

It's tempting in a quick test to inline the credential just to see it work. The problem is what happens next: that string gets copied into a config file, committed, shared in a chat, or dropped into a ticket — and now a live credential is sitting somewhere it shouldn't be, with no easy way to know everywhere it leaked. The env: and file: forms exist precisely so the working string and the secret travel separately:

# Good — the secret lives in the environment, the string references it
zariss://zaris-a.example.com:7861/?store=orders&token=env:ZARIS_TOKEN

# Good — the secret lives in a mounted file, the string references it
zariss://zaris-a.example.com:7861/?store=orders&token=file:/var/run/secrets/zaris-token

In Kubernetes, file: pairs naturally with a mounted secret; in a VM or container, env: pairs with whatever injects environment variables. Either way, rotating the token means changing the secret, not editing every connection string.

The payoff​

One canonical string means one place to get it right and one thing to reason about. The host list, the TLS choice, the store, and the credential source are all encoded the same way whether the reader is .NET configuration, a PowerShell cmdlet, or a human copying from the console. That's how you retire the "works in dev, breaks in prod" connection bug: there's simply no second spelling of the connection for prod to disagree with.