导读
本文描述了两种场景下,申请Let’s Encrypt证书的途径:
- 云服务器中,通过K8S集群中部署cert-manager来申请,这种方式下,您需要具备如下条件:
- 具备独立公网IP资源的K8S集群(比如公有云服务器上运行的K8S集群)
- K8S集群已经安装了Ingress控制器
- 服务器已经安装了helm
- 一个域名,且指向该公网IP
- 对于国内服务器,域名已经备案(如果没有备案,将不能通过cert-manager申请证书)
- 在云服务器中,通过安装certbot来申请证书,这种方式下,您需要具备如下条件:
- 具备独立公网IP资源的云服务器(本文的脚本为centos 7.x适用的脚本)
- 一个域名,且指向该公网IP
- 对于国内服务器,域名已经备案
安装的详细步骤建议参考官网的文档。本文中的具体配置供参考。
方式一:通过在K8S集群中部署cert-manager申请
通过helm安装
执行以下命令安装(详情参见官网)
helm repo add jetstack https://charts.jetstack.io
helm repo update
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.8.0 \
--set installCRDs=true
安装完成后,通过部署一个测试的Issuer,并签发证书进行测试,也可以通过安装cmctl测试(详情参见官网)
cat <<EOF > test-resources.yaml
apiVersion: v1
kind: Namespace
metadata:
name: cert-manager-test
---
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: test-selfsigned
namespace: cert-manager-test
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: selfsigned-cert
namespace: cert-manager-test
spec:
dnsNames:
- example.com
secretName: selfsigned-cert-tls
issuerRef:
name: test-selfsigned
EOF
kubectl apply -f test-resources.yaml
kubectl describe certificate -n cert-manager-test
创建ACME方式的ClusterIssuer
通过如下命令创建ClusterIssuer(集群级的证书签发机构):
cat << __EOF__ > clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
preferredChain: "ISRG Root X1"
email: <your email>
privateKeySecretRef:
name: <Cluster Issuer Secret Name>
solvers:
- http01:
ingress:
name: <Exist Ingress Name>
__EOF__
kubectl apply -f clusterissuer.yaml
在上述例子中,solver
表示可以完成Challenge
(Challenge即证书签发机构要求你完成的一项任务,即证明你对域名拥有控制权)的资源。ACME的Challenge分为两种:
- http01:提供一个可以通过域名访问的web服务,证明你拥有该域名
- dns01: 查询域名信息时,能够获得指定的DNS TXT记录,证明你拥有该域名
我们使用http01这种方式。
配置http01 solver时,我们通过下列配置指定现有的ingress:
- http01:
ingress:
name: <Exist Ingress Name>
此时,cert-manager会编辑该Ingress,以使证书签发机构的查询流量走到我们集群内部的solver pod中。
签发证书
安装完后,部署下面的资源签发证书:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: my-certificate
spec:
secretName: my-certificate-tls
issuerRef:
name: letsencrypt-prod # Same to the name of the cluster issuer
kind: ClusterIssuer
dnsNames:
- <your domain>
通过以下命令查看签发的证书是否成功:
kubectl get certificate
如果签发证书不成功,可以根据官网FAQ进行排查。
如果在cert-manager的pod中遇到下面类似的错误,可能是因为域名没有备案:
sync.go:386 cert-manager/challenges/acceptChallenge "msg"="error waiting for authorization" "error"="acme: authorization error for t.sharework.cn: 403 urn:ietf:params:acme:error:unauthorized: : Invalid response from https://dnspod.qcloud.com/static/webblock.html?d=<your domain>: \"
Let’s Encrypt现委托qcloud.com进行域名查询,如果您的域名尚未备案,将得到上述错误。
方式二:通过安装certbot申请
您也可以直接通过安装certbot来进行申请,假设您拥有云服务器,并且在服务器创建时执行了以下脚本(按需要修改前三项参数):
#!/bin/sh
CERT_DOMAIN="your.domain"
CERT_EMAIL="your email"
ROOT_PASSWORD="<root password>"
# Ensure centos-release installed
if test -z $(rpm -qa centos-release); then
yum install -y centos-release
fi
basearch=$(arch)
releasever=$(rpm -q --qf %{version} centos-release)
# Setup nginx
if test -z "$(rpm -qa nginx)"; then
cat << __EOF__ > /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
module_hotfixes=true
__EOF__
REFRESH_INSTALL="y"
yum install -y nginx
systemctl start nginx.service
systemctl enable nginx.service
else
REFRESH_INSTALL="n"
systemctl restart nginx.service
systemctl enable nginx.service
fi
# Setup snapd
yum install -y snapd
systemctl restart snapd.service
systemctl enable snapd
snap install core
snap refresh core
if test ! -d /snap; then
ln -s -d /var/lib/snapd/snap /snap
fi
# Setup certbot
snap install --classic certbot
if test ! -f /usr/bin/certbot; then
ln -s /snap/bin/certbot /usr/bin/certbot
fi
# Enable port 80 and 443
if test ! -z "$(firewall-cmd --state | grep -e "^running")"; then
FIREWALL_POLICY_ADDED=""
if test -z "$(firewall-cmd --list-ports | tr ' ' '\n'|sed 's/[ ]//g' | grep "80/tcp")"; then
firewall-cmd --permanent --add-port=80/tcp
FIREWALL_POLICY_ADDED="80"
fi
if test -z "$(firewall-cmd --list-ports | tr ' ' '\n'|sed 's/[ ]//g' | grep "443/tcp")"; then
firewall-cmd --permanent --add-port=443/tcp
FIREWALL_POLICY_ADDED=$FIREWALL_POLICY_ADDED"443"
fi
if test ! -z "$FIREWALL_POLICY_ADDED"; then
firewall-cmd --reload
fi
fi
cat << __EOF__ > /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost $CERT_DOMAIN;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
__EOF__
# Restart Nginx to accept the new domain
systemctl restart nginx.service
# change root password
echo $ROOT_PASSWORD | passwd --stdin root
cat << __EOF__ >> /etc/profile
echo "Certbot Server"
echo "=============="
echo "You can request certificate by following steps(<IP> is the IP address of THIS VPS) : "
echo ""
echo "1. Setup DNS A record, bind the domain to the <IP>"
echo "2. certbot run --nginx -n --email $CERT_EMAIL -d $CERT_DOMAIN --agree-tos"
echo "3. cd to a proper local directory"
echo "4. scp -r root@<IP>:{/etc/letsencrypt/live/$CERT_DOMAIN,/etc/letsencrypt/options-ssl-nginx.conf,/etc/letsencrypt/ssl-dhparams.pem,/etc/nginx/conf.d/default.conf} ."
echo ""
echo "You can find certificates in sub folder $CERT_DOMAIN, besides with nginx configuration files."
__EOF__
服务器启动后,您可以登录服务器并按照上面的提示进行证书申请。