Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Create protocol for specifying secrets' project and versions #2302

Merged
merged 20 commits into from
Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/_configprops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
|spring.cloud.gcp.pubsub.subscriber.retry.retry-delay-multiplier | | RetryDelayMultiplier controls the change in retry delay. The retry delay of the previous call is multiplied by the RetryDelayMultiplier to calculate the retry delay for the next call.
|spring.cloud.gcp.pubsub.subscriber.retry.rpc-timeout-multiplier | | RpcTimeoutMultiplier controls the change in RPC timeout. The timeout of the previous call is multiplied by the RpcTimeoutMultiplier to calculate the timeout for the next call.
|spring.cloud.gcp.pubsub.subscriber.retry.total-timeout-seconds | | TotalTimeout has ultimate control over how long the logic should keep trying the remote call until it gives up completely. The higher the total timeout, the more retries can be attempted.
|spring.cloud.gcp.secretmanager.bootstrap.enabled | true | Auto-configure GCP Secret Manager support components.
|spring.cloud.gcp.secretmanager.enabled | true | Auto-configure GCP Secret Manager support components.
|spring.cloud.gcp.secretmanager.credentials.encoded-key | |
|spring.cloud.gcp.secretmanager.credentials.location | |
|spring.cloud.gcp.secretmanager.credentials.scopes | |
Expand Down
82 changes: 51 additions & 31 deletions docs/src/main/asciidoc/secretmanager.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ A detailed summary of its features can be found in the https://cloud.google.com/

Spring Cloud GCP provides:

* A Spring Boot starter which automatically loads the secrets of your GCP project into your application context as a https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#_the_bootstrap_application_context[Bootstrap Property Source].
* A property source which allows you to specify and load the secrets of your GCP project into your application context as a https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#_the_bootstrap_application_context[Bootstrap Property Source].
* A `SecretManagerTemplate` which allows you to read, write, and update secrets in Secret Manager.

=== Dependency Setup
Expand All @@ -31,34 +31,68 @@ dependencies {
}
----

==== Configuration

By default, Spring Cloud GCP Secret Manager will authenticate using Application Default Credentials.
This can be overridden using the authentication properties.

NOTE: All of the below settings must be specified in a https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#_the_bootstrap_application_context[`bootstrap.properties`] (or `bootstrap.yaml`) file which is the properties file used to configure settings for bootstrap-phase Spring configuration.

|===
| Name | Description | Required | Default value
| `spring.cloud.gcp.secretmanager.enabled` | Enables the Secret Manager bootstrap property and template configuration. | No | `true`
| `spring.cloud.gcp.secretmanager.credentials.location` | OAuth2 credentials for authenticating to the Google Cloud Secret Manager API. | No | By default, infers credentials from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
| `spring.cloud.gcp.secretmanager.credentials.encoded-key` | Base64-encoded contents of OAuth2 account private key for authenticating to the Google Cloud Secret Manager API. | No | By default, infers credentials from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
| `spring.cloud.gcp.secretmanager.project-id` | The default GCP Project used to access Secret Manager API for the template and property source. | No | By default, infers the project from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
|===

=== Secret Manager Property Source

The Spring Cloud GCP integration for Google Cloud Secret Manager enables you to use Secret Manager as a bootstrap property source.

This feature allows you to automatically load your GCP project's secrets as properties into the application context during the https://cloud.spring.io/spring-cloud-commons/reference/html/#the-bootstrap-application-context[Bootstrap Phase], which refers to the initial phase when a Spring application is being loaded.
This allows you to specify and load secrets from Google Cloud Secret Manager as properties into the application context during the https://cloud.spring.io/spring-cloud-commons/reference/html/#the-bootstrap-application-context[Bootstrap Phase], which refers to the initial phase when a Spring application is being loaded.

NOTE: This feature disabled by default; to use it, you must set `spring.cloud.gcp.secretmanager.bootstrap.enabled` to **true** in your `bootstrap.properties` file.
The Secret Manager property source uses the following syntax to specify secrets:

Spring Cloud GCP will load the **latest** version of each secret into the application context.
[source]
----
# 1. Long form - specify the project ID, secret ID, and version
sm://projects/<project-id>/secrets/<secret-id>/versions/<version-id>}

All secrets will be loaded into the application environment using their `secretId` as the property name.
For example, if your secret's id is `my-secret` then it will be accessible as a property using the name `my-secret`.
If you would like to append a prefix string to all property names imported from Secret Manager, you may use the `spring.cloud.gcp.secretmanager.secret-name-prefix` setting described below.
# 2. Long form - specify project ID, secret ID, and use latest version
sm://projects/<project-id>/secrets/<secret-id>

==== Configuration (Bootstrap)
# 3. Short form - specify project ID, secret ID, and version
sm://<project-id>/<secret-id>/<version-id>

Spring Cloud GCP Secret Manager offers several bootstrap configuration properties to customize the behavior.
# 4. Short form - default project; specify secret + version
#
# The project is inferred from the spring.cloud.gcp.secretmanager.project-id setting
# in your bootstrap.properties (see Configuration) or from application-default credentials if
# this is not set.
sm://<secret-id>/<version>

NOTE: All of the below settings must be specified in a https://cloud.spring.io/spring-cloud-commons/multi/multi__spring_cloud_context_application_context_services.html#_the_bootstrap_application_context[`bootstrap.properties`] (or `bootstrap.yaml`) file which is the properties file used to configure settings for bootstrap-phase Spring configuration.
# 5. Shortest form - specify secret ID, use default project and latest version.
sm://<secret-id>
----

|===
| Name | Description | Required | Default value
| `spring.cloud.gcp.secretmanager.bootstrap.enabled` | Enables loading secrets from Secret Manager as a bootstrap property source. Set this to **true** to enable the feature. | No | `false`
| `spring.cloud.gcp.secretmanager.secret-name-prefix` | A prefix string to prepend to the property names of secrets read from Secret Manager | No | "" (empty string)
| `spring.cloud.gcp.secretmanager.versions.<secret-id>` | Defines a version for a specific secret-id to read from Secret Manager instead of using the latest version. | No | "" (empty string)
|===
You can use this syntax in the following places:

1. In your `application.properties` or `bootstrap.properties` files:
+
[source]
----
# Example of the project-secret long-form syntax.
spring.datasource.password=${sm://projects/my-gcp-project/secrets/my-secret}
----

See the Authentication Settings section below for information on how to set properties to authenticate to Secret Manager.
2. Access the value using the `@Value` annotation.
+
[source]
----
// Example of using shortest form syntax.
@Value("${sm://my-secret}")
----

=== Secret Manager Template

Expand All @@ -74,20 +108,6 @@ private SecretManagerTemplate secretManagerTemplate;

Please consult https://github.com/spring-cloud/spring-cloud-gcp/blob/master/spring-cloud-gcp-secretmanager/src/main/java/org/springframework/cloud/gcp/secretmanager/SecretManagerOperations.java[`SecretManagerOperations`] for information on what operations are available for the Secret Manager template.

==== Configuration

The auto-configured `SecretManagerTemplate` bean can be customized using configuration properties.
By default, Spring Cloud GCP Secret Manager will authenticate using Application Default Credentials.
This can be overridden using the authentication properties.

|===
| Name | Description | Required | Default value
| `spring.cloud.gcp.secretmanager.enabled` | Enables the autowiring of the `SecretManagerTemplate` in the application context. | No | `true`
| `spring.cloud.gcp.secretmanager.credentials.location` | OAuth2 credentials for authenticating to the Google Cloud Secret Manager API. | No | By default, infers credentials from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
| `spring.cloud.gcp.secretmanager.credentials.encoded-key` | Base64-encoded contents of OAuth2 account private key for authenticating to the Google Cloud Secret Manager API. | No | By default, infers credentials from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
| `spring.cloud.gcp.secretmanager.project-id` | The GCP Project used to access Secret Manager API. | No | By default, infers the project from https://cloud.google.com/docs/authentication/production[Application Default Credentials].
|===

=== Sample

A https://github.com/spring-cloud/spring-cloud-gcp/tree/master/spring-cloud-gcp-samples/spring-cloud-gcp-secretmanager-sample[Secret Manager Sample Application] is provided which demonstrates basic property source loading and usage of the template class.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.springframework.cloud.gcp.core.DefaultGcpProjectIdProvider;
import org.springframework.cloud.gcp.core.GcpProjectIdProvider;
import org.springframework.cloud.gcp.core.UserAgentHeaderProvider;
import org.springframework.cloud.gcp.secretmanager.SecretManagerPropertySourceLocator;
import org.springframework.cloud.gcp.secretmanager.SecretManagerTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
Expand All @@ -48,11 +50,9 @@
@Configuration
@EnableConfigurationProperties(GcpSecretManagerProperties.class)
@ConditionalOnClass(SecretManagerServiceClient.class)
@ConditionalOnProperty("spring.cloud.gcp.secretmanager.bootstrap.enabled")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs need to be updated following this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, updated docs.

@ConditionalOnProperty(value = "spring.cloud.gcp.secretmanager.enabled", matchIfMissing = true)
public class GcpSecretManagerBootstrapConfiguration {

private final GcpSecretManagerProperties properties;

private final CredentialsProvider credentialsProvider;

private final GcpProjectIdProvider gcpProjectIdProvider;
Expand All @@ -61,7 +61,6 @@ public GcpSecretManagerBootstrapConfiguration(
GcpSecretManagerProperties properties,
ConfigurableEnvironment configurableEnvironment) throws IOException {

this.properties = properties;
this.credentialsProvider = new DefaultCredentialsProvider(properties);
this.gcpProjectIdProvider = properties.getProjectId() != null
? properties::getProjectId
Expand All @@ -85,6 +84,13 @@ public byte[] convert(ByteString source) {
});
}

@Bean
public PropertySourceLocator secretManagerPropertySourceLocator(SecretManagerServiceClient client) {
SecretManagerPropertySourceLocator propertySourceLocator =
new SecretManagerPropertySourceLocator(client, this.gcpProjectIdProvider);
return propertySourceLocator;
}

@Bean
@ConditionalOnMissingBean
public SecretManagerServiceClient secretManagerClient() throws IOException {
Expand All @@ -97,10 +103,8 @@ public SecretManagerServiceClient secretManagerClient() throws IOException {
}

@Bean
public PropertySourceLocator secretManagerPropertySourceLocator(SecretManagerServiceClient client) {
SecretManagerPropertySourceLocator propertySourceLocator = new SecretManagerPropertySourceLocator(
client, this.gcpProjectIdProvider, this.properties.getSecretNamePrefix());
propertySourceLocator.setVersions(this.properties.getVersions());
return propertySourceLocator;
@ConditionalOnMissingBean
public SecretManagerTemplate secretManagerTemplate(SecretManagerServiceClient client) {
return new SecretManagerTemplate(client, this.gcpProjectIdProvider);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@

package org.springframework.cloud.gcp.autoconfigure.secretmanager;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.cloud.gcp.core.Credentials;
Expand All @@ -39,17 +36,6 @@ public class GcpSecretManagerProperties implements CredentialsSupplier {
*/
private String projectId;

/**
* Defines a prefix String that will be prepended to the environment property names
* of secrets in Secret Manager.
*/
private String secretNamePrefix = "";
meltsufin marked this conversation as resolved.
Show resolved Hide resolved

/**
* Defines versions for specific secret-ids.
*/
private Map<String, String> versions = new HashMap<>();

public Credentials getCredentials() {
return credentials;
}
Expand All @@ -61,20 +47,4 @@ public String getProjectId() {
public void setProjectId(String projectId) {
this.projectId = projectId;
}

public String getSecretNamePrefix() {
return secretNamePrefix;
}

public void setSecretNamePrefix(String secretNamePrefix) {
this.secretNamePrefix = secretNamePrefix;
}

public Map<String, String> getVersions() {
return versions;
}

public void setVersions(Map<String, String> versions) {
this.versions = versions;
}
}
Loading