Skip to content

Connection config reference

The connection config is the CLI-side, kubeconfig-style file that describes how to reach a remote cornus server: a set of named contexts, each holding an endpoint, credentials, TLS material, and an optional in-cluster port-forward target. It lives on a developer's machine and is never read by the server (that is a separate, server-side data-directory config).

You normally manage this file with cornus config rather than editing it by hand, but the format is documented here. The canonical source of truth is pkg/clientconfig/clientconfig.go.

File location

The default path is the platform user config directory, under cornus/config.yaml:

  • Linux/BSD: ~/.config/cornus/config.yaml
  • macOS: ~/Library/Application Support/cornus/config.yaml
  • Windows: %AppData%\cornus\config.yaml

An explicitly set $XDG_CONFIG_HOME is honored on every OS (an opt-in for users who standardize on XDG): the file is then $XDG_CONFIG_HOME/cornus/config.yaml. The global --config-file flag and the CORNUS_CONFIG environment variable override the path entirely.

The file holds bearer tokens and key paths, so it is written mode 0600 under a 0700 directory. A missing file is not an error — the CLI treats it the same as an empty config.

Sample config

yaml
current-context: staging
contexts:
  local:
    server: http://127.0.0.1:5000

  remote-docker:
    # No static server URL: carry HTTP to the remote loopback listener over SSH.
    ssh-tunnel:
      addr: devbox
      user: ops
      remote-addr: 127.0.0.1:5000

  staging:
    server: https://cornus.staging.example.com
    # Every image in this environment is Debian-based; try bash first.
    shells:
      - /bin/bash
      - /bin/sh
    key-auth:
      identity-file: /home/alice/.ssh/id_ed25519
      key-fingerprint: SHA256:example
      name: alice-laptop
    tls:
      ca-cert: /etc/cornus/staging-ca.pem
    conduit:
      mode: socks5
      socks5:
        listen: 127.0.0.1:1080
        service-host-suffix: .cornus.internal
      ingress:
        mode: emulate
        certificates:
          - certificate: /etc/cornus/web.pem
            key: /etc/cornus/web-key.pem

  prod-cluster:
    # No static server URL: dial the in-cluster Service via port-forward.
    port-forward:
      kube-context: prod
      namespace: cornus
      service: cornus
      remote-port: 5000
    kube-auth:
      audience: cornus
      expiration-seconds: 3600
    registry-host: registry.prod.example.com:5000

File

The top-level document.

FieldTypeDefaultDescription
current-contextstringThe context used when no --context flag is given. Empty means "no context selected"; the CLI then relies on per-command flags and environment variables.
contextsmap[string]ContextThe named connection profiles, keyed by name.

Context

One named remote endpoint with the credentials and transport settings to reach it.

FieldTypeDefaultDescription
serverstringThe cornus server base URL (e.g. https://cornus.example.com or http://127.0.0.1:5000). When port-forward is set and server is empty, the CLI forwards to the in-cluster Service and dials the local end instead.
registry-hoststringderived from the serverOverrides the host[:port] that built images are tagged with and that deploy pull refs carry. Empty (the usual case) derives it: the CLI asks the server (GET /.cornus/v1/info), falling back to the server endpoint's host. Set this only for topologies the server cannot introspect.
tokenstringCORNUS_TOKEN envThe bearer token / JWT sent as Authorization: Bearer. Empty falls back to the CORNUS_TOKEN environment variable.
tlsTLSsystem defaultsOptional custom-CA / mTLS / insecure settings for HTTPS endpoints.
port-forwardPortForwardWhen set, an in-cluster Service the CLI port-forwards to before dialing.
kube-authKubeAuthWhen set, derives the bearer token from the cluster (a short-lived ServiceAccount token via the Kubernetes TokenRequest API) instead of a static token. Takes precedence over token but yields to an explicit CORNUS_TOKEN override.
key-authKeyAuthWhen set, proves possession of an enrolled SSH key and mints a short-lived session. It takes precedence over kube-auth and token, but yields to CORNUS_TOKEN. key-auth and kube-auth are mutually exclusive.
via-serverbool (nullable)unset (direct)Forces workload streaming operations (compose logs, port-forward) to route through the cornus server proxy instead of the CLI reaching workload pods directly with the developer's kubeconfig. Only matters for a cluster profile. Lowest-precedence layer, below the CORNUS_VIA_SERVER env var and the --via-server flag. Transport-only: it does not disable kube-auth token minting.
conduitConduitport-forwardHow a client session exposes a deployment's ports to the caller. Lowest-precedence layer, below the CORNUS_CONDUIT env var and the --conduit flag. See Networking and conduits.
ssh-tunnelSSHTunnelWhen server is empty, reaches a cornus server through SSH. This is the host-backend analogue of port-forward; the two automatic transports are mutually exclusive. An explicit server makes this block inert.
tunnelTunnelDefaults for public tunnels (cornus tunnel, cornus ingress-tunnel), so they need not be repeated on every invocation.
shellslist of stringsCandidate interactive shells for workloads reached through this profile, most preferred first. Read by the cornus web terminal, which probes a workload's own x-cornus-shells: first, then these, then the browser's own list. Each entry is a command string, not a pre-split argument list (/bin/busybox sh is one entry). Security-sensitive: it names a binary that gets executed inside your workload, so a project override supplies it only when trusted.

KeyAuth

Selects the SSH signer used for short-lived Cornus client sessions. The profile contains only a path and public fingerprint, never private-key material or a minted session token.

FieldTypeDefaultDescription
identity-filestringLocal SSH private-key path. Encrypted keys use the normal interactive/SSH_ASKPASS prompt.
key-fingerprintstringSHA256 public-key fingerprint. With no identity file it selects a key from SSH_AUTH_SOCK; with a file it pins the expected public key and lets the background agent address the session cache without unlocking the key.
namestringfingerprintHuman-readable enrollment name and resulting caller identity.
scopestringapiRequested session scope.
ttlstring1hRequested Go-duration lifetime, at most 24h.

Conduit

A context's session conduit preference: the mode plus, for SOCKS5, its proxy settings.

FieldTypeDefaultDescription
modestringport-forwardport-forward (per-port automatic forwarding, Compose-like) or socks5 (a single client-side SOCKS5 split-tunnel proxy).
socks5Socks5Tunes the SOCKS5 proxy; consulted only when mode is socks5.
ingressIngressConfigures native or emulated ingress handling and optional user-provided server certificates.

Socks5

Configures the SOCKS5 split-tunnel proxy.

FieldTypeDefaultDescription
listenstring127.0.0.1:1080Local address the proxy binds.
service-host-suffixstring.cornus.internalBuilds the everyday default resolution rule: a CONNECT host bearing this suffix is stripped to a service name and tunneled in, everything else egresses directly. Ignored when resolve is set.
resolve[]ResolveRuleAn advanced, ordered list of resolution rules that replaces the suffix default entirely; the first matching rule wins.
bare-service-namesbool (nullable)enabledWhether a bare, single-label host that names a live service (e.g. web, in addition to web.cornus.internal) is routed inward. Set false to disable it when a service name would shadow a real single-label host reached directly.

SSHTunnel

Describes the SSH connection used to reach a cornus server on a remote container host. The transport is backend-agnostic — it carries raw bytes to a cornus server, so the same block reaches a dockerhost, containerd, bare, or incus server unchanged. Once it is configured, ordinary commands use it transparently; no per-command tunnel flag is required. addr may be an ssh_config host alias, so the normal user, port, identity, proxy, and host-key settings continue to apply unless no-ssh-config disables them.

FieldTypeDefaultDescription
addrstringSSH destination: an ssh_config Host alias or a literal host[:port].
userstringssh_config, then current userSSH login user.
remote-addrstring127.0.0.1:5000Cornus listen address as seen from the remote host.
identity-filestringSSH agent / ssh_configExplicit PEM private-key path for public-key authentication.
no-agentboolfalseDisables authentication through the local SSH_AUTH_SOCK.
known-hostsstringssh_config, then ~/.ssh/known_hostsExplicit known_hosts file used for host-key verification.
host-keystringPins one expected host key as an authorized_keys-format line.
insecure-host-keyboolfalseDisables host-key verification. Development use only.
remote-tlsboolfalseUses HTTPS through the SSH tunnel because the remote cornus process terminates TLS. Usually paired with tls.server-name.
no-ssh-configboolfalseSkips both user and system SSH config files; only the explicit fields in this block are used.
use-ssh-binaryboolautoForces the persistent ssh -N -L fallback transport. Cornus selects it automatically when the resolved host has a ProxyCommand; it honors the full OpenSSH configuration, including Match.

Ingress

Configures ingress reached through a SOCKS5 conduit. Its certificate rules are also used before a native Kubernetes deploy, including a detached deploy, to create and wire managed TLS Secrets; that materialization does not require a conduit to remain running.

FieldTypeDefaultDescription
modestringoffnative uses the cluster ingress controller; emulate terminates ingress locally; empty/off disables ingress handling.
controllerIngressControllerdiscoveredNative ingress controller Service override.
ca-filestringgeneratedEmulate-mode CA certificate used to sign fallback leaf certificates. Must be paired with ca-key-file.
ca-key-filestringgeneratedPrivate key paired with ca-file.
certificates[]IngressCertificateOrdered user-provided server-certificate rules shared by emulated and native ingress.

Tunnel

Per-profile defaults for public tunnels. It stores no credential — only the path to one — so a profile that is shared or checked in can never leak an authtoken.

KeyTypeDefaultMeaning
authtoken-filestringPath to a file holding the tunnel-backend credential, used as the default --authtoken-file. Empty means passing one per invocation, or relying on the server's own default (CORNUS_TUNNEL_AUTHTOKEN in the server's environment).
ingress-host-modestringautoDefault --host-mode for cornus ingress-tunnel: auto, passthrough, alias, or rewrite. See host handling.

An explicit flag always wins over these defaults. cornus setup offers to fill them in after probing what the server can actually host.

IngressCertificate

FieldTypeDefaultDescription
patternstringcertificate DNS SANsExact DNS name or one-label wildcard such as *.example.com. An explicit pattern must be covered by the certificate SANs. Exact rules win over wildcards; among wildcards, the longest suffix wins.
certificatestringPath to a PEM certificate chain. Required with key.
keystringPath to the matching PEM private key. Required with certificate.

For emulated ingress, SNI selects a rule and an unmatched name uses the configured or generated fallback CA. For native Kubernetes ingress, every explicit concrete ingress host must match a rule. Cornus groups hosts that select the same certificate, creates stable kubernetes.io/tls Secrets owned by the workload Deployment, updates them on certificate rotation, wires them into the Ingress, and removes obsolete managed Secrets. Auto-derived hosts and the @ token must be expanded to concrete hostnames when managed certificates are used.

Because native materialization sends private-key bytes with the deploy request, Cornus permits it only over HTTPS, an SSH tunnel/custom dialer, or plaintext HTTP on loopback (including a local Kubernetes port-forward). It rejects remote plaintext HTTP before serializing the request.

IngressController

FieldTypeDefaultDescription
kube-contextstringprofile cluster contextKubeconfig context used for the native controller port-forward.
namespacestringNamespace containing the ingress controller Service.
servicestringdiscoveredIngress controller Service name.
http-portintdiscoveredController HTTP Service port.
https-portintdiscoveredController HTTPS Service port.

ResolveRule

One SOCKS5 resolution rule.

FieldTypeDefaultDescription
patternstringA regexp tested against the host:port CONNECT subject.
replacestringA template yielding service:port (sed-style \1 backreferences accepted).

TLS

Client-side TLS material for an HTTPS endpoint. Config() returns the system defaults when none of these are set. client-cert and client-key must be set together.

FieldTypeDefaultDescription
ca-certstringsystem trust storePath to a PEM CA bundle that verifies the server certificate, for a server whose CA is not in the system trust store.
server-namestringURL hostnameOverrides the SNI and certificate hostname, for example when remote-tls reaches a certificate-bearing server through 127.0.0.1.
insecure-skip-verifyboolfalseDisables server certificate verification. Testing only.
client-certstringPath to a PEM client certificate for mTLS.
client-keystringPath to the matching PEM client key for mTLS.

See Security and authentication for the server side of mTLS and bearer authentication.

PortForward

An in-cluster Service to forward to before dialing (consumed by the CLI's service-forwarder).

FieldTypeDefaultDescription
kube-contextstringcurrent kube contextThe kubeconfig context to use.
namespacestringNamespace of the Service.
servicestringService name to forward to.
remote-portintThe Service port; the CLI resolves it to a ready backing pod and its target port.

KubeAuth

A cluster-issued ServiceAccount token to mint as the cornus bearer credential.

FieldTypeDefaultDescription
kube-contextstringthe port-forward block's valueThe kubeconfig context to mint against.
namespacestringthe port-forward block's valueNamespace of the ServiceAccount.
service-accountstringServiceAccount to mint the token for.
audiencestringToken audience. Must match the server's CORNUS_JWT_AUDIENCE.
expiration-secondsint64cluster defaultRequested token lifetime.

TokenExchange

Trade whatever credential the fields above produced for a short-lived Cornus credential via OAuth 2.0 Token Exchange, cached between commands.

FieldTypeDefaultDescription
enabledboolfalsePerform the exchange.
scopestringNarrow the issued credential (e.g. registry:pull). Empty takes whatever the server's scope map grants.
sh
cornus config set-context cluster \
  --pf-namespace cornus --pf-service cornus --pf-remote-port 5000 \
  --kube-auth-service-account cornus-client --kube-auth-audience cornus \
  --token-exchange --token-exchange-scope registry:pull
  • It is independent of which field produced the subject token, so a cluster ServiceAccount token, an OIDC token, and a static token all exchange the same way.
  • scope may only narrow. A scope the server's policy does not grant is refused rather than quietly reduced, so a profile that pins one fails loudly if policy changes underneath it instead of silently gaining access.
  • A key-auth profile is left alone: that credential is already Cornus-minted and names its scope, so there is nothing to exchange.
  • A server with no exchange endpoint — an older Cornus, or one with no JWT/JWKS verifier — is not an error. The credential is sent directly, exactly as before.

The issued credential is cached so the exchange happens once per token lifetime rather than once per command; see CORNUS_TOKEN_CACHE.

Project context override

A project can carry a bare Context document named cornus-context.json, cornus-context.yaml, cornus-context.yml, or cornus-context.toml. Cornus searches upward from the working directory, uses the nearest file, and stops at the repository root or your home directory. Its fields overlay the selected stored context; explicit command flags and environment variables still win. It can also provide a connection when no stored context is selected.

yaml
server: https://cornus.staging.example.com
via-server: true
conduit:
  mode: socks5

Use --context-file PATH or CORNUS_CONTEXT_FILE=PATH for an explicit file. A missing explicit file is an error. --no-context-file disables discovery and cannot be combined with --context-file.

Trust boundary

An auto-discovered file is working-tree input, not a trusted credential store. By default it contributes only via-server; endpoint, token, TLS, registry, port-forward, kube-auth, SSH-tunnel, conduit, and shell settings are ignored. On Unix, Cornus also ignores a file owned by another user or one in a world-writable non-sticky directory.

shells is in that stripped set even though it carries no credential: it names a binary the web terminal executes inside your workload, so a file anyone who can open a pull request may write must not choose it.

Use --trust-context-file / CORNUS_TRUST_CONTEXT_FILE=1 only for a trusted working tree. An explicitly named --context-file is also trusted. An override that changes the endpoint must supply its own token or kube-auth; otherwise the selected context credential is dropped. Cornus warns whenever it skips or strips a project override.

See also

Released under the Apache-2.0 License.