AnnouncementsIntroducing Arkoren

    Menu

    Secret Rotation

    Coordinate credential replacement, consumer refresh, verification overlap, and retained encryption material.

    What's on this page
    1. Coordinate issuer credentials, stored versions, consumer rollout, and eventual revocation.
    2. Refresh validated process-local snapshots without claiming atomic adoption across consumers.
    3. Plan verification overlap and retain encryption material until data and backups no longer need it.
    On this page

    A new secret-store version changes what the next current-value read selects. It does not change an external credential, update an existing connection pool, or make every application instance read again. Rotation coordinates creating replacement material, moving consumers to it, and retiring the old material when it is no longer needed.

    Plan the overlap before writing: if old and new credentials can both work during the rollout, consumers can switch independently. Not every issuer supports overlap. If it cannot, use that system’s supported cutover or maintenance procedure rather than assuming Arkoren makes the change atomic or downtime-free.

    Credential Rollout

    For a reporting API token or database credential, the issuer determines which values are accepted. Use a separately authorized provisioning identity and keep the existing logical secret’s history intact:

    1. Create a replacement at the issuer while the old credential remains valid, if supported—for example, a second API token or database user.
    2. Validate the replacement against its intended permissions without logging it.
    3. Write it as a new secret version, using the payload shape your consumers expect.
    4. Restart or refresh every consumer, including workers and scheduled jobs, and verify that the replacement actually works there.
    5. Revoke the old credential only after consumers no longer depend on it and the issuer’s overlap requirements are satisfied.

    Track rollout state without recording values or private secret names. Provider usage records or connection inventory can help establish that old credentials are no longer used; a successful write or mutation notification cannot. Include infrequent jobs and dormant instances in the verification, not just the web fleet.

    If a write fails, reconcile its possibly uncertain outcome before retrying. If consumers fail after publication, keep the old credential valid while you investigate when the issuer permits it. Reading an old stored version can recover its bytes only while retained and authorized; it cannot reactivate a credential already revoked at the issuer.

    After a compromise, the old credential may need immediate revocation even if that interrupts service. Choose that incident policy explicitly; overlap extends the time an attacker can use a leaked value. Do not delete the logical secret as a substitute for revocation.

    Runtime Refresh

    Startup-loaded credentials change when the consumer restarts. Prefer that path when a client captures credentials during construction: a database pool, for example, may need rebuilding and draining, not merely a new string in memory. Read and validate credentials before building the replacement client, then retire the old client according to its lifecycle.

    For a credential read on each outgoing call, application-owned refresh can publish a complete immutable snapshot. This is not a built-in secret-store feature. The fragments below use the ReportingCredentials type and reportingSecret definition from Typed Credentials, a configured secrets facade, and standard-library errors and sync/atomic.

    Initialize the snapshot during startup, before any reader or refresh work runs:

    initial, err := secrets.Get(ctx, reportingSecret)
    if err != nil || initial.Account == "" || initial.Token == "" {
    	return errors.New("initial reporting credential is unavailable")
    }
    
    var active atomic.Pointer[ReportingCredentials]
    active.Store(&initial)

    The guarded success path publishes one validated credential. Keep active at its application’s owning scope and do not copy the atomic object after use. Never modify a published credential through its pointer.

    In each supervised refresh attempt, use a bounded operation context and replace the snapshot only after both reading and application validation succeed:

    next, err := secrets.Get(ctx, reportingSecret)
    if err != nil || next.Account == "" || next.Token == "" {
    	return errors.New("reporting credential refresh failed")
    }
    active.Store(&next)

    A failed attempt leaves the old snapshot unchanged. Schedule attempts through your managed background work, stop them on shutdown, and monitor failure counts and snapshot age. Choose the interval and retry budget well inside the issuer’s overlap window. Retaining the last good snapshot preserves access only while that credential remains valid; define when stale credentials must stop being used instead of retrying forever.

    After successful startup initialization, a caller loads one snapshot for the whole operation:

    snapshot := active.Load()
    token := snapshot.Token

    Use fields from that same snapshot if a request also needs Account; separate loads could span a refresh. The pointer exchange is atomic in this process only. It does not coordinate replicas, change in-flight requests, or prove the issuer accepts the new value. Never call Load before initialization, and never print token or the snapshot.

    Verification Secrets

    When another system signs requests that your application verifies, overlap has to exist in the verifier too. Follow the provider’s signing format, timestamp rules, replay policy, and supported rotation behavior. Do not replace a provider-specific verifier with a generic string comparison.

    If the protocol supports current and previous secrets together, you can keep them in one JSON object so a read loads the pair from one stored version:

    type VerificationSecrets struct {
    	Current  string `json:"current"`
    	Previous string `json:"previous,omitempty"`
    }
    
    var verificationSecret = secret.NewSecret[VerificationSecrets]("partner-verification")

    Here secret is imported from arkoren.dev/core/service/secret. Validate the current field before publishing a decoded snapshot. Pass only nonempty values to a verifier that explicitly supports overlap; this definition does not add multi-key support to an existing webhook adapter. If your integration fixes its secret at construction, rebuilding that verifier is part of adoption.

    Keep old verification material until the sender has switched and the protocol’s allowed delivery/retry window has ended. Then remove it in a new version and refresh consumers again. For application-owned HMAC verification, compare computed MACs with hmac.Equal; use the provider’s full verification procedure for incoming webhooks, including replay defenses.

    Encryption Material

    Encryption keys have a different retirement condition: data encrypted with an old key still needs that key to decrypt. Publishing a new current key does not rewrite stored ciphertext, and revoking an old key too soon can make retained data or backups unreadable.

    Provision replacement material explicitly using the key command workflow, then load the stored representation as typed key configuration. For shared application keys, key.ParseShared from arkoren.dev/foundation/key parses the encoded representation; encryption drivers consume key.Shared, not the secret-store version string or unparsed text. Check read and parse errors before constructing a driver. Never generate a replacement because startup loading failed.

    Follow Encryption Keys for previous-key configuration and Storing Encrypted Data for re-encryption. Retain old material until live records and retained backups no longer require it, according to your recovery policy. A pinned store version is useful only while that logical secret and version remain readable; it does not preserve material by itself.

    For the storage operations used during rotation, see the secret API reference.

    Open a bulk documentation archive?

    This file contains every guide in its scope, not API declarations. Loading it all into an agent can exhaust its context window and increase processing time and cost. For coding tasks, start with the index and read only the relevant pages.

    Use the full archive for offline indexing, bulk processing, or deliberate large-context use.

    Browse the index instead
    Open archive