【ES三周年】Elasticsearch安全配置详解

腾讯云   2023-03-07 16:08:14

腾讯云上的Elasticsearch service已经开始为我们提供基于HTTPS协议访问的Elasticsearch集群了;Elastic Cloud的Elasticsearch服务则一直都是默认使用的HTTPS安全协议。而我们自建的Elasticsearch集群,从8.0版本开始,也默认地简化了安全功能,为用户自动配置:用户认证、基于角色的访问控制进行用户授权、使用 TLS 加密的节点到节点通信、使用 HTTPS 与 Elasticsearch API 进行加密通信。


【资料图】

为什么我们需要进行如此复杂的安全配置,并启用SSL/TLS对Elasticsearch的服务进行认证与通信加密?

因为这将帮助我们获得:

数据传输的安全性:启用HTTPS和TLS可以加密Elasticsearch集群中所有数据的传输,这有助于保护敏感数据不被未经授权的第三方访问、窃取或篡改。身份验证和授权:通过启用TLS可以保护集群不受未经授权的访问,同时可以使用客户端证书进行身份验证。遵守合规要求:启用HTTPS和TLS有助于满足各种行业和法规标准的要求,例如HIPAA、PCI DSS、GDPR等。安全性提升:启用HTTPS和TLS可以增强集群的安全性,防止攻击者通过中间人攻击(Man-in-the-middle attack)来窃取数据或者篡改数据。

总的来说,将Elasticsearch集群配置为使用HTTPS和TLS可以提高数据的保护和安全性,对于任何要求数据保密性的场合,都是一个重要的安全措施。

虽然我们明白安全配置的重要性,但是要知其然,知其所以然却并不是一件简单的事情,特别是涉及到这些安全配置相关的各种CA证书、证书、公钥、秘钥、数字签名、证书指纹(finger print)登,要搞清楚他们之间的关系,通常会让我们头晕脑胀。

本文,我们将尝试为大家解析整个Elasticsearch配置加密通信的各种概念,以让我们清楚,如何才能够配置合适的安全配置来配合我们生产环境的安全需求。

HTTPS和TLS中的基本概念

HTTPS(Hypertext Transfer Protocol Secure)是一种安全的HTTP协议,通过使用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)协议对数据进行加密和认证,以保护网络通信的安全性。

以下是HTTPS中的一些重要概念:

CA证书(Certificate Authority Certificate):由服务器证书认证机构(CA)签发的证书,用于验证服务器证书的真实性。浏览器或客户端会在与服务器建立连接时检查其证书是否被受信任的CA机构签发。服务器证书(Server Certificate):是一种服务器证书,用于验证服务器的身份和提供公钥给客户端,以进行数据加密和认证。CA指纹(Certificate Authority Fingerprint):指由CA签发的证书的数字指纹,用于验证证书的真实性。公钥和私钥:公钥用于加密数据,私钥用于解密数据和数字签名。数字签名(Digital Signature):在服务器证书中使用的一种数字技术,用于验证证书的真实性和完整性,确保证书内容未被篡改。

而在配置Elasticsearch集群的安全通信时,我们都会用到上面提到的这些元素,用于验证服务器和客户端的验证,以及通信的加密和完整。

Elasticsearch集群中的对应元素

我们在配置Elasticsearch集群的安全通信时,需要分别配置集群间节点的TLS通信,以及客户端与集群的HTTPS通信。

现在,假设我们有一个多节点的集群,有Kibana和Logstash需要和集群进行通信。因此,会有类似的角色需要去配置:

[root@node1 cert_blog]# vi ~/tmp/cert_blog/instance.yml# add the instance information to yml fileinstances:  - name: "node1"    dns: [ "node1.elastic.test.com" ]  - name: "node2"    dns: [ "node2.elastic.test.com" ]  - name: "my-kibana"    dns: [ "kibana.local" ]  - name: "logstash"    dns: [ "logstash.local" ]

然后使用配套的elasticsearch-certutil工具来生成对应的CA证书和服务器证书。

[root@node1 elasticsearch]# bin/elasticsearch-certutil cert --keep-ca-key --pem --in ~/tmp/cert_blog/instance.yml --out ~/tmp/cert_blog/certs.zip

解压certs.zip后,会有如下的文件目录与文件:

├── ca│   ├── ca.crt│   └── ca.key├── ca.zip├── certs2.zip├── node1│   ├── node1.crt│   └── node1.key├── node2│   ├── node2.crt│   └── node2.key├── my-kibana│   ├── my-kibana.crt│   └── my-kibana.key├── logstash│   ├── logstash.crt│   └── logstash.key

在这其中,ca.crt就是Elasticsearch自签名的CA证书,而 es01.crtes02.crtmy-kibana.crtlogstash.crt等,都是用这个ca.crt签发的服务器证书

具体一点,ca.keyca.crt是用于生成和签发服务器证书的CA(Certificate Authority,证书授权机构)的私钥和公钥。CA是用来签发服务器证书的可信任实体,用于验证证书持有者身份并对证书进行数字签名,以确保证书在传输过程中的完整性和真实性。

ca.key是CA的私钥,用于对服务器证书进行数字签名。通常应该仅由CA拥有人访问,因为它可以用于签发任何证书,并将其认为是受信任的证书。因此,如果私钥被泄露或丢失,就会使得签发的所有证书都不能被信任。也就是说,上面的服务器证书(比如,node1.crt)内的数字签名,就是用ca.key来加密签发的。

ca.crt是CA的公钥证书,用于验证服务器证书的真实性和完整性。证书中包含了CA的公钥,以及签名信息。在验证服务器证书时,接收方可以使用ca.crt来验证证书的签名是否可信。如果可信,就可以确认证书的真实性和完整性。比如,客户端在链接node1时,node1的服务器证书node1.crt内的数字签名,将使用ca.crt中的CA的公钥来进行解密,如果解密出来的值,是该服务器证书(node1.crt)的哈希值,则表明服务器可信。

因此,我们会看到,在Kibana的配置中,我们会需要配置elasticsearch.ssl.certificateAuthorities,因为我们需要它来验证我们链接的es就是我们期望链接的es。

elasticsearch.username: "kibana"elasticsearch.password: ""elasticsearch.ssl.certificateAuthorities: [ "/etc/kibana/config/certs/ca.crt" ]

CA证书是如何验证网站的身份和证书的真实性的?

上面讲的比较粗浅,我们再来深入说明一下CA证书验证ES节点身份和证书(服务器证书)真实性的基本流程:

当一个ES的节点,或者客户端,想要使用SSL/TLS协议时与集群进行通信时,它会向CA机构申请服务器证书。CA机构会对网站的身份进行验证,并生成一个服务器证书。简单的说,就是通过ca.crtca.key来生成node1.crt服务器证书包含了服务器的公钥、网站的名称(node1.elastic.test.com)、有效期限以及数字签名等信息。服务器证书的数字签名是由CA机构使用私钥对服务器证书的内容进行加密生成的,这个数字签名是证书真实性的关键。当一个客户端访问节点时,节点会将服务器证书发送给客户端。客户端会验证服务器证书的真实性,具体的验证流程如下:客户端首先会检查服务器证书的有效期限是否过期,如果过期则不信任此证书。客户端会检查服务器证书的颁发机构是否被信任,也就是检查CA证书是否存在于客户端的信任列表中。客户端会对服务器证书中的数字签名进行验证,以确保服务器证书的内容没有被篡改过。客户端会使用CA证书中的公钥对数字签名进行解密,如果解密后的结果与服务器证书中的内容一致,说明服务器证书是真实的,否则就不信任此证书。

如何通过CA证书验证服务器证书里的数字签名?

数字签名是通过公钥和私钥生成的。CA机构会使用自己的私钥为服务器证书的数字签名进行签名。因此,在验证服务器证书时,需要先使用CA机构的公钥对数字签名进行解密,得到服务器证书的哈希值,然后再将服务器证书的哈希值与服务器证书本身进行比对,如果一致,则表明该服务器证书是由该CA机构签发的,可以被信任。如果不一致,则说明该服务器证书可能被篡改或伪造,不应该被信任。这个过程可以通过证书链(certificate chain)的方式完成,即通过验证服务器证书的数字签名是否能够成功地与CA机构的证书相匹配来确认服务器证书的可信度。

服务器证书中都包含哪些内容?

上面,我们提到了服务器证书中包含了公钥、网站的名称、有效期限以及数字签名等信息。具体来说,服务器证书包含了以下几个主要部分:

证书版本号:标识服务器证书的版本号。序列号:证书的唯一序列号,用于区分不同的服务器证书。签名算法标识:指定用于对服务器证书进行签名的算法。颁发者:服务器证书颁发机构的信息。有效期限:服务器证书的有效期限,包括起始时间和截止时间。主体:服务器证书持有者的信息,通常是网站或个人。公钥信息:包含了证书持有者的公钥。数字签名:用服务器证书颁发机构的私钥对证书的内容进行签名,用于验证证书的真实性。

比如,es01的服务器证书的内容为:

base64解码后,内容为:

https是如何通过服务器证书和密钥来加密和解密通信中的数据的?

上面,我们提到了客户端通过持有ES的CA证书,然后以ES的CA证书来验证节点的服务器证书,以确保我们连接的节点确实是该集群的节点。起到一个认证的作用。

但HTTPS/TLS除了身份验证的功能外,还有通信加密的功能,这是如何实现的呢?

当客户端与服务器(ES节点)建立HTTPS连接时,首先会进行握手协议。在握手过程中,服务器会将其服务器证书发送给客户端,客户端会对证书进行验证,验证成功后,客户端就可以使用证书中包含的公钥(比如node1.crt中的公钥)对一个称为"Pre-master secret"的随机数进行加密并发送给服务器。服务器收到加密后的"Pre-master secret"后,使用私钥(比如,node1.key)对其进行解密,得到"Pre-master secret"。接下来,服务器和客户端都使用这个"Pre-master secret"生成一个称为"Master secret"的密钥,该密钥将用于后续的通信加密。一旦"Master secret"生成,服务器和客户端都可以使用它来加密和解密通信中的数据。具体来说,当客户端向服务器发送数据时,它会使用"Master secret"对数据进行加密,并将加密后的数据发送给服务器。服务器接收到数据后,使用相同的"Master secret"对数据进行解密。

在这个过程中,服务器证书起到了验证服务器身份和提供公钥的作用,而私钥则用于解密客户端发送的数据。同时,"Pre-master secret"和"Master secret"这两个密钥也起到了加密和解密通信数据的作用。这些步骤共同确保了HTTPS连接的安全性和私密性。

需要每一个Elasticsearch的节点都有自己不同的证书和秘钥吗?

在上面的配置中,我们看到node1和node2都有自己的服务器证书和私钥,这是因为,ES的集群由节点组成,节点和节点之间的transport通信,也需要基于TLS协议。在使用Elasticsearch的TLS层时,每个节点都需要拥有自己的证书和秘钥,以确保通信的安全性和私密性。

每个节点都有自己的IP地址或者主机名,需要使用相应的证书和秘钥来与其他节点或客户端(transport client)进行通信。如果所有节点共用同一份证书和秘钥,那么这个证书和秘钥的私密性就会被破坏,从而使得通信不再安全。

因此,在使用Elasticsearch的TLS层时,建议为每个节点都生成独立的证书和秘钥,以保障通信的安全性和私密性。可以使用相同的CA证书来生成节点证书,以确保证书的可信性和一致性。同时,也可以使用自动化工具来简化证书和秘钥的管理和部署过程,例如使用Elasticsearch自带的证书自动化工具或者第三方的证书管理工具。

使用自签名的CA证书来实现证书的签发和管理

上面,我们提到Elasticsearch提供配套的elasticsearch-certutil工具,来生成自签名的CA证书,并用该证书来实现服务器证书的签发和管理。

具体来说,以下是使用自签名的CA证书颁发其他证书的步骤:

创建自签名的CA证书首先,我们需要使用elasticsearch-certutil创建自签名的CA证书。在创建证书时,需要填写一些基本信息,例如证书的名称、有效期限等等。这些信息都由elasticsearch-certutil帮我们自动生成了。在服务器上安装自签名的CA证书将自签名的CA证书安装到服务器上,通常是将证书文件放置在特定目录下,并将证书信息写入到相应的配置文件中。在这里,我们会看到,每个ES节点,或者客户端,都需要配置CA证书的路径:
xpack.security.enabled: truexpack.security.http.ssl.enabled: truexpack.security.transport.ssl.enabled: truexpack.security.http.ssl.key: certs/node1.keyxpack.security.http.ssl.certificate: certs/node1.crt-> xpack.security.http.ssl.certificate_authorities: certs/ca.crtxpack.security.transport.ssl.key: certs/node1.keyxpack.security.transport.ssl.certificate: certs/node1.crt-> xpack.security.transport.ssl.certificate_authorities: certs/ca.crt
创建服务器证书通过elasticsearch-certutil创建一个证书请求,该请求包含服务器的公钥和一些基本信息,例如服务器的名称、域名等等。请求通常是一个包含公钥和证书信息的文件。比如,
./bin/elasticsearch-certutil cert \  --name node1 \  --ca-cert /path/to/ca/ca.crt \  --ca-key /path/to/ca/ca.key \  --dns your.host.name.here \  --ip 192.0.2.1 \  --pem
由自签名的CA证书颁发服务器证书使用自签名的CA证书对服务器证书请求进行签名,从而生成一个新的服务器证书。此时,服务器证书已经包含了服务器的公钥、证书信息以及CA证书的签名,可以用于服务器的安全通信。安装服务器证书将服务器证书安装到服务器上,并将证书信息写入到相应的配置文件中。此时,服务器可以使用该证书进行安全通信。
xpack.security.enabled: truexpack.security.http.ssl.enabled: truexpack.security.transport.ssl.enabled: true-> xpack.security.http.ssl.key: certs/node1.key-> xpack.security.http.ssl.certificate: certs/node1.crtxpack.security.http.ssl.certificate_authorities: certs/ca.crt-> xpack.security.transport.ssl.key: certs/node1.key-> xpack.security.transport.ssl.certificate: certs/node1.crtxpack.security.transport.ssl.certificate_authorities: certs/ca.crt

需要注意的是,自签名的CA证书在安全性方面可能不如购买的第三方CA证书可靠,因为自签名的CA证书并没有经过第三方机构的验证和认证。因此,在使用自签名的CA证书时,需要确保私钥的安全性,以避免证书被恶意使用或泄漏。

是不是客户端也可以选择不校验服务器的证书?

我们看到,无论是beats还是Logstash等工具,在连接ES的时候,为了避免将自签名的CA证书拷贝到所有的采集端上,我们会选择将ssl.verification_mode参数配置为none。这意味着,客户端将不执行服务器证书的验证。

这种情况是被允许的,这种方式也被称为不安全的HTTPS连接。但在不校验服务器证书的情况下,客户端可能会受到中间人攻击,导致传输的数据被篡改或窃取。因此,建议客户端始终验证服务器证书的有效性来确保安全通信。

verification_mode 控制服务器证书的验证。有效值为:# full验证提供的证书是否由可信机构 (CA) 签名,并验证服务器的主机名(或 IP 地址)是否与证书中标识的名称相匹配。# strict验证提供的证书是否由可信机构 (CA) 签名,并验证服务器的主机名(或 IP 地址)是否与证书中标识的名称相匹配。如果 Subject Alternative Name 为空,则返回错误。# certificate验证提供的证书是否由可信机构 (CA) 签名,但不执行任何主机名验证。# none不执行服务器证书的验证。此模式会禁用 SSL/TLS 的许多安全优势,应仅在谨慎考虑后使用。它主要用作尝试解决 TLS 错误时的临时诊断机制;强烈建议不要在生产环境中使用它。

不校验证书的情况下,加密通信的步骤是怎么样的?

即使客户端选择不校验服务器证书,HTTPS仍然可以提供加密通信的保护。在这种情况下,加密通信的步骤如下:

客户端向服务器发起HTTPS请求,请求中包含加密算法和协议版本等信息。服务器返回证书,包括公钥、网站名称、有效期限以及数字签名。客户端使用证书中的公钥对一个随机生成的对称密钥进行加密,该密钥将用于加密通信过程中的数据。客户端将加密后的密钥发送给服务器。服务器使用私钥解密接收到的随机生成的对称密钥。客户端和服务器都使用对称密钥来加密和解密数据,确保通信过程中的数据保密性和完整性。需要注意的是,如果客户端选择不校验服务器证书,那么服务器可以使用任意证书来伪装自己,因此通信过程中的数据可能被窃取或篡改,因此不建议使用不安全的HTTPS连接。

为什么我们访问Elastic cloud上的Elasticsearch服务时,不需要证书?

Elastic Cloud上使用的证书是由经过浏览器和操作系统信任的公共CA颁发的,因此您可以直接使用浏览器或API工具与Elastic Cloud上的Elasticsearch集群通信,而不需要进行额外的证书验证。这些公共CA包括像DigiCert、GlobalSign、Let"s Encrypt等知名的第三方CA机构,他们的根证书已经预装在操作系统和浏览器中。这意味着在与Elastic Cloud上的Elasticsearch进行通信时,您的API工具会验证证书链是否可以追溯到其中一个信任的CA的根证书。

而现在,Elastic Cloud使用的是Let"s Encrypt的CA证书。