Secret Injection Patterns
Secret Injection Patterns
Note — As of 2026-04-30, the per-service
@cuilabs/qnsp-vault-sdkpackage is consolidated into the unified@cuilabs/qnspSDK (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 avault.secret.readevent automatically when their tenant has audit enabled) - For the TypeScript family, the per-service
@cuilabs/qnsp-vault-sdkis the right choice; the single-packageqnsp(Python),qnsp/vault(Go), andqnsp::vault(Rust) cover the same surface