【问题标题】:How to generate self-signed certificate for IP address (without domain name)?如何为 IP 地址(无域名)生成自签名证书?
【发布时间】:2021-06-16 00:47:46
【问题描述】:

我在 google cloud k8s 集群中有一个私有 docker 注册表,只能通过 IP 访问

我尝试做的事情:

  1. 编写脚本生成自签名证书。
  2. 在 Docker 注册表端使用生成的自签名客户端密钥和证书。
  3. 将每个k8s节点上的CA证书放到/etc/ssl/certs/registry-proxy-ca.pem并运行update-ca-certificates && systemctl restart docker

我希望客户端自签名证书将在 k8s 节点尝试创建 pod 并从 docker 注册表中提取图像时获得批准。

但我还是有错误:

x509: certificate signed by unknown authority

谁能帮助我理解我做错了什么?我的脚本:

IP=10.3.240.100

LIFESPAN_DAYS=35600

CERTS_DIR=platform/cert-customizations/certs
CA_KEY=$CERTS_DIR/registry-proxy-ca.key
CA_PEM=$CERTS_DIR/registry-proxy-ca.pem
OPENSSL_CONFIG=$CERTS_DIR/openssl.cnf

REGISTRY_CERT_DIR=platform/registry-proxy/certs
REGISTRY_CERT_KEY=$REGISTRY_CERT_DIR/tls.key
REGISTRY_CERT=$REGISTRY_CERT_DIR/tls.crt
REGISTRY_CSR=$REGISTRY_CERT_DIR/registry-proxy.csr
REGISTRY_EXTFILE=$REGISTRY_CERT_DIR/extfile.cnf

echo subjectAltName = IP:$IP > $REGISTRY_EXTFILE

cat >>$OPENSSL_CONFIG <<EOL
[ req ]
default_bits        = 2048
req_extensions      = req_ext
x509_extensions     = x509_ext
string_mask         = utf8only
distinguished_name  = subject

[ subject ]

# For simplicity, I will skip over the contents.
# ...

[ x509_ext ]

subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid,issuer

basicConstraints        = CA:FALSE
keyUsage                = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names

[ req_ext ]

subjectKeyIdentifier    = hash

basicConstraints        = CA:FALSE
keyUsage                = digitalSignature, keyEncipherment
subjectAltName          = @alternate_names

[ alternate_names ]

IP.1 = ${IP}
EOL

# Private key
openssl genrsa -out $CA_KEY 2048

# Public root CA
openssl req -subj "/CN=Nerdia Root CA" -x509 -new -nodes -key $CA_KEY -sha256 -days $LIFESPAN_DAYS -out $CA_PEM

# Create a cert for docker registry
openssl genrsa -out $REGISTRY_CERT_KEY 2048
openssl req -subj "/CN=${IP}" -config $OPENSSL_CONFIG -new -key $REGISTRY_CERT_KEY -out $REGISTRY_CSR
openssl x509 -req -in $REGISTRY_CSR -CA $CA_PEM -CAkey $CA_KEY -CAcreateserial -out $REGISTRY_CERT -days $LIFESPAN_DAYS -sha256 -extfile $REGISTRY_EXTFILE

【问题讨论】:

  • 嗨,您是否尝试过将此设置与安装了 Docker 的普通 VM 一起使用。它会产生相同的错误吗?您还可以告诉您正在运行哪个确切的GKE 版本(以及节点映像)吗?
  • 所有自签名证书都会产生这个错误:x509: certificate signed by unknown authority.
  • @DawidKruk GKE 版本是1.19.9-gke.1400,节点图像是gke-1199-gke1400-cos-85-13310-1209-12-v210407-c-pre。不,我没有用普通的VM 尝试过这个设置。
  • 您引用的图像使用 containerd 作为 CRI,而不是 Docker。您可以在此处阅读更多信息:cloud.google.com/kubernetes-engine/docs/concepts/…。请尝试重新启动 containerd 而不是 Docker。您还可以详细介绍一下您的用例吗?使用这种方法有什么特别的原因吗?作为替代方案,您可以尝试使用已与GKE 集成的Container registry
  • @DawidKruk 是的,这是一个正确的解决方案,谢谢,当我在谷歌云文档中找到这个主题时,我也做出了这个决定。我不能使用 GCR,因为我需要严格划分不同存储库的权限,所以我为每个用户使用自己的注册表。

标签: docker google-cloud-platform openssl ssl-certificate google-kubernetes-engine


【解决方案1】:

这个特定问题中的问题与GKE 正在使用的CRI 有关。

引用略有修改的官方文档(部分):

OS Node images Description
Container-Optimized OS Container-Optimized OS with Containerd (cos_containerd) The cos_containerd image uses Containerd as the container runtime directly integrated with Kubernetes. For more information, see Using Containerd images
Container-Optimized OS with Docker (cos) The cos image uses the Docker container runtime

-- Cloud.google.com: Kubernetes Engine: Docs: Concepts: Node images: Available Node images

具体图片:

  • gke-1199-gke1400-cos-85-13310-1209-12-v210407-c-pre

使用containerd 作为CRI 而不是Docker(参见-c-)。因此:$ systemctl restart docker 没有给出预期的结果。解决方案是将systemctl restart ...中的docker替换为containerd

您可以通过以下任一运行来检查您正在使用的CRI

  • $ kubectl get nodes --output wide
  • 签入Cloud Console(Web UI)

附注!

在 Containerd 节点上运行 Docker 命令

虽然 Docker 二进制文件目前在 Containerd 节点上可用,但我们不建议在迁移到 Containerd 后使用它。 Docker 不管理 Kubernetes 在 Containerd 节点上运行的容器,因此您无法使用 Docker 命令或 Docker API 使用它来查看正在运行的 Kubernetes 容器或与之交互。

警告:Docker 无法查看或访问由 Kubernetes 管理的容器或镜像。您的应用程序不应直接与 Docker 交互。对于一般故障排除或调试,请改用 crictl。

-- Cloud.google.com: Kubernetes Engine: Docs: Concepts: Using containerd: Migrating


其他资源:

【讨论】:

  • @WytrzymałyWiktor 是的,这个由 Dawid Kruk 提出的解决方案是正确的。我刚刚通过使用 DaemonSet 在每个节点上将 systemctl restart docker 更改为 systemctl restart containerd 调用,并且在创建 pod 时拉取 docker 映像时证书已获批准。