Estou instalando Home Assistant
em meu cluster K3S Kubernetes por meio do Ansible e quero usar um certificado Let's Encrypt para minha entrada que foi gerada pela Cert-Manager
execução em meu cluster.
Estou usando o seguinte manual ao instalar o 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
Substituí o real FQDN
por um nome pertencente a example.com
. :-)
Alguns pontos-chave:
O Home Assistant suporta criptografia TLS.
Meu primeiro trabalho é, portanto, criar um certificado Let's Encrypt, que estou nomeando homeassistant-tls
. Possui o segredo associado homeassistant-tls-secret
.
O próximo passo é extrair o certificado e a chave do segredo homeassistant-tls-secret
e usá-los para criar os arquivos fullchain.pem
e privkey.pem
no ConfigMap home-config
.
Os arquivos contêm o certificado e a chave decodificados em base64.
Os arquivos de certificado e chave são então armazenados na /ssl
pasta dentro do contêiner, o que leva de volta ao último arquivo importante definido no ConfigMap: configuration.yaml
.
Para habilitar a criptografia TLS, precisamos adicionar as seguintes linhas à http
seção de configuration.yaml:
ssl_certificate: /ssl/fullchain.pem
ssl_key: /ssl/privkey.pem
Tentei chamar os arquivos tls.crt
e tls.key
, mas aparentemente o Home Assistant não gostou. :-)
Tudo o que sei com certeza é que os arquivos devem ser codificados em PEM.
Depois de executar o manual, recebo a seguinte saída:
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
O site está funcionando quando digito o endereço: https://192.168.0.203:8123/
ou https://homeassistant.example.com
no navegador.
No entanto, quando inspeciono os certificados associados, recebo o seguinte:
https://192.168.0.203:803
(LoadBalancer) aponta para o certificado Let's Encrypt, que pelo que sei é porque defini os certificados na/ssl
pasta.https://homeassistant.example.com
(Ingress) aponta para um certificado de cluster Kubernetes genérico.
Então, como faço para Ingress
usar o certificado correto? :-)
Alterar secretName
para homeassist-tls-secret
não funciona com certeza. :-)
O problema que você está enfrentando é que o controlador de ingresso nem sempre capta o nome do jogo que contém seus certificados Let's Encrypt para homeassistant.example.com .
Para resolver seu problema:
Em vez de especificar o secretName para sua entrada aparecer, utilize anotações para fazer referência ao segredo TLS e ao emissor do cluster;
Depois de atualizar o ingresso com anotações, é recomendável reiniciar o pod do controlador nginx-ingress para selecionar as alterações
Ao usar anotações, você fornece maior contexto ao controlador de entrada. Ele pode aproveitar o emissor do cluster para validar os certificados e usar o segredo referenciado homeassistant-tls-secret para atender visitantes seguros em homeassistant.example.Com
Os padrões e etapas de configuração associados ao uso de ingress-nginx com certificados Lets Encrypt por meio de anotações são normalmente os mesmos para k8s e k3s.
Para mais informações, consulte este blog Medium de Ivan Khramov
Uma rápida reformatação e explicação do meu comentário à resposta de Sai Chandini Routhu:
O Medium Blog de Ivan Khramov estava quase certo sobre o que estava acontecendo, embora sua implementação não fosse compatível com meu cluster, mas considerando que sua postagem no blog tem 6 anos , atribuirei isso ao Kubernetes que fez algumas renomeações enquanto isso.
Como afirmado no meu comentário, não há nenhuma anotação nomeada
nginx.ingress.kubernetes.io/ssl-secret
.A correspondência mais próxima é nginx.ingress.kubernetes.io/proxy-ssl-secret: secretName , mas mesmo isso não funcionou durante os experimentos.
O que descobri que funcionou é que, se eu renomear
secretName
minha configuração de entrada dehomeassistant-tls
atéhomeassistant-ingress-tls
então, obterei o resultado que desejo.Para referência, consulte a configuração abaixo que está funcionando conforme o esperado:
A razão pela qual está funcionando é porque o ingresso está chamando
cert-manager
para criar um novo certificado que é essencialmente uma cópia do certificado instalado no contêiner.(Não verifiquei se o código hash em ambos os certificados é o mesmo).
Depois fico com dois certificados como pode ser visto aqui:
(Acho que deveria renomear minha definição de
homeassistant-tls
). :-)Isso faz com que meu navegador sempre veja o certificado Let's Encrypt, não importa se eu chamo o site através do endereço IP e, assim, acessando meu
Load Balancer
ou via DNS e acessando o arquivoIngress
.Eu estou feliz agora. :-)