【问题标题】:PySpark via Dataproc + SSL Connection to Cloud SQLPySpark 通过 Dataproc + SSL 连接到 Cloud SQL
【发布时间】:2017-09-21 07:27:36
【问题描述】:

我有一个在数据库中存储数据的 Cloud SQL 实例,并且我已选中此 Cloud SQL 实例的选项以阻止所有未加密的连接。当我选择此选项时,我将获得三个 SSL 证书——一个服务器证书、一个客户端公钥和一个客户端私钥(三个单独的 .pem 文件)(link to relevant CloudSQL+SSL documentation)。这些证书文件用于建立与 Cloud SQL 实例的加密连接。

我能够使用 MySQL 从命令行成功连接到 Cloud SQL,使用 --ssl-ca、--ssl-cert 和 --ssl-key 选项分别指定服务器证书、客户端公钥和客户端私钥:

mysql -uroot -p -h <host-ip-address> \
--ssl-ca=server-ca.pem \
--ssl-cert=client-cert.pem \
--ssl-key=client-key.pem

我现在正在尝试运行一个连接到此 Cloud SQL 实例的 PySpark 作业,以提取数据进行分析。 PySpark 作业与谷歌云培训团队提供的this example 基本相同。在上述脚本的line 39 上,有一个与 Cloud SQL 实例建立的 JDBC 连接:

jdbcDriver = 'com.mysql.jdbc.Driver'
jdbcUrl = 'jdbc:mysql://%s:3306/%s?user=%s&password=%s' % (CLOUDSQL_INSTANCE_IP, CLOUDSQL_DB_NAME, CLOUDSQL_USER, CLOUDSQL_PWD)

但这不会进行加密连接,也不会提供三个证书文件。如果我与 Cloud SQL 实例的连接未加密已禁用,我会看到以下错误消息:

17/09/21 06:23:21 INFO org.spark_project.jetty.util.log: Logging initialized @5353ms
17/09/21 06:23:21 INFO org.spark_project.jetty.server.Server: jetty-9.3.z-SNAPSHOT
17/09/21 06:23:21 INFO org.spark_project.jetty.server.Server: Started @5426ms
17/09/21 06:23:21 INFO org.spark_project.jetty.server.AbstractConnector: Started ServerConnector@74af54ac{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}

[...snip...]

py4j.protocol.Py4JJavaError: An error occurred while calling o51.load.
: java.sql.SQLException: Access denied for user 'root'@'<cloud-sql-instance-ip>' (using password: YES)

而如果我与 Cloud SQL 实例的未加密连接启用,则作业运行良好。 (这表明问题不在于 Cloud SQL API 权限 - 我运行 PySpark 作业的集群绝对有权访问 Cloud SQL 实例。)

我发现的涉及 SSL add a &amp;useSSL=true or &amp;encrypt=true but do not point to external certificates 的 JDBC 连接字符串;或者,他们在某种特定于 Java 的过程中使用keystore。如何从上面链接的 Python 脚本修改 JDBC 连接字符串,以便将 JDBC(通过 PySpark)指向服务器证书和客户端公钥/私钥(server-ca.pem、client-cert.pem)的位置, 和 client-key.pem) 在磁盘上?

【问题讨论】:

  • 你看过github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory吗?它使用临时 SSL 证书为整个连接建立隧道,避免了手动管理证书的需要。
  • PySpark 正在使用 pyspark 库中的 SQL context - 您链接到的库是 Java,所以我无法使用它。但这个想法很好。据我所知,Cloud SQL Proxy 正在做类似这个库所做的事情,但使用的是命令行实用程序。
  • 据我所知,即使您使用 python 编写作业,连接也是使用 Java 发生的,因此我给您的链接仍然适用。另见:stackoverflow.com/questions/27698111/…
  • 感谢最后一个链接。我看到了运行 Dataproc PySpark 作业时可以在哪里指定 jar,以及如何修改 JDBC 连接字符串以指定使用套接字工厂。但是在这种情况下,jar 是什么 - 只是 cloud-sql-jdbc-socket-factory 库内置/捆绑到一个 jar 中?

标签: python ssl jdbc google-cloud-sql google-cloud-dataproc


【解决方案1】:

Dataproc 集群上有一个 handy initialization action for configuring the CloudSQL Proxy。默认情况下,它假定您打算将 CloudSQL 用于 Hive 元存储,但如果您下载它并自定义它设置 ENABLE_CLOUD_SQL_METASTORE=0,然后将其重新上传到您自己的存储桶中以用作您的自定义初始化操作,那么您应该自动获取CloudSQL 代理安装在您的所有节点上。然后你只需将你的mysql连接字符串设置为指向localhost而不是真正的CloudSQL IP。

指定元数据标志时,如果您在元数据中禁用了additional-cloud-sql-instances 而不是 hive-metastore-instance:

--metadata "additional-cloud-sql-instances=<PROJECT_ID>:<REGION>:<ANOTHER_INSTANCE_NAME>=tcp<PORT_#>`

在这种情况下,您可以选择使用脚本默认为 Metastore 使用的相同端口分配,即端口 3306。

【讨论】:

  • 太好了,这正是我想要的。剩下的一个问题 - 谁提供凭据?是否会自动使用来自 Dataproc 实例的凭据(假设它们有权访问 Cloud SQL API)?
  • 正确,默认情况下会自动使用 VM 介导的服务帐户凭据,因此您需要确保在集群上启用了 CloudSQL 范围。从理论上讲,也可以使用单独的凭据密钥文件,但这并没有得到很好的探索,特别是对于那个 init 操作。
  • 没有运气让这个工作 - ADDITIONAL_INSTANCES 变量总是空的,所以test on line 63 总是失败。如果 Cloud SQL 实例信息已在 METASTORE_INSTANCE 中提供,那么 ADDITIONAL_INSTANCES 应该包含什么?为什么需要它?
  • 抱歉忘记了这个细节;我们应该在 README 中添加一个示例; ADDITIONAL_INSTANCES 与您放入 METASTORE_INSTANCE 的内容基本相同,只是它可以是一个列表。区别只是该脚本的作者认为将不会用作 Hive Metastore 的东西说成“METASTORE_INSTANCE”是用词不当。所以要回答,只需将 METASTORE_INSTANCE 留空,并在 ADDITIONAL_INSTANCES 中以 additional-cloud-sql-instances=&lt;PROJECT_ID&gt;:&lt;REGION&gt;:&lt;ANOTHER_INSTANCE_NAME&gt;=tcp&lt;PORT_#&gt; 的形式指定您的目标 CloudSQL 实例
  • 更新了答案以包含此信息
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-15
  • 2019-02-19
相关资源
最近更新 更多