diff --git a/config/cloud_sql_security_provider.yml b/config/cloud_sql_security_provider.yml
new file mode 100644
index 0000000000..b5c97e95ef
--- /dev/null
+++ b/config/cloud_sql_security_provider.yml
@@ -0,0 +1,18 @@
+# Cloud Foundry Java Buildpack
+# Copyright 2013-2020 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Configuration for the CloudSql Security Provider framework
+---
+enabled: true
\ No newline at end of file
diff --git a/config/components.yml b/config/components.yml
index 90a12ec28e..af10f5b4b1 100644
--- a/config/components.yml
+++ b/config/components.yml
@@ -49,6 +49,7 @@ frameworks:
- "JavaBuildpack::Framework::ClientCertificateMapper"
- "JavaBuildpack::Framework::ContainerCustomizer"
- "JavaBuildpack::Framework::ContainerSecurityProvider"
+ - "JavaBuildpack::Framework::CloudSqlSecurityProvider"
- "JavaBuildpack::Framework::ContrastSecurityAgent"
- "JavaBuildpack::Framework::DatadogJavaagent"
- "JavaBuildpack::Framework::Debug"
diff --git a/docs/framework-splunk_otel_java_agent.md b/docs/framework-splunk_otel_java_agent.md
index e8b438376b..ef5fb1a10d 100644
--- a/docs/framework-splunk_otel_java_agent.md
+++ b/docs/framework-splunk_otel_java_agent.md
@@ -1,9 +1,8 @@
# Splunk Distribution of OpenTelemetry Java Instrumentation
-The Splunk OpenTelemetry Java Agent buildpack framework will cause an application to be automatically instrumented
-with the [Splunk distribution of OpenTelemetry Java Instrumentation](https://github.com/signalfx/splunk-otel-java).
-
-Trace data will be sent directly to Splunk Observability Cloud.
+This buildpack framework automatically instruments your Java application
+with the [Splunk distribution of OpenTelemetry Java Instrumentation](https://github.com/signalfx/splunk-otel-java)
+to send trace data to Splunk Observability Cloud.
@@ -16,15 +15,17 @@ Trace data will be sent directly to Splunk Observability Cloud.
-Tags are printed to standard output by the buildpack detect script
+The buildpack detect script prints tags to standard output.
## User-Provided Service
-Users are currently expected to `create-user-provided-service` (cups) of the collector
-and bind it to their application. The service MUST contain the string `splunk-o11y`.
+Users are currently expected to provide their own `user-provided-service` (cups) of the collector
+and bind it to their application.
+
+The service name MUST contain the string `splunk-o11y`.
For example, to create a service named `splunk-o11y` that represents Observability Cloud
-realm `us0` and represents a user environment named `cf-demo`, you could use the following
+realm `us0` and represents a user environment named `cf-demo`, use the following
commands:
```
@@ -34,27 +35,29 @@ $ cf bind-service myApp splunk-o11y
$ cf restage myApp
```
-The `credential` field of the service should provide these entries:
+Provide the following values using the `credential` field of the service:
| Name | Required? | Description
|------------------------|-----------| -----------
-| `splunk.access.token` | Yes | The Splunk [org access token](https://docs.splunk.com/observability/admin/authentication-tokens/org-tokens.html).
-| `splunk.realm` | Yes | The Splunk realm where data will be sent. This is commonly `us0` or `eu0` etc.
-| `otel.*` or `splunk.*` | Optional | All additional credentials starting with these prefixes will be appended to the application's JVM arguments as system properties.
+| `splunk.access.token` | Yes | Splunk [org access token](https://docs.splunk.com/observability/admin/authentication-tokens/org-tokens.html).
+| `splunk.realm` | Yes | Splunk realm where data will be sent. This is commonly `us0`, `eu0`, and so on. See [Available regions or realms](https://docs.splunk.com/observability/en/get-started/service-description.html#available-regions-or-realms) for more information.
+| `otel.*` or `splunk.*` | Optional | All additional credentials starting with these prefixes are appended to the application's JVM arguments as system properties.
### Choosing a version
-Most users should skip this and simply use the latest version of the agent available (the default).
-To override the default and choose a specific version, you can use the `JBP_CONFIG_*` mechanism
+To override the default and choose a specific version, use the `JBP_CONFIG_*` mechanism
and set the `JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT` environment variable for your application.
-For example, to use version 1.16.0 of the Splunk OpenTelemetry Java Instrumentation, you
-could run:
+For example, to use version 1.16.0 of the Splunk OpenTelemetry Java Instrumentation, run:
+
```
$ cf set-env testapp JBP_CONFIG_SPLUNK_OTEL_JAVA_AGENT '{version: 1.16.0}'
```
+
+In most cases you can use the latest or default version of the agent available.
# Additional Resources
* [Splunk Observability](https://www.splunk.com/en_us/products/observability.html)
+* [Official documentation of the Splunk Java agent](https://docs.splunk.com/observability/en/gdi/get-data-in/application/java/get-started.html)
* [Splunk Distribution of OpenTelemetry Java](https://github.com/signalfx/splunk-otel-java) on GitHub
diff --git a/lib/java_buildpack/framework/cloud_sql_security_provider.rb b/lib/java_buildpack/framework/cloud_sql_security_provider.rb
new file mode 100644
index 0000000000..192adb19c1
--- /dev/null
+++ b/lib/java_buildpack/framework/cloud_sql_security_provider.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+# Cloud Foundry Java Buildpack
+# Copyright 2013-2020 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'fileutils'
+require 'shellwords'
+require 'tempfile'
+require 'java_buildpack/component/base_component'
+require 'java_buildpack/framework'
+require 'java_buildpack/util/qualify_path'
+
+module JavaBuildpack
+ module Framework
+
+ # Encapsulates the functionality for enabling secure communication with GCP CloudSQL instances.
+ class CloudSqlSecurityProvider < JavaBuildpack::Component::BaseComponent
+ include JavaBuildpack::Util
+
+ # (see JavaBuildpack::Component::BaseComponent#compile)
+ def compile
+ return unless supports?
+
+ @droplet.copy_resources
+
+ credentials = @application.services.find_service(FILTER, 'sslrootcert', 'sslcert', 'sslkey')['credentials']
+
+ pkcs12 = merge_client_credentials credentials
+ add_client_credentials pkcs12
+
+ add_trusted_certificate credentials['sslrootcert']
+ end
+
+ # (see JavaBuildpack::Component::BaseComponent#release)
+ def release
+ return unless supports?
+
+ java_opts = @droplet.java_opts
+
+ add_additional_properties(java_opts)
+ end
+
+ def detect
+ CloudSqlSecurityProvider.to_s.dash_case
+ end
+
+ protected
+
+ def supports?
+ @application.services.one_service? FILTER, 'sslrootcert', 'sslcert', 'sslkey'
+ end
+
+ private
+
+ FILTER = /csb-google-/.freeze
+
+ private_constant :FILTER
+
+
+ def add_additional_properties(java_opts)
+ java_opts
+ .add_system_property('javax.net.ssl.keyStore', keystore)
+ .add_system_property('javax.net.ssl.keyStorePassword', password)
+ end
+
+ def add_client_credentials(pkcs12)
+ shell "#{keytool} -importkeystore -noprompt -destkeystore #{keystore} -deststorepass #{password} " \
+ "-srckeystore #{pkcs12.path} -srcstorepass #{password} -srcstoretype pkcs12" \
+ " -alias #{File.basename(pkcs12)}"
+ end
+
+ def add_trusted_certificate(trusted_certificate)
+ cert = Tempfile.new('ca-cert-')
+ cert.write(trusted_certificate)
+ cert.close
+
+ shell "#{keytool} -import -trustcacerts -cacerts -storepass changeit -noprompt -alias CloudSQLCA -file #{cert.path}"
+ end
+
+ def keystore
+ @droplet.sandbox + 'cloud-sql-keystore.jks'
+ end
+
+ def keytool
+ @droplet.java_home.root + 'bin/keytool'
+ end
+
+ def merge_client_credentials(credentials)
+ certificate = write_certificate credentials['sslcert']
+ private_key = write_private_key credentials['sslkey']
+
+ pkcs12 = Tempfile.new('pkcs12-')
+ pkcs12.close
+
+ shell "openssl pkcs12 -export -in #{certificate.path} -inkey #{private_key.path} " \
+ "-name #{File.basename(pkcs12)} -out #{pkcs12.path} -passout pass:#{password}"
+
+ pkcs12
+ end
+
+ def password
+ 'cloud-sql-keystore-password'
+ end
+
+ def write_certificate(certificate)
+ Tempfile.open('certificate-') do |f|
+ f.write "#{certificate}\n"
+ f.sync
+ f
+ end
+ end
+
+ def write_private_key(private_key)
+ Tempfile.open('private-key-') do |f|
+ f.write "#{private_key}\n"
+ f.sync
+ f
+ end
+ end
+
+ end
+ end
+end
diff --git a/resources/cloud_sql_security_provider/index.yml b/resources/cloud_sql_security_provider/index.yml
new file mode 100644
index 0000000000..e69de29bb2