k8s设置证书acme

0. 前置:安装 cert-manager & reflector

0.1 cert-manager(如果已经装了可以跳过)

1
2
3
4
5
6
7
8
9
helm repo add jetstack https://charts.jetstack.io
helm repo update

kubectl create namespace cert-manager || true

helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--set crds.enabled=true \
--wait

0.2 reflector(跨 namespace 同步 Secret 用)

建议装在 kube-system 或单独的 reflector ns,这里用 kube-system 举例。

1
2
3
4
5
6
7
helm repo add emberstack https://emberstack.github.io/helm-charts
helm repo update

helm upgrade --install reflector emberstack/reflector \
--namespace kube-system \
--create-namespace \
--wait

1. ClusterIssuer:Let’s Encrypt + DNS-01 + ECC

文件名:clusterissuer-letsencrypt-prod-ecc.yaml
请根据你的 DNS 提供商修改 solvers 那块示例(下面是 Cloudflare 模板)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod-ecc
spec:
acme:
# ⚠️ 换成你的邮箱
email: you@example.com
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: letsencrypt-prod-ecc-account-key
solvers:
- dns01:
cloudflare: # 如果使用其它 DNS,改成对应 provider
email: you@example.com # Cloudflare 账号邮箱
apiTokenSecretRef:
# 下面的 Secret 请先用 kubectl 创建
name: cloudflare-api-token-secret
key: api-token

配套的 DNS token Secret(Cloudflare 示例):

1
2
3
kubectl create secret generic cloudflare-api-token-secret \
-n cert-manager \
--from-literal=api-token='你的Cloudflare Token'

应用 ClusterIssuer:

1
kubectl apply -f clusterissuer-letsencrypt-prod-ecc.yaml

确认 Ready:

1
2
kubectl describe clusterissuer letsencrypt-prod-ecc
# Type: Ready Status: True 才算 OK

2. Certificate:ECC 通配证书 + 自动加 reflector 注解

文件名:certificate-wildcard-tls-ecc.yaml
⚠️ 把 example.com 换成你的真实域名。
这里利用 secretTemplate 直接给生成的 Secret 打上 reflector 的注解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-tls-ecc
namespace: cert-manager
spec:
# 证书生成后,保存到这个 Secret 名
secretName: wildcard-tls-ecc-secret

# 关键:生成的 Secret 自动带上 reflector 注解,从而自动同步到其它 ns
secretTemplate:
annotations:
reflector.v1.k8s.emberstack.com/reflection-allowed: "true"
reflector.v1.k8s.emberstack.com/reflection-auto-enabled: "true"
# 自动同步到哪些命名空间:
# - 想同步到所有 ns:用 ".*"
# - 想只同步到某些 ns:用逗号+正则,例如 "default,app-.*"
reflector.v1.k8s.emberstack.com/reflection-auto-namespaces: ".*"

issuerRef:
name: letsencrypt-prod-ecc
kind: ClusterIssuer

# ⚠️ 换成你的域名
commonName: "*.example.com"
dnsNames:
- "*.example.com"
- "example.com"

# ECC 私钥配置:ECDSA + P-256
privateKey:
algorithm: ECDSA
size: 256

# 证书总有效期(Let’s Encrypt 一般 90 天,这里是期望值)
duration: 2160h # 90 天
# 距离到期多少时间开始续期
renewBefore: 720h # 30 天

应用:

1
kubectl apply -f certificate-wildcard-tls-ecc.yaml

然后看状态:

1
2
kubectl describe certificate wildcard-tls-ecc -n cert-manager
kubectl get secret wildcard-tls-ecc-secret -n cert-manager

Certificate 变成:

  • Type: Ready Status: True

并且 wildcard-tls-ecc-secret 里有 tls.crt / tls.key 时说明证书已经签好了。

再验证下同步情况(reflector 自动帮你镜像 Secret):

1
2
3
kubectl get secret wildcard-tls-ecc-secret -n default
kubectl get secret wildcard-tls-ecc-secret -n kube-system
kubectl get secret wildcard-tls-ecc-secret -n <你的业务ns>

能看到同名 Secret,就说明「全命名空间统一证书」已经实现 ✅。


3. Ingress-NGINX(或任意 Ingress Controller)

若你已经有 ingress controller,可以跳过安装,直接用第 4 步的 Ingress。

安装 ingress-nginx 示例:

1
2
3
4
5
6
7
8
9
10
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

kubectl create namespace ingress-nginx || true

helm upgrade --install ingress-nginx ingress-nginx/ingress-nginx \
-n ingress-nginx \
--set controller.ingressClassResource.name=nginx \
--set controller.ingressClassResource.default=true \
--wait

4. 所有业务 Namespace 统一使用这张证书的 Ingress 示例

文件名示例:ingress-app-a.yaml
⚠️ 换掉:

  • namespace: app-a
  • host: app-a.example.com
  • service.name: app-a-svc

只要 reflector 已经同步 Secret,这个 Ingress 在任何命名空间都可以直接用同一个 secretName

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-a-ingress
namespace: app-a # 业务命名空间,随便哪个都可以
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
ingressClassName: nginx
tls:
- hosts:
- app-a.example.com # 业务域名
secretName: wildcard-tls-ecc-secret # 所有 ns 统一用这一份 Secret
rules:
- host: app-a.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: app-a-svc
port:
number: 80

另外一个命名空间 app-b 直接复制一份,改 namespace / host / service 就行,secretName 仍然用 wildcard-tls-ecc-secret


5. DNS 解析(最后一步)

在你的 DNS 提供商那里,给这张通配证书配置解析即可:

  • Ingress LB 对外 IP:假设 1.2.3.4
  • 或对外域名:比如 lb-xxxx.cloudprovider.com

方案 A:IP(A 记录)

主机记录 类型
@ A 1.2.3.4
* A 1.2.3.4

方案 B:LB 域名(CNAME)

主机记录 类型
@ CNAME lb-xxxx.cloudprovider.com
* CNAME lb-xxxx.cloudprovider.com

这样:

  • app-a.example.com
  • app-b.example.com
  • ……

都会走同一个 Ingress Controller,用同一张 *.example.com 的 ECC 证书。


总结一下这套“最终版本”

你完成下面 3 件事,这个方案就完全落地了:

  1. ClusterIssuer + Certificate

    • letsencrypt-prod-ecc
    • wildcard-tls-ecc(ECC + 通配 + secretTemplate 里带 reflector 注解)
  2. reflector 安装 OK,且自动把 wildcard-tls-ecc-secret 同步到所有业务 ns

  3. 所有 Ingress 的 spec.tls.secretName 统一写 wildcard-tls-ecc-secret

    • DNS 把 *.你的域名 指到 Ingress LB
评论

:D 一言句子获取中...