Secret Manager supports using entity tags (ETags) for optimistic concurrency control.
In some cases, two processes updating the same resource in parallel may interfere with one another, where the latter process overwrites the effort of the former one.
ETags provide a means for optimistic concurrency control by allowing processes to see if a resource has been modified before taking action on that resource.
Use ETags with Secret Manager
The following resource modification requests support ETags:
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 isn't 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 doesn't affect the secret ETag, and similarly, updating the ETag doesn't affect the secret version.
Even when an update doesn't change a resource's state, it still updates the resource ETag.
Consider the following example:
-
User 1 tries to enable a secret version unaware that it's already enabled. The system processes this, changing nothing but the version's ETag.
-
User 2, using the old ETag, tries to disable the version.
-
This fails because the system recognizes the newer ETag, which indicates a more recent intent to keep the version enabled.
Even seemingly minor updates matter due to ETag changes. This ensures data consistency, especially with multiple users or systems interacting with the same resource.
The resource etag
is returned in the response whenever a resource
(Secret or
SecretVersion)
is included.
Delete a secret with ETags
This section describes using ETags when deleting a secret. If the secret has been modified by another process, the delete operation fails.
Before using any of the command data below, make the following replacements:
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret.
- LOCATION: the Google Cloud location of the secret.
- ETAG: the entity tag of the secret. The ETag must include the surrounding quotes.
For example, if the ETag value was
"abc"
, the shell-escaped value would be"\"abc\""
.
Execute the following command:
Linux, macOS, or Cloud Shell
gcloud secrets deleteSECRET_ID --location=LOCATION \ --etag "ETAG "
Windows (PowerShell)
gcloud secrets deleteSECRET_ID --location=LOCATION ` --etag "ETAG "
Windows (cmd.exe)
gcloud secrets deleteSECRET_ID --location=LOCATION ^ --etag "ETAG "
Before using any of the request data, make the following replacements:
- LOCATION: the Google Cloud location of the secret.
- PROJECT_ID: the Google Cloud project ID.
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret.
- ETAG: the entity tag of the secret. The ETag is specified as part of the URL's querystring
and must be URL-encoded. For example, if the ETag value is
"abc"
, the URL-encoded value would be%22abc%22
because the quote character is encoded as%22
.
HTTP method and URL:
DELETE https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?etag=ETAG
Request JSON body:
{}
To send your request, choose one of these options:
Save the request body in a file named request.json
,
and execute the following command:
curl -X DELETE \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?etag=ETAG "
Save the request body in a file named request.json
,
and execute the following command:
$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred" }
Invoke-WebRequest `
-Method DELETE `
-Headers $headers `
-ContentType: "application/json; charset=utf-8" `
-InFile request.json `
-Uri "https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?etag=ETAG " | Select-Object -Expand Content
You should receive a JSON response similar to the following:
{}
To run this code, first set up a Go development environment and install the Secret Manager Go SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Java development environment and install the Secret Manager Java SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Python development environment and install the Secret Manager Python SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
Update a secret with ETags
This section describes using ETags when updating a secret. If the secret has been modified by another process, the update operation will fail.
Before using any of the command data below, make the following replacements:
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret.
- LOCATION: the Google Cloud location of the secret.
- KEY: the label name.
- VALUE: the corresponding label value.
- ETAG: the entity tag of the secret. The ETag must include the surrounding quotes.
For example, if the ETag value was
"abc"
, the shell-escaped value would be"\"abc\""
.
Execute the following command:
Linux, macOS, or Cloud Shell
gcloud secrets updateSECRET_ID --location=LOCATION \ --update-labels "KEY =VALUE " \ --etag "ETAG "
Windows (PowerShell)
gcloud secrets updateSECRET_ID --location=LOCATION ` --update-labels "KEY =VALUE " ` --etag "ETAG "
Windows (cmd.exe)
gcloud secrets updateSECRET_ID --location=LOCATION ^ --update-labels "KEY =VALUE " ^ --etag "ETAG "
The response returns the secret.
Before using any of the request data, make the following replacements:
- LOCATION: the Google Cloud location of the secret.
- PROJECT_ID: the Google Cloud project ID.
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret.
- ETAG: the entity tag of the secret. The ETag is specified as a field on the
Secret
and must include the surrounding quotes. For example, if the ETag value was
"abc"
, the JSON-escaped value would be{"etag":"\"abc\""}
. - KEY: the label name.
- VALUE: the corresponding label value.
HTTP method and URL:
PATCH https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?updateMask=labels
Request JSON body:
{"etag":"ETAG ", "labels":{"KEY ": "VALUE "}}
To send your request, choose one of these options:
Save the request body in a file named request.json
,
and execute the following command:
curl -X PATCH \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?updateMask=labels"
Save the request body in a file named request.json
,
and execute the following command:
$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred" }
Invoke-WebRequest `
-Method PATCH `
-Headers $headers `
-ContentType: "application/json; charset=utf-8" `
-InFile request.json `
-Uri "https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ?updateMask=labels" | Select-Object -Expand Content
You should receive a JSON response similar to the following:
{ "name": "projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID ", "createTime": "2024-09-04T04:06:00.660420Z", "labels": { "KEY ": "VALUE " }, "etag": "\"162145a4f894d5\"" }
To run this code, first set up a Go development environment and install the Secret Manager Go SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Java development environment and install the Secret Manager Java SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Python development environment and install the Secret Manager Python SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
Update a secret version with ETags
This section describes using ETags when updating a secret version. If the secret version has been modified by another process, the update operation will fail.
The code sample here describes disabling a secret version with ETags. You can also specify ETags during other secret mutation operations, such as when enabling disabled versions or destroying secret versions. Refer to the code samples for Secret Manager.
Before using any of the command data below, make the following replacements:
- VERSION_ID: the ID of the secret version.
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret.
- LOCATION: the Google Cloud location of the secret.
- ETAG: the entity tag. The ETag must include the surrounding quotes.
For example, if the ETag value was
"abc"
, the shell-escaped value would be"\"abc\""
.
Execute the following command:
Linux, macOS, or Cloud Shell
gcloud secrets versions disableVERSION_ID \ --secretSECRET_ID \ --location=LOCATION \ --etag "ETAG "
Windows (PowerShell)
gcloud secrets versions disableVERSION_ID ` --secretSECRET_ID ` --location=LOCATION ` --etag "ETAG "
Windows (cmd.exe)
gcloud secrets versions disableVERSION_ID ^ --secretSECRET_ID ^ --location=LOCATION ^ --etag "ETAG "
The response returns the secret.
Before using any of the request data, make the following replacements:
- LOCATION: the Google Cloud location of the secret
- PROJECT_ID: the Google Cloud project ID
- SECRET_ID: the ID of the secret or fully qualified identifier for the secret
- VERSION_ID: the ID of the secret version
- ETAG: the entity tag of the secret version. The ETag is specified as a field on the
SecretVersion
and must include the surrounding quotes. For example, if the ETag value was
"abc"
, the JSON-escaped value would be{"etag":"\"abc\""}
.
HTTP method and URL:
POST https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID /versions/VERSION_ID :disable
Request JSON body:
{"etag":"ETAG "}
To send your request, choose one of these options:
Save the request body in a file named request.json
,
and execute the following command:
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d @request.json \
"https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID /versions/VERSION_ID :disable"
Save the request body in a file named request.json
,
and execute the following command:
$cred = gcloud auth print-access-token
$headers = @{ "Authorization" = "Bearer $cred" }
Invoke-WebRequest `
-Method POST `
-Headers $headers `
-ContentType: "application/json; charset=utf-8" `
-InFile request.json `
-Uri "https://secretmanager.LOCATION .rep.googleapis.com/v1/projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID /versions/VERSION_ID :disable" | Select-Object -Expand Content
You should receive a JSON response similar to the following:
{ "name": "projects/PROJECT_ID /locations/LOCATION /secrets/SECRET_ID /versions/VERSION_ID ", "createTime": "2024-09-04T06:41:57.859674Z", "state": "DISABLED", "etag": "\"1621457b3c1459\"" }
To run this code, first set up a Go development environment and install the Secret Manager Go SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Java development environment and install the Secret Manager Java SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.
To run this code, first set up a Python development environment and install the Secret Manager Python SDK. On Compute Engine or GKE, you must authenticate with the cloud-platform scope.