ELK Stack의 보안
ELK Stack의 보안 (feat. X-PACK)
Elastic Stack 6.8과 7.1부터 TLS 암호화된 통신 기능이 기본 배포 내에서 무료로 제공됩니다.
실제로 ELK를 Production에 적용하면서 얻은 Lesson Learned를 공유합니다. 실제로 개발 모드에서는 아래와 같이 복잡하게 할 필요가 없습니다. 그러나 Production 으로 올라게게되면 보안 / Heap 셋팅 / Memlock 셋팅 등 자잘하게 손 대야 할 부분이 많이 생깁니다. 그 중, 보안을 적용하여 ELK Stack을 구축하는 부분을 간단하게 정리해 봅니다. 자세한 내용은 Elastic Stack 보안 설명서를 읽어보실 것을 권장합니다.
ELK의 보안 스펙은 별도로 설정하는 것이 아니라 yml 파일에 host 주소에 loop-back(127.0.0.1) 이 아닌 값이 들어가면 자동으로 X-PACK Bootstrap을 시작합니다.
또한 http.port와 transport.port의 경우, 작성하지 않으면 default로 9200/9300을 잡을 것으로 예상했으나 그렇지 않았습니다. 해당 값을 넣지 않으면 아마도 elasticsearch 내부에서 http는 9200~9299, transport는 9300~9399 사이에 값을 사용하는 것 같습니다.
인증서는 공인된 기관의 인정서가 있는 경우, 해당 인증서를 사용하면 됩니다. 그러나 ELK의 경우, 거의 내부망 (Nginx / Apache / API Server를 사용하여 통신하고 ELK를 직접 인터넷 망에 붙이지는 않는다.) 에 위치하므로 별도의 도메인을 붙여야 할 필요가 없습니다.
Elastic은 아래와 같은 utility 를 제공합니다.
bin/elasticsearch-certutil 을 사용하여 훨씬 수월하게 만들 수 있습니다.
bin/elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass "" |
위와 같이 p12 파일을 패스워드 없이 생성할 수 있습니다.
가장 간단한 방법으로 인증서를 생성할 수 있는 방법입니다. 다만logstash / kibana를 적용하려면 crt / key 파일을 별도로 만드는 것이 좋습니다.
즉, ELK Stack을 구축하려면 위의 방법 보다는 CA 파일과 인증서 / 키를 별도로 만드는 것이 좋습니다.
bin/elasticsearch-certutil cert ca --pem --in instance.yml –out certs.zip |
Instances.yml은 다음과 같이 구성합니다.
instances: - name: "hb-es-node1" ip: - "10.10.15.201" - name: 'hb-es-node2' ip: - "10.10.15.202" - name: "hb-es-node3" ip: - "10.10.15.203" - name: 'hb-kibana' ip: - "110.10.15.190" - name: 'logstash' ip: - "10.10.15.192"
|
/etc/hosts 파일을 사용할 경우, ip를 dns로 변경할 수 있으며 ip와 dns를 둘 다 사용해도 좋습니다.
# yml 파일에 인스턴스 정보 추가 instances: - name: 'node1' dns: [ 'node1.elastic.elixian.co.kr' ] - name: "node2" dns: [ 'node2.elastic.elixian.co.kr'] - name: kibana' dns: [ 'kibana.local' ] - name: 'logstash' dns: [ 'logstash.local' ] |
이렇게 인증 관련 파일을 생성하면 각 계정 별 비밀 번호를 생성해야 합니다.
비밀 번호는 elasticsearch에서 제공하는 별도의 util을 사용합니다.
bin/elasticsearch-setup-passwords auto
bin/elasticsearch-setup-passwords interactive |
Auto의 경우, elasticsearch가 자동으로 임의의 password를 생성해 주고, interactive의 경우, 사용자가 입력할 수 있습니다.
Please confirm that you would like to continue [y/N]y
Changed password for user apm_system PASSWORD apm_system = KwGA9NiowJiwle9PQHqo
Changed password for user kibana PASSWORD kibana = cZAdtghFDIfdgU03tDzP
Changed password for user logstash_system PASSWORD logstash_system = tKoKvBacSFPjEKdShmfY
Changed password for user beats_system PASSWORD beats_system = 52tCYGE846D0BtvtGsXU
Changed password for user remote_monitoring_user PASSWORD remote_monitoring_user = 4L3coyUwc8DRTB7y84ze
Changed password for user elastic PASSWORD elastic = z2HGfIqeAoz1SwTRmXuV |
어디 잘 적어줘야 합니다.
중요한 것은 비밀 번호는 항상 Master Node에서 하는 것이 좋습니다.
Elasticsearch를 clustering으로 실행했을 때, Master 한 군데서 비밀 번호를 만들면 다른 곳에서는 하지 않아도 됩니다.
(실제로 node2가 마스터였는데 node1에 비밀 번호를 설정하면 인증 실패가 나올겁니다. – 테스트하지 않아서 확실하지 않습니다.
인증 실패는 docker-compose down 하여 password 가 초기화 된 것이 원인 같다.)
다음은 elasticsearch.yml 파일의 구성입니다.
3개의 노드를 실행하고 각각의 노드는 Master / Data 속성이 true 입니다.
많은 수의 노드를 구성할 것이 아니라면 별도로 Master 노드와 Data 노드를 분리하는 것은 낭비일 수 있습니다.
그리고Clustering을 구축하여 Brain Split 을 피하기 위해서는 최소한 3개의 노드가 있어야 합니다.
# cluster setting cluster.name: "hb-es-cluster" cluster.initial_master_nodes: ["hb-es-node1", "hb-es-node2", "hb-es-node3"]
# node name node.name: "hb-es-node1"
# host network setting network.host: 10.10.15.201 http.port: 9200 transport.port: 9300
# node attribute setting node.master: true node.data: true
# detail the private IPs of your nodes: discovery.seed_hosts: ["10.10.15.201", "10.10.15.202", "10.10.15.203"]
# lock memory heap bootstrap.memory_lock: true
# xpack setting xpack.security.enabled: true
#xpack.security.transport.ssl.verification_mode: certificate #xpack.security.transport.ssl.keystore.path: elastic-certificates.p12 #xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
xpack.security.transport.ssl.enabled: true xpack.security.transport.ssl.key: /usr/share/elasticsearch/config/cert/hb-es-node1.key xpack.security.transport.ssl.certificate: /usr/share/elasticsearch/config/cert/hb-es-node1.crt xpack.security.transport.ssl.certificate_authorities: /usr/share/elasticsearch/config/cert/ca.crt
#xpack.security.http.ssl.verification_mode: certificate #xpack.security.http.ssl.keystore.path: elastic-certificates.p12 #xpack.security.http.ssl.truststore.path: elastic-certificates.p12
xpack.security.http.ssl.enabled: true xpack.security.http.ssl.key: /usr/share/elasticsearch/config/cert/hb-es-node1.key xpack.security.http.ssl.certificate: /usr/share/elasticsearch/config/cert/hb-es-node1.crt xpack.security.http.ssl.certificate_authorities: /usr/share/elasticsearch/config/cert/ca.crt |
위의 YAML 파일 중, 주석 처리한 부분을 확인할 수 있습니다.
#xpack.security.transport.ssl.verification_mode: certificate #xpack.security.transport.ssl.keystore.path: elastic-certificates.p12 #xpack.security.transport.ssl.truststore.path: elastic-certificates.p12 |
이렇게 설정하면 p12 파일로 비교적 간단하게 설정을 할 수 있습니다.
하지만 위의 설정 코드를 logstash / kibana에 넣으면 docker-compose up시, 오류를 발생합니다.
해당 설정은elasticsearch에서만 가능해 보입니다.
또한 logstash와 kibana 사이에도 속성이 미묘하게 다릅니다.
예를 들어 Logstash에서는 CA 파일만 있으면 elasticsearch와 TLS 통신이 가능합니다.
xpack.monitoring.elasticsearch.ssl.certificate_authority: /usr/share/logstash/config/cert/ca.crt |
여기에 반해 Kibana의 경우,
server.ssl.enabled: true server.ssl.certificate: /usr/share/kibana/config/cert/hb-kibana.crt server.ssl.key: /usr/share/kibana/config/cert/hb-kibana.key
elasticsearch.ssl.certificateAuthorities: [ "/usr/share/kibana/config/cert/ca.crt" ] |
CA 파일 뿐만 아니라 crt / key 페어도 넣어줘야 정상적으로 연동됩니다.
모든 설정이 끝났다면 테스트를 해봐야 합니다.
# curl https 요청하기 curl --insecure -X GET -u elastic:xxxxxxx "https://10.10.15.202:9200?pretty"
curl --cacert ca.crt -u elastic: xxxxxxx 'https://node2.elastic.elixian.co.kr:9200/_cat/nodes?v'
|
인증서가 있는 경우, --cacert 옵션을 이용하고, 테스트의 경우에는 간단하게 –insecure 옵션을 주고 테스트 합니다.
인증 관련 작업이 마무리 되면 Elasticsearch가 운용되는 서버의 VM 설정을 해야 합니다.
설정은 Elasticsearch 홈페이지를 캡쳐했습니다.
RPM 등으로 설치하면 자동으로 잡아주는데 Docker로 설치할 경우, 별도로 셋팅해야 합니다.
셋팅은 Docker Host에서 잡습니다.