我希望在连接到我的Google Cloud SQL(postgres(实例时强制使用SSL,但我找不到向部署到app Engine的Python应用程序提供证书的方法-psycopg2
要求证书具有正确的权限:<cert> has group or world access; permissions should be u=rw(0600) or less
,但由于app Engine上无法访问chmod,我不知道如何更改它。
有什么想法吗?
为了提供上下文,目标主要是强制在GCP之外(从我的工作站(对DB进行安全访问。应用程序引擎应用程序的问题是此更改的副作用。但也许有一种不同的、更好的方式来实现同样的目标?
谢谢。
谷歌云应用程序引擎对任何使用内置/cloudsql
unix套接字目录的连接使用云SQL代理。这些连接会自动封装在SSL层中,直到它们到达您的Cloud SQL实例。
您不需要担心使用证书,因为代理会自动为您执行此过程。
这有点棘手,因为这里有一个鸡和蛋的问题:
- Postgres驱动程序想要一个文件(因为它是读取文件的C库的包装器(
- 并且您无法在启动时在应用程序引擎内设置正确的文件权限
这个问题有几种情况(和解决方案(:
- AppEngine经典环境
- 解决方法-在/tmp ramdisk中自己编写证书文件
- 使用UNIX套接字连接到具有公共IP地址(无SSL(的云SQL实例
- 或者使用VPC和私有VPC访问私有IP地址和的云SQL实例,使用变通方法
- AppEngine Flex环境
- 在docker映像中包含证书文件
解决方法:在/tmp中自己编写证书文件
解决这个问题的最简单方法是将cert文件自己写入/tmp中——这是应用程序引擎环境中的ramdisk。
像这样的东西就可以了:
import os
import psycopg2
certfile_path = '/tmp/certfile' # /tmp/ is a ramdisk
certfile_content = os.environ.get('CERTFILE')
if certfile_content != None:
with open(certfile_path,'w+') as fp:
fp.write(certfile_content)
os.chmod(certfile_path, 0o600)
# Now the certfile is "safe" to use, we can pass it in our connection string:
connection_string= f"postgres+prycopg2://host/database?sslmode=require&sslcert={certfile_path}"
else:
connection_string = 'postgres+prycopg2://host/database'
# or just trow an exception, log the problem, and exit.
(有关SSL选项,请参阅Postgres连接字符串参考(
长期解决方案
使用SSL的目的是在数据库和您之间进行加密通信,同时避免中间人攻击。
我们在这里有一些选择:
选项1:当您在App EngineAND中时,您的云SQL实例具有公共IP地址。
在这种情况下,您可以使用Unix域套接字连接到Postgres实例。谷歌使用一个监听套接字的代理,并负责加密和保护端点(btw-SSL被禁用(。
在这种情况下,您需要向使用的服务帐户添加
SQL Client
权限,并在Yaml文件中添加UNIX套接字目录(请参阅谷歌文档(。选项2:当您在App Engine ClassicAND中时,您的云SQL实例具有PRIVATE IP地址。
如果您的云SQL实例具有私有IP,这可能有点";更简单";。我们需要启用无服务器VPC访问-这将AppEngine连接到我们在私有IP上有资源的VPC(对于公共IP,因为公共IP不重叠,所以不需要(,并且云SQL服务器必须连接到VPC。
现在,您可以像往常一样连接到Postgres。VPC网络内部的流量是加密的。如果你在VPC中只有这个CloudSQL实例,就不需要使用SSL(没有人可以在网络上放置嗅探器或进行Mitm攻击(。
但是,如果您仍然希望/需要使用SSL,则必须使用前面描述的解决方法。
选项3:使用AppEngine FLEX环境。
flex环境"只是"一个docker镜像。您需要为Python运行时构建一个包含certfile的自定义docker映像。请记住,Flex环境不包括在免费层中。