Grails:如何通过 SSL 访问 mongodb

Grails: how to access mongodb via SSL

我写了一个 grails 3.3 + mongo 4.0.4 应用程序,但在生产中 mongo 服务器只接受通过 SSL(自签名证书)的连接。我还没有在任何地方找到关于如何为 mongo (http://gorm.grails.org/latest/mongodb/manual/) 配置 GORM 的文档。有一个选项(sslEnabled,我想我应该使用 socketFactory)在 grails 中使用启用 SSL 的连接,但我不确定如何配置连接

对谁来说它与我有完全相同的问题,我仍然没有正确的方法直接使用 SSL 从 grails 连接到 mongodb。我发现的间接解决方案是在运行 grails 的机器上部署一个 mongos 客户端(mongo 分片客户端)启用 SSL 以连接到数据库,但不加密本地连接.因此,我可以通过 SSL 安全地访问远程数据库,但仍然使用 mongos 和 grails 之间的清晰连接进行连接。 mongos 配置应如下所示:

net:
  ssl:
    mode: preferSSL
    PEMKeyFile: /installDir/cert.pem
    CAFile: /installDir/chain.pem
    clusterFile: /installDir/cert.pem

  port: 27017
  bindIp: 0.0.0.0

security:
  clusterAuthMode: x509

preferSSL 允许 mongos 使用 SSL 连接到数据库,并且仍然允许 grails 应用程序将明文连接到 mongos

我找到了一种不用 mongos 连接的方法。

您需要在 grails-app/conf/runtime.groovy 中指定 socketFactory 个实例来验证服务器证书

import com.mongodb.ConnectionString
import grails.mongodb.MongoSSLContextBuilder

grails.mongodb = [
        url    : new ConnectionString("mongodb+srv://username:password@hostname/dbname?authSource=admin&tls=true"),
        options: [
                autoConnectRetry: true,
                connectTimeout  : 300,
                sslEnabled      : true,
                socketFactory   : new MongoSSLContextBuilder().getSSLContext("private/mongo/ca-certificate.crt").getSocketFactory()
        ]
]

实施MongoSSLContextBuilder


package grails.mongodb

import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import org.grails.io.support.ClassPathResource

import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate

@CompileStatic
@Slf4j
class MongoSSLContextBuilder {
    SSLContext getSSLContext(String pathToCert) {
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate caCert = (X509Certificate) cf.generateCertificate(getCert(pathToCert));

            TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
            ks.load(null);
            ks.setCertificateEntry("caCert", caCert);

            tmf.init(ks);

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());

            return sslContext;
        } catch (Exception e) {
            log.error("Error during building mongo ssl context: ", e);
            throw new RuntimeException(e);
        }

    }

    private InputStream getCert(String pathToCert) throws IOException {
        return new ClassPathResource(pathToCert).getInputStream();
    }

}

将你的ca-certificate.crt放在src/main/resources目录下

如果您需要 mongodb+srv:// 协议工作,您需要将 build.gradle 中的 org.mongodb:mongodb-driver 库更新到至少 3.6.0

版本
    // https://mvnrepository.com/artifact/org.mongodb/mongodb-driver
    compile 'org.mongodb:mongodb-driver:3.6.4'

    compile('org.grails.plugins:mongodb:6.1.6') {
        exclude group: 'org.mongodb', module: 'mongodb-driver'
    }