我通过 Ansible 在我的 K3S Kubernetes 集群中进行安装,并且我想使用在集群上运行Home Assistant
时生成的 Let's Encrypt 证书作为我的入口。Cert-Manager
我在安装 Home Assistant 时使用以下剧本:
---
- name: Create HomeAssistant namespace
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: home-system
- name: Generate certificate for HomeAssistant
kubernetes.core.k8s:
state: present
definition:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: homeassistant-tls
namespace: home-system
spec:
secretName: homeassistant-tls-secret
commonName: "homeassistant.example.com"
dnsNames:
- "homeassistant.example.com"
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
- name: Get TLS certificate secret
kubernetes.core.k8s_info:
api_version: v1
name: homeassistant-tls-secret
kind: Secret
namespace: home-system
register: tls_secret
- name: Create ConfigMap for HomeAssistant
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: ConfigMap
metadata:
name: home-config
namespace: home-system
data:
fullchain.pem: "{{ tls_secret.resources[0].data['tls.crt'] | b64decode }}"
privkey.pem: "{{ tls_secret.resources[0].data['tls.key'] | b64decode }}"
groups.yaml: |-
scripts.yaml: |-
scenes.yaml: |-
known_devices.yaml: |-
automations.yaml: |-
configuration.yaml: |-
# Loads Default configuration - DO NOT REMOVE
default_config:
# Load frontend themes from the themes folder
frontend:
themes: !include_dir_merge_named themes
# Text-to-speech
tts:
- platform: google_translate
group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
- 10.42.0.0/16
- 10.43.0.0/16
- 192.168.0.0/24
ssl_certificate: /ssl/fullchain.pem
ssl_key: /ssl/privkey.pem
- name: Define storage space for HomeAssistant
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: homeassist-pvc
namespace: home-system
spec:
accessModes:
- ReadWriteOnce
storageClassName: small-longhorn # Store data on only 2 nodes instead of 3
resources:
requests:
storage: 5Gi
- name: Add HomeAssistant StatefulSet
kubernetes.core.k8s:
state: present
definition:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: homeassistant
namespace: home-system
labels:
app: homeassistant
spec:
serviceName: home-svc
replicas: 1
selector:
matchLabels:
app: homeassistant
template:
metadata:
labels:
app: homeassistant
spec:
volumes:
- name: home-config-vol
persistentVolumeClaim:
claimName: homeassist-pvc
- name: home-config-file
configMap:
name: home-config
containers:
- name: homeassistant
image: lscr.io/linuxserver/homeassistant:latest
ports:
- containerPort: 8123
volumeMounts:
- name: home-config-vol
mountPath: /config
- name: home-config-file
mountPath: /config/configuration.yaml
subPath: configuration.yaml
- name: home-config-file
mountPath: /config/automations.yaml
subPath: automations.yaml
- name: home-config-file
mountPath: /config/scripts.yaml
subPath: scripts.yaml
- name: home-config-file
mountPath: /config/scenes.yaml
subPath: scenes.yaml
- name: home-config-file
mountPath: /config/groups.yaml
subPath: groups.yaml
- name: home-config-file
mountPath: /ssl/fullchain.pem
subPath: fullchain.pem
- name: home-config-file
mountPath: /ssl/privkey.pem
subPath: privkey.pem
env:
- name: PUID
value: "1000"
- name: PGID
value: "1000"
- name: TZ
value: "Etc/UTC"
securityContext:
capabilities:
add:
- NET_ADMIN
- NET_RAW
- SYS_ADMIN
priviledged: true
- name: Define HomeAssistant service ports
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Service
metadata:
name: home-svc
namespace: home-system
annotations:
metallb.universe.tf/address-pool: default-pool
spec:
type: LoadBalancer
externalTrafficPolicy: Local
selector:
app: homeassistant
ports:
- name: "8123"
port: 8123
targetPort: 8123
- name: Add HomeAssistant ingress
kubernetes.core.k8s:
state: present
definition:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homeassistant
namespace: home-system
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- homeassistant.example.com
secretName: homeassistant-tls
rules:
- host: 'homeassistant.example.com'
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: home-svc
port:
number: 8123
我已将实际名称替换FQDN
为属于 的名称example.com
。 :-)
几个关键点:
家庭助理支持 TLS 加密。
因此,我的第一份工作是创建一个 Let's Encrypt 证书,我将其命名为homeassistant-tls
。它有相关的秘密homeassistant-tls-secret
。
接下来是从密钥中提取证书和密钥homeassistant-tls-secret
,并使用它来创建文件fullchain.pem
并privkey.pem
在 ConfigMap 中home-config
。
这些文件包含 base64 解码的证书和密钥。
然后,证书和密钥文件存储在/ssl
容器内的文件夹中,这会返回到 ConfigMap 中定义的最后一个重要文件:configuration.yaml
。
为了启用 TLS 加密,我们需要将以下行添加到http
configuration.yaml 部分:
ssl_certificate: /ssl/fullchain.pem
ssl_key: /ssl/privkey.pem
我尝试调用文件tls.crt
和tls.key
,但显然家庭助理不喜欢它。 :-)
我唯一确定的是文件必须是 PEM 编码的。
运行剧本后,我得到以下输出:
root@central:~# kubectl get svc -n home-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
home-svc LoadBalancer 10.43.23.186 192.168.0.203 8123:30630/TCP 81m
root@central:~# kubectl get ingress -n home-system
NAME CLASS HOSTS ADDRESS PORTS AGE
homeassistant nginx homeassistant.example.com 192.168.0.200 80, 443 85m
当我输入地址:https://192.168.0.203:8123/
或https://homeassistant.example.com
在浏览器中时,该网站正在运行。
但是,当我检查相关证书时,我得到以下信息:
https://192.168.0.203:803
(LoadBalancer) 指向 Let's Encrypt 证书,据我所知,这是因为我在文件/ssl
夹中定义了证书。https://homeassistant.example.com
(Ingress) 指向通用 Kubernetes 集群证书。
那么我该如何Ingress
使用正确的证书呢? :-)
更改为secretName
肯定不起作用。 :-)homeassist-tls-secret
您面临的问题是入口控制器并不总是获取包含 homeassistant.example.com 的 Let's Encrypt 证书的游戏名称。
要解决您的问题:
使用注释来引用 TLS 密钥和集群颁发者,而不是为您的入口指定指定密钥名称;
更新入口后出现注释,建议重新启动 nginx-ingress 控制器 pod 以选择更改
通过使用注释,您可以为入口控制器提供更多上下文。它可以利用集群颁发者来验证证书并使用引用的秘密 homeassistant-tls-secret 为 homeassistant.example.Com 上的安全访问者提供服务
对于 k8s 和 k3s,与通过注释使用 Lets Encrypt 证书的 ingress-nginx 相关的标准和配置步骤通常是相同的。
欲了解更多信息,请参阅Ivan Khramov 的Medium博客
对我对 Sai Chandini Routhu 的回答的评论进行快速重新格式化和解释:
Ivan Khramov 的 Medium 博客几乎说到了正在发生的事情,尽管他的实现与我的集群不兼容,但考虑到他的博客文章已经有6 年了,我将其归因于 Kubernetes 同时进行了一些重命名。
正如我的评论中所述,没有名为 的注释
nginx.ingress.kubernetes.io/ssl-secret
。最接近的匹配是nginx.ingress.kubernetes.io/proxy-ssl-secret: SecretName,但即使这样在实验时也不起作用。
我发现有效的是,如果我
secretName
在入口配置中将其重命名为homeassistant-tls
,homeassistant-ingress-tls
那么我将得到我想要的结果。作为参考,请参阅下面的配置,该配置按预期工作:
它起作用的原因是因为入口正在调用
cert-manager
创建一个新证书,该证书本质上是容器中安装的证书的副本。(我还没有检查两个证书上的哈希码是否相同)。
之后我留下了两张证书,如下所示:
(我想我应该在我的定义中进行一些重命名
homeassistant-tls
)。 :-)这使得我的浏览器始终看到 Let's Encrypt 证书,无论我是否通过 IP 地址调用该网站,从而访问我的网站
Load Balancer
或通过 DNS 访问Ingress
.我现在很开心。 :-)