使用 ssl 证书和带有卷的密钥部署 postgresql docker
Posted
技术标签:
【中文标题】使用 ssl 证书和带有卷的密钥部署 postgresql docker【英文标题】:Deploying postgresql docker with ssl certificate and key with volumes 【发布时间】:2019-07-31 00:25:35 【问题描述】:我正在尝试部署一个 postgresql 容器。我正在尝试使用卷将 ssl 证书和密钥放入容器中,但我无法获得正确的权限。这些文件需要容器的postgres
用户可读,但也有有限的权限(600
)。
是否可以使用卷,或者我必须为此覆盖 Dockerfile?
谢谢。
【问题讨论】:
【参考方案1】:可以将密钥和证书挂载到 postgres 容器中,以便 postgres 从那里使用它们。但是您将不得不面对server.key
的所有者和权限的问题。
来自PostgreSQL Documentation on this subject:
在 Unix 系统上,server.key 的权限必须禁止任何 进入世界或团体;通过命令 chmod 0600 实现这一点 服务器.key。或者,该文件可以由 root 拥有并具有 组读权限(即 0640 权限)。
这意味着您必须:
-
将
server.key
文件的所有者设置为root
或postgres
。
根据 server.key 文件的所有者,您必须分别设置 600
或 640
权限。 (更新:这里暗示该文件的组所有者是一个包含postgres
用户的组,就像默认的postgres
组)
如果您在 Windows 主机上工作,您将很难处理。因为您映射到容器中的卷中任何文件的权限都是-rwxr-xr-x
(755
),而所有者是root
。只要文件是从 Windows 卷安装的,您就无法更改此设置。如果您尝试在文件上使用chmod
,它只会静默失败。
另一方面,如果您使用的是 linux 主机,则可以轻松完成此操作。来自主机系统的权限将保留在映像中。所有权也将如此。我的意思是,server.key
的数字所有者和组所有者在它们被卷映射到容器时将被保留。在主机和容器之间,它们共享 linux ACL,因此它们只是观察文件的相同属性。 (所有者、组所有者、权限)。所以如果你的宿主机本地linux用户有UID:GID
1000:1000
,而你创建了server.key
文件,那么文件的UID:GID
也将设置为1000:1000
。如果您随后将文件映射到容器中,并从内部观察它 - 它也只会看到 1000:1000
。这意味着,当从 linux 主机映射时,我们可以从容器内部和外部控制 UID:GID
。
注意。您指定为文件所有者的UID
的用户不一定是用户,允许设置不存在的文件UID:GID
所有者。 p>
在 postgres alpine
派生图像中,postgres
用户/组具有 UID:GID
70:70
。在debian
派生上,postgres UID:GID
是999:999
。毫不奇怪,root 对它们都有0:0
。
这意味着要么必须:
-
更改文件
server.key
的UID:GID
在我们启动容器之后,当卷已经挂载时。
更改文件server.key
的UID:GID
在我们启动容器之前
由于在容器启动后设置它,将意味着篡改 postgres 映像的启动脚本 - 让我们选择在启动容器之前设置它们。在您挂载它们的本地文件系统中。
将600
权限和postgres
设置为server.key
的所有者
如果您要使用alpine
衍生产品,您需要将所有者/组更改为70:70
。如果您使用的是debian
派生类,则使用999:999
。
您的主机上可能没有用户,例如 UID
: 70
,但这不是问题。
示例:
chown 70:70 server.key # 70:70 for alpine, 999:999 for debian
chmod 600 server.key
将640
权限和root
设置为server.key
的所有者
这个例子也适用于高山图像
示例:
chown 0:70 server.key
chmod 640 server.key
此时您可以开始了。您只需要将密钥和证书映射到容器中,然后像往常一样启动 postgres。
解决方案(linux/unix/macOS)
我将在此处包含一个脚本 sn-p,它将为您完成所有关于 alpine 衍生产品的工作。此示例将设置 server.key 的 root 所有者和 postgres 组所有者。
# generate the server.key and server.crt
openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt
# set postgres (alpine) user as owner of the server.key and permissions to 600
chown 0:70 server.key
chmod 640 server.key
# start a postgres docker container, mapping the .key and .crt into the image.
docker run -d --name postgres \
-v "$PWD/server.crt:/var/lib/postgresql/server.crt:ro" \
-v "$PWD/server.key:/var/lib/postgresql/server.key:ro" \
postgres:11-alpine \
-c ssl=on \
-c ssl_cert_file=/var/lib/postgresql/server.crt \
-c ssl_key_file=/var/lib/postgresql/server.key
我希望这能解决问题?
生成密钥和证书的密钥来源是this gist。
自己构建映像(Windows 解决方案)
我将包含一个关于如何自己构建映像的小指南,以便您可以拥有一个带有 ssl 的 postgres 数据库容器。这也适用于 Windows。
这里是 Dockerfile 将为您做这件事:
Dockerfile
FROM postgres:11-alpine
# On Windows root will own the files, and they will have permissions 755
COPY server.key /var/lib/postgresql/server.key
COPY server.crt /var/lib/postgresql/server.crt
# update the privileges on the .key, no need to touch the .crt
RUN chmod 600 /var/lib/postgresql/server.key
RUN chown postgres:postgres /var/lib/postgresql/server.key
构建镜像:
docker build -t mypg:01 .
然后运行:
docker run -d --name postgres mypg:01 \
-c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt \
-c ssl_key_file=/var/lib/postgresql/server.key
【讨论】:
我无法使用 root 作为所有者和 0640 作为权限使其工作。数据库因 `FATAL: could not load private key file "/etc/postgresql/server.key": Permission denied`而失败。 感谢@AndreasLorenzen 非常详细的回答!我尝试了两种方法(chown 70:70 && chmod 0600
和 chown 0:70 && chmod 640
),第一种方法我得到could not load private key file "/var/lib/postgresql/server.key": Permission denied
,第二种方法我得到private key file "/var/lib/postgresql/server.key" has group or world access
此解决方案似乎在 osx 中不起作用,显然该文件未使用正确的所有者安装。
mac os x 的任何解决方案?
好吧,在这种情况下,您自己构建映像的“Windows”解决方案会起作用。如果您可以确认它可以这样工作,我将更新答案。我添加了 macos,因为我读到当某个地方的卷映射文件时,docker 不会以这种方式运行 - 但情况似乎并非如此。不过,我没有 Mac 可以在自己身上进行测试。【参考方案2】:
在我的特殊情况下,我有兴趣在通过 docker-compose 使用标准 postgres 映像时启用 SSL。此解决方案允许initdb
照常运行,这对于设置数据库和用户很有用。
docker-compose.yaml
version: '3'
services:
postgres:
image: postgres:12.2
environment:
- POSTGRES_PASSWORD=password
- POSTGRES_USER=myuser
- POSTGRES_HOST_AUTH_METHOD=trust
volumes:
- ./postgres-initdb:/docker-entrypoint-initdb.d/
- ./postgres-certs/:/var/lib/postgresql/certs/
postgres-initdb/config.sql
ALTER SYSTEM SET ssl_cert_file TO '/var/lib/postgresql/certs/server.crt';
ALTER SYSTEM SET ssl_key_file TO '/var/lib/postgresql/certs/server.key';
ALTER SYSTEM SET ssl TO 'ON';
这适用于任何配置。对于 SSL,您还需要生成证书(取自 a Gist):
set -euo pipefail
mkdir postgres-certs
cd postgres-certs
openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt
chmod 600 server.key
test $(uname -s) == Linux && chown 999 server.key
【讨论】:
这个答案提供了服务器证书/密钥,如何获取客户端证书/密钥以使用 ssl=verify-full 连接到 postgres? 恐怕我帮不了你@steve。这仅用于开发目的。以上是关于使用 ssl 证书和带有卷的密钥部署 postgresql docker的主要内容,如果未能解决你的问题,请参考以下文章