From d0849dcdf78ff1d0615e6844e4b002c4a4a9ee47 Mon Sep 17 00:00:00 2001 From: Gareth Evans Date: Tue, 10 May 2022 10:26:52 +0100 Subject: [PATCH] Adding a ServiceBindingPropertySource The property source allows values in Tomcat's configuration files to be injected directly from a servicebinding.io's Service Binding without having to be converted to an environment variable first. Co-authored-by: Sumit Kulhadia Co-authored-by: Gareth Evans --- .../ServiceBindingPropertySource.java | 119 ++++++++++++++++++ webapps/docs/config/systemprops.xml | 5 +- 2 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 java/org/apache/tomcat/util/digester/ServiceBindingPropertySource.java diff --git a/java/org/apache/tomcat/util/digester/ServiceBindingPropertySource.java b/java/org/apache/tomcat/util/digester/ServiceBindingPropertySource.java new file mode 100644 index 000000000000..526ad37a1e54 --- /dev/null +++ b/java/org/apache/tomcat/util/digester/ServiceBindingPropertySource.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.tomcat.util.digester; + +import java.security.Permission; + +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.security.PermissionCheck; +import java.io.IOException; +import java.io.FilePermission; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * A {@link org.apache.tomcat.util.IntrospectionUtils.SecurePropertySource} + * that uses Kubernetes service bindings to resolve expressions. + * + *

Usage example:

+ * + * Configure the certificate with a service binding. + * + * When the service binding is constructed as follows: + * + *
+ *    $SERVICE_BINDING_ROOT/
+ *                         /custom-certificate/
+ *                                            /keyFile
+ *                                            /file
+ *                                            /chainFile
+ * 
+ *
+ *   {@code
+ *     
+ *           
+ *      }
+ * 
+ * + * How to configure: + *
+ * {@code
+ *   echo "org.apache.tomcat.util.digester.PROPERTY_SOURCE=org.apache.tomcat.util.digester.ServiceBindingPropertySource" >> conf/catalina.properties}
+ * 
+ * or add this to {@code CATALINA_OPTS} + * + *
+ * {@code
+ *   -Dorg.apache.tomcat.util.digester.PROPERTY_SOURCE=org.apache.tomcat.util.digester.ServiceBindingPropertySource}
+ * 
+ * + * NOTE: When configured the PropertySource for resolving expressions + * from system properties is still active. + * + * @see Digester + * + * @see Tomcat Configuration Reference System Properties + */ +public class ServiceBindingPropertySource implements IntrospectionUtils.SecurePropertySource { + + private static final String SERVICE_BINDING_ROOT_ENV_VAR = "SERVICE_BINDING_ROOT"; + + @Override + public String getProperty(String key) { + return null; + } + + @Override + public String getProperty(String key, ClassLoader classLoader) { + // can we determine the service binding root + if (classLoader instanceof PermissionCheck) { + Permission p = new RuntimePermission("getenv." + SERVICE_BINDING_ROOT_ENV_VAR, null); + if (!((PermissionCheck) classLoader).check(p)) { + return null; + } + } + + // get the root to search from + String serviceBindingRoot = System.getenv(SERVICE_BINDING_ROOT_ENV_VAR); + if (serviceBindingRoot == null) { + return null; + } + + // we expect the keys to be in the format $SERVICE_BINDING_ROOT// + String[] parts = key.split("\\."); + if (parts.length != 2) { + return null; + } + + Path path = Paths.get(serviceBindingRoot, parts[0], parts[1]); + try { + if (classLoader instanceof PermissionCheck) { + Permission p = new FilePermission(path.toString(), "read"); + if (!((PermissionCheck) classLoader).check(p)) { + return null; + } + } + return new String(Files.readAllBytes(path)); + } catch (IOException e) { + return null; + } + } +} diff --git a/webapps/docs/config/systemprops.xml b/webapps/docs/config/systemprops.xml index 690463ce693c..bdb77bc72192 100644 --- a/webapps/docs/config/systemprops.xml +++ b/webapps/docs/config/systemprops.xml @@ -51,13 +51,16 @@

Property replacement from the specified property source on the JVM system properties can also be done using the REPLACE_SYSTEM_PROPERTIES system property.

+

org.apache.tomcat.util.digester.ServiceBindingPropertySource + can be used to replace parameters from any Kubernetes service bindings + that follows the servicebinding.io spec

org.apache.tomcat.util.digester.EnvironmentPropertySource can be used to replace parameters from the process' environment variables, e.g. injected ConfigMaps or Secret objects in container based systems like OpenShift or Kubernetes.

org.apache.tomcat.util.digester.SystemPropertySource does replacement with system properties. It is always enabled, - but can also be spefied as part of the property value.

+ but can also be specified as part of the property value.

Set this boolean system property to true to cause