End-to-end Azure security: NSG IP allowlisting, key-only SSH, centralized syslog into Log Analytics via Azure Monitor Agent, KQL detections for SSH success / failure / brute-force, and alert rules for brute-force threshold and stale heartbeat.
This is Cell B of the Cloud Cells series — see Related projects.
Provision → Harden → Monitor → Detect → Respond → Improve
The lab walks the full security operations lifecycle in Azure: stand up infrastructure (Cell A), harden it (NSG, SSH key-only), instrument it (Log Analytics + AMA + DCR), write KQL detections, configure alerts, and verify by exercising the alerts.
| Capability | Implementation | Proof |
|---|---|---|
| Network exposure control | NSG nsg-cloudcells-mgmt with Allow-SSH-MyIP scoped to /32 |
NSG rule screenshot |
| Key-only SSH access | Password auth disabled; SSH key required | sshd_config + login proof |
| Centralized logging | Log Analytics Workspace law-cloudcells-b + AMA + DCR dcr-cloudcell-b-linux (LOG_AUTH, LOG_AUTHPRIV) |
DCR + LAW screenshots |
| Heartbeat validation | Heartbeat table returns VM rows | KQL output screenshot |
| Syslog validation | Syslog table returns auth / authpriv rows | KQL output screenshot |
| SSH success detection | KQL on Syslog for Accepted publickey/password |
KQL output |
| SSH failure detection | KQL on Syslog for Invalid user, Failed publickey/password |
KQL output |
| Brute-force detection | Threshold query: ≥ 5 failures in 5 minutes | KQL output + fired alert |
| Stale heartbeat alerting | heartbeat-stale-5m Sev 3 fires when LastSeen < ago(5m) |
Alert detail screenshot |
Note: the VM hostname appears as
vm-mgmt-ubunto-01in Linux logs; the Azure resource name isvm-mgmt-ubuntu-01.
- Resource Group:
rg-cloudcells-a - VM:
vm-mgmt-ubuntu-01- Public IP:
<your-vm-public-ip>(replace with your deployment's assigned IP) - Private IP:
10.0.2.4
- Public IP:
- NSG:
nsg-cloudcells-mgmt- Rule:
Allow-SSH-MyIP(22/TCP) - Source:
<YOUR_PUBLIC_IP>/32(must be updated when IP changes) - Destination:
10.0.2.4
- Rule:
Full queries in logs/detections.md:
- Heartbeat ingestion check
- SSH successes (
Accepted publickey/password) - SSH failures (
Invalid user/Failed publickey/password) - Brute-force threshold query (≥ 5 failures in 5 minutes)
Full rule definitions in alerts/alert-rules.md:
| Alert | Severity | Trigger |
|---|---|---|
ssh-bruteforce-5in5m |
Sev 3 | KQL brute-force query returns > 0 results |
heartbeat-stale-5m |
Sev 3 | LastSeen < ago(5m) (agent stopped reporting) |
Screenshots live in screenshots/ — key proof artifacts:
- NSG rule showing SSH restricted to
/32 - Network Watcher IP Flow Verify = Allowed
- DCR creation + LAW workspace creation
- KQL query results (Heartbeat / Syslog / SSH success / SSH failures)
- Fired alerts and alert detail panes
Copy/paste:
- Hardened Azure VM access by restricting inbound SSH via NSG IP allowlisting and enforcing key-only authentication.
- Centralized Linux auth logging using Azure Monitor Agent + Data Collection Rule into a Log Analytics Workspace.
- Built and validated KQL detections for SSH success / failures and configured alert rules for brute-force behavior and stale heartbeats.
| Path | Purpose |
|---|---|
hardening/ |
NSG configs and SSH hardening notes |
monitoring/ |
Log Analytics + AMA + DCR setup |
logs/detections.md |
KQL detections (heartbeat, SSH success/fail, brute-force) |
alerts/alert-rules.md |
Alert rule definitions |
incident-simulation/ |
Brute-force exercise that triggered the alert |
remediation/ |
Response actions and lessons |
screenshots/ |
Proof artifacts |
lessons-learned.md |
Field notes |
review_cellb.sh |
Self-review checker |
- azure-fundamentals-cell — Cell A: foundation (prerequisite)
- azure-security-monitoring-lab (this repo) — Cell B: hardening + monitoring + detection
- logging-siem-wazuh — on-prem counterpart (Wazuh single-node)
- vulnerability-management-lab — on-prem vuln management
RealPhantomLee Tucker — github.com/RealPhantomLee