This repository builds a small SIEM lab in AWS using Elasticsearch, Logstash, and Kibana on EC2. The stack is provisioned with Terraform and includes subnet separation, Secrets Manager integration, KMS-backed encryption, VPC flow logs, and S3 snapshot storage.
The project was built as a practical security engineering exercise rather than a production-ready platform. The focus here is standing up the environment, moving log data end to end, validating the pipeline with real events, and keeping the whole thing easy to destroy when the lab is done.
- Private access by default: Kibana is intended to be reached over SSM port forwarding, so there is no requirement for public ingress.
- Reasonable security baseline: EBS, S3, and Secrets Manager are encrypted with KMS, security groups are narrow, and VPC flow logs are enabled.
- Minimal manual setup: Instances bootstrap from user data and pull required secrets at launch.
- Easy cleanup: The lab is meant to be created, tested, documented, and torn down without much leftover infrastructure.
Filebeat (demo host) → internal NLB :5044 (TCP) → Logstash → Elasticsearch (HTTPS :9200) → Kibana (HTTPS :5601)
Kibana is not in the ingest path; it reads from Elasticsearch.
-
Kibana stays private unless you explicitly expose it
- Default operator access is
SSM port-forward -> https://localhost:5601. - Public Kibana is supported, but only if DNS and ACM are already in place. To enable it, set
enable_public_kibana=trueand provideacm_cert_arn.
- Default operator access is
-
TLS is enabled on the Elasticsearch side
- Elasticsearch uses TLS for both HTTP (
:9200) and node transport (:9300). - In this lab build, Beats to Logstash traffic is plain TCP inside the VPC.
- Elasticsearch uses TLS for both HTTP (
-
Beats on
5044was kept simple on purpose- During bootstrap testing, Logstash failed repeatedly because the Beats input expected a cert/key pair that was not present on disk when the service started.
- For this version of the lab, reliability mattered more than full transport hardening, so
:5044was left as TCP inside the VPC with the NLB operating as a pass-through listener. - For anything beyond a lab build, Beats or Elastic Agent to Logstash should use TLS, ideally mTLS.
-
Secrets are retrieved at boot
- Instances use IAM roles and SSM to pull required values from Secrets Manager during user data execution.
- That avoids storing credentials in the repository or embedding them into AMIs.
-
Snapshots are part of the build
- Elasticsearch snapshots are written to a dedicated S3 bucket with SSE-KMS and versioning enabled.
- The default lifecycle moves objects to Glacier after
30days and deletes them after365days.
- Beats transport: move from plain TCP to mTLS for Beats or Elastic Agent to Logstash.
- Kibana exposure: place Kibana behind an ALB and WAF with DNS and an ACM certificate.
- Host security: apply a harder baseline, tighten egress, improve patching, and reduce IAM scope further.
The NLB stays L4 TCP; Logstash terminates TLS. Repo changes:
elk-siem/modules/ec2_elk/templates/user_data_logstash.sh.tftpl: restore Beats input TLS (ssl_certificate/ssl_key) and fetch the cert/key from Secrets Manager (e.g.siem/tls/logstash-cert).elk-siem/modules/ec2_elk/main.tf: pass the Logstash TLS secret name back into the template variables.elk-siem/modules/beats_demo/templates/user_data_filebeat.sh.tftpl: setoutput.logstash.ssl.enabled: trueand trust the CA (eitherssl.certificate_authoritiesor a pinned CA bundle file).
bootstrap/: Remote Terraform backend (S3 state bucket + DynamoDB lock table + KMS key).elk-siem/: Main stack (VPC, EC2, internal Beats NLB, Secrets Manager, snapshot bucket, flow logs, alarms).images/: Architecture diagrams and screenshots.
SSM managed nodes:
Set the required values in elk-siem/terraform.tfvars, then run:
cd bootstrap && terraform init && terraform apply
cd ../elk-siem && terraform init -reconfigure && terraform applycd elk-siem && terraform destroy
cd ../bootstrap && terraform destroySome resources, especially KMS keys, will remain in a pending deletion state for a period of time by design. Other resources should delete on a terraform destroy smoothly



