Go SDK
Connect Go applications to SikkerKey with a machine identity, then read, export, cache, and monitor the secrets they are permitted to access.
The SikkerKey Go SDK gives Go applications secure, read-only access to secrets in your vault. Each client uses a machine identity, so the application can retrieve only the secrets and projects that machine is permitted to access.
#Requirements
Go 1.22 or later
A SikkerKey vault
A machine identity with access to the secrets your application needs
The SDK uses only the Go standard library and adds no third-party runtime dependencies to your application.
#Install the SDK
go get github.com/SikkerKeyOfficial/sikkerkey-go@latestImport the package with the name sikkerkey in your Go code:
import sikkerkey "github.com/SikkerKeyOfficial/sikkerkey-go"#Read your first secret
package main
import (
"log"
sikkerkey "github.com/SikkerKeyOfficial/sikkerkey-go"
)
func main() {
sk, err := sikkerkey.New("vault_..."")
if err != nil {
log.Fatal(err)
}
apiKey, err := sk.GetSecret("sk_...")
if err != nil {
log.Fatal(err)
}
_ = apiKey // Pass the value to the client or service that needs it.
}The SDK loads the identity registered for that vault, signs the request with the machine's Ed25519 private key, and returns the current secret value as a string.
Do not print secret values or include them in application logs.
#Choose a machine identity
Use a standard machine for persistent servers and workstations. Use an ephemeral machine for short-lived workloads that should keep their identity only in memory.
Use a standard machine
After provisioning the machine with the SikkerKey CLI, select its vault:
sk, err := sikkerkey.New("vault_...")You can also load a specific identity file:
sk, err := sikkerkey.New("/etc/sikkerkey/identity.json")For automatic selection, use NewAutoDetect() or pass an empty string to New:
sk, err := sikkerkey.NewAutoDetect()Automatic selection first checks SIKKERKEY_IDENTITY. If it is not set, the SDK selects the identity when exactly one vault is registered on the machine. If several vaults are available, select one explicitly.
By default, identities are stored beneath ~/.sikkerkey/vaults/. Set SIKKERKEY_HOME when the application uses a different protected identity directory:
export SIKKERKEY_HOME=/var/lib/sikkerkeyUse an ephemeral machine
For serverless functions, CI jobs, containers, and other short-lived workloads, create an in-memory identity with an enrollment token:
sk, err := sikkerkey.BootstrapInMemory(
os.Getenv("vault_...""),
os.Getenv("SIKKERKEY_ENROLLMENT_TOKEN"),
sikkerkey.BootstrapOptions{
Hostname: "checkout-worker",
Name: "Checkout worker",
},
)
if err != nil {
log.Fatal(err)
}
apiKey, err := sk.GetSecret("YOUR_SECRET_ID")The SDK generates an Ed25519 key pair in memory, registers the ephemeral machine, and returns a ready client. It does not write an identity or private key to disk. The private key disappears when the process exits.
The machine follows the access, hostname rules, use limit, and lifetime configured on the enrollment token. Hostname defaults to the HOSTNAME environment variable and then to serverless. A name pattern configured on the token takes precedence over Name.
Set the ephemeral machine lifetime long enough for the workload to finish, allow enough token uses for concurrent starts, and keep enrollment tokens in protected runtime configuration.
#Read secrets
Read a standard secret
apiKey, err := sk.GetSecret("sk_...")
if err != nil {
return err
}Read a structured secret
Retrieve every field as a map:
database, err := sk.GetFields("sk_...")
if err != nil {
return err
}
host := database["host"]
username := database["username"]
password := database["password"]Use GetField when the application needs one field:
password, err := sk.GetField("sk_...", "password")Structured values are returned as strings. The SDK returns an error if the secret is not a supported structured object or if the requested field is missing.
#Discover accessible secrets
List the secret metadata available to the current machine:
secrets, err := sk.ListSecrets()
if err != nil {
return err
}
for _, secret := range secrets {
log.Printf("available secret: %s (%s)", secret.Name, secret.ID)
}Limit the list to a project:
secrets, err := sk.ListSecretsByProject("proj_...")Each SecretListItem includes the secret ID and display name. It can also include the owning project and the available structured field names. Listing returns metadata, not secret values.
#Export secrets for application configuration
Export all accessible values in one request:
configuration, err := sk.Export("")Pass a project ID to limit the export:
configuration, err := sk.Export("YOUR_PROJECT_ID")The returned map[string]string uses uppercase environment-style names. Spaces and punctuation become underscores. Structured secrets are flattened into one entry per field, such as DATABASE_HOST and DATABASE_PASSWORD.
#Enable encrypted fallback
Encrypted fallback allows a persistent application to use a previously retrieved value during a temporary network or service interruption. It is disabled until you enable it.
sk.EnableCache(sikkerkey.CacheOptions{
MaxAge: time.Hour,
OnFallback: func(secretID string, cachedAt time.Time) {
log.Printf("using cached value for %s from %s", secretID, cachedAt)
},
})Successful reads are encrypted locally with AES-256-GCM using a key derived from the machine identity and vault. A zero MaxAge means cached values do not expire automatically. OnFallback is optional and runs only when the SDK serves a cached value.
Fallback is limited to connection failures and temporary gateway or service availability responses. Authentication failures, denied access, missing secrets, rate limits, and other authoritative responses are returned to the application instead of being replaced by an older value.
Cache entries are kept under the vault's identity directory. They are bound to the machine, vault, secret, and creation time, and are rejected if they have been altered or belong to another identity. The cache format is compatible with SikkerKey CLI and the other SikkerKey SDKs.
Encrypted fallback is designed for a host with a persistent, protected identity directory. An ephemeral identity cannot recover its cache key after the process exits.
#Monitor secrets for changes
sk.Watch("sk_...", func(event sikkerkey.WatchEvent) {
switch event.Status {
case sikkerkey.WatchStatusChanged:
reloadClient(event.Value, event.Fields)
case sikkerkey.WatchStatusDeleted:
log.Printf("secret %s was deleted", event.SecretID)
case sikkerkey.WatchStatusAccessDenied:
log.Printf("access to %s was removed", event.SecretID)
case sikkerkey.WatchStatusError:
log.Printf("watch failed: %s", event.Error)
}
})The SDK checks watched secrets from a background goroutine every 15 seconds by default. A changed event includes the latest value and parsed fields when the secret is structured. Deleted secrets and secrets the machine can no longer access are automatically removed from the watch list.
Callbacks run on the polling goroutine. Send slow or blocking work to another goroutine or worker queue.
Change the interval, stop one watcher, or stop all monitoring:
sk.SetPollInterval(30) // seconds; minimum 10
sk.Unwatch("sk_...")
sk.Close()Closing the watcher does not prevent later secret reads.
#Work with multiple vaults
Create one client for each vault the application uses:
production, err := sikkerkey.New("PRODUCTION_VAULT_ID")
staging, err := sikkerkey.New("STAGING_VAULT_ID")List locally registered vault IDs with:
vaultIDs := sikkerkey.ListVaults()#Inspect the active machine
The client exposes the identity it is using for diagnostics:
machineID := sk.MachineID()
machineName := sk.MachineName()
vaultID := sk.VaultID()
apiURL := sk.APIURL()#Handle errors
HTTP responses and network failures use *sikkerkey.APIError. Inspect its status code when your application needs a different response for authentication, access, missing secrets, or connectivity:
value, err := sk.GetSecret("sk_...")
if err != nil {
var apiErr *sikkerkey.APIError
if errors.As(err, &apiErr) {
switch apiErr.StatusCode {
case 0:
log.Printf("network failure: %s", apiErr.Message)
case http.StatusUnauthorized:
log.Printf("machine authentication failed")
case http.StatusForbidden:
log.Printf("machine access was denied")
case http.StatusNotFound:
log.Printf("secret was not found")
default:
log.Printf("SikkerKey returned HTTP %d", apiErr.StatusCode)
}
} else {
log.Printf("configuration or parsing error: %s", err)
}
}
_ = valueA status code of 0 represents a DNS, connection, TLS, timeout, or other transport failure. Local identity, key, configuration, and parsing problems are returned as ordinary Go errors with a sikkerkey: prefix and contextual message.
Retries and timeout
Authenticated requests retry transport failures and HTTP 429 or 503 responses up to three times, waiting 1, 2, and 4 seconds. Every retry uses a fresh timestamp and nonce. Each request has a 15-second timeout; other HTTP responses are returned immediately.
#Method reference
Task | Method |
|---|---|
Connect with a registered identity |
|
Automatically select an identity |
|
Create an ephemeral identity |
|
Read a standard secret |
|
Read every structured field |
|
Read one structured field |
|
List accessible secrets |
|
List secrets in one project |
|
Export configuration values |
|
Enable encrypted fallback |
|
Monitor a secret |
|
Stop monitoring a secret |
|
Stop all monitoring |
|
List local vault identities |
|
#Source code and license
The Go SDK is open source under the MIT License. Review the source, report an issue, or contribute through the SikkerKeyOfficial GitHub organization.