mTLS за допомогою Envoy як контейнера-сайдкара
Огляд
У цьому посібнику я покажу, як налаштувати mTLS для додатку, розгорнутого в Kubernetes, з використанням envoy.
Ми поетапно розгорнемо echo-сервер і захистимо його за допомогою mTLS через envoy як контейнер-сайдкар.
Кроки:
- Розгорнути echo-сервер.
- Доступ до echo-сервера через проксі envoy.
- Додати mTLS до проксі envoy.
🗣 Розгортання echo-сервера
Давайте спершу розгорнемо простий echo-сервер і перевіримо його доступність. Для цього я використовую ealen/echo-server і розгорну його з використанням minikube. Однак ви можете використовувати будь-який інший інструмент, наприклад, kind.
Після налаштування нашого кластера minikube застосуємо наступний yaml файл:
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserver-deployment
labels:
app: echoserver
spec:
replicas: 1
selector:
matchLabels:
app: echoserver
template:
metadata:
labels:
app: echoserver
spec:
containers:
- name: echoserver
image: ealen/echo-server:latest
ports:
- containerPort: 80
name: http-web-svc
---
apiVersion: v1
kind: Service
metadata:
name: echoserver-direct-service
labels:
app: echoserver
spec:
type: LoadBalancer
selector:
app: echoserver
ports:
- name: http
protocol: TCP
port: 8082
targetPort: http-web-svc
Запустив:
> kubectl apply -f echoserver.yaml
> minikube tunnel
Ми повинні зуміти зайти на url http://localhost:8082 і побачити відповідь від echo-сервера.
Отже, це поточна налаштування:
Ми можемо безпосередньо отримати доступ до контейнера echo-сервера через порт 8082.
Файли розгортання можна знайти тут: https://github.com/manuelarte/demo-mTLS/tree/master/steps/echoserver-simple
⛩️🗣 Розгортання echo-сервера і проксі envoy
Тепер, замість прямого доступу до echo-сервера, ми введемо проксі envoy.
Отже, ось схема того, що ми хочемо досягти:
У цьому випадку ми не отримуємо доступ до echo-сервера безпосередньо, а робимо це через envoy.
Envoy працює як проксі для нашого сервісу.
Ось файл yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserver-deployment
labels:
app: echoserver
spec:
replicas: 1
selector:
matchLabels:
app: echoserver
template:
metadata:
labels:
app: echoserver
spec:
containers:
- name: echoserver
image: ealen/echo-server:latest
ports:
- containerPort: 80
name: http-web-svc
- name: sidecar
image: envoyproxy/envoy:v1.29-latest
ports:
- containerPort: 8080
name: http-web-envoy
volumeMounts:
- name: config-envoy-vol
mountPath: /etc/envoy
volumes:
- name: config-envoy-vol
configMap:
name: config-envoy
items:
- key: envoy.yaml
path: envoy.yaml
---
apiVersion: v1
kind: Service
metadata:
name: echoserver-envoy-service
labels:
app: echoserver
spec:
type: LoadBalancer
selector:
app: echoserver
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
Як ви можете бачити, нам також потрібен ConfigMap з наступним файлом для envoy
static_resources:
listeners:
- name: echoserver-listener
address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
http_protocol_options:
accept_http_10: true
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: echoserver-route
virtual_hosts:
- name: echoserver
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: echoserver-cluster
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: echoserver-cluster
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: echoserver
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: localhost
port_value: 80
Файли для розгортання можна знайти тут: https://github.com/manuelarte/demo-mTLS/tree/master/steps/echoserver-proxy
🔒⛩️🗣 Розгортання echo-сервера з envoy та mTLS
Тепер давайте налаштуємо envoy для забезпечення взаємного TLS.
- Генерація сертифікатів авторитету (CA) та серверних сертифікатів
Перше, що потрібно зробити — це згенерувати сертифікати
openssl genrsa -out "ca.key" 4096
export CA_SUBJECT="/C=NL/ST=North Holland/L=AMS/O=manuelarte/OU=IT/CN=rootCA"
openssl req -x509 -new -nodes -key "ca.key" -sha256 -days 365 -out "ca.crt" -subj "$CA_SUBJECT"
# Генерація серверного ключа та сертифікату
openssl req -nodes -x509 -sha256 -newkey rsa:4096 \
-keyout key.pem \
-subj /C=NL/ST=NH/O=ING/CN=echoserver-envoy-service \
-out cert.pem \
-addext subjectAltName=DNS:echoserver-envoy-service
Це згенерує:
- ca.crt: Корінний сертифікат авторитету.
- cert.pem: Сертифікат сервера.
- key.pem: Приватний ключ сервера.
Ми додамо ці серверні сертифікати в envoy.yaml.
- Генерація клієнтських сертифікатів
Тепер згенеруємо клієнтські сертифікати:
# Створення приватного ключа для клієнтського сертифіката
openssl genrsa -out client.key 4096
# Генерація запиту на сертифікат для клієнтського сертифіката
openssl req -new -sha256
-out client.csr
# Підписання запиту з використанням збереженого CA для створення клієнтського сертифіката
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-out client.crt \
-days 365 -sha256 -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:localhost,DNS:manuelarte")
Це згенерує:
- client.cert: Клієнтські сертифікати.
- client.key: Приватний ключ клієнта.
Ці сертифікати можна використовувати, наприклад, у команді cURL.
- Envoy.yaml з конфігурацією mTLS
Ось як виглядає новий файл envoy.yaml:
admin:
address:
socket_address:
address: 0.0.0.0
port_value: 9901
static_resources:
listeners:
- name: echoserver-listener
address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
http_protocol_options:
accept_http_10: true
stat_prefix: ingress_http
access_log:
- name: envoy.access_loggers.stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
route_config:
name: echoserver-route
virtual_hosts:
- name: echoserver
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: echoserver-cluster
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
require_client_certificate: true
common_tls_context:
validation_context:
trusted_ca:
filename: /etc/certs/ca.crt
tls_certificates:
- certificate_chain:
filename: /etc/certs/cert.pem
private_key:
filename: /etc/certs/key.pem
clusters:
- name: echoserver-cluster
type: STRICT_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: echoserver
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: localhost
port_value: 80
Як ви можете бачити, деякі нові додані рядки виглядають так:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
...
common_tls_context:
validation_context:
trusted_ca:
filename: /etc/certs/ca.crt # сертифікат CA
tls_certificates:
- certificate_chain:
filename: /etc/certs/cert.pem # серверний сертифікат
private_key:
filename: /etc/certs/key.pem # приватний ключ сервера
(Не забудьте змінити deployment.yaml, щоб включити обсяг /etc/certs/ і додати відповідні файли до цього шляху. Якщо ви хочете побачити всю конфігурацію yaml, перевірте https://github.com/manuelarte/demo-mTLS/tree/master/echoserver).
Тепер, якщо ми спробуємо перейти на https://localhost:8080, ми не отримаємо жодної відповіді.
Але ми можемо використати команду cURL з клієнтськими сертифікатами:
> curl -k -v --cacert /echoserver/certs/ca.crt --cert /echoserver/certs/client.crt --key /echoserver/certs/client.key https://localhost:8080
(Не забудьте змінити ).
щоб отримати правильну відповідь від echo.
Перекладено з: 🔒Configuring mTLS For Your App