Elasticsearch, Kibana, Beats, Logstash의 보안을 유지하기 위한 SSL, TLS, HTTPS 구성 | Elastic Blog
엔지니어링

Elasticsearch, Kibana, Beats, Logstash의 보안을 유지하기 위한 SSL, TLS, HTTPS 구성

Elastic Stack 6.7.x / 7.0.x 또는 그 이전 버전을 실행 중이신가요? 그렇다면, "TLS를 설정하는 방법..." 블로그를 확인해보세요. 사용하시는 버전 내에서 통신 보안을 유지하는 데 도움을 받으실 수 있습니다. 이 블로그 게시물에서 다루는 무료 보안 기능에는 Elastic Stack 6.8/7.1 이상이 필요합니다.

Elastic은 Elastic Stack 6.8과 7.1부터 기본 배포(기본 라이선스)의 일환으로 일부 보안 기능을 무료로 릴리즈했습니다. SSL을 이용해 네트워크 트래픽을 암호화하고, 사용자들을 생성 및 관리하며, 인덱스와 클러스터 수준의 액세스를 보호하는 역할을 정의하고, Kibana의 보안을 완전히 유지할 수 있는 새로운 기능이 여기에 포함됩니다. 릴리즈 직후에 나온 저희의 시작하기 블로그 포스팅에서 Elasticsearch와 Kibana 간에 TLS 통신을 사용하는 방법에 대해 설명해드리고 있습니다. 다음 블로그에서는 이 안내지침을 좀더 확장시켜 Logstash와 Beats 등 Elastic Stack의 다른 구성 요소도 다룹니다. 구성 요소 간의 TLS 활성화와 HTTP 클라이언트 통신 암호화에 대해 얘기하게 됩니다.

HTTP 레이어에서 TLS 활성화가 꼭 필요한 것은 아니지만, 데이터를 보호하는, 특히 사용자 이름/비밀번호 정보가 새어나가지 않도록 보호하는 엔드-투-엔드 보안을 위해 적극 권장됩니다. 사용자 이름/비밀번호 정보가 새어나가면 클러스터가 제 기능을 하지 못하게 됩니다. TLS 암호화, 인증, 제한된 스크립트 또는 격리 등에 대해 더 자세히 알고 싶으시면, 암호화, 사용자 등으로 무료로 Elasticsearch 클러스터의 보안을 유지하기 위한 팁 블로그를 참조하세요.

한 가지 더 말씀드리자면, 아래에서 활성화되는 보안 기능은 Elastic Cloud의 Elasticsearch Service에서 표준 기능으로 제공됩니다. Elasticsearch Service에서 운영 중이신 경우, 다 건너뛰고 바로 5단계로 가셔도 됩니다.

Elastic Stack의 보안을 유지하기 위한 단계

  1. 준비
  2. node1의 Elasticsearch를 위한 SSL 인증서 생성과 TLS 활성화
  3. node1의 Kibana를 위한 TLS 활성화
  4. node2의 Elasticsearch를 위한 TLS 활성화
  5. node1의 Logstash 사용자 준비
  6. node1의 Logstash를 위한 TLS 활성화
  7. Filebeat 실행 및 node1의 TLS 설정
  8. Filebeat를 이용한 데이터 수집

Elastic Stack 다이어그램

1단계. 준비

Elastic Stack 7.1 또는 그 이후 버전의 다음 구성 요소를 다운로드하세요.

[1-1] /etc/hosts 파일 구성

이 예제에서는 node1에 브라우저가 설치되어 있기 때문에 kibana.local이 Kibana 웹페이지에 접속할 수 있습니다.

# [node1]을 위한 /etc/hosts 파일(kibana.local과 logstash.local이 필요합니다)
127.0.0.1 kibana.local logstash.local
192.168.0.2 node1.elastic.test.com node1
192.168.0.3 node2.elastic.test.com node2
# [node2]를 위한 /etc/hosts 파일(여기서는 kibana.local과 logstash.local이 필요 없습니다)
192.168.0.2 node1.elastic.test.com node1
192.168.0.3 node2.elastic.test.com node2

2단계. node1의 Elasticsearch를 위한 SSL 인증서 생성과 TLS 활성화

[2-1] 환경 변수 설정(Elasticsearch가 어디서, 어떻게 다운로드되었는지에 따라 이 변수 경로를 변경해줍니다)

[root@node1 ~]# ES_HOME=/usr/share/elasticsearch
[root@node1 ~]# ES_PATH_CONF=/etc/elasticsearch

[2-2] tmp 폴더 생성

[root@node1 ~]# mkdir tmp
[root@node1 ~]# cd tmp/
[root@node1 tmp]# mkdir cert_blog

[2-3] 인스턴스 yaml 파일 생성

[root@node1 cert_blog]# vi ~/tmp/cert_blog/instance.yml
# yml 파일에 인스턴스 정보 추가
instances:
  - 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' ]

[2-4] CA 및 서버 인증서 생성(Elasticsearch가 설치된 후)

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

[2-5] 인증서 압축 해제

[root@node1 elasticsearch]# cd ~/tmp/cert_blog
[root@node1 cert_blog]# unzip certs.zip -d ./certs

[2-6] Elasticsearch TLS 설정

[2-6-1] cert 파일을 config 폴더로 복사

[root@node1 ~]# cd $ES_PATH_CONF
[root@node1 elasticsearch]# pwd
/etc/elasticsearch
[root@node1 elasticsearch]# mkdir certs
[root@node1 elasticsearch]# cp ~/tmp/cert_blog/certs/ca/ca.crt ~/tmp/cert_blog/certs/node1/* certs
[root@node1 elasticsearch]# ll certs
total 12
-rw-r--r--. 1 root elasticsearch 1834 Apr 12 08:47 ca.crt
-rw-r--r--. 1 root elasticsearch 1509 Apr 12 08:47 node1.crt
-rw-r--r--. 1 root elasticsearch 1679 Apr 12 08:47 node1.key
[root@node1 elasticsearch]#

[2-6-2] elasticsearch.yml 구성

[root@node1 elasticsearch]# vi elasticsearch.yml 
## 다음 콘텐츠 추가
node.name: node1
network.host: node1.elastic.test.com
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.http.ssl.key: certs/node1.key
xpack.security.http.ssl.certificate: certs/node1.crt
xpack.security.http.ssl.certificate_authorities: certs/ca.crt
xpack.security.transport.ssl.key: certs/node1.key
xpack.security.transport.ssl.certificate: certs/node1.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crt
discovery.seed_hosts: [ "node1.elastic.test.com" ]
cluster.initial_master_nodes: [ "node1" ]

[2-6-3] 시작 및 클러스터 로그 확인

[root@node1 elasticsearch]# grep '\[node1\] started' /var/log/elasticsearch/elasticsearch.log 
[o.e.n.Node               ] [node1] started

[2-6-4] 기본 사용자 비밀번호 설정

[root@node1 elasticsearch]# cd $ES_HOME
[root@node1 elasticsearch]# bin/elasticsearch-setup-passwords auto -u "https://node1.elastic.test.com:9200"
Initiating the setup of passwords for reserved users elastic,apm_system,kibana,logstash_system,beats_system,remote_monitoring_user.
The passwords will be randomly generated and printed to the console.
Please confirm that you would like to continue [y/N] y
Changed password for user apm_system
PASSWORD apm_system = 
Changed password for user kibana
PASSWORD kibana = 
Changed password for user logstash_system
PASSWORD logstash_system = 
Changed password for user beats_system
PASSWORD beats_system = 
Changed password for user remote_monitoring_user
PASSWORD remote_monitoring_user = 
Changed password for user elastic
PASSWORD elastic = 

[2-6-5] HTTPS를 통한 _cat/nodes API 연결

[root@node1 elasticsearch]# curl --cacert ~/tmp/cert_blog/certs/ca/ca.crt -u elastic 'https://node1.elastic.test.com:9200/_cat/nodes?v'
Enter host password for user 'elastic':
ip          heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.0.2           16          95  10    0.76    0.59     0.38 mdi       *      node1

3단계. node1의 Kibana를 위한 TLS 활성화

[3-1] 환경 변수 설정

Kibana가 어디서, 어떻게 다운로드되었는지에 따라 이 변수 경로를 변경해줍니다.

[root@node1 ~]# KIBANA_HOME=/usr/share/kibana
[root@node1 ~]# KIBANA_PATH_CONFIG=/etc/kibana

[3-2] config 및 config/certs 폴더 생성과 certs 복사(Kibana가 설치된 후)

앞서 2-4단계에서 생성된 인증 파일을 복사해서 kibana/config/certs에 붙여넣기합니다.

[root@node1 kibana]# ls config/certs
total 12
ca.crt
my-kibana.crt
my-kibana.key

[3-3] kibana.yml 구성

위의 기본 사용자에 대해 생성된 비밀번호를 사용하세요. 2-6-4단계에서 정의된 비밀번호로 바꿔야 합니다.

[root@node1 kibana]# vi kibana.yml 
server.name: "my-kibana"
server.host: "kibana.local"
server.ssl.enabled: true
server.ssl.certificate: /etc/kibana/config/certs/my-kibana.crt
server.ssl.key: /etc/kibana/config/certs/my-kibana.key
elasticsearch.hosts: ["https://node1.elastic.test.com:9200"]
elasticsearch.username: "kibana"
elasticsearch.password: ""
elasticsearch.ssl.certificateAuthorities: [ "/etc/kibana/config/certs/ca.crt" ]

[3-4] Kibana 시작 및 Kibana 로그인 테스트

브라우저에서 https://kibana.local:5601/에 연결합니다. 2-6-4단계에서 정의된 elastic 사용자 및 비밀번호를 사용해 로그인합니다. 이 예제에서는 node1에 브라우저가 설치되어 있기 때문에 kibana.local이 Kibana에 접속할 수 있습니다.

Kibana에 로그인

공개적으로 신뢰할 수 있는 기관은 적절한 신원 소유권을 확인한 후에만 인증서가 생성되도록 하기 위해 대단히 엄격한 기준과 감사 관행을 마련하고 있습니다. 이 블로그 포스팅의 목적으로, 우리는 Kibana를 위해 자체 서명된 인증서를 생성하겠습니다(생성된 인증서가 그 자체의 개인 키를 사용해 서명되었다는 뜻입니다). 자체 서명된 Kibana 인증서를 신뢰하지 않는 고객으로 인해, 엔터프라이즈 또는 공개 CA가 생성한 인증서를 사용해 적절한 신뢰가 확립될 때까지, Kibana 로그에서 다음과 비슷한 메시지를 보시게 됩니다(다음은 Kibana 리포지토리에 있는 문제 링크입니다). 이 문제는 Kibana에서 작업할 수 있는 기능에는 영향을 미치지 않습니다.

[18:22:31.675] [error][client][connection] Error: 4443837888:error:14094416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown:../deps/openssl/openssl/ssl/s3_pkt.c:1498:SSL alert number 46

4단계. node2의 Elasticsearch를 위한 TLS 활성화

[4-1] 환경 변수 설정

[root@node2 ~]# ES_HOME=/usr/share/elasticsearch
[root@node2 ~]# ES_PATH_CONF=/etc/elasticsearch

[4-2] node2의 TLS 설정

scp 명령을 이용해 node1에서 node2로 인증서를 복사할 수 있습니다. 두 노드 모두 인증서와 키가 있어야 연결에 대한 보안을 유지할 수 있습니다. 프로덕션 환경에서는, 각 노드에 대해 적절하게 서명된 키를 사용할 것을 권장합니다. 데모 목적으로, 우리는 자동 생성된 CA 인증서와 우리가 생성한 CA가 서명한 여러 DNS 호스트명 인증서를 사용하고 있습니다.

[root@node2 ~]# cd $ES_PATH_CONF
[root@node2 elasticsearch]# pwd
/etc/elasticsearch
[root@node2 elasticsearch]# mkdir certs
[root@node2 elasticsearch]# cp ~/tmp/cert_blog/certs/ca/ca.crt ~/tmp/cert_blog/certs/node2/* certs  
[root@node2 elasticsearch]# 
[root@node2 elasticsearch]# ll certs
total 12
-rw-r--r--. 1 root elasticsearch 1834 Apr 12 10:55 ca.crt
-rw-r--r--. 1 root elasticsearch 1509 Apr 12 10:55 node2.crt
-rw-r--r--. 1 root elasticsearch 1675 Apr 12 10:55 node2.key

[4-3] elasticsearch.yml 구성

[root@node2 elasticsearch]# vi elasticsearch.yml 
node.name: node2
network.host: node2.elastic.test.com
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.http.ssl.key: certs/node2.key
xpack.security.http.ssl.certificate: certs/node2.crt
xpack.security.http.ssl.certificate_authorities: certs/ca.crt
xpack.security.transport.ssl.key: certs/node2.key
xpack.security.transport.ssl.certificate: certs/node2.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crt
discovery.seed_hosts: [ "node1.elastic.test.com" ]

[4-4] 시작 및 클러스터 로그 확인

[root@node2 elasticsearch]# grep '\[node2\] started' /var/log/elasticsearch/elasticsearch.log 
[o.e.n.Node               ] [node2] started

[4-5] HTTPS를 통한 _cat/nodes API 연결

[root@node2 elasticsearch]# curl --cacert ~/tmp/cert_blog/certs/ca/ca.crt -u elastic: 'https://node2.elastic.test.com:9200/_cat/nodes?v'
ip          heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.0.2           25          80   5    0.18    0.14     0.30 mdi       *      node1
192.168.0.3           14          96  44    0.57    0.47     0.25 mdi       -      node2

5단계. node1의 Logstash 사용자 준비

[5-1] logstash_write_role 생성

여러 방법으로 역할을 생성할 수 있습니다.

다음과 같이 Kibana 역할 UI를 사용해 생성할 수 있습니다. 

logstash_write_role 생성

또는 다음과 같이 Kibana 개발자 도구 탭에서 API를 사용하여 사용자를 생성하세요.

POST /_security/role/logstash_write_role
{
    "cluster": [
      "monitor",
      "manage_index_templates"
    ],
    "indices": [
      {
        "names": [
          "logstash*"
        ],
        "privileges": [
          "write",
          "create_index"
        ],
        "field_security": {
          "grant": [
            "*"
          ]
        }
      }
    ],
    "run_as": [],
    "metadata": {},
    "transient_metadata": {
      "enabled": true
    }
}

그러면 다음과 같은 응답을 받게 됩니다.

{"role":{"created":true}}

이 역할을 배정받은 사용자는 어떤 문서도 삭제할 수 없습니다. 이 역할은 사용자가 logstash를 시작하는 경우에만 인덱스를 생성할 수 있도록 제한하며, 또는 그러한 인덱스의 문서들만 색인하도록 제한합니다.

ILM 사용자를 위한 참고 사항: logstash_writer_roleindex lifecycle management (ILM)을 사용하려면(7.3 이상부터 기본적으로 지원) 다음 권한이 포함되어 있어야 합니다.


"privileges": ["write","create","delete","create_index","manage","manage_ilm"]
		

[5-2] logstash_writer 사용자 생성(logstash_writer 사용자에 대한 비밀번호를 변경하세요)

여러 방법으로 사용자를 생성할 수 있습니다.

다음과 같이 Kibana 사용자 UI를 사용해 생성할 수 있습니다.

logstash_writer 사용자 생성

또는 다음과 같이 Kibana 개발자 도구 탭에서 API를 사용하여 사용자를 생성하세요.

POST /_security/user/logstash_writer
{
  "username": "logstash_writer",
  "roles": [
    "logstash_write_role"
  ],
  "full_name": null,
  "email": null,
  "password": "",
  "enabled": true
}

그러면 다음과 같은 응답을 받게 됩니다.

{"user":{"created":true}}

6단계. node1의 Logstash를 위한 TLS 활성화

[6-1] 폴더 생성 및 인증서 복사

[root@node1 logstash]# ls -l
total 24
ca.crt
logstash.crt
logstash.key

[6-2] Beats 입력 플러그인을 위해 logstash.key를 PKCS#8 형식으로 변환

[root@node1 logstash]# openssl pkcs8 -in config/certs/logstash.key -topk8 -nocrypt -out config/certs/logstash.pkcs8.key

[6-3] logstash.yml 구성

logstash_system 사용자를 위해 자동 생성된 비밀번호를 사용하세요. 2-6-4단계에서 정의된 비밀번호를 사용하세요.

[root@node1 logstash]# vi logstash.yml

그리고 나서, 다음과 같이 편집하세요.

node.name: logstash.local
path.config: /etc/logstash/conf.d/*.conf
xpack.monitoring.enabled: true
xpack.monitoring.elasticsearch.username: logstash_system
xpack.monitoring.elasticsearch.password: ''
xpack.monitoring.elasticsearch.hosts: [ 'https://node1.elastic.test.com:9200' ]
xpack.monitoring.elasticsearch.ssl.certificate_authority: /etc/logstash/config/certs/ca.crt

[6-4] conf.d/example.conf 생성 및 구성

Elasticsearch 출력에서,5-2단계에서 정의된 비밀번호를 사용하세요.

[root@node1 logstash]# vi conf.d/example.conf 
input {
  beats {
    port => 5044
    ssl => true
    ssl_key => '/etc/logstash/config/certs/logstash.pkcs8.key'
    ssl_certificate => '/etc/logstash/config/certs/logstash.crt'
  }
}
output {
  elasticsearch {
    hosts => ["https://node1.elastic.test.com:9200","https://node2.elastic.test.com:9200"]
    cacert => '/etc/logstash/config/certs/ca.crt'
    user => 'logstash_writer'
    password => 
  }
}

[6-5] 예제 구성으로 Logstash 시작 및 Logstash 로그 확인

다음 로그 메시지를 볼 수 있어야 합니다.

[INFO ][logstash.pipeline        ] Pipeline started successfully {:pipeline_id=>".monitoring-logstash", :thread=>"#