Secret Injection Patterns

Secret Injection Patterns

Note — As of 2026-04-30, the per-service @cuilabs/qnsp-vault-sdk package is consolidated into the unified @cuilabs/qnsp SDK (one package per language). New integrations should use:

import { QnspClient } from "@cuilabs/qnsp";
const qnsp = new QnspClient({ apiKey: process.env.QNSP_API_KEY! });
await qnsp.vault./* method */(...);

See SDK overview for the consolidated package. The per-service shapes documented below remain accurate at the wire level (REST/gRPC) and are kept for reference.

Secret Injection Patterns

How to inject QNSP-managed secrets into applications. Equivalent shapes are available in all five SDK languages — TypeScript, Python, Go, Rust, JVM/Android — so the pattern below ports across stacks.

Environment variables

The platform does not currently ship a Kubernetes-native valueFrom provider.

SDK-based injection

Fetch secrets at application startup using the Vault SDK and populate process.env (or the language equivalent) before any code that needs them runs.

File-based injection

For Kubernetes-native file injection, prefer integrating via External Secrets Operator (webhook provider) and syncing into a Kubernetes Secret.

SDK injection examples

TypeScript / Node.js

import { VaultClient } from "@cuilabs/qnsp-vault-sdk";

const vault = new VaultClient({
  baseUrl: "https://api.qnsp.cuilabs.io/proxy/vault",
  apiKey: process.env.QNSP_API_KEY!,
});

const secret = await vault.getSecret({ tenantId: process.env.QNSP_TENANT_ID!, id: "openai-api-key" });
process.env.OPENAI_API_KEY = Buffer.from(secret.payload, "base64").toString("utf8");

Python

import base64
import os
from qnsp import QnspClient

with QnspClient(api_key=os.environ["QNSP_API_KEY"]) as q:
    secret = q.vault.get_secret("openai-api-key")
    os.environ["OPENAI_API_KEY"] = base64.b64decode(secret["payloadB64"]).decode()

Go

import (
    "context"
    "encoding/base64"
    "os"

    "github.com/cuilabs/qnsp-public/sdks/go/qnsp"
)

c, _ := qnsp.NewClient(qnsp.ClientOptions{APIKey: os.Getenv("QNSP_API_KEY")})
defer c.Close()

s, _ := c.Vault().GetSecret(context.Background(), "openai-api-key")
payload, _ := base64.StdEncoding.DecodeString(s["payloadB64"].(string))
os.Setenv("OPENAI_API_KEY", string(payload))

Rust

use base64::{engine::general_purpose::STANDARD, Engine};
use qnsp::{Client, ClientOptions};

let c = Client::new(ClientOptions::with_api_key(std::env::var("QNSP_API_KEY")?))?;
let s = c.vault().get_secret("openai-api-key").await?;
let payload = STANDARD.decode(s["payloadB64"].as_str().unwrap())?;
std::env::set_var("OPENAI_API_KEY", String::from_utf8(payload)?);

JVM / Android

import io.cuilabs.qnsp.QnspClient
import kotlinx.serialization.json.jsonPrimitive
import okio.ByteString.Companion.decodeBase64

val qnsp = QnspClient(System.getenv("QNSP_API_KEY"))
val s = qnsp.vault.getSecret("openai-api-key")
val payload = s["payloadB64"]!!.jsonPrimitive.content.decodeBase64()!!.utf8()
// inject into your process config / DI container — never log the value

Best practices

  • Never log secret values — log secret IDs only
  • Use short TTLs and rotate on deployment
  • Treat returned plaintext as ephemeral; never persist to disk outside the OS-level keychain or systemd-credentials store
  • Audit every read via audit-service (the SDKs emit a vault.secret.read event automatically when their tenant has audit enabled)
  • For the TypeScript family, the per-service @cuilabs/qnsp-vault-sdk is the right choice; the single-package qnsp (Python), qnsp/vault (Go), and qnsp::vault (Rust) cover the same surface