学习单向认证,双向认证,对 Downstream 和 UpStream 的认证。
Envoy 对 Downstream 进行单向认证:
admin:
access_log_path: /dev/stdout
address:
socket_address:
address: 0.0.0.0
port_value: 8081
node:
cluster: hello-service
id: node1
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 82
filter_chains:
- transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext
common_tls_context:
tls_certificates:
certificate_chain: { "filename": "/home/admin/k8s-cluster/envoy/ssl/cert/server.crt" }
private_key: { "filename": "/home/admin/k8s-cluster/envoy/ssl/cert/server.key" }
validation_context:
trusted_ca:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/ca.crt
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
access_log:
name: envoy.file_access_log
typed_config:
"@type": type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog
path: /dev/stdout
route_config:
name: local_route
virtual_hosts:
- name: service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: ping-service
http_filters:
- name: envoy.filters.http.router
clusters:
- name: ping-service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: ping-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9090
测试:
$ curl --cacert /home/admin/k8s-cluster/envoy/ssl/cert/ca.crt https://fueltank-1:82/ping
不加 ca 证书也可以访问:
$ curl --cacert /home/admin/k8s-cluster/envoy/ssl/cert/ca.crt https://fueltank-1:82/ping
配置如下:
admin:
access_log_path: /dev/stdout
address:
socket_address:
address: 0.0.0.0
port_value: 8081
node:
cluster: hello-service
id: node1
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 82
filter_chains:
- filters:
- name: envoy.filters.network.client_ssl_auth
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.client_ssl_auth.v2.ClientSSLAuth
auth_api_cluster: cert-service
stat_prefix: cert
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
access_log:
name: envoy.file_access_log
typed_config:
"@type": type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog
path: /dev/stdout
route_config:
name: local_route
virtual_hosts:
- name: service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: ping-service
http_filters:
- name: envoy.filters.http.router
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext
require_client_certificate: true # 开启双向认证,要求客户端提供证书
common_tls_context:
tls_certificates:
certificate_chain:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/server.crt
private_key:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/server.key
validation_context:
trusted_ca:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/ca.crt
trust_chain_verification: ACCEPT_UNTRUSTED # 必须要加的
clusters:
- name: cert-service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: cert-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 6060
- name: ping-service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: ping-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9090
transport_socket: # 对服务端进行单向认证
name: envoy.transport_sockets.tls
typed_config: {}
这里 golang 的自己开发的服务端 ping-service 的代码如下,命名为 main.go :
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
_ = r.RunTLS("0.0.0.0:9090", "/home/admin/k8s-cluster/envoy/ssl/cert/server.crt", "/home/admin/k8s-cluster/envoy/ssl/cert/server.key")
}
因为这里 golang 的服务端开启了单向认证,所以要在对应的 cluster
中添加 envoy.transport_sockets.tls
,因为是单向认证,所以这里内容可以置空。
因为这里我使用了 envoy.filters.network.client_ssl_auth
这个过滤器来验证客户端证书。所以要自研 cert-service
服务。其代码如下,命名为 server.go :
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/v1/certs/list/approved", func(c *gin.Context) {
c.JSON(200, gin.H{
"certificates": []map[string]string{
{
"fingerprint_sha256": "a45e46487977c62cd60a3a4e8ec044f8fe16115bd1c8f5cddf3d99f82dc864a7",
},
},
})
})
_ = r.Run("0.0.0.0:6060")
}
这里 API 的地址和响应的格式是固定的,必须这么配置,Envoy 才能得到对应的响应信息,响应格式如下:
{
"certificates": [
{
"fingerprint_sha256": "a45e46487977c62cd60a3a4e8ec044f8fe16115bd1c8f5cddf3d99f82dc864a7"
}
]
}
这里 fingerprint_sha256
中的内容是客户端证书的摘要,其生成方式如下:
$ openssl x509 -in client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2
a45e46487977c62cd60a3a4e8ec044f8fe16115bd1c8f5cddf3d99f82dc864a7
如果客户端使用的证书的摘要和这里规定的不匹配,则客户端会访问失败!
分别启动两个服务端:
$ go run server.go
$ go run main.go
然后启动 Envoy:
$ sudo getenvoy run standard:1.14.1 -- --config-path ./envoy-config.yaml
客户端访问:
$ curl --cert ./server.crt --key ./server.key https://fueltank-1:82/ping
如果证书对了是可以访问成功的,证书不对,则访问失败
查看 Envoy 的统计信息:
auth.clientssl.cert.auth_digest_match: 4
auth.clientssl.cert.auth_digest_no_match: 1
auth.clientssl.cert.auth_ip_white_list: 0
auth.clientssl.cert.auth_no_ssl: 0
auth.clientssl.cert.total_principals: 1
auth.clientssl.cert.update_failure: 0
auth.clientssl.cert.update_success: 2
SNI(Server Name Indication)是 TLS 的扩展,用来解决一个服务器拥有多个域名的情况。
见教程:https://www.envoyproxy.io/docs/envoy/latest/faq/configuration/sni#faq-how-to-setup-sni
配置如下:
admin:
access_log_path: /dev/stdout
address:
socket_address:
address: 0.0.0.0
port_value: 8081
node:
cluster: hello-service
id: node1
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 82
listener_filters:
- name: "envoy.filters.listener.tls_inspector" # 必须要配置
typed_config: {}
filter_chains:
- filter_chain_match:
server_names: ["fueltank-1"]
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.api.v2.auth.DownstreamTlsContext
require_client_certificate: true
common_tls_context:
tls_certificates:
certificate_chain:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/server.crt
private_key:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/server.key
validation_context:
trusted_ca:
filename: /home/admin/k8s-cluster/envoy/ssl/cert/ca.crt
trust_chain_verification: ACCEPT_UNTRUSTED
filters:
- name: envoy.filters.network.client_ssl_auth
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.client_ssl_auth.v2.ClientSSLAuth
auth_api_cluster: cert-service
stat_prefix: cert
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
access_log:
name: envoy.file_access_log
typed_config:
"@type": type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog
path: /dev/stdout
route_config:
name: local_route
virtual_hosts:
- name: service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: ping-service
http_filters:
- name: envoy.filters.http.router
clusters:
- name: cert-service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: cert-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 6060
- name: ping-service
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
load_assignment:
cluster_name: ping-service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9090
transport_socket:
name: envoy.transport_sockets.tls
typed_config: {}