Skip to content

Commit fe036ec

Browse files
committed
Merge branch '4.3.x'
2 parents 807d5fa + 28e441a commit fe036ec

2 files changed

Lines changed: 144 additions & 0 deletions

File tree

docs/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*** xref:server/environment-repository/aws-s3-backend.adoc[]
1515
*** xref:server/environment-repository/aws-parameter-store-backend.adoc[]
1616
*** xref:server/environment-repository/aws-secrets-manager-backend.adoc[]
17+
*** xref:server/environment-repository/gcp-secret-manager-backend.adoc[]
1718
*** xref:server/environment-repository/credhub-backend.adoc[]
1819
*** xref:server/environment-repository/mongo-backend.adoc[]
1920
*** xref:server/environment-repository/composite-repositories.adoc[]
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
[[gcp-secret-manager-backend]]
2+
= Google Secret Manager Backend
3+
4+
Spring Cloud Config Server can use link:https://cloud.google.com/secret-manager[Google Cloud Secret Manager] as an `EnvironmentRepository`.
5+
Secrets are exposed as a `PropertySource` whose entries are built from secret payloads.
6+
7+
== Enabling the backend
8+
9+
The repository is registered when all of the following hold:
10+
11+
* The Spring profile `secret-manager` is active.
12+
* `com.google.cloud.secretmanager.v1.SecretManagerServiceClient` is on the classpath (typically by adding `google-cloud-secretmanager`).
13+
14+
[source,xml,indent=0]
15+
.pom.xml
16+
----
17+
<dependency>
18+
<groupId>com.google.cloud</groupId>
19+
<artifactId>google-cloud-secretmanager</artifactId>
20+
</dependency>
21+
----
22+
23+
If you use `spring-cloud-config-server` without its optional Google libraries, add the artifacts your build needs explicitly.
24+
The permission check described below uses the Cloud Resource Manager API; include `google-api-services-cloudresourcemanager` and `google-auth-library-oauth2-http` when you rely on that behavior.
25+
26+
[source,yaml]
27+
----
28+
spring:
29+
profiles:
30+
active: secret-manager
31+
cloud:
32+
config:
33+
server:
34+
gcp-secret-manager:
35+
order: 0
36+
application-label: application
37+
profile-label: profile
38+
service-account: /path/to/service-account.json
39+
token-mandatory: true
40+
version: 1
41+
----
42+
43+
Configuration properties are bound under `spring.cloud.config.server.gcp-secret-manager`:
44+
45+
|===
46+
| Property | Default | Description
47+
48+
| `order`
49+
| Same as other environment repositories
50+
| Order in a composite repository (`org.springframework.core.Ordered`).
51+
52+
| `application-label`
53+
| `application`
54+
| Secret Manager label key used to match the Config Server `\{application}` name (see <<gcp-secret-manager-mapping>>).
55+
56+
| `profile-label`
57+
| `profile`
58+
| Secret Manager label key used to match each active profile (see <<gcp-secret-manager-mapping>>).
59+
60+
| `service-account`
61+
| _empty_
62+
| Path to a Google Cloud service account JSON key file. If set, the Secret Manager client uses these credentials. If unset, the client uses https://cloud.google.com/docs/authentication/application-default-credentials[Application Default Credentials] (for example the metadata server on Google Compute Engine).
63+
64+
| `token-mandatory`
65+
| `true`
66+
| When `true`, secrets are only loaded if <<gcp-secret-manager-permission-check>> succeeds. When `false`, that check is skipped and secrets are loaded using only the server-side Secret Manager credentials.
67+
68+
| `version`
69+
| `1`
70+
| API access strategy version (only `1` is supported).
71+
72+
|===
73+
74+
[[gcp-secret-manager-mapping]]
75+
== Mapping applications and profiles
76+
77+
The server lists secrets in the Google Cloud project (see <<gcp-secret-manager-project>>) and filters them for each Config Client request.
78+
79+
* **Label-based matching (default):** A secret is included for a given `\{application}` and profile when its Secret Manager labels match, case-insensitively, on the configured keys (`application-label` and `profile-label`). If a label is missing on the secret, the code treats it as the default string `application` or `profile` respectively (same keys as the property names), so unlabeled secrets align with those defaults.
80+
81+
* **Prefix-based matching:** If the HTTP request includes a non-empty `X-Secret-Prefix` header, secrets whose *short* name (the segment after `projects/.../secrets/`) starts with that prefix are also included. The prefix is stripped from the property key. This path can be combined with label filtering logic in the same loop (see `GoogleSecretManagerEnvironmentRepository`).
82+
83+
The repository always ensures the `default` profile is considered before additional profiles (similar to other backends): if the client does not send `default` first, the server prepends it.
84+
85+
For each matching secret, the property **value** is the payload of the **latest enabled** secret version, where “latest” is determined by comparing numeric version IDs (not the Secret Manager “latest” alias).
86+
87+
Property sources are named `gsm:\{application}-\{profile}`.
88+
89+
The Config Server `\{label}` path segment is accepted on the API but **this backend does not use it** to select secrets; version selection is based on secret versions as described above.
90+
91+
[[gcp-secret-manager-project]]
92+
== Resolving the Google Cloud project
93+
94+
Secret Manager API calls are scoped to a project ID. The server obtains it in this order:
95+
96+
. The `X-Project-ID` HTTP header on the incoming Config Client request, if present.
97+
. Otherwise, a GET to `http://metadata.google.internal/computeMetadata/v1/project/project-id` with header `Metadata-Flavor: Google` (works when the Config Server runs on Google Compute Engine or similar).
98+
99+
If neither source is available (for example local development without metadata), configure clients to send `X-Project-ID` or run the server where metadata is available.
100+
101+
[[gcp-secret-manager-credentials]]
102+
== Credentials for listing and reading secrets
103+
104+
Listing secrets and accessing secret values uses `SecretManagerServiceClient` only:
105+
106+
* With `service-account` set: credentials from that JSON file.
107+
* Without it: Application Default Credentials.
108+
109+
The OAuth access token in `X-Config-Token` is **not** passed to the Secret Manager client. Those credentials are always the server’s (or the key file’s), independent of the client token.
110+
111+
[[gcp-secret-manager-permission-check]]
112+
== Optional permission check (`token-mandatory`)
113+
114+
When `token-mandatory` is `true` (default), before loading any secrets the server calls `checkRemotePermissions()`:
115+
116+
. It reads the access token from the `X-Config-Token` HTTP header (required for this check; a missing or invalid header causes the check to fail).
117+
. It uses the Cloud Resource Manager REST API `projects.testIamPermissions` for the target project with the permission `secretmanager.versions.access`.
118+
. If that permission is reported for the token, the check passes and secrets are loaded. If not, or if the API call fails, the check fails and **no** GSM-backed property sources are added for that request.
119+
120+
So the token in `X-Config-Token` acts as a **gate** for whether GSM data is returned, while **reading** secrets still uses <<gcp-secret-manager-credentials,the server’s Secret Manager credentials>>. The principal that passes IAM testing and the principal used for Secret Manager API calls can differ.
121+
122+
When `token-mandatory` is `false`, this remote check is not performed and secrets are loaded solely subject to server credentials and Secret Manager data access.
123+
124+
== HTTP headers (Config Client to Config Server)
125+
126+
|===
127+
| Header | Required when | Purpose
128+
129+
| `X-Config-Token`
130+
| `token-mandatory` is `true` for the permission check
131+
| Bearer-style access token used only for Cloud Resource Manager `testIamPermissions`.
132+
133+
| `X-Project-ID`
134+
| Recommended when not running on GCP with metadata
135+
| Google Cloud project ID for Secret Manager and IAM checks.
136+
137+
| `X-Secret-Prefix`
138+
| Optional
139+
| Restricts which secrets contribute properties when matching by name prefix (see <<gcp-secret-manager-mapping>>).
140+
141+
|===
142+
143+
Header names are case-insensitive per HTTP; the implementation uses `X-Config-Token`, `X-Project-ID`, and `X-Secret-Prefix`.

0 commit comments

Comments
 (0)