家里 Homelab 使用了 Let’s Encrypt 的通配符证书提供外网的 HTTPS 访问,内网则是使用 HTTP 或者 IP 直接访问。最近把 Homelab 的外网完全关闭了,通过 VPN 回家以提高安全性。
当全切回内网后,Bitwarden iOS 客户端无法正常使用,在登录时会提示错误。大概原因是 Apple 会禁止使用不安全的连接。
其实应该使用 HTTPS 的,毕竟是一个存储密码的服务,安全性还是很重要的。本文记录了给内网 Homelab 绑定自定与域名以及启用 HTTPS 证书的相关步骤,大致为:
我将创建证书的逻辑整理成了以下脚本,执行根据提示输入即可。
#!/bin/bash
function check_file() {
local file_path="$1"
if [ -e "${file_path}" ]; then
read -p "${file_path} 已存在,是否覆盖?(y/n):" yn
if [[ "${yn}" != "y" ]]; then
echo "操作已取消。"
exit 1
fi
fi
}
# 询问用户 CA 存储的目录
read -p "请输入 CA 存储的目录(例如:/root/my_ca):" ca_dir
mkdir -p "${ca_dir}"
cd "${ca_dir}"
# 询问用户 CA 文件名(默认为 ca.key 和 ca.crt)
read -p "请输入 CA 私钥文件名(默认:ca.key):" ca_key
ca_key=${ca_key:-ca.key}
read -p "请输入 CA 证书文件名(默认:ca.crt):" ca_crt
ca_crt=${ca_crt:-ca.crt}
read -p "请输入 组织名(默认:Homelab.LAB):" org_name
org_name=${org_name:-Homelab.LAB}
check_file "${ca_key}"
check_file "${ca_crt}"
# 询问用户要创建通配符证书的域名(默认为 xxxx.lab)
read -p "请输入要创建通配符证书的域名(默认:xxxx.lab):" domain
domain=${domain:-xxxx.lab}
wildcard_key="wildcard.${domain}.key"
wildcard_csr="wildcard.${domain}.csr"
wildcard_crt="wildcard.${domain}.crt"
wildcard_ext="wildcard.ext"
check_file "${wildcard_key}"
check_file "${wildcard_csr}"
check_file "${wildcard_crt}"
check_file "${wildcard_ext}"
ca_openssl_cnf="ca_openssl.cnf"
check_file "${ca_openssl_cnf}"
cat > "${ca_openssl_cnf}" << EOL
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
[ dn ]
C = ZZ
ST = Utopia
L = The Peach Garden
O = ${org_name}
OU = ${org_name}
CN = CA.${domain}
EOL
# 创建 CA
openssl genrsa -out "${ca_key}" 4096
openssl req -x509 -new -nodes -key "${ca_key}" -sha256 -days 3650 -out "${ca_crt}" -config "${ca_openssl_cnf}"
wildcard_openssl_cnf="wildcard_openssl.cnf"
check_file "${wildcard_openssl_cnf}"
cat > "${wildcard_openssl_cnf}" << EOL
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = req_ext
[ dn ]
C = ZZ
ST = Utopia
L = The Peach Garden
O = ${org_name}
OU = ${org_name}
CN = *.${domain}
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = *.${domain}
DNS.2 = ${domain}
EOL
# 为通配符证书创建私钥
openssl genrsa -out "${wildcard_key}" 2048
# 为通配符证书创建证书签名请求(CSR)
openssl req -new -key "${wildcard_key}" -out "${wildcard_csr}" -config "${wildcard_openssl_cnf}"
# 创建通配符证书的扩展文件
# 其中需要注意参数:extendedKeyUsage = serverAuth 需要添加,
cat > "${wildcard_ext}" << EOL
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = *.${domain}
DNS.2 = ${domain}
EOL
# 使用 CA 对 CSR 文件进行签名,生成通配符证书
openssl x509 -req -in "${wildcard_csr}" -CA "${ca_crt}" -CAkey "${ca_key}" -CAcreateserial -out "${wildcard_crt}" -days 820 -sha256 -extfile "${wildcard_ext}"
echo "创建完成,证书和私钥位于 ${ca_dir} 目录。"
代码执行完成后,会在第一步指定的目录生成几个证书文件:
以上代码中,需要注意两个地方(Apple - Requirements for trusted certificates in iOS 13 and macOS 10.15):
extendedKeyUsage = serverAuth
参数,不添加的话 Safari 可能会提示:“certificate is not standards compliant”-days 820
参数,天数不能大于 825 天,不然 Safari 也会有上面的提示。在 Kubernates 中创建一个名为 helloworld-lab-tls 的通配符证书,需要注意下是使用了通配符的证书文件,而不是 CA 文件。
kubectl create secret tls helloword-lab-tls \
--cert=wildcard.helloword.lab.crt \
--key=wildcard.helloword.lab.key
由于我是区分了 Namespace:
所以需要将证书同步到多个命名空间。我使用了 kuberops/config-syncer 来做多命名空间的同步。
安装 kuberops/config-syncer 比较简单,跟着这 #installation 部分操作就行。
使用也比较简单,步骤是:
# 1. 给证书打注解,支持同步到其他命名空间
kubectl annotate secret \
helloword-lab-tls \
kubed.appscode.com/sync="tls-certs=helloword.lab" \
-n default
# 2. 给需要同步证书的命名空间添加 label,使能将证书同步到当前命名空间
apiVersion: v1
kind: Namespace
metadata:
name: infra
labels:
tls-certs: helloword.lab
# 3. 查看证书是否已经同步到其他命名空间
~/Workspace/kube [main] → kubectl get secret -A | grep helloword-lab-tls
default helloword-lab-tls kubernetes.io/tls 2 44m
selfhosts helloword-lab-tls kubernetes.io/tls 2 22m
infra helloword-lab-tls kubernetes.io/tls 2 22m
部署的相关服务需要使用证书也可以直接在 Ignress
配置上配置,如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: memos-ingress
namespace: selfhosts
annotations:
kubernetes.io/ingress.class: "traefik"
spec:
tls:
- hosts:
- memo.helloword.lab
secretName: helloword-lab-tls
rules:
- host: memo.helloword.lab
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: memos-svc
port:
name: memos-web
添加好配置记得应到 pod,完成以上步骤后,可以在浏览器访问下服务,应该会提示证书错误,接下来就需要给设备添加自签名的通配符证书。
需要注意下,上面在绑定证书时是使用的通配符证书,而在设备上使用时是需要导入 CA 证书。
导入并信任之后为:
sudo cp wildcard.helloword.lab.crt /usr/local/share/ca-certificates
sudo update-ca-certificates
然后 curl 看一下是否有证书错误即可。
Firefox 访问依旧提示证书错误,Firefox 没有使用系统的证书存储,需要自己单独导入一次。
之后再访问就正常了。
iPhone
ca.crt
文件)。它应该在 “针对根证书启用完全信任” 部分。Android(以下来源为 Add & remove certificates - Google)
我家庭网络的核心是 OpenWrt,所以这里贴出 OpenWrt 配置 DNS 的部分。
思路是将指定域名指定到 K3s 上(我的 Kubernates 是 K3s 版本),K3s 的 IP 为: 10.0.0.2
。
OpenWrt - Network - DHCP and DNS - Addresses 配置,格式如下:
/git.helloworld.lab/10.0.0.2
也可以直接通过登录到 OpenWrt 用命令行修改:
/etc/config/dhcp
文件config dnsmasq
部分的底部添加:list address '/git.helloworld.lab/10.0.0.2'
/etc/init.d/dnsmasq restart
给各个设备、路由器都配置好后,就可以完全无障碍访问自签名的 HTTPS 域名了。