├── Chapter 3 └── Lab build │ ├── esk │ ├── .env │ └── docker-compose.yaml │ └── fleet │ ├── .env │ └── docker-compose.yaml ├── Chapter 4 └── docker-compose.yaml ├── Chapter 7 └── sysmon_config.xml ├── Chapter 8 └── Possible-MOTW-bypass-ISO.yaml ├── LICENSE ├── README.md └── lab ├── esk ├── .env └── docker-compose.yml ├── fleet ├── .env └── docker-compose.yml └── readme.md /Chapter 3/Lab build/esk/.env: -------------------------------------------------------------------------------- 1 | ELASTIC_PASSWORD=<> 2 | KIBANA_PASSWORD=<> 3 | STACK_VERSION=8.4.3 4 | CLUSTER_NAME=docker-cluster 5 | LICENSE=basic 6 | ES_PORT=9200 7 | KIBANA_PORT=5601 8 | MEM_LIMIT=1073741824 9 | XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=<> 10 | XPACK_SECURITY_ENCRYPTIONKEY=<> 11 | XPACK_REPORTING_ENCRYPTIONKEY=<> 12 | -------------------------------------------------------------------------------- /Chapter 3/Lab build/esk/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | setup: 5 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 6 | volumes: 7 | - ../certs:/usr/share/elasticsearch/config/certs 8 | user: "0" 9 | command: > 10 | bash -c ' 11 | if [ x${ELASTIC_PASSWORD} == x ]; then 12 | echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; 13 | exit 1; 14 | elif [ x${KIBANA_PASSWORD} == x ]; then 15 | echo "Set the KIBANA_PASSWORD environment variable in the .env file"; 16 | exit 1; 17 | fi; 18 | if [ ! -f config/certs/ca.zip ]; then 19 | echo "Creating CA"; 20 | bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; 21 | unzip config/certs/ca.zip -d config/certs; 22 | fi; 23 | if [ ! -f config/certs/certs.zip ]; then 24 | echo "Creating certs"; 25 | echo -ne \ 26 | "instances:\n"\ 27 | " - name: es01\n"\ 28 | " dns:\n"\ 29 | " - es01\n"\ 30 | " - localhost\n"\ 31 | " ip:\n"\ 32 | " - 127.0.0.1\n"\ 33 | " - name: es02\n"\ 34 | " dns:\n"\ 35 | " - es02\n"\ 36 | " - localhost\n"\ 37 | " ip:\n"\ 38 | " - 127.0.0.1\n"\ 39 | > config/certs/instances.yml; 40 | bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; 41 | unzip config/certs/certs.zip -d config/certs; 42 | fi; 43 | echo "Setting file permissions" 44 | chown -R root:root config/certs; 45 | find . -type d -exec chmod 750 \{\} \;; 46 | find . -type f -exec chmod 640 \{\} \;; 47 | echo "Waiting for Elasticsearch availability"; 48 | until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; 49 | echo "Setting kibana_system password"; 50 | until curl -s -X POST --cacert config/certs/ca/ca.crt -u elastic:${ELASTIC_PASSWORD} -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done; 51 | echo "All done!"; 52 | ' 53 | healthcheck: 54 | test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] 55 | interval: 1s 56 | timeout: 5s 57 | retries: 120 58 | 59 | es01: 60 | depends_on: 61 | setup: 62 | condition: service_healthy 63 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 64 | volumes: 65 | - ../certs:/usr/share/elasticsearch/config/certs 66 | ports: 67 | - ${ES_PORT}:9200 68 | environment: 69 | - node.name=es01 70 | - cluster.name=${CLUSTER_NAME} 71 | - cluster.initial_master_nodes=es01,es02 72 | - discovery.seed_hosts=es02 73 | - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} 74 | - bootstrap.memory_lock=true 75 | - xpack.security.enabled=true 76 | - xpack.security.http.ssl.enabled=true 77 | - xpack.security.http.ssl.key=certs/es01/es01.key 78 | - xpack.security.http.ssl.certificate=certs/es01/es01.crt 79 | - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt 80 | - xpack.security.http.ssl.verification_mode=certificate 81 | - xpack.security.transport.ssl.enabled=true 82 | - xpack.security.transport.ssl.key=certs/es01/es01.key 83 | - xpack.security.transport.ssl.certificate=certs/es01/es01.crt 84 | - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt 85 | - xpack.security.transport.ssl.verification_mode=certificate 86 | - xpack.license.self_generated.type=${LICENSE} 87 | mem_limit: ${MEM_LIMIT} 88 | ulimits: 89 | memlock: 90 | soft: -1 91 | hard: -1 92 | healthcheck: 93 | test: 94 | [ 95 | "CMD-SHELL", 96 | "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", 97 | ] 98 | interval: 10s 99 | timeout: 10s 100 | retries: 120 101 | 102 | es02: 103 | depends_on: 104 | - es01 105 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 106 | volumes: 107 | - ../certs:/usr/share/elasticsearch/config/certs 108 | environment: 109 | - node.name=es02 110 | - cluster.name=${CLUSTER_NAME} 111 | - cluster.initial_master_nodes=es01,es02 112 | - discovery.seed_hosts=es01 113 | - bootstrap.memory_lock=true 114 | - xpack.security.enabled=true 115 | - xpack.security.http.ssl.enabled=true 116 | - xpack.security.http.ssl.key=certs/es02/es02.key 117 | - xpack.security.http.ssl.certificate=certs/es02/es02.crt 118 | - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt 119 | - xpack.security.http.ssl.verification_mode=certificate 120 | - xpack.security.transport.ssl.enabled=true 121 | - xpack.security.transport.ssl.key=certs/es02/es02.key 122 | - xpack.security.transport.ssl.certificate=certs/es02/es02.crt 123 | - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt 124 | - xpack.security.transport.ssl.verification_mode=certificate 125 | - xpack.license.self_generated.type=${LICENSE} 126 | mem_limit: ${MEM_LIMIT} 127 | ulimits: 128 | memlock: 129 | soft: -1 130 | hard: -1 131 | healthcheck: 132 | test: 133 | [ 134 | "CMD-SHELL", 135 | "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", 136 | ] 137 | interval: 10s 138 | timeout: 10s 139 | retries: 120 140 | kibana: 141 | depends_on: 142 | es01: 143 | condition: service_healthy 144 | es02: 145 | condition: service_healthy 146 | image: docker.elastic.co/kibana/kibana:${STACK_VERSION} 147 | volumes: 148 | - ../certs:/usr/share/kibana/config/certs 149 | ports: 150 | - ${KIBANA_PORT}:5601 151 | environment: 152 | - SERVERNAME=kibana 153 | - ELASTICSEARCH_HOSTS=https://es01:9200 154 | - ELASTICSEARCH_USERNAME=kibana_system 155 | - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} 156 | - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt 157 | - XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY} 158 | - XPACK_SECURITY_ENCRYPTIONKEY=${XPACK_SECURITY_ENCRYPTIONKEY} 159 | - XPACK_REPORTING_ENCRYPTIONKEY=${XPACK_REPORTING_ENCRYPTIONKEY} 160 | mem_limit: ${MEM_LIMIT} 161 | healthcheck: 162 | test: 163 | [ 164 | "CMD-SHELL", 165 | "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'", 166 | ] 167 | interval: 10s 168 | timeout: 10s 169 | retries: 120 170 | networks: 171 | default: 172 | name: elastic-stack-network 173 | volumes: 174 | certs: 175 | driver: local 176 | esdata01: 177 | driver: local 178 | esdata02: 179 | driver: local 180 | kibanadata: 181 | driver: local 182 | -------------------------------------------------------------------------------- /Chapter 3/Lab build/fleet/.env: -------------------------------------------------------------------------------- 1 | FLEET_SERVER_SERVICE_TOKEN=<> 2 | -------------------------------------------------------------------------------- /Chapter 3/Lab build/fleet/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | services: 3 | fleet-server: 4 | image: docker.elastic.co/beats/elastic-agent:8.4.3 5 | container_name: fleet-server 6 | restart: always 7 | volumes: 8 | - ../certs:/certs 9 | ports: [8220:8220] 10 | user: root 11 | environment: 12 | - FLEET_SERVER_ENABLE=true 13 | - FLEET_SERVER_POLICY_NAME=fleet-server-policy 14 | - FLEET_SERVER_ELASTICSEARCH_HOST=https://es01:9200 15 | - FLEET_SERVER_SERVICE_TOKEN=${FLEET_SERVER_SERVICE_TOKEN} 16 | - FLEET_SERVER_ELASTICSEARCH_CA=/certs/ca/ca.crt 17 | - FLEET_INSECURE=true 18 | networks: 19 | default: 20 | name: elastic-stack-network 21 | -------------------------------------------------------------------------------- /Chapter 4/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | webapp: 4 | build: 5 | context: ./diwa 6 | ports: 7 | - 80:80 8 | volumes: 9 | - /var/log/apache2:/var/log/apache2 -------------------------------------------------------------------------------- /Chapter 7/sysmon_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HKLM\SYSTEM\CurrentControlSet\Services 6 | 7 | 8 | \ImagePath 9 | 10 | 11 | \ImagePath 12 | 13 | 14 | 15 | 16 | 17 | \ 18 | 19 | 20 | msedgeview 21 | \wkssvc 22 | \srvsvc 23 | \lsass 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Chapter 8/Possible-MOTW-bypass-ISO.yaml: -------------------------------------------------------------------------------- 1 | [metadata] 2 | creation_date = "2023/01/30" 3 | maturity = "development" 4 | updated_date = "2023/01/30" 5 | 6 | [rule] 7 | author = ["Jason Deyalsingh"] 8 | description = """ 9 | This detection identifies an ISO mounted from a zip existing in a temp directory, which is a procedure used by Qakbot 10 | to perform MOTW bypass. Mark of the web tags exist on Windows operating systems, to inform the user and system 11 | when certain files were downloaded from the internet. This tag attempts to block or otherwise subvert certain 12 | potentially unsafe actions from being performed. Mark of the web bypass techniques attempt to deliver files to the end 13 | user without this tag set, allowing potentially unsafe actions to be taken. 14 | """ 15 | from = "now-9m" 16 | index = ["winlogbeat-*"] 17 | language = "eql" 18 | license = "MIT" 19 | name = "ISO mounted from zip temporary directory" 20 | note = """## Investigation Suggestions: 21 | 22 | The ISO run within the temporary directory should be investigated as possible malware. Attempt to identify and evaluate the carrier email message that delivered the ISO as a possible phishing email or investigate the domain or website the ISO was downloaded from. Continue to monitor the endpoint for the "Wermgr running reconnaissance commands" alert which identifies suspicious activity that has been seen occurring after this activity and can be used to confirm the threat as a true positive. 23 | 24 | ##Responses or Remediations: 25 | If confirmed as malicious activity, contain the endpoint prior to remediating. Check all outgoing network connections from the endpoint to identify possible C2. This activity has been associated with ransomware activity and lateral movement using Brute Ratel and Cobalt Strike. 26 | 27 | ##False Positives 28 | Users can legitimately download a zipped ISO file as a developer or network admin role. 29 | """ 30 | references = [ 31 | "https://www.trendmicro.com/en_us/research/22/j/black-basta-infiltrates-networks-via-qakbot-brute-ratel-and-coba.html" 32 | ] 33 | risk_score = 50 34 | rule_id = "8a1d4831-3ce6-4859-9891-28931fa6101d" 35 | severity = "medium" 36 | tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] 37 | timestamp_override = "event.ingested" 38 | type = "eql" 39 | 40 | query = ''' 41 | any where event.code=="1" and winlog.channel=="Microsoft-Windows-VHDMP-Operational" and winlog.event_data.VhdFileName like~ ("*Temp*","*.zip*","*.iso") 42 | ''' 43 | 44 | 45 | [[rule.threat]] 46 | framework = "MITRE ATT&CK" 47 | [[rule.threat.technique]] 48 | id = "T1027" 49 | name = "Obfuscated Files or Information" 50 | reference = "https://attack.mitre.org/techniques/T1027/" 51 | 52 | framework = "MITRE ATT&CK" 53 | [[rule.threat.technique]] 54 | id = "T1553" 55 | name = "Subvert Trust Controls" 56 | reference = "https://attack.mitre.org/techniques/T1553/" 57 | [[rule.threat.technique.subtechnique]] 58 | id = "T1553.005" 59 | name = "Subvert Trust Controls: Mark-of-the-Web" 60 | reference = "https://attack.mitre.org/techniques/T1553/005/" 61 | 62 | 63 | [rule.threat.tactic] 64 | id = "TA0005" 65 | name = "Defense Evasion" 66 | reference = "https://attack.mitre.org/tactics/TA0005/" 67 | [[rule.threat]] 68 | 69 | framework = "MITRE ATT&CK" 70 | [[rule.threat.technique]] 71 | id = "T1204" 72 | name = "User Execution" 73 | reference = "https://attack.mitre.org/techniques/T1204/" 74 | [[rule.threat.technique.subtechnique]] 75 | id = "T1204.002" 76 | name = "User Execution: Malicious Image" 77 | reference = "https://attack.mitre.org/techniques/T1059/002/" 78 | 79 | [rule.threat.tactic] 80 | id = "TA0002" 81 | name = "Execution" 82 | reference = "https://attack.mitre.org/tactics/TA0002/" 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practical Threat Detection Engineering 2 | 3 | 4 | 5 | This is the code repository for [Practical Threat Detection Engineering](https://www.packtpub.com/product/practical-detection-engineering/9781801076715?utm_source=github&utm_medium=repository&utm_campaign=9781801076715), published by Packt. 6 | 7 | **A hands-on guide to planning, developing, and validating detection capabilities** 8 | 9 | ## What is this book about? 10 | 11 | This book covers the following exciting features: 12 | * Become well versed in the detection engineering process 13 | * Build a detection engineering test lab 14 | * Discover how to maintain detections as code 15 | * Find out how threat intelligence can be used to drive detection development 16 | * Demonstrate the effectiveness of detection capabilities to business leadership 17 | * Limit the attackers’ ability to inflict damage by detecting malicious activity early 18 | 19 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1801076715) today! 20 | 21 | https://www.packtpub.com/ 23 | 24 | ## Instructions and Navigations 25 | All of the code is organized into folders. For example, Chapter 3. 26 | 27 | The code will look like the following: 28 | ``` 29 | ES1_DATA=/path/to/large/disk/elasticdata/es01 30 | ES2_DATA=/path/to/large/disk/elasticdata/es02 31 | KIBANA_DATA=/path/to/large/disk/elasticdata/kibana_data 32 | ``` 33 | Any command-line input or output is written as follows: 34 | ``` 35 | $ docker --version 36 | Docker version v20.10.12, build 20.10.12-0ubuntu4 37 | ``` 38 | 39 | **Following is what you need for this book:** 40 | This book is for security analysts and engineers seeking to improve their organization’s security posture by mastering the detection engineering lifecycle. 41 | To get started with this book, you’ll need a basic understanding of cybersecurity concepts, along with some experience with detection and alert capabilities. 42 | 43 | With the following software and hardware list you can run all code files present in the book (Chapter 1-12). 44 | ### Software and Hardware List 45 | | Software/hardware covered in the bookd | Operating system requirements | 46 | | ------------------------------------ | ----------------------------------- | 47 | | Docker | Windows or Linux | 48 | | VirtualBox | Windows or Linux | 49 | 50 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it]( https://packt.link/qt1nr). 51 | 52 | ### Related products 53 | * Incident Response Techniques for Ransomware Attacks [[Packt]](https://www.packtpub.com/product/incident-response-techniques-for-ransomware-attacks/9781803240442?utm_source=github&utm_medium=repository&utm_campaign=9781803240442) [[Amazon]](https://www.amazon.com/dp/180324044X) 54 | 55 | * Incident Response with Threat Intelligence [[Packt]](https://www.packtpub.com/product/incident-response-with-threat-intelligence/9781801072953?utm_source=github&utm_medium=repository&utm_campaign=9781801072953) [[Amazon]](https://www.amazon.com/dp/1801072957) 56 | 57 | ## Get to Know the Authors 58 | **Megan Roddie** 59 | is an experienced information security professional with a diverse background ranging from incident response to threat intelligence to her current role as a detection engineer. Additionally, Megan is a course author and instructor with the SANS Institute where she regularly publishes research on cloud incident response and forensics. Outside of the cyber security industry, Megan trains and competes as a high-level amateur Muay Thai fighter in Austin, TX. 60 | 61 | **Jason Deyalsingh** 62 | is an experienced consultant with over nine years of experience in the cyber security space. He has spent the last 5 years focused on digital forensics and incident response (DFIR). His current hobbies include playing with data and failing to learn Rust. 63 | 64 | **Gary J. Katz** 65 | is still trying to figure out what to do with his life while contemplating what its purpose really is. While not spiraling into this metaphysical black hole compounded by the plagues and insanity of this world, he sometimes thinks about cyber security problems and writes them down. These ruminations are, on occasion, captured in articles and books. 66 | -------------------------------------------------------------------------------- /lab/esk/.env: -------------------------------------------------------------------------------- 1 | ELASTIC_PASSWORD=<> 2 | KIBANA_PASSWORD=<> 3 | STACK_VERSION=8.4.3 4 | CLUSTER_NAME=docker-cluster 5 | LICENSE=basic 6 | ES_PORT=9200 7 | KIBANA_PORT=5601 8 | MEM_LIMIT=1073741824 9 | XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=<> 10 | XPACK_SECURITY_ENCRYPTIONKEY=<> 11 | XPACK_REPORTING_ENCRYPTIONKEY=<> 12 | -------------------------------------------------------------------------------- /lab/esk/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | 3 | services: 4 | setup: 5 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 6 | volumes: 7 | - ../certs:/usr/share/elasticsearch/config/certs 8 | user: "0" 9 | command: > 10 | bash -c ' 11 | if [ x${ELASTIC_PASSWORD} == x ]; then 12 | echo "Set the ELASTIC_PASSWORD environment variable in the .env file"; 13 | exit 1; 14 | elif [ x${KIBANA_PASSWORD} == x ]; then 15 | echo "Set the KIBANA_PASSWORD environment variable in the .env file"; 16 | exit 1; 17 | fi; 18 | if [ ! -f config/certs/ca.zip ]; then 19 | echo "Creating CA"; 20 | bin/elasticsearch-certutil ca --silent --pem -out config/certs/ca.zip; 21 | unzip config/certs/ca.zip -d config/certs; 22 | fi; 23 | if [ ! -f config/certs/certs.zip ]; then 24 | echo "Creating certs"; 25 | echo -ne \ 26 | "instances:\n"\ 27 | " - name: es01\n"\ 28 | " dns:\n"\ 29 | " - es01\n"\ 30 | " - localhost\n"\ 31 | " ip:\n"\ 32 | " - 127.0.0.1\n"\ 33 | " - name: es02\n"\ 34 | " dns:\n"\ 35 | " - es02\n"\ 36 | " - localhost\n"\ 37 | " ip:\n"\ 38 | " - 127.0.0.1\n"\ 39 | > config/certs/instances.yml; 40 | bin/elasticsearch-certutil cert --silent --pem -out config/certs/certs.zip --in config/certs/instances.yml --ca-cert config/certs/ca/ca.crt --ca-key config/certs/ca/ca.key; 41 | unzip config/certs/certs.zip -d config/certs; 42 | fi; 43 | echo "Setting file permissions" 44 | chown -R root:root config/certs; 45 | find . -type d -exec chmod 750 \{\} \;; 46 | find . -type f -exec chmod 640 \{\} \;; 47 | echo "Waiting for Elasticsearch availability"; 48 | until curl -s --cacert config/certs/ca/ca.crt https://es01:9200 | grep -q "missing authentication credentials"; do sleep 30; done; 49 | echo "Setting kibana_system password"; 50 | until curl -s -X POST --cacert config/certs/ca/ca.crt -u elastic:${ELASTIC_PASSWORD} -H "Content-Type: application/json" https://es01:9200/_security/user/kibana_system/_password -d "{\"password\":\"${KIBANA_PASSWORD}\"}" | grep -q "^{}"; do sleep 10; done; 51 | echo "All done!"; 52 | ' 53 | healthcheck: 54 | test: ["CMD-SHELL", "[ -f config/certs/es01/es01.crt ]"] 55 | interval: 1s 56 | timeout: 5s 57 | retries: 120 58 | 59 | es01: 60 | depends_on: 61 | setup: 62 | condition: service_healthy 63 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 64 | volumes: 65 | - ../certs:/usr/share/elasticsearch/config/certs 66 | ports: 67 | - ${ES_PORT}:9200 68 | environment: 69 | - node.name=es01 70 | - cluster.name=${CLUSTER_NAME} 71 | - cluster.initial_master_nodes=es01,es02 72 | - discovery.seed_hosts=es02 73 | - ELASTIC_PASSWORD=${ELASTIC_PASSWORD} 74 | - bootstrap.memory_lock=true 75 | - xpack.security.enabled=true 76 | - xpack.security.http.ssl.enabled=true 77 | - xpack.security.http.ssl.key=certs/es01/es01.key 78 | - xpack.security.http.ssl.certificate=certs/es01/es01.crt 79 | - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt 80 | - xpack.security.http.ssl.verification_mode=certificate 81 | - xpack.security.transport.ssl.enabled=true 82 | - xpack.security.transport.ssl.key=certs/es01/es01.key 83 | - xpack.security.transport.ssl.certificate=certs/es01/es01.crt 84 | - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt 85 | - xpack.security.transport.ssl.verification_mode=certificate 86 | - xpack.license.self_generated.type=${LICENSE} 87 | mem_limit: ${MEM_LIMIT} 88 | ulimits: 89 | memlock: 90 | soft: -1 91 | hard: -1 92 | healthcheck: 93 | test: 94 | [ 95 | "CMD-SHELL", 96 | "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", 97 | ] 98 | interval: 10s 99 | timeout: 10s 100 | retries: 120 101 | 102 | es02: 103 | depends_on: 104 | - es01 105 | image: docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} 106 | volumes: 107 | - ../certs:/usr/share/elasticsearch/config/certs 108 | environment: 109 | - node.name=es02 110 | - cluster.name=${CLUSTER_NAME} 111 | - cluster.initial_master_nodes=es01,es02 112 | - discovery.seed_hosts=es01 113 | - bootstrap.memory_lock=true 114 | - xpack.security.enabled=true 115 | - xpack.security.http.ssl.enabled=true 116 | - xpack.security.http.ssl.key=certs/es02/es02.key 117 | - xpack.security.http.ssl.certificate=certs/es02/es02.crt 118 | - xpack.security.http.ssl.certificate_authorities=certs/ca/ca.crt 119 | - xpack.security.http.ssl.verification_mode=certificate 120 | - xpack.security.transport.ssl.enabled=true 121 | - xpack.security.transport.ssl.key=certs/es02/es02.key 122 | - xpack.security.transport.ssl.certificate=certs/es02/es02.crt 123 | - xpack.security.transport.ssl.certificate_authorities=certs/ca/ca.crt 124 | - xpack.security.transport.ssl.verification_mode=certificate 125 | - xpack.license.self_generated.type=${LICENSE} 126 | mem_limit: ${MEM_LIMIT} 127 | ulimits: 128 | memlock: 129 | soft: -1 130 | hard: -1 131 | healthcheck: 132 | test: 133 | [ 134 | "CMD-SHELL", 135 | "curl -s --cacert config/certs/ca/ca.crt https://localhost:9200 | grep -q 'missing authentication credentials'", 136 | ] 137 | interval: 10s 138 | timeout: 10s 139 | retries: 120 140 | kibana: 141 | depends_on: 142 | es01: 143 | condition: service_healthy 144 | es02: 145 | condition: service_healthy 146 | image: docker.elastic.co/kibana/kibana:${STACK_VERSION} 147 | volumes: 148 | - ../certs:/usr/share/kibana/config/certs 149 | ports: 150 | - ${KIBANA_PORT}:5601 151 | environment: 152 | - SERVERNAME=kibana 153 | - ELASTICSEARCH_HOSTS=https://es01:9200 154 | - ELASTICSEARCH_USERNAME=kibana_system 155 | - ELASTICSEARCH_PASSWORD=${KIBANA_PASSWORD} 156 | - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=config/certs/ca/ca.crt 157 | - XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY=${XPACK_ENCRYPTEDSAVEDOBJECTS_ENCRYPTIONKEY} 158 | - XPACK_SECURITY_ENCRYPTIONKEY=${XPACK_SECURITY_ENCRYPTIONKEY} 159 | - XPACK_REPORTING_ENCRYPTIONKEY=${XPACK_REPORTING_ENCRYPTIONKEY} 160 | mem_limit: ${MEM_LIMIT} 161 | healthcheck: 162 | test: 163 | [ 164 | "CMD-SHELL", 165 | "curl -s -I http://localhost:5601 | grep -q 'HTTP/1.1 302 Found'", 166 | ] 167 | interval: 10s 168 | timeout: 10s 169 | retries: 120 170 | networks: 171 | default: 172 | name: elastic-stack-network 173 | volumes: 174 | certs: 175 | driver: local 176 | esdata01: 177 | driver: local 178 | esdata02: 179 | driver: local 180 | kibanadata: 181 | driver: local 182 | -------------------------------------------------------------------------------- /lab/fleet/.env: -------------------------------------------------------------------------------- 1 | FLEET_SERVER_SERVICE_TOKEN=<> 2 | -------------------------------------------------------------------------------- /lab/fleet/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.6" 2 | services: 3 | fleet-server: 4 | image: docker.elastic.co/beats/elastic-agent:8.4.3 5 | container_name: fleet-server 6 | restart: always 7 | volumes: 8 | - ../certs:/certs 9 | ports: [8220:8220] 10 | user: root 11 | environment: 12 | - FLEET_SERVER_ENABLE=true 13 | - FLEET_SERVER_POLICY_NAME=fleet-server-policy 14 | - FLEET_SERVER_ELASTICSEARCH_HOST=https://es01:9200 15 | - FLEET_SERVER_SERVICE_TOKEN=${FLEET_SERVER_SERVICE_TOKEN} 16 | - FLEET_SERVER_ELASTICSEARCH_CA=/certs/ca/ca.crt 17 | - FLEET_INSECURE=true 18 | networks: 19 | default: 20 | name: elastic-stack-network 21 | -------------------------------------------------------------------------------- /lab/readme.md: -------------------------------------------------------------------------------- 1 | # Elasticstack - docker deployment 2 | 3 | 4 | 5 | 6 | Before running docker-compose, make sure to execute the following command: 7 | 8 | ~~~bash 9 | sysctl -w vm.max_map_count=262144 10 | ~~~ 11 | 12 | 13 | ### Windows and docker desktop 14 | 15 | 16 | #### requirements 17 | - requires: WSL 2 18 | - use a static IP address 19 | 20 | #### Procedure - elastic stack 21 | 22 | 1. Install docker desktop 23 | 2. install docker-compose [Other install scearios](https://docs.docker.com/compose/install/other/#on-windows-server) 24 | 3. copy docker-compose.yaml and .env to a separate folder 25 | 4. configure vm.max_map_count variable for docker wsl distribution 26 | ~~~powershell 27 | c:\progs\docker\elastic>wsl -l 28 | Windows Subsystem for Linux Distributions: 29 | Ubuntu (Default) 30 | podman-machine-default 31 | docker-desktop 32 | docker-desktop-data 33 | c:\progs\docker\elastic>wsl -d docker-desktop 34 | labhost8:/mnt/host/c/progs/docker/elastic# sysctl -w vm.max_map_count=262144 35 | vm.max_map_count = 262144 36 | ~~~ 37 | 38 | 5. run docker-compose up -d 39 | 40 | --------------------------------------------------------------------------------