TomcatのコンテキストXMLファイルには機密情報(データベースへの接続に必要な資格情報が含まれることが多い)が含まれる傾向があるため、プレーンテキストのcontext.xml以外のソースからこれらの値を動的にロードするにはどうすればよいですか?
4 に答える
次のようなtomcat/conf/context.xmlファイルがあるとします。
<?xml version="1.0" encoding="utf-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource
name="jdbc/MyDB"
auth="Container"
type="javax.sql.DataSource"
removeAbandoned="true"
removeAbandonedTimeout="15"
maxActive="5"
maxIdle="5"
maxWait="7000"
username="${db.mydb.uid}"
password="${db.mydb.pwd}"
driverClassName="${db.mydb.driver}"
url="${db.mydb.url}${db.mydb.dbName}?autoReconnectForPools=true&characterEncoding=UTF-8"
factory="com.mycompany.util.configuration.CustomDataSourceFactory"
validationQuery="SELECT '1';"
testOnBorrow="true"/>
</Context>
この場合に置き換えたいのは、このリソース定義の${。*}のものです。ただし、以下のコードを少し変更するだけで、これらの置換をほぼすべての基準で実行できます。
行に注意してくださいfactory="com.mycompany.util.configuration.CustomDataSourceFactory"
これが意味するのは、Tomcatがこのファクトリを使用してこのリソースを処理しようとするということです。これは、このファクトリが起動時にTomcatのクラスパス上にある必要があることを意味することに注意してください(個人的には、Tomcatlib
ディレクトリのJARに私のものを入れました)。
これが私の工場の様子です。
package com.mycompany.util.configuration;
import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import org.apache.commons.dbcp.BasicDataSourceFactory;
public class CustomDataSourceFactory extends BasicDataSourceFactory implements ObjectFactory {
private static final Pattern _propRefPattern = Pattern.compile("\\$\\{.*?\\}");
//http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html#Adding_Custom_Resource_Factories
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
if (obj instanceof Reference) {
Reference ref = (Reference) obj;
System.out.println("Resolving context reference values dynamically");
for(int i = 0; i < ref.size(); i++) {
RefAddr addr = ref.get(i);
String tag = addr.getType();
String value = (String) addr.getContent();
Matcher matcher = _propRefPattern.matcher(value);
if (matcher.find()) {
String resolvedValue = resolve(value);
System.out.println("Resolved " + value + " to " + resolvedValue);
ref.remove(i);
ref.add(i, new StringRefAddr(tag, resolvedValue));
}
}
}
// Return the customized instance
return super.getObjectInstance(obj, name, nameCtx, environment);
}
private String resolve(String value) {
//Given the placeholder, do stuff to figure out what it's true value should be, and return that String.
//This could be decryption, or maybe using a properties file.
}
}
次に、このコードがクラスパスに追加されたら、Tomcatを再起動し、catalina.outでログメッセージを確認します。注:System.out.println
ステートメントは機密情報をログに出力する可能性が高いため、デバッグが完了したら、ステートメントを削除することをお勧めします。
補足として、多くの例が1つの特定のトピック(暗号化の利用など)に固有であることがわかったため、これを書き留めました。これを一般的に行う方法を示したいと思いました。さらに、この質問に対する他の回答のいくつかは、それ自体を十分に説明しておらず、この作業を行うために何をする必要があるかを理解するために、いくつかの掘り下げを行う必要がありました。私の発見を皆さんと共有したいと思いました。これについてコメントしたり、質問したり、問題が見つかった場合は修正したりしてください。修正を私の答えに反映させます。
なぜすべてのトラブルを経験するのですか?
ホスト マシンで重要なパラメータをJVM システム プロパティとして設定するだけで、Tomcat がそれらを自動的に認識し、すべてのプレースホルダの値を置き換えます${...}
。このようにして、機密データはホスト マシンにのみ保持され、ソース コードで漏洩することはありません。
出典: https://tomcat.apache.org/tomcat-7.0-doc/config/
Apache Ant スタイルの変数置換がサポートされています。propname という名前のシステム プロパティは、構文 ${propname} を使用して構成ファイルで使用できます。-D 構文を使用して設定されたもの、JVM によって自動的に使用可能になったもの、および $CATALINA_BASE/conf/catalina.properties ファイルで構成されたものを含む、すべてのシステム プロパティを使用できます。
@ 注: この回答は、あなたと他の Tomcat 構成ファイルが SCM の下にあることを前提としています。これcontext.xml
は、仮想化された展開 (Openshift など) を使用するときに通常発生することです。
これを行いたい場合は、非常に単純なものを実装する独自のクラスを実装できます
org.apache.tomcat.util.IntrospectionUtils.PropertySource
インターフェイスを作成し、システム プロパティを使用してこれを登録します。
org.apache.tomcat.util.digester.PROPERTY_SOURCE
context.xml、server.xml などで暗号化された値を使用できるようにするために、同じことを行いました。
http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html#Property_replacementsを参照してください。
Zookeeper プロパティ ソースを実装している場合は、同じことを検討しているので、結果に興味があります。
できません。この質問は、無限回帰を意味します。クレデンシャルをロードする安全なソースがある場合は、セキュアなソースのクレデンシャルを定義する必要があります。
この種の問題に対する最終的な答えは、サーバー マシンの物理的なセキュリティと、その展開ディレクトリを外部から参照できるユーザーに対するアクセス制御です。