syslog服务器配置
配置rsyslog配置文件/etc/rsyslog.conf
rsyslog服务端接收
作为日志聚合服务,接受客户端发送过来的日志
开启UDP/TCP接收:
代码语言:properties复制# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
配置日志接收规则:
代码语言:properties复制$template RemoteLogs,"/data/logs/%fromhost-ip%/%$YEAR%-%$MONTH%-%$DAY%.log"
:fromhost-ip, !isequal, "127.0.0.1" ?RemoteLogs
#& ~
rsyslog客户端发送
rsyslog也可以作为客户端向远程的rsyslog服务端转发日志
开启转发:
代码语言:properties复制# UDP转发
*.* @server_ip:514
# TCP转发
*.* @@server_ip:514
重启rsyslog服务
当rsyslog服务端或客户端配置完成后,重启服务使配置生效
代码语言:bash复制systemctl restart rsyslog
systemctl status rsyslog
配置支持TLS的rsyslog
安装依赖包
配置支持TLS的rsyslog需要安装以下依赖包
代码语言:bash复制yum install rsyslog-gnutls
yum install rsyslog
yum install gnutls-utils
yum install gnutls
生成密钥与证书
代码语言:bash复制# 生成根证书
certtool --generate-privkey --outfile ca-key.pem
certtool --generate-self-signed --load-privkey ca-key.pem --outfile ca.pem
# 生成服务端密钥与证书
certtool --generate-privkey --outfile rslserver-key.pem --bits 2048
certtool --generate-request --load-privkey rslserver-key.pem --outfile request.pem
certtool --generate-certificate --load-request request.pem --outfile rslserver-cert.pem --load-ca-certificate ca.pem --load-ca-privkey ca-key.pem
# 生成客户端密钥与证书
certtool --generate-privkey --outfile rslclient-key.pem --bits 2048
certtool --generate-request --load-privkey rslclient-key.pem --outfile request.pem
certtool --generate-certificate --load-request request.pem --outfile rslclient-cert.pem --load-ca-certificate ca.pem --load-ca-privkey ca-key.pem
注意:输入证书信息时名字不要留空,不然后面Java中会报java.security.cert.CertificateParsingException: X.509 Certificate is incomplete: subject field is empty
的错误
配置服务端接收TLS连接
代码语言:properties复制$DefaultNetstreamDriver gtls
$DefaultNetstreamDriverCAFile /root/tls/ca.pem
$DefaultNetstreamDriverCertFile /root/tls/rslserver-cert.pem
$DefaultNetstreamDriverKeyFile /root/tls/rslserver-key.pem
# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514
$InputTCPServerStreamDriverAuthMode anon
$InputTCPServerStreamDriverMode 1
$ActionSendStreamDriverAuthMode x509/name
$ActionSendStreamDriverMode 1
$MaxOpenFiles 2048
配置客户端启用TLS连接
代码语言:properties复制$DefaultNetstreamDriver gtls
$DefaultNetstreamDriverCAFile /root/tls/private/ca.pem
$DefaultNetstreamDriverCertFile /root/tls/private/rslclient-cert.pem
$DefaultNetstreamDriverKeyFile /root/tls/private/rslclient-key.pem
$ActionSendStreamDriverPermittedPeer your.server.com # that should be your rsyslog server
$ActionSendStreamDriverMode 1 # run driver in TLS-only mode
$ActionSendStreamDriverAuthMode x509/name
注意:如果证书报错的话,可以改为$ActionSendStreamDriverAuthMode anon
,即不需认证证书。
Log4j转发日志
Log4j 1.X转发syslog
这里Log4j的版本是1.2.17,配置log4j配置文件开启syslog转发
代码语言:plain复制log4j.rootLogger=INFO, console, fout, SYSLOG
log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender
log4j.appender.SYSLOG.threshold=INFO
log4j.appender.SYSLOG.syslogHost={SYSLOG_HOST}
log4j.appender.SYSLOG.facility=LOCAL4
log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.SYSLOG.layout.conversionPattern=%d{HH:mm:ss,SSS} %-5p %-60c %x - %m%n
需要在代码中导入系统变量
代码语言:java复制System.setProperty("SYSLOG_HOST", "127.0.0.1");
Log4j2中转发syslog
maven依赖
代码语言:xml复制<!--Log4j 2 dependencies-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2-version}</version>
</dependency>
配置模版
代码语言:xml复制<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="5">
<Properties>
<Property name="console-layout">%d{HH:mm:ss} %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${console-layout}"/>
</Console>
<Syslog name="udp-syslog" host="localhost" port="514" protocol="UDP">
<PatternLayout pattern="${console-layout}"/>
</Syslog>
<Syslog name="tcp-syslog" host="localhost" port="514" protocol="TCP">
<PatternLayout pattern="${console-layout}"/>
</Syslog>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
<AppenderRef ref="tcp-syslog"/>
</Root>
</Loggers>
</Configuration>
使用TLS转发日志
代码语言:xml复制<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" monitorInterval="5">
<Properties>
<Property name="console-layout">%d{HH:mm:ss} %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${console-layout}"/>
</Console>
<Syslog name="tls-syslog" host="localhost" port="6514">
<SSL>
<TrustStore location="truststore.jks" password="KEYSTORE_PASSWORD"/>
</SSL>
</Syslog>
<Syslog name="mtls-syslog" host="localhost" port="6514">
<SSL>
<KeyStore location="log4j2-keystore.jks" password="KEYSTORE_PASSWORD"/>
<TrustStore location="truststore.jks" password="KEYSTORE_PASSWORD"/>
</SSL>
</Syslog>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Console"/>
<AppenderRef ref="tls-syslog"/>
</Root>
</Loggers>
</Configuration>
其中,如果是单向TLS,只需要提供Rsyslog服务端的公钥证书,存入TrustStore中即可,配置中只需要指定TrustStore。如果需要双向TLS,则需要生成客户端的私钥与证书,存入KeyStore中。
读取证书与私钥
通过以下代码将base64编码的证书或私钥读入程序中
代码语言:java复制private static X509Certificate base64toCert(String base64String) throws CertificateException {
byte[] decoded = Base64.getDecoder().decode(base64String);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decoded));
}
private static RSAPrivateKey base64toPrivateKey(String base64String) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] decoded = Base64.getDecoder().decode(base64String);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
注意:私钥如果不是pkcs8格式的,上面代码无法读取,可以通过以下命令转换私钥格式
代码语言:bash复制certtool --to-p8 --load-privkey rslclient-key.pem --outfile rslclient-key-8.pem
将证书和私钥存入KeyStore
代码语言:java复制KeyStore keyStore = KeyStore.getInstance("jks");
String password = "yourpassword";
X509Certificate caCert = base64toCert(caBase64String);
// create new key store
keyStore.load(null, password.toCharArray());
// store certificate
keyStore.setCertificateEntry("cert name", caCert);
// store private key
X509Certificate[] certChain = new X509Certificate[2];
certChain[0] = cert;
certChain[1] = caCert;
Key privateKey = base64toPrivateKey(keyBase64String);
keyStore.setKeyEntry("key name", privateKey, password.toCharArray() , certChain);
// save to file
FileOutputStream fos = new FileOutputStream(trustStoreFileName);
keyStore.store(fos, password.toCharArray());
动态修改Log4j2配置
在配置文件中加上monitorInterval
属性
<Configuration monitorInterval="5" status="WARN">
</Configuration>
在程序中指定配置文件的位置,这样就会定期拉取最新的配置文件。注意,需要在所有的logger启动之前执行。
代码语言:java复制// set log4j2 configuration file location
LoggerContext context = (LoggerContext) LogManager.getContext(false);
File log4j2XmlFile = new File("log4j2.xml");
context.setConfigLocation(log4j2XmlFile.toURI());
接下来只需要修改"log4j2.xml"文件即可
修改XML文件
用Apache Commons Configuration来修改log4j2.xml配置文件
代码语言:java复制// 读取默认配置
File log4j2XmlFile = new File("log4j2.xml");
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(XMLConfiguration.class)
.configure(params.fileBased()
.setFile(log4j2XmlFile));
Configuration config = builder.getConfiguration();
// 修改配置
String configNode = "Appenders.Syslog(1)"; // Appreders下有多个Syslog,所以需要指定第几个Syslog
config.addProperty(configNode ".PatternLayout.[@pattern]", "${remote-layout}") // 为节点添加属性
// 保存配置
builder.save();
maven依赖
代码语言:xml复制<!--Apache Commons Configuration dependency-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
<version>${apache.commons.configuration-version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
拷贝默认文件
可以用Apache Commons IO中的FileUtils.copyFile
来拷贝文件
File originLog4j2XmlFile = new File("log4j2-origin.xml");
File log4j2XmlFile = new File("log4j2.xml");
FileUtils.copyFile(originLog4j2XmlFile, log4j2XmlFile);
maven依赖
代码语言:xml复制<!--Apache Commons IO dependency-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
References
- How to Configure rsyslog Server to Accept Logs via SSL/TLS
- Log4j2 - SyslogAppender
- Log4j 2 API Overview
- Log4j Programmatic Configuration
- Java KeyStore API
- How to read .pem file to get private and public key
- Apache Commons Configuration