Etags

Overview

Secret Manager supports using etags for optimistic concurrency control. A user may optionally include etags in the following resource modification requests.

In a secrets.patch request, the request etag is embedded in the Secret data. All other requests accept an optional etag parameter. If an etag is provided and matches the current resource etag, the request succeeds; otherwise, it fails with a FAILED_PRECONDITION error and an HTTP status code 400. If an etag is not provided, the request proceeds without checking the currently stored etag value.

Resource etags are generated at resource creation (projects.secrets.create, projects.secrets.addVersion), and updated for each of the above-listed modification requests. A modification request only updates the etag of the resource to which it applies. That is, updating a secret version does not affect the secret etag, and vice versa.

A no-operation resource update also updates the resource etag. For example, take the following scenario: A caller issues a request to enable a secret version which is already enabled, without them being aware. The request is processed successfully, does not change the version state but changes the version etag. Another caller, using the older etag, attempts to disable the same version. Their request fails, since we captured the intent to enable the version prior to the disable request in the modified etag.

As per aip/154, the etag string includes quotes, i.e. a valid etag string is "123", not 123.

The resource etag is returned in the response whenever a resource (Secret or SecretVersion) is included.

Example Usage

Assume the current etag for secret ${SM_SECRET_ID} is "123". The following is a valid request to delete the secret while providing an etag:

API

curl -s -X DELETE "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/${SM_SECRET_ID}?alt=json&etag=%22123%22" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"

In order to update the secret, its etag needs to be passed within the provided Secret object, as follows:

API

curl -s -X PATCH "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/${SM_SECRET_ID}?alt=json&updateMask=labels" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d "{\"etag\": \"\\\"123\\\"\", \"labels\": {\"foo\": \"bar\"}}"

For secret version updates, the etag is passed in the body of a POST request:

API

curl -s -X POST "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/${SM_SECRET_ID}/versions/${VERSION_NUM}:disable?alt=json" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d "{\"etag\": \"\\\"123\\\"\"}"

Gcloud

Etag in a gcloud request is passed via an --etag flag, supported in the following commands (now in beta):