login: installer
password: opnsense
Once the WAN and LAN parameters are provisioned, connect to the web GUI using an endpoint workstation configured with a valid static IP address within the LAN segment, as the internal DHCP service is currently offline.
Default Access Credentials:
* Username: root
Password: 1234*
Next, enable the structural network interfaces and provision the primary IP gateway addresses for each LAN segment. Navigate to Interfaces and select the target LAN instance.
Activate the interface by selecting the Enable Interface checkbox. To configure the static gateway IP address, modify the IPv4 Configuration Type dropdown field to Static IPv4.
To configure the dynamic addressing services across our internal networks, navigate to Services / ISC DHCPv4, and select the specific LAN zone where the DHCP service needs to be enabled.
After choosing the target LAN zone, check the Enable DHCP server on the work interface checkbox. Define the range of dynamic IP allocations reserved for local network hosts in the Range fields.
The next engineering phase involves provisioning our firewall access control rules. For this deployment, security policy dictates that the internal network zone ("inter") host sandbox machines containing unverified code repositories; therefore, this zone must remain completely isolated. The "inter" network zone must only receive inbound SSH traffic initiated explicitly from the DMZ zone. No workloads inside the "inter" zone are permitted to initiate outbound requests to other local networks.
To configure these access control policies, navigate to Firewall -> Rules -> <network>. For this segment, choose the inter interface policies.
Create a dedicated firewall rule on the "inter" interface that exclusively allows inbound SSH sessions originating from the DMZ subnet. Click the + action icon to append a new rule definition.
Set the administrative action of this policy rule to Pass, allowing traffic matching the criteria defined below to pass through the packet filter.
Set the target interface constraint to the specific hardware network card mapped to the inter zone.
Set the traffic direction parameter to in. By default, OPNsense firewall rule logic filters inbound traffic vectors on a given interface. Outbound configuration directions are rarely necessary; the core firewall uses a default-deny posture. If only an inbound rule exists without an explicitly corresponding outbound rule, the firewall automatically blocks all traffic paths that do not match the inbound rule criteria.
Set the acceptable layer 4 transmission protocol to TCP, which matches the transport standard used by SSH.
Set the packet source context to the DMZ net object and define the destination target as the inter net object.
Set the destination port scope constraint exclusively to SSH. Leave all remaining extended structural configurations at their default settings and click Save.
Create an explicit ANY rule on the DMZ interface network profile. This policy allows DMZ nodes to send and receive any traffic standard, including outbound access to the public internet. Because OPNsense defaults to a strict default-deny model, omitting this permissive definition would result in total isolation of the DMZ network zone.
The next phase involves validating our access control rules. For validation testing, we deploy a Kali Linux instance running an active openssh-server instance within the isolated "inter" network zone, along with a Windows workstation acting as the testing node.
As verified by the terminal capture, the Windows client successfully initiates and establishes a remote SSH session to the Kali Linux target host.
Next, we test the outbound network isolation of the "inter" zone by attempting to forge outbound requests from the Kali Linux host to external networks.
The terminal capture confirms that the Kali Linux instance cannot resolve public web requests or reach adjacent protected networks (validated via a failed curl request hitting a T-Pot honeypot node listening on the DMZ network segment).
To build our centralized logging environment, we deploy 3 discrete server nodes: one dedicated to Elasticsearch, another hosting the Kibana visual portal, and a third running Logstash. We configured isolated SSH sessions on each server node to improve text readability and optimize our command pipeline. The deployment logs and installation steps are detailed below:
vm.max_map_count to a minimum value of 262144. The default operating system values are insufficient for Elasticsearch memory allocations and will trigger runtime initialization failures.echo "vm.max\_map\_count=262144" | sudo tee \-a /etc/sysctl.confsudo sysctl \-p
sudo apt install apt-transport-https ca-certificates curl gnupg \-ycurl \-fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg \--dearmor \-o /usr/share/keyrings/elastic.gpgecho "deb \[signed-by=/usr/share/keyrings/elastic.gpg\] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.listsudo apt update
apt engine.Crucial Operational Note: During this automated package setup phase, the installation script dynamically generates and outputs a temporary superuser credential for the root account. This string must be securely documented.
Administrative Notice: The root administrative password string recorded for this lab deployment is: zBlLm2UOlj_rCerTDwqJ
sudo systemctl enable –now elasticsearchsudo systemctl status elasticsearch
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token \-s kibana
Generated Enrollment Token String: eyJ2ZXIiOiI4LjE0LjAiLCJhZHIiOlsiMTkyLjE2OC4zMS41MDo5MjAwIl0sImJnciI6IjQ4YjdlMTkzZjgzZTkxOTNkZThjYmRkMjMwMzY5ZDg4NTJmZGFlNDQ5OGY5YzgwMWYzZjhiNjg2ODRmOGQzMzkiLCJrZXkiOiJuOGo5dnB3QjAzT2swSUlKXzhweDptaGtybGtBeGlXUUViZXNPRW9wVGN3In0=
This generated security token string will be used later during the Kibana service enrollment setup to link the log analytics layers.
sudo apt install apt-transport-https ca-certificates curl gnupg \-ycurl \-fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg \--dearmor \-o /usr/share/keyrings/elastic.gpgecho "deb \[signed-by=/usr/share/keyrings/elastic.gpg\] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.listsudo apt update
apt:sudo apt install kibana
sudo systemctl enable \--now kibana
5601). Paste the secure cluster enrollment token generated on the Elasticsearch server node during Step 7.kibana-verification-code on the host console:elastic and the secure operational password string recorded during Step 3 of the Elasticsearch setup phase.sudo apt install apt-transport-https ca-certificates curl gnupg \-ycurl \-fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg \--dearmor \-o /usr/share/keyrings/elastic.gpgecho "deb \[signed-by=/usr/share/keyrings/elastic.gpg\] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.listsudo apt update
sudo apt install logstash \-y
sudo systemctl enable \--now logstash
sudo nano /etc/logstash/conf.d/elk-lab.conf
input {
stdin {}
}
filter {
# Add future filters here (grok, mutate, date...)
}
output {
elasticsearch {
hosts => ["[https://192.168.31.50:9200](https://192.168.31.50:9200)"]
user => "elastic"
password => "zBlLm2UOlj_rCerTDwqJ"
ssl => true
ssl_certificate_verification => false
index => "logs-lab-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}
sudo /usr/share/logstash/bin/logstash \-f /etc/logstash/conf.d/elk-lab.conf
stdin {} input block captures arbitrary text strings typed into the terminal window and routes them as standard log structures directly to the Elasticsearch API endpoint.
input {
beats {
port => 5044
host => "0.0.0.0"
}
}
sudo systemctl restart logstash
curl \-fsSL https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg \--dearmor \-o /usr/share/keyrings/elastic.gpgecho "deb \[signed-by=/usr/share/keyrings/elastic.gpg\] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list sudo apt update
apt:sudo apt install filebeat \-y
/etc/filebeat/filebeat.yml. Assign a unique host identifier to the node and enable the Filebeat tracking engine.sudo filebeat modules enable system
sudo filebeat test config
sudo filebeat test output
sudo systemctl enable \--now filebeat
sudo journalctl \-u logstash \-f
System Monitor (Sysmon) is a Windows system service and device driver that remains resident across system reboots. It monitors and logs system activity directly to the Windows Event Log, providing detailed tracking data on process creation, network connections, and file modification timestamps.
Documentation link: https://learn.microsoft.com/en-us/sysinternals/downloads/sysmon
The software package can be deployed using multiple administrative methods depending on environment constraints.
Execute the core installation sequence via the command line with the following argument:
sysmon -i
Default Credentials:
Username: admin
Password: 1234
install.sh shell script and run the installation script. Enter the confirmation flag y to proceed with the T-Pot automated setup.Prerequisite requirement: The local host must have an active instance of the openssh-server service preinstalled.
For our environment deployment, the target Elastic Stack instance is distributed across separate processing servers operating on the same local subnet.
Once the setup script finishes processing, reboot the system. Hardening the SSH daemon configuration afterward is recommended.
Before running the sensor deployment routines, generate a cryptographic SSH keypair on the administrative system for the user account assigned to manage the remote sensor array over SSH.
Generate the key structure with: ssh-keygen
ssh-copy-id \-p \<port\> \<user\>@\<IP\_T-Pot\>
Generate the required Nginx server layer cryptographic keys before continuing the setup phase.
Once the key pair generation completes, rename the generated certificate extension identifier from .cert to .crt.
With the prerequisite configurations complete, run the primary automated T-Pot deployment script: deploy.sh. Follow the prompts provided by the command-line interface.
Once the deployment process wraps up, run the standard container diagnostic tool to verify that all T-Pot container services are active:
docker ps
T-Pot deploys an array of integrated honeypots alongside a Suricata IDS monitoring layer. While the ecosystem supports an automated local ELK deployment option, we omitted it here to route logs to our dedicated external ELK stack instead.
filebeat.yml for editing:/home/admin/), update the source log paths to point precisely to the directory where the honeypot container runtime logs are generated.Run the file configuration diagnostic verification tool to ensure there are no configuration syntax errors:
Run an operational connection validation test against the destination Logstash endpoint to verify communication paths are open:
Verify the live Logstash ingestion console stream to confirm that telemetry logs from T-Pot's integrated Suricata instance are successfully arriving and parsing client connection attempts hitting our decoy honeypot ports.
apt install nut
| apt install libusb-1.0-0-dev libupsclient-dev |
|---|
After installation, configure the application files located within the primary system path directory /etc/nut/.
ups.conf:Testing Configuration Note: Because we are implementing the mock dummy driver engine, we must configure a virtual system data file port. This allows us to write mock status indicators to simulate the real telemetry returned by a physical UPS array.
upsd.users:upsd.conf:upsmon.conf:#!/bin/bash
case "${NOTIFYTYPE}" in
ONLINE)
_notifymessage="🟢 UPS ${UPSNAME} | Power restored ⚡ System is running on normal utility power."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
ONBATT)
_notifymessage="🔴 UPS ${UPSNAME} | Power outage ⚠️ The system is currently running on battery."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
LOWBATT)
_notifymessage="🪫 UPS ${UPSNAME} | Low battery warning ⚠️ The UPS battery level is critically low."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
FSD)
_notifymessage="⛔ UPS ${UPSNAME} | Forced shutdown. The system is forcing shutdown to protect the equipment."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
COMMOK)
_notifymessage="📡 UPS ${UPSNAME} | Communication restored ✅ Connection with the UPS has been successfully established."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
COMMBAD)
_notifymessage="❌ UPS ${UPSNAME} | Communication lost. Unable to communicate with the UPS."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
SHUTDOWN)
_notifymessage="🔌 System shutdown in progress. Logging out and powering off the system."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
REPLBATT)
_notifymessage="🔋 UPS ${UPSNAME} | Battery replacement required ⚠️ The UPS battery needs to be replaced."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
NOCOMM)
_notifymessage="⚠️ UPS ${UPSNAME} | UPS not available. The UPS device is currently unreachable."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
NOPARENT)
_notifymessage="🚨 Automatic shutdown failed. Administrator intervention is required."
/usr/bin/python3 /etc/nut/bot.py "${_notifymessage}"
;;
*)
/usr/bin/python3 /etc/nut/bot.py "❓ UPS | Unknown event detected."
;;
esac
With the handling automation script ready, start the service daemon components.
import requests
import sys
bot_token = "BOT_KEY" # Replace with your production bot token API string
chat_id = "CHATID"
def main():
url = f"[https://api.telegram.org/bot](https://api.telegram.org/bot){bot_token}/sendMessage"
message = sys.argv[1]
payload = {"chat_id": chat_id, "text": message}
response = requests.post(url, json=payload)
if response.status_code != 200:
print('ERROR')
if __name__ == "__main__":
main()
sudo apt-get install -y software-properties-common wget
sudo mkdir -p /etc/apt/keyrings/
wget -q -O - [https://apt.grafana.com/gpg.key](https://apt.grafana.com/gpg.key) | sudo tee /etc/apt/keyrings/grafana.asc
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] [https://apt.grafana.com](https://apt.grafana.com) stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo systemctl enable --now grafana-server
Default credentials: admin:admin