Go Services Can Refresh Google Cloud Secrets Without Restarting

Oct 19, 2026 979 views

Immutable versions meet cached configuration

Secret Manager treats each secret as a container for immutable, numbered versions. You add a version rather than edit one, then direct consumers to it through latest or disable the previous version. The model is orderly; the operational snag is that a Go service calling AccessSecretVersion("latest") only once won't see that change on its own. Go teams may need a scheduled redeploy to pick up the new value, and a disabled version can turn the delay into an incident. Mamori’s live reload approach targets that gap, letting services refresh secrets without relying on a restart.

Why a startup read becomes a lasting decision

A service commonly reads configuration while it starts, then stores the result in memory so request handling doesn't need to contact an external service each time. That design can reduce repeated work and keep the application’s normal path simple. It also means the process has its own copy of the secret, separate from the version currently selected by Secret Manager.

The distinction is easy to miss because latest sounds like a continuously updated value. In practice, it identifies the newest version when the service makes its request. If the request happens only during startup, the application has no reason to learn that a later version was added. The alias can move while the running process's in-memory value stays put.

That behavior isn't unique to secrets. Any application that reads changing configuration once and caches it can continue acting on an older snapshot. The cache may be a deliberate performance choice, but it creates a freshness tradeoff: fewer lookups in exchange for a period when the service's view can lag behind the source of truth.

Rotation depends on the whole delivery path

Adding a secret version is only one step in rotation. The new value has to reach the application, the application has to adopt it, and the old value may need to remain usable until that transition is complete. If a service reads only at boot, redeployment becomes the mechanism that carries the change into the process. That can be workable when deployments are frequent and predictable; it becomes harder to reason about when instances restart at different times or run for long periods.

Disabling an old version makes the timing issue more visible. A process that already holds the old value may continue using it, while a fresh request for that disabled version may fail. The exact outcome depends on when and how the service accesses the secret. The practical concern is that operators can believe a rotation has taken effect everywhere when some running processes still have the previous value in memory.

This is more significant than it looks. Secret rotation isn't complete just because a console or API shows a new version. The service's retrieval pattern determines when that change affects actual work, and the gap between those two states can complicate troubleshooting.

Live reload changes the operational model

A live reload approach aims to refresh the secret while the service is running, so a redeploy isn't the only path for adopting a new version. That shifts responsibility from the deployment schedule toward runtime behavior: the service needs a way to notice or request an update, replace its in-memory value, and continue handling work safely.

There are several general patterns for doing this. A service can check periodically, react to a signal from another component, or refresh when a particular operation requires current credentials. Each approach involves choices about how quickly to detect a change, how much work to perform, and what to do if Secret Manager can't be reached at that moment. The source describes Mamori’s approach as live reload, but doesn't specify its exact mechanism, timing, or failure handling.

And this is the part most people overlook: refreshing a value is not the same as safely switching every use of it. If one request is using the old credential while another begins using the new one, the application needs a clear rule for that transition. In many systems, keeping the current value available until a replacement has been fetched and validated is a sensible general pattern, though implementation details depend on the service.

Freshness has costs and failure cases

Reading a secret more often can narrow the time during which a process holds an old value. It can also add network calls and create another dependency in the service's runtime path. Teams need to decide how a refresh interval or trigger fits their availability needs, and how the service behaves when a refresh fails. There isn't one right answer for every workload.

For example, a service might continue using its last known value after a temporary lookup failure, or it might refuse operations that require a fresh credential. Those choices have different consequences. Continuing may preserve service availability but prolong use of a value that has been rotated; stopping may enforce freshness but interrupt work. The appropriate behavior depends on what the secret controls and how rotation is coordinated.

If you're working in this space, the key question isn't simply whether a service can reload a secret. It's whether the reload behavior is observable and predictable: operators should be able to tell which version a process is using, whether a refresh succeeded, and what happens when it doesn't. A feature that updates memory without clear status can move uncertainty from deployment time into runtime.

What to watch in the implementation

The source identifies the core benefit of Mamori’s live reload approach: services can refresh secrets without depending on restarts. That addresses the specific mismatch between immutable secret versions and startup-only reads. It doesn't, by itself, establish how quickly updates arrive, how multiple service instances stay in sync, or how errors are reported. Those details matter when evaluating any runtime refresh mechanism.

Teams should also consider where the secret is used. Some values can be swapped in memory with little disruption; others may be consumed by a client connection or a component that needs to be rebuilt when credentials change. A reload mechanism may need to update that dependent component too. Otherwise, the application could hold the new string while continuing to use an existing connection established with the old one.

There’s a further operational question: does the service track a specific numbered version or follow latest? A numbered version can make behavior easier to reproduce because the target is explicit. Following latest can simplify rotation, but requires the service to resolve that alias again after changes. The article's example centers on latest; the broader lesson is that version selection and refresh timing work together.

Implications for service teams

Startup caching is a reasonable design choice when configuration changes rarely and restarts are routine. It becomes a sharper constraint when secret rotation needs to take effect during a process's lifetime. Teams using this pattern should map the path from adding a version to the point where every relevant process adopts it, including what happens if a version is disabled before that path completes.

Live reload can reduce reliance on redeployment for that transition, but it adds runtime behavior that needs to be understood and monitored. The useful test is not just whether a new secret can be fetched; it's whether the service changes over cleanly, reports failures, and behaves deliberately while the old and new values overlap. That said, the available description doesn't provide enough detail to judge Mamori’s particular implementation on those points.

For Go services, the central engineering choice is straightforward: treat a secret as a one-time startup setting, or build a path for refreshing it while the process runs. Either can be appropriate. The important thing is to make the freshness delay an explicit operational property, rather than assuming that a moving alias updates a value already cached in memory.

One quiet design decision with real consequences.

Source: Xavier Portilla Edo · dzone.com

Comments

Sign in to comment.
No comments yet. Be the first to comment.

Related Articles

GCP Secret Manager, Live-Reloaded in Go With mamori