第77节 管理集群中的 TLS 认证
❤️💕💕新时代拥抱云原生,云原生具有环境统一、按需付费、即开即用、稳定性强特点。Myblog:http://nsddd.top
[TOC]
管理集群中的 TLS 认证
Kubernetes 提供 certificates.k8s.io
API,可让你配置由你控制的证书颁发机构(CA) 签名的 TLS 证书。 你的工作负载可以使用这些 CA 和证书来建立信任。
certificates.k8s.io
API使用的协议类似于 ACME 草案。
集群中的 TLS 信任
信任 Pod 中运行的应用程序所提供的自定义 CA 通常需要一些额外的应用程序配置。 你需要将 CA 证书包添加到 TLS 客户端或服务器信任的 CA 证书列表中。 例如,你可以使用 Golang TLS 配置通过解析证书链并将解析的证书添加到 tls.Config
结构中的 RootCAs
字段中。
说明:
即使自定义 CA 证书可能包含在文件系统中(在 ConfigMap
kube-root-ca.crt
中), 除了验证内部 Kubernetes 端点之外,你不应将该证书颁发机构用于任何目的。 内部 Kubernetes 端点的一个示例是默认命名空间中名为kubernetes
的服务。如果你想为你的工作负载使用自定义证书颁发机构,你应该单独生成该 CA, 并使用你的 Pod 有读权限的 ConfigMap 分发该 CA 证书。
请求证书
以下部分演示如何为通过 DNS 访问的 Kubernetes 服务创建 TLS 证书。
说明: 本教程使用 CFSSL:Cloudflare's PKI 和 TLS 工具包 点击此处了解更多信息。
创建证书签名请求
通过运行以下命令生成私钥和证书签名请求(或 CSR):
cat <<EOF | cfssl genkey - | cfssljson -bare server
{
"hosts": [
"my-svc.my-namespace.svc.cluster.local",
"my-pod.my-namespace.pod.cluster.local",
"192.0.2.24",
"10.0.34.2"
],
"CN": "my-pod.my-namespace.pod.cluster.local",
"key": {
"algo": "ecdsa",
"size": 256
}
}
EOF
其中 192.0.2.24
是服务的集群 IP,my-svc.my-namespace.svc.cluster.local
是服务的 DNS 名称,10.0.34.2
是 Pod 的 IP,而 my-pod.my-namespace.pod.cluster.local
是 Pod 的 DNS 名称。 你能看到的输出类似于:
2022/02/01 11:45:32 [INFO] generate received request
2022/02/01 11:45:32 [INFO] received CSR
2022/02/01 11:45:32 [INFO] generating key: ecdsa-256
2022/02/01 11:45:32 [INFO] encoded CSR
此命令生成两个文件;它生成包含 PEM 编码 PKCS#10 证书请求的 server.csr
, 以及 PEM 编码密钥的 server-key.pem
,用于待生成的证书。
创建证书签名请求(CSR)对象发送到 Kubernetes API
你可以使用以下命令创建 CSR 清单(YAML 格式),并发送到 API 服务器:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: my-svc.my-namespace
spec:
request: $(cat server.csr | base64 | tr -d '\n')
signerName: example.com/serving
usages:
- digital signature
- key encipherment
- server auth
EOF
请注意,在步骤 1 中创建的 server.csr
文件是 base64 编码并存储在 .spec.request
字段中的。你还要求提供 “digital signature(数字签名)”, “密钥加密(key encipherment)” 和 “服务器身份验证(server auth)” 密钥用途, 由 example.com/serving
示例签名程序签名的证书。 你也可以要求使用特定的 signerName
。更多信息可参阅 支持的签署者名称。
在 API server 中可以看到这些 CSR 处于 Pending 状态。执行下面的命令你将可以看到:
kubectl describe csr my-svc.my-namespace
批准证书签名请求(CSR)
证书签名请求 的批准或者是通过自动批准过程完成的,或由集群管理员一次性完成。 如果你被授权批准证书请求,你可以使用 kubectl
来手动完成此操作;例如:
kubectl certificate approve my-svc.my-namespace
判断状态:Status: Approved
你现在应该能看到如下输出:
controlplane $ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR REQUESTEDDURATION CONDITION
csr-46sxj 37d kubernetes.io/kube-apiserver-client-kubelet system:bootstrap:z6kr08 <none> Approved,Issued
csr-6z592 38d kubernetes.io/kube-apiserver-client-kubelet system:node:controlplane <none> Approved,Issued
my-svc.my-namespace 9m17s example.com/serving kubernetes-admin <none> Approved
这意味着证书请求已被批准,并正在等待请求的签名者对其签名。
签名证书签名请求(CSR)
接下来,你将扮演证书签署者的角色,颁发证书并将其上传到 API 服务器。
签名者通常会使用其 signerName
查看对象的 CertificateSigningRequest API, 检查它们是否已被批准,为这些请求签署证书,并使用已颁发的证书更新 API 对象状态。
创建证书颁发机构
你需要授权在新证书上提供数字签名。
首先,通过运行以下命令创建签名证书:
cat <<EOF | cfssl gencert -initca - | cfssljson -bare ca
{
"CN": "My Example Signer",
"key": {
"algo": "rsa",
"size": 2048
}
}
EOF
你应该看到类似于以下的输出:
2022/02/01 11:50:39 [INFO] generating a new CA key and certificate from CSR
2022/02/01 11:50:39 [INFO] generate received request
2022/02/01 11:50:39 [INFO] received CSR
2022/02/01 11:50:39 [INFO] generating key: rsa-2048
2022/02/01 11:50:39 [INFO] encoded CSR
2022/02/01 11:50:39 [INFO] signed certificate with serial number 263983151013686720899716354349605500797834580472
这会产生一个证书颁发机构密钥文件(ca-key.pem
)和证书(ca.pem
)。
下载证书并使用它
现在,作为请求用户,你可以通过运行以下命令下载颁发的证书并将其保存到 server.crt
文件中:
CSR 被签署并获得批准后,你应该看到以下内容:
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' \
| base64 --decode > server.crt
现在你可以将 server.crt
和 server-key.pem
填充到 Secret 中, 稍后你可以将其挂载到 Pod 中(例如,用于提供 HTTPS 的网络服务器)。
kubectl create secret tls server --cert server.crt --key server-key.pem
secret/server created
最后,你可以将 ca.pem
填充到 ConfigMap 并将其用作信任根来验证服务证书:
kubectl create configmap example-serving-ca --from-file ca.crt=ca.pem
configmap/example-serving-ca created
批准证书签名请求(CSR)
Kubernetes 管理员(具有适当权限)可以使用 kubectl certificate approve
和 kubectl certificate deny
命令手动批准(或拒绝)证书签名请求(CSR)。 但是,如果你打算大量使用此 API,则可以考虑编写自动化的证书控制器。
注意:
批准证书 CSR 的能力决定了在你的环境中谁信任谁。 不应广泛或轻率地授予批准 CSR 的能力。
在授予 approve
权限之前,你应该确保自己充分了解批准人的验证要求和颁发特定证书的后果。
无论上述机器或人使用 kubectl,“批准者”的作用是验证 CSR 满足如下两个要求:
- CSR 的 subject 控制用于签署 CSR 的私钥。这解决了伪装成授权主体的第三方的威胁。 在上述示例中,此步骤将验证该 Pod 控制了用于生成 CSR 的私钥。
- CSR 的 subject 被授权在请求的上下文中执行。 这点用于处理不期望的主体被加入集群的威胁。 在上述示例中,此步骤将是验证该 Pod 是否被允许加入到所请求的服务中。
当且仅当满足这两个要求时,审批者应该批准 CSR,否则拒绝 CSR。
有关证书批准和访问控制的更多信息, 请阅读证书签名请求参考页。
手动轮换 CA 证书
注意:
确保备份你的证书目录、配置文件以及其他必要文件。
这里的方法假定 Kubernetes 的控制面通过运行多个 API 服务器以高可用配置模式运行。 另一假定是 API 服务器可体面地终止,因而客户端可以彻底地与一个 API 服务器断开 连接并连接到另一个 API 服务器。
如果集群中只有一个 API 服务器,则在 API 服务器重启期间会经历服务中断期。
将新的 CA 证书和私钥(例如:
ca.crt
、ca.key
、front-proxy-ca.crt
和front-proxy-client.key
)分发到所有控制面节点,放在其 Kubernetes 证书目录下。更新 kube-controller-manager 的
--root-ca-file
标志,使之同时包含老的和新的 CA,之后重启 kube-controller-manager。自此刻起,所创建的所有ServiceAccount 都会获得同时包含老的 CA 和新的 CA 的 Secret。
创建外部负载均衡器
创建服务时,你可以选择自动创建云网络负载均衡器。 负载均衡器提供外部可访问的 IP 地址,可将流量发送到集群节点上的正确端口上 (假设集群在支持的环境中运行,并配置了正确的云负载均衡器驱动包)。
基于清单文件创建服务
要创建外部负载均衡器,请将以下内容添加到你的 Service 清单文件:
type: LoadBalancer
你的清单文件可能会如下所示:
apiVersion: v1
kind: Service
metadata:
name: example-service
spec:
selector:
app: example
ports:
- port: 8765
targetPort: 9376
type: LoadBalancer
使用 kubectl 创建 Service
你也可以使用 kubectl expose
命令及其 --type=LoadBalancer
参数创建服务:
kubectl expose deployment example --port=8765 --target-port=9376 \
--name=example-service --type=LoadBalancer
此命令通过使用与引用资源(在上面的示例的情况下,名为 example
的 Deployment) 相同的选择器来创建一个新的服务。
找到你的 IP 地址
你可以通过 kubectl
获取服务信息,找到为你的服务创建的 IP 地址:
kubectl describe services example-service
这将获得类似如下输出:
Name: example-service
Namespace: default
Labels: app=example
Annotations: <none>
Selector: app=example
Type: LoadBalancer
IP Families: <none>
IP: 10.3.22.96
IPs: 10.3.22.96
LoadBalancer Ingress: 192.0.2.89
Port: <unset> 8765/TCP
TargetPort: 9376/TCP
NodePort: <unset> 30593/TCP
Endpoints: 172.17.0.3:9376
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
负载均衡器的 IP 地址列在 LoadBalancer Ingress
旁边。
说明:
如果你在 Minikube 上运行服务,你可以通过以下命令找到分配的 IP 地址和端口:
minikube service example-service --url
保留客户端源 IP
默认情况下,目标容器中看到的源 IP 将不是客户端的原始源 IP。 要启用保留客户端 IP,可以在服务的 .spec
中配置以下字段:
.spec.externalTrafficPolicy
- 表示此 Service 是否希望将外部流量路由到节点本地或集群范围的端点。 有两个可用选项:Cluster
(默认)和Local
。Cluster
隐藏了客户端源 IP,可能导致第二跳到另一个节点,但具有良好的整体负载分布。Local
保留客户端源 IP 并避免 LoadBalancer 和 NodePort 类型服务的第二跳, 但存在潜在的不均衡流量传播风险。.spec.healthCheckNodePort
- 指定服务的 healthcheck nodePort(数字端口号)。 如果你未指定healthCheckNodePort
,服务控制器从集群的 NodePort 范围内分配一个端口。 你可以通过设置 API 服务器的命令行选项--service-node-port-range
来配置上述范围。 在服务type
设置为 LoadBalancer 并且externalTrafficPolicy
设置为Local
时, Service 将会使用用户指定的healthCheckNodePort
值(如果你指定了它)。
可以通过在服务的清单文件中将 externalTrafficPolicy
设置为 Local 来激活此功能。比如:
apiVersion: v1
kind: Service
metadata:
name: example-service
spec:
selector:
app: example
ports:
- port: 8765
targetPort: 9376
externalTrafficPolicy: Local
type: LoadBalancer
一些云服务供应商的负载均衡服务不允许你为每个目标配置不同的权重。
由于每个目标在向节点发送流量方面的权重相同,因此外部流量不会在不同 Pod 之间平均负载。 外部负载均衡器不知道每个节点上用作目标的 Pod 数量。
在 NumServicePods << _NumNodes
或 NumServicePods >> NumNodes
时, 即使没有权重,也会看到接近相等的分布。
内部 Pod 到 Pod 的流量应该与 ClusterIP 服务类似,所有 Pod 的概率相同。
回收负载均衡器
特性状态: Kubernetes v1.17 [stable]
在通常情况下,应在删除 LoadBalancer 类型 Service 后立即清除云服务供应商中的相关负载均衡器资源。 但是,众所周知,在删除关联的服务后,云资源被孤立的情况很多。 引入了针对服务负载均衡器的终结器保护,以防止这种情况发生。 通过使用终结器,在删除相关的负载均衡器资源之前,也不会删除服务资源。
具体来说,如果服务具有 type
LoadBalancer,则服务控制器将附加一个名为 service.kubernetes.io/load-balancer-cleanup
的终结器。 仅在清除负载均衡器资源后才能删除终结器。 即使在诸如服务控制器崩溃之类的极端情况下,这也可以防止负载均衡器资源悬空。
外部负载均衡器供应商
请务必注意,此功能的数据路径由 Kubernetes 集群外部的负载均衡器提供。
当服务 type
设置为 LoadBalancer 时,Kubernetes 向集群中的 Pod 提供的功能等同于 type
设置为 ClusterIP,并通过使用托管了相关 Kubernetes Pod 的节点作为条目对负载均衡器 (从外部到 Kubernetes)进行编程来扩展它。 Kubernetes 控制平面自动创建外部负载均衡器、健康检查(如果需要)和包过滤规则(如果需要)。 一旦云服务供应商为负载均衡器分配了 IP 地址,控制平面就会查找该外部 IP 地址并将其填充到 Service 对象中。
Kubernetes Ingress 配置泛域名 TLS 证书
让 Ingress 高可用可以用 LB, 当然也有 Local 的方法,
这里录了利用 let's encrytp
泛域名证书实现 Kubernetes 集群外部服务自动证书配置和证书到期自动更新,支持 HTTPS 访问。我们还部署了证书自动分发组件,实现证书文件自动分发到其他 namespace 。
- 创建 Ingress 选用 HTTPS 监听协议时,选用合适的服务器证书能够确保访问安全。
- 为所有的 HTTPS 域名绑定同一个证书,简化配置 Ingress 下所有 HTTPS 规则的证书,使更新操作更加便捷。
- 为不同的域名绑定不同的证书,改善服务器与客户端 SSL/TLS。
利用 dnspod 、 cert-manager 、let’s encrytp 等开源组件,实现泛域名证书的自动生成、续期管理,为现有kubernetes 集群应用启动 HTTPS,提高系统安全性。
架构:
在 Kubernetes 集群中使用 HTTPS 协议,需要一个证书管理器、一个证书自动签发服务
cert-manager 是一个云原生证书管理开源项目,用于在 Kubernetes 集群中提供 HTTPS 证书并自动续期,支持 Let’s Encrypt, HashiCorp Vault 这些免费证书的签发。在Kubernetes集群中,我们可以通过 Kubernetes Ingress 和 Let’s Encrypt 实现外部服务的自动化 HTTPS。
Issuers/ClusterIssuers:定义使用什么证书颁发机构 (CA) 来去颁发证书,Issuers 和 ClusterIssuers 区别是: issuers
是一个名称空间级别的资源,只能用来签发自己所在 namespace 下的证书,ClusterIssuer 是个集群级别的资源 可以签发任意 namespace 下的证书
Certificate:定义所需的 X.509 证书,该证书将更新并保持最新。Certificate 是一个命名空间资源,当 Certificate 被创建时,它会去创建相应的 CertificateRequest 资源来去申请证书。
安装证书管理器
安装证书管理器比较简单,直接执行以下脚本就可以了。
kubectl create ns cert-manager
helm uninstall cert-manager -n cert-manager
helm install cert-manager jetstack/cert-manager \
-n cert-manager \
--version v1.8.0 \
--set installCRDs=true \
--set prometheus.enabled=false \
--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=119.29.29.29:53\,8.8.8.8:53}'
选择证书颁发者
cert-manager支持以下几种证书颁发者
- SelfSigned
- CA
- Vault
- Venafi
- External
- ACME 我们选择使用ACME来颁发证书。
选择证书校验方式
常用的校验方式有 HTTP-01 、DNS-01 。
DNS-01 校验原理
DNS-01 的校验原理是利用 DNS 提供商的 API Key 拿到 DNS 控制权限, 在 Let’s Encrypt 为 ACME 客户端提供令牌后,ACME 客户端 (cert-manager) 将创建从该令牌和我的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge。 然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书。此方法支持泛域名证书。
HTTP-01 校验原理
HTTP-01 的校验原理是给域名指向的 HTTP 服务增加一个临时 location ,Let’s Encrypt 会发送 http 请求,参数中 YOUR_DOMAIN 就是被校验的域名,TOKEN 是 ACME 协议的客户端负责放置的文件,ACME 客户端就是 cert-manager,它通过修改或创建 Ingress 规则来增加这个临时校验路径并指向提供 TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,不支持泛域名证书。
配置
HTTP-01 配置示例
这个配置示例仅供参考,使用这种方式,有多少的 ingress 服务,就需要申请多少张证书 ,比较麻烦,但是配置较为简单,不依赖 DNS 服务商。
1. 创建 CA 群集证书颁发者
证书管理器需要 Issuer 或 ClusterIssuer 资源,才能颁发证书。 这两种 Kubernetes 资源的功能完全相同,区别在于 Issuer 适用于单一命名空间,而 ClusterIssuer 适用于所有命名空间。 ClusterIssuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: xxxx@xyz.cn
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-account-key
solvers:
- http01:
ingress:
class: nginx
说明:
metadata.name
: 是我们创建的签发机构的名称,后面我们创建证书的时候会引用它spec.acme.email
: 是你自己的邮箱,证书快过期的时候会有邮件提醒,不过 cert-manager 会利用 acme 协议自动给我们重新颁发证书来续期spec.acme.server
: 是 acme 协议的服务端,我们使用 Let’s Encryptspec.acme.privateKeySecretRef
: 指示此签发机构的私钥将要存储到哪个 Secret 对象中spec.acme.solvers
: 这里指示签发机构校验方式,有 http01 和 dns01 两种,该字段下配置的 class 和 name 只能同时存在一个, class 指定使用的 ingress class 名称, name 比较少用,通常用于 kubernetes 的 ingress。
kubectl apply -f ClusterIssuer.yaml -n cert-manager
2. 创建 ingress 服务
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/proxy-body-size: "0"
name: ingress-wikijs
spec:
ingressClassName: nginx
rules:
- host: wiki.xyz.cn
http:
paths:
- backend:
service:
name: wikijs
port:
number: 3000
path: /
pathType: Prefix
tls:
- hosts:
- wikijs.xyz.cn
secretName: ingress-wikijs-tls
注意:
在 annotations 里 设置cert-manager.io/cluster-issuer
为签名创建的集群证书颁发者 letsencrypt
使用 yaml 文件创建 ingress 后,就可以使用该 ingress 对外提供 https 服务了。
# 创建 ingress
kubectl apply -f ingress-wikijs.yaml -n infra
# 查看证书是否自动创建成功
kubectl -n infra get certificate
DNS01配置示例
使用这种方式需要 DNS 服务商支持通过 API 创建 DNS 记录,正好我的 DNS 服务商是 dnspod 支持,因此在我们的及群里,最终采用了这种方式。
这个方式的配置会比较麻烦,踩了很久的坑,主要是因为我的集群启用了本地 DNS 服务器,默认 cert-manager 会通过本地 DNS 服务器去验证通过 API 创建的 DNS txt记录,会一直检查不到新增的 txt 记录,造成在 challenge 阶段就一直 pendding。解决方案附后。
1. 在 dnspod 创建 API ID 和 API Token
参考dnspod 云官方文档 记录下创建的 API ID 和 API Token 。
<API ID >
<API Token>
2. 安装 cert-manager-webhook-dnspod
使用 helm 安装 roc/cert-manager-webhook-dnspod。
helm repo add roc https://charts.imroc.cc
helm uninstall cert-manager-webhook-dnspod -n cert-manager
helm install cert-manager-webhook-dnspod roc/cert-manager-webhook-dnspod \
-n cert-manager \
--set clusterIssuer.secretId=<API ID > \
--set clusterIssuer.secretKey=<API Token> \
--set clusterIssuer.email=xxxx@xyz.cn
3. 创建泛域名证书
xyz-crt.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: xyz-crt
spec:
secretName: xyz-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "*.xyz.cn"
4. 验证证书
查看证书是否创建成功
[root@ks-master infra]# kubectl get Certificate -n cert-manager
NAME READY SECRET AGE
cert-manager-webhook-dnspod-ca True cert-manager-webhook-dnspod-ca 18m
cert-manager-webhook-dnspod-webhook-tls True cert-manager-webhook-dnspod-webhook-tls 18m
xyz-crt True xyz-crt 3m12s
以上可以看出 xyz-crt 已经创建成功, READY 状态也是 True。
查看证书对应的域名
[root@ks-master infra]# kubectl describe Certificate xyz-crt -n cert-manager
Name: xyz-crt
Namespace: cert-manager
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Creation Timestamp: 2022-05-07T14:19:07Z
Generation: 1
Managed Fields:
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
.:
f:conditions:
Manager: cert-manager-certificates-trigger
Operation: Update
Subresource: status
Time: 2022-05-07T14:19:07Z
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:dnsNames:
f:issuerRef:
.:
f:group:
f:kind:
f:name:
f:secretName:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2022-05-07T14:19:07Z
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
f:revision:
Manager: cert-manager-certificates-issuing
Operation: Update
Subresource: status
Time: 2022-05-07T14:19:14Z
API Version: cert-manager.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
f:conditions:
k:{"type":"Ready"}:
.:
f:lastTransitionTime:
f:message:
f:observedGeneration:
f:reason:
f:status:
f:type:
f:notAfter:
f:notBefore:
f:renewalTime:
Manager: cert-manager-certificates-readiness
Operation: Update
Subresource: status
Time: 2022-05-07T14:19:14Z
Resource Version: 4784901
UID: f2c9be82-f4cb-4243-b2c3-19f64242cc91
Spec:
Dns Names:
*.xyz.cn
Issuer Ref:
Group: cert-manager.io
Kind: ClusterIssuer
Name: dnspod
Secret Name: xyz-crt
Status:
Conditions:
Last Transition Time: 2022-05-07T14:19:14Z
Message: Certificate is up to date and has not expired
Observed Generation: 1
Reason: Ready
Status: True
Type: Ready
Not After: 2022-08-05T13:19:11Z
Not Before: 2022-05-07T13:19:12Z
Renewal Time: 2022-07-06T13:19:11Z
Revision: 1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 4m35s cert-manager-certificates-trigger Issuing certificate as Secret does not exist
Normal Generated 4m35s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "xyz-crt-4ml59"
Normal Requested 4m35s cert-manager-certificates-request-manager Created new CertificateRequest resource "xyz-crt-r76wp"
Normal Issuing 4m28s cert-manager-certificates-issuing The certificate has been successfully issued
[root@ks-master infra]#
从 Certificate 的描述信息可以看到,这个证书是对应所有 *.xyz.cn 的泛域名。所以可以直接用在集群的任何地方。
查看证书内容
[root@ks-master infra]# kubectl describe secret xyz-crt -n cert-manager
Name: xyz-crt
Namespace: cert-manager
Labels: <none>
Annotations: cert-manager.io/alt-names: *.xyz.cn
cert-manager.io/certificate-name: xyz-crt
cert-manager.io/common-name: *.xyz.cn
cert-manager.io/ip-sans:
cert-manager.io/issuer-group: cert-manager.io
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: dnspod
cert-manager.io/uri-sans:
Type: kubernetes.io/tls
Data
====
tls.crt: 5587 bytes
tls.key: 1675 bytes
TLS 证书保存在 cert-manager 命名空间里的 xyz-crt secret。可以供所有 *.xyz.cn 的服务使用。
其他
这个过程中,最大的坑是,我的集群使用了自建的 DNS 服务器,默认 cert-manager 会使用这个集群的自建 DNS SERVER 进行证书发行的验证,虽然通过调用 dnspod 的 webook 在 腾讯云 DNS 服务器上创建的 _acme-challenge 握手数据,但是在我的 自建 DNS 里是查不到的,所以会一直卡 pending 状态,
[root@ks-master infra]# kubectl get challenge -A
NAMESPACE NAME STATE DOMAIN AGE
cert-manager xyz-crt-f9kp6-381578565-136350475 pending xyz.cn 24s
查看原因是: Waiting for DNS-01 challenge propagation: DNS record for "xyz.cn" not yet
[root@ks-master infra]# kcm describe challenge xyz-crt-f9kp6-381578565-136350475
Name: xyz-crt-f9kp6-381578565-136350475
Namespace: cert-manager
Labels: <none>
Annotations: <none>
API Version: acme.cert-manager.io/v1
Kind: Challenge
---
中间略
---
Status:
Presented: true
Processing: true
Reason: Waiting for DNS-01 challenge propagation: DNS record for "xyz.cn" not yet propagated
State: pending
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 41s cert-manager-challenges Challenge scheduled for processing
Normal Presented 39s cert-manager-challenges Presented challenge using DNS-01 challenge mechanism
查了很多资料,在官网上找到解决方案。办法是让 cert-manager 强制使用指定的 DNS 服务器进行握手验证。
我是用的是 helm 安装 cert-manager,所以添加一下 set 参数
--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=119.29.29.29:53\,8.8.8.8:53}'
使用 TLS 证书配置 ingress
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: wikijs
namespace: infra
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: '0'
spec:
ingressClassName: nginx
tls:
- hosts:
- wiki.xyz.cn
secretName: xyz-crt
rules:
- host: wiki.xyz.cn
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: wikijs
port:
number: 3000
以上配置完成后,就可以使用 https 来访问新的 wiki.js 服务了。
Let’s Encrypt
为了在您的网站上启用 HTTPS,您需要从证书颁发机构(CA)获取证书(一种文件)。 Let’s Encrypt 正是其中一家证书颁发机构。 要从 Let’s Encrypt 获取您网站域名的证书,您必须证明您对域名的实际控制权。 这一过程通常由 Web 主机上运行的 ACME 协议客户端完成。
申请证书的最佳方式取决于您是否具备服务器的命令行访问权限(也称为 SSH 权限)。 如果您仅使用控制面板(例如 cPanel、Plesk 或 WordPress)管理您的网站,您很有可能没有命令行访问权限。 您可以联系您的托管服务提供商确认。
拥有命令行访问权限
我们建议大多数具有命令行访问权限的人使用 Certbot ACME 客户端。 它可以在不下线您的服务器的前提下自动执行证书颁发和安装。 对于不需要自动配置的用户,Certbot 还提供专家模式。 它易于使用,适用于许多操作系统,并且具有出色的(注:英文)文档。 前往 Certbot 官网即可获取针对各类操作系统与服务器软件的使用说明。
如果 Certbot 不能满足您的需求,或者您想尝试别的客户端,还有更多 ACME 客户端可供选择。 选定 ACME 客户端软件后,请参阅该客户端的文档。
END 链接
✴️版权声明 © :本书所有内容遵循CC-BY-SA 3.0协议(署名-相同方式共享)©