Azure Network Security Groups - Complete Implementation Guide
1. Azure Network Security Overview and Architecture
graph TB
subgraph "Azure Subscription"
subgraph "Resource Group"
subgraph "Virtual Network (VNet)"
subgraph "Subnet 1"
VM1[Virtual Machine 1]
NIC1[Network Interface 1]
end
subgraph "Subnet 2"
VM2[Virtual Machine 2]
NIC2[Network Interface 2]
end
end
NSG1[Network Security Group 1]
NSG2[Network Security Group 2]
ASG1[Application Security Group 1]
ASG2[Application Security Group 2]
Bastion[Azure Bastion]
end
end
Internet((Internet))
OnPrem[On-Premises Network]
Internet --> Bastion
Internet --> NSG1
OnPrem --> NSG2
NSG1 --> Subnet1
NSG2 --> Subnet2
NSG1 --> NIC1
NSG2 --> NIC2
ASG1 --> NIC1
ASG2 --> NIC2
VM1 --> NIC1
VM2 --> NIC2
style NSG1 fill:#e1f5fe
style NSG2 fill:#e1f5fe
style ASG1 fill:#f3e5f5
style ASG2 fill:#f3e5f5
style Bastion fill:#fff3e0
Architecture Explanation:
This diagram illustrates the complete Azure network security architecture:
- Network Security Groups (NSGs) - Act as virtual firewalls controlling traffic flow at subnet and NIC levels
- Application Security Groups (ASGs) - Logical grouping of resources for simplified rule management
- Azure Bastion - Secure RDP/SSH connectivity without exposing VMs to the internet
- Traffic Flow - Internet traffic flows through NSGs, while on-premises traffic uses separate NSG rules
- Multi-layer Security - NSGs can be applied at both subnet and NIC levels for defense in depth
2. Prerequisites and Initial Setup
Foundation Requirements:
Before implementing NSG security, ensure you have the basic infrastructure in place:
- Resource Group: Create "rg-network-security" in your preferred region
- Virtual Network: Create "vnet-security-demo" with address space 10.0.0.0/16
- Subnets: Create three subnets:
- subnet-web (10.0.1.0/24) - for web tier resources
- subnet-app (10.0.2.0/24) - for application tier resources
- subnet-db (10.0.3.0/24) - for database tier resources
These foundational components are standard Azure networking basics and provide the infrastructure where we'll implement our security policies.
3. Creating Network Security Groups (NSGs)
Step 1 Create the NSG resource first
Step 2 Define security rules within the NSG
Step 3 Associate NSG to subnet or NIC
graph LR
A[Create NSG] --> B[Add Security Rules]
B --> C[Associate to Subnet]
B --> D[Associate to NIC]
C --> E[Traffic Filtering Active]
D --> E
subgraph "NSG Rules Processing"
F[Inbound Rules] --> G[Rule Priority Check]
H[Outbound Rules] --> G
G --> I[Allow/Deny Decision]
end
E --> F
E --> H
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#fff3e0
style E fill:#ffebee
NSG Creation and Rule Processing Flow:
This diagram shows the sequential process of NSG implementation and how traffic filtering works:
- Creation Phase - NSG must be created before rules can be added
- Rule Definition - Security rules define traffic filtering criteria
- Association - NSGs can be associated with subnets (affects all resources) or NICs (specific resources)
- Traffic Processing - Rules are evaluated by priority (lower numbers first) until a match is found
Creating Web Tier NSG
# Create NSG for Web Tier
az network nsg create \
--resource-group "rg-network-security" \
--name "nsg-web-tier" \
--location "East US" \
--tags Tier=Web Environment=Production
Parameters Explanation:
Parameter | Description | Best Practice |
--name | NSG identifier | Use descriptive naming convention (nsg-{purpose}) |
--location | Azure region | Should match VNet location |
--tags | Metadata for organization | Include tier, environment, purpose |
Purpose: Creates an empty NSG that will contain security rules for web tier resources. This NSG will typically allow HTTP/HTTPS traffic while blocking direct administrative access.
Creating Application Tier NSG
# Create NSG for Application Tier
az network nsg create \
--resource-group "rg-network-security" \
--name "nsg-app-tier" \
--location "East US" \
--tags Tier=Application Environment=Production
Purpose: Creates NSG for application servers that typically receive traffic only from the web tier and communicate with the database tier. This implements network segmentation principles.
Creating Database Tier NSG
# Create NSG for Database Tier
az network nsg create \
--resource-group "rg-network-security" \
--name "nsg-db-tier" \
--location "East US" \
--tags Tier=Database Environment=Production
Purpose: Creates the most restrictive NSG for database resources, allowing only necessary database traffic from application tier and administrative access through bastion.
4. Associating NSGs to Resources
graph TB
subgraph "NSG Association Options"
NSG[Network Security Group]
subgraph "Subnet Level"
Subnet[Subnet]
VM1[VM 1]
VM2[VM 2]
VM3[VM 3]
end
subgraph "NIC Level"
NIC1[NIC 1]
NIC2[NIC 2]
VMa[VM A]
VMb[VM B]
end
end
NSG --> Subnet
NSG --> NIC1
NSG --> NIC2
Subnet --> VM1
Subnet --> VM2
Subnet --> VM3
NIC1 --> VMa
NIC2 --> VMb
style NSG fill:#e1f5fe
style Subnet fill:#e8f5e8
style NIC1 fill:#fff3e0
style NIC2 fill:#fff3e0
NSG Association Strategy:
This diagram illustrates two association approaches:
- Subnet-level Association - One NSG affects all resources in the subnet (easier management, broader scope)
- NIC-level Association - Individual NSG per network interface (granular control, complex management)
- Dual Association - Both subnet and NIC NSGs can be applied (rules are additive - both must allow traffic)
- Traffic Flow - Subnet NSG processes first, then NIC NSG for inbound traffic (reverse for outbound)
Associate NSG to Subnet
# Associate Web NSG to Web Subnet
az network vnet subnet update \
--resource-group "rg-network-security" \
--vnet-name "vnet-security-demo" \
--name "subnet-web" \
--network-security-group "nsg-web-tier"
Parameters Explanation:
Parameter | Description | Impact |
--network-security-group | NSG to associate | All VMs in subnet inherit these rules |
--name | Target subnet name | Must exist in the specified VNet |
Purpose: Associates the NSG with the entire subnet, meaning all current and future resources in this subnet will be subject to the NSG rules. This is the most common and efficient approach for applying consistent security policies.
# Associate Application NSG to App Subnet
az network vnet subnet update \
--resource-group "rg-network-security" \
--vnet-name "vnet-security-demo" \
--name "subnet-app" \
--network-security-group "nsg-app-tier"
# Associate Database NSG to DB Subnet
az network vnet subnet update \
--resource-group "rg-network-security" \
--vnet-name "vnet-security-demo" \
--name "subnet-db" \
--network-security-group "nsg-db-tier"
Associate NSG to Network Interface (Alternative/Additional)
# Create a VM first to get NIC, then associate NSG to specific NIC
az vm create \
--resource-group "rg-network-security" \
--name "vm-web-01" \
--image "Ubuntu2204" \
--admin-username "azureuser" \
--generate-ssh-keys \
--subnet "subnet-web" \
--vnet-name "vnet-security-demo" \
--public-ip-sku "Standard" \
--size "Standard_B2s"
# Associate NSG to the VM's NIC
az network nic update \
--resource-group "rg-network-security" \
--name "vm-web-01VMNic" \
--network-security-group "nsg-web-tier"
Purpose: Demonstrates NIC-level NSG association. This provides granular control but is more complex to manage. Use this approach when you need different security rules for specific VMs within the same subnet.
Note: When both subnet and NIC NSGs are present, traffic must pass through both sets of rules. For inbound traffic: Subnet NSG → NIC NSG. For outbound traffic: NIC NSG → Subnet NSG.
5. Application Security Groups (ASGs)
🏢 NSG vs ASG: The Office Building Analogy
🚪 NSG = Security Guards & Doors
What it is: NSGs are like security guards stationed at building entrances and elevator doors.
What they do:
- Check IDs: "Are you from the internet or internal network?"
- Verify purpose: "What port/service do you need access to?"
- Allow/deny entry: "You can enter" or "Access denied"
- Guard locations: At building entrance (subnet-level) or office door (NIC-level)
Example: "Only people from the internet can access the web servers on port 80, but no one from the internet can access the database servers on port 1433."
👥 ASG = Employee Departments/Groups
What it is: ASGs are like department badges or employee groups (Sales, IT, HR, etc.)
What they do:
- Group similar people: "All web servers belong to the Web Team"
- Simplify rules: Instead of naming each person, say "Web Team can talk to App Team"
- Dynamic membership: New web servers automatically join the "Web Team"
- Make rules readable: "Sales can access CRM" vs "IP 10.1.1.5 can access IP 10.2.1.8"
Example: "All servers in the 'Web-Servers' group can communicate with all servers in the 'App-Servers' group, regardless of their specific IP addresses."
🔄 How They Work Together:
Traditional approach (NSG only):
"Security guard, allow John Smith (IP: 10.0.1.4), Mary Johnson (IP: 10.0.1.5), and Bob Wilson (IP: 10.0.1.6) to access the database room."
Modern approach (NSG + ASG):
"Security guard, allow anyone with a 'Web-Developer' badge to access the database room."
Benefits:
- When a new web developer joins, just give them the badge - no need to update security guard instructions
- When someone leaves, remove their badge - automatic access revocation
- Rules are easier to understand: "Web-Developers can access Database-Servers" vs a list of IP addresses
- Scales better: Adding 10 new web servers doesn't require updating 10 different security rules
⚠️ Key Difference:
NSG: The actual security enforcement mechanism (the guard who checks and allows/denies)
ASG: A logical grouping tool that makes NSG rules easier to manage (the department badges)
You need both: ASGs without NSGs are like having department badges but no security guards. NSGs without ASGs work but require managing individual IP addresses.
🚦 CRITICAL: There's NO "NSG vs ASG Precedence" - They Work Together!
❌ Common Misconception:
WRONG: "If I have both NSG and ASG rules, which one wins?"
WHY IT'S WRONG: ASGs are not a separate security layer - they're just labels used WITHIN NSG rules!
✅ Correct Understanding:
RIGHT: ASGs are used as targets or sources in NSG rules instead of IP addresses
Example NSG Rules:
Traditional NSG Rule:
Allow traffic from 10.0.1.4 to 10.0.2.5 on port 8080
ASG-Enhanced NSG Rule:
Allow traffic from asg-web-servers to asg-app-servers on port 8080
Both are NSG rules! The second one just uses ASG names instead of IP addresses.
🔄 What ACTUALLY Determines Precedence:
Precedence Factor | Description | Example |
Rule Priority Number | Lower numbers processed first | Priority 100 beats Priority 200 |
NSG Layer (Subnet vs NIC) | Both must allow traffic | Subnet NSG → NIC NSG (inbound) |
First Match Wins | Processing stops at first match | Allow rule at 100 stops Deny rule at 200 |
Security Admin Rules | Override all NSG rules | Azure VNet Manager admin rules |
🎯 Real-World Example:
Scenario: VM "web-01" is in ASG "asg-web-servers" and has these NSG rules:
- Priority 100: DENY traffic from Internet to asg-web-servers on port 22
- Priority 200: ALLOW traffic from Internet to 10.0.1.4 on port 22
Result: SSH is DENIED because Priority 100 (ASG-based rule) is processed first and matches, so Priority 200 (IP-based rule) never gets evaluated.
Key Point: The ASG didn't "override" the IP rule - the PRIORITY did!
graph TB
subgraph "Traditional NSG Rules"
NSG1[NSG Rule]
IP1[10.0.1.4]
IP2[10.0.1.5]
IP3[10.0.2.6]
IP4[10.0.2.7]
end
subgraph "ASG-Based Rules"
NSG2[NSG Rule with ASG]
ASG_Web[ASG: WebServers]
ASG_App[ASG: AppServers]
VM1[VM-Web-01]
VM2[VM-Web-02]
VM3[VM-App-01]
VM4[VM-App-02]
end
NSG1 --> IP1
NSG1 --> IP2
NSG1 --> IP3
NSG1 --> IP4
NSG2 --> ASG_Web
NSG2 --> ASG_App
ASG_Web --> VM1
ASG_Web --> VM2
ASG_App --> VM3
ASG_App --> VM4
style NSG1 fill:#ffebee
style NSG2 fill:#e8f5e8
style ASG_Web fill:#f3e5f5
style ASG_App fill:#f3e5f5
ASG vs Traditional IP-based Rules:
This diagram compares traditional IP-based NSG rules with ASG-based rules:
- Traditional Approach - NSG rules reference specific IP addresses, requiring updates when VMs change
- ASG Approach - NSG rules reference logical groups, automatically including all group members
- Scalability - ASGs eliminate the need to update rules when adding/removing VMs
- Maintainability - Logical grouping makes rules more readable and manageable
Creating Application Security Groups
# Create ASG for Web Servers
az network asg create \
--resource-group "rg-network-security" \
--name "asg-web-servers" \
--location "East US" \
--tags Function=WebServer Tier=Frontend
Parameters Explanation:
Parameter | Description | Best Practice |
--name | ASG identifier | Use descriptive names (asg-{function}) |
--location | Azure region | Must match associated resources |
--tags | Logical categorization | Include function, tier, purpose |
Purpose: Creates a logical container for web server resources. VMs assigned to this ASG can be referenced collectively in NSG rules, simplifying rule management and improving scalability.
# Create ASG for Application Servers
az network asg create \
--resource-group "rg-network-security" \
--name "asg-app-servers" \
--location "East US" \
--tags Function=ApplicationServer Tier=Backend
# Create ASG for Database Servers
az network asg create \
--resource-group "rg-network-security" \
--name "asg-db-servers" \
--location "East US" \
--tags Function=DatabaseServer Tier=Data
Associating ASG to Network Interface Cards
# Create additional VMs for demonstration
az vm create \
--resource-group "rg-network-security" \
--name "vm-app-01" \
--image "Ubuntu2204" \
--admin-username "azureuser" \
--generate-ssh-keys \
--subnet "subnet-app" \
--vnet-name "vnet-security-demo" \
--public-ip-sku "Standard" \
--size "Standard_B2s" \
--no-wait
# Associate Web VM NIC to Web ASG
az network nic ip-config update \
--resource-group "rg-network-security" \
--nic-name "vm-web-01VMNic" \
--name "ipconfigvm-web-01" \
--application-security-groups "asg-web-servers"
🔍 Azure VM Auto-Generated Resource Names:
Understanding Azure's Naming Convention:
When you create a VM named "vm-web-01", Azure automatically creates these resources with predictable names:
Resource Type | Auto-Generated Name | Pattern |
Network Interface | vm-web-01VMNic | {VM-Name}VMNic |
IP Configuration | ipconfigvm-web-01 | ipconfig{VM-Name} |
Public IP | vm-web-01PublicIP | {VM-Name}PublicIP |
OS Disk | vm-web-01_OsDisk_1_... | {VM-Name}_OsDisk_1_{guid} |
💡 Pro Tip: You can discover the actual NIC name using this command:
# Find the NIC name for any VM
az vm show --resource-group "rg-network-security" --name "vm-web-01" \
--query "networkProfile.networkInterfaces[0].id" --output tsv | \
awk -F'/' '{print $NF}'
# Or get all network interface details
az vm show --resource-group "rg-network-security" --name "vm-web-01" \
--query "networkProfile.networkInterfaces[].id" --output table
⚠️ Important Notes:
- This naming convention applies when Azure creates the NIC automatically during VM creation
- If you create the NIC separately first, you control the naming
- Some special characters in VM names may be modified in the NIC name
- Always verify the actual NIC name in production environments
Parameters Explanation:
Parameter | Description | Usage |
--nic-name | Network interface name | Usually {VMName}VMNic for Azure-created NICs |
--name | IP configuration name | Default is ipconfig{VMName} |
--application-security-groups | ASG assignments | Can specify multiple ASGs separated by spaces |
Purpose: Associates the VM's network interface with an ASG, making it a member of that logical group. The VM will now be included in any NSG rules that reference this ASG.
Important: You must update the IP configuration, not the NIC directly. Each NIC can have multiple IP configurations, and ASGs are associated at the IP configuration level.
# Associate App VM NIC to App ASG (after VM creation completes)
az network nic ip-config update \
--resource-group "rg-network-security" \
--nic-name "vm-app-01VMNic" \
--name "ipconfigvm-app-01" \
--application-security-groups "asg-app-servers"
6. Creating and Configuring NSG Rules
flowchart TD
A[Incoming Traffic] --> B{Rule Priority Check}
B --> C[Priority 100]
B --> D[Priority 200]
B --> E[Priority 300]
B --> F[Default Rules 65000+]
C --> G{Match Conditions?}
D --> H{Match Conditions?}
E --> I{Match Conditions?}
F --> J{Match Conditions?}
G -->|Yes| K[Allow/Deny Action]
G -->|No| H
H -->|Yes| L[Allow/Deny Action]
H -->|No| I
I -->|Yes| M[Allow/Deny Action]
I -->|No| J
J -->|Yes| N[Default Action]
J -->|No| O[Implicit Deny]
K --> P[Traffic Processed]
L --> P
M --> P
N --> P
O --> Q[Traffic Blocked]
style A fill:#e3f2fd
style B fill:#fff3e0
style K fill:#e8f5e8
style L fill:#e8f5e8
style M fill:#e8f5e8
style N fill:#e8f5e8
style O fill:#ffebee
style Q fill:#ffebee
NSG Rule Processing Logic:
This flowchart shows how NSG rules are evaluated:
- Priority Order - Rules are processed in ascending priority order (100, 200, 300, etc.)
- First Match Wins - Once a rule matches, processing stops and the action is taken
- Default Rules - Built-in rules (65000+) handle common scenarios if no custom rules match
- Implicit Deny - If no rules match, traffic is blocked by default
Web Tier NSG Rules
# Allow HTTP traffic from Internet to Web Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-web-tier" \
--name "Allow-HTTP-Inbound" \
--priority 100 \
--source-address-prefixes "Internet" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-web-servers" \
--destination-port-ranges "80" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound" \
--description "Allow HTTP traffic from Internet to Web Servers"
Parameters Explanation:
Parameter | Description | Options/Values |
--priority | Rule processing order | 100-4096 (lower = higher priority) |
--source-address-prefixes | Traffic source | IP, CIDR, Service Tag (Internet, VirtualNetwork) |
--source-port-ranges | Source port | * (any), specific port, or range (e.g., 8000-8080) |
--destination-application-security-groups | Target ASG | ASG name(s) - alternative to IP addresses |
--destination-port-ranges | Target port | Specific port or range |
--protocol | Network protocol | Tcp, Udp, Icmp, Esp, Ah, * (any) |
--access | Rule action | Allow, Deny |
--direction | Traffic direction | Inbound, Outbound |
Purpose: Allows HTTP traffic from the internet to reach web servers. This rule uses ASG for destination, making it automatically apply to all VMs in the web servers ASG without specifying IP addresses.
# Allow HTTPS traffic from Internet to Web Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-web-tier" \
--name "Allow-HTTPS-Inbound" \
--priority 110 \
--source-address-prefixes "Internet" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-web-servers" \
--destination-port-ranges "443" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
Purpose: Allows HTTPS traffic for secure web communication. Priority 110 ensures it's processed after the HTTP rule (priority 100) but will be the second rule evaluated.
# Allow Web Servers to communicate with App Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-web-tier" \
--name "Allow-Web-to-App" \
--priority 200 \
--source-application-security-groups "asg-web-servers" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-app-servers" \
--destination-port-ranges "8080" \
--protocol "Tcp" \
--access "Allow" \
--direction "Outbound"
Purpose: Enables communication from web tier to application tier. This outbound rule allows web servers to send requests to application servers on port 8080, supporting a typical web application architecture.
Application Tier NSG Rules
# Allow traffic from Web Servers to App Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-app-tier" \
--name "Allow-Web-to-App-Inbound" \
--priority 100 \
--source-application-security-groups "asg-web-servers" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-app-servers" \
--destination-port-ranges "8080" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
Purpose: Complements the outbound rule from web tier. This inbound rule allows application servers to receive traffic from web servers, creating a secure communication channel between tiers.
# Allow App Servers to communicate with Database Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-app-tier" \
--name "Allow-App-to-DB" \
--priority 200 \
--source-application-security-groups "asg-app-servers" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-db-servers" \
--destination-port-ranges "1433" \
--protocol "Tcp" \
--access "Allow" \
--direction "Outbound"
Database Tier NSG Rules
# Allow traffic from App Servers to Database Servers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-db-tier" \
--name "Allow-App-to-DB-Inbound" \
--priority 100 \
--source-application-security-groups "asg-app-servers" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-db-servers" \
--destination-port-ranges "1433" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
Purpose: Creates the most restrictive access to database servers, allowing only application servers to connect on the database port (1433 for SQL Server). This implements the principle of least privilege.
Deny Rules for Security Hardening
# Explicitly deny direct RDP/SSH from Internet to all tiers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-web-tier" \
--name "Deny-Internet-RDP-SSH" \
--priority 4000 \
--source-address-prefixes "Internet" \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges "22" "3389" \
--protocol "Tcp" \
--access "Deny" \
--direction "Inbound"
Purpose: Explicitly blocks direct administrative access from the internet. This rule has lower priority (4000) so legitimate bastion traffic (if configured with higher priority) can still be allowed while blocking general internet access.
Security Best Practice: Always use explicit deny rules for sensitive ports like RDP (3389) and SSH (22) to prevent accidental exposure, even if you believe no allow rules exist.
7. Virtual Network Flow Logs Implementation
graph TB
subgraph "Flow Logs Architecture"
subgraph "Network Traffic"
VM1[Virtual Machine]
NIC1[Network Interface]
NSG1[Network Security Group]
end
subgraph "Flow Logs Collection"
FL[Flow Logs Service]
SA[Storage Account]
LA[Log Analytics]
end
subgraph "Analysis & Monitoring"
TA[Traffic Analytics]
AM[Azure Monitor]
AL[Alert Rules]
end
end
VM1 --> NIC1
NIC1 --> NSG1
NSG1 --> FL
FL --> SA
FL --> LA
SA --> TA
LA --> TA
TA --> AM
AM --> AL
style FL fill:#e3f2fd
style SA fill:#e8f5e8
style TA fill:#fff3e0
style AL fill:#ffebee
Flow Logs Data Flow:
This diagram illustrates the complete flow logs ecosystem:
- Data Collection - Flow logs capture network traffic metadata from NSGs
- Storage Options - Logs can be stored in Storage Account and/or Log Analytics workspace
- Traffic Analytics - Processes flow logs to provide insights and visualizations
- Monitoring Integration - Enables alerts and automated responses based on traffic patterns
Create Storage Account for Flow Logs
# Create Storage Account for Flow Logs
az storage account create \
--resource-group "rg-network-security" \
--name "saflowlogs$(date +%s)" \
--location "East US" \
--sku "Standard_LRS" \
--kind "StorageV2" \
--access-tier "Hot" \
--tags Purpose=FlowLogs Environment=Production
Parameters Explanation:
Parameter | Description | Recommendation |
--name | Storage account name | Must be globally unique, use timestamp or random suffix |
--sku | Replication type | Standard_LRS for cost efficiency, Standard_GRS for geo-redundancy |
--kind | Account type | StorageV2 for latest features and performance |
--access-tier | Default access tier | Hot for frequently accessed flow logs |
Purpose: Creates a dedicated storage account for flow logs. Flow logs generate significant data volume, so proper storage configuration is crucial for cost management and performance.
Create Log Analytics Workspace
# Create Log Analytics Workspace
az monitor log-analytics workspace create \
--resource-group "rg-network-security" \
--workspace-name "law-network-security" \
--location "East US" \
--sku "PerGB2018" \
--retention-time 30 \
--tags Purpose=NetworkAnalytics Environment=Production
Parameters Explanation:
Parameter | Description | Options |
--sku | Pricing tier | PerGB2018 (pay-per-GB), CapacityReservation |
--retention-time | Data retention days | 30-730 days (affects cost significantly) |
Purpose: Creates a Log Analytics workspace for storing and analyzing flow log data. This enables advanced querying, alerting, and integration with Azure Monitor and Traffic Analytics.
Enable NSG Flow Logs
# Get NSG Resource ID
NSG_ID=$(az network nsg show \
--resource-group "rg-network-security" \
--name "nsg-web-tier" \
--query "id" --output tsv)
# Get Storage Account ID
STORAGE_ID=$(az storage account show \
--resource-group "rg-network-security" \
--name "saflowlogs$(date +%s)" \
--query "id" --output tsv)
# Enable Flow Logs
az network watcher flow-log create \
--resource-group "NetworkWatcherRG" \
--name "fl-web-tier" \
--nsg $NSG_ID \
--storage-account $STORAGE_ID \
--enabled true \
--retention 7 \
--log-format JSON \
--log-version 2
Parameters Explanation:
Parameter | Description | Best Practice |
--resource-group | Network Watcher RG | Usually "NetworkWatcherRG" (auto-created) |
--retention | Storage retention days | Balance compliance needs with storage costs |
--log-format | Output format | JSON recommended for analysis tools |
--log-version | Flow log schema version | Version 2 includes more metadata |
Purpose: Enables NSG flow logging with optimized settings for analysis. Version 2 logs include flow state information and byte/packet counts, providing richer data for security analysis.
Note: Network Watcher must be enabled in the region before creating flow logs. Azure typically auto-creates the NetworkWatcherRG resource group.
Configure Traffic Analytics
# Get Log Analytics Workspace ID
LA_WORKSPACE_ID=$(az monitor log-analytics workspace show \
--resource-group "rg-network-security" \
--workspace-name "law-network-security" \
--query "customerId" --output tsv)
# Update Flow Log with Traffic Analytics
az network watcher flow-log update \
--resource-group "NetworkWatcherRG" \
--name "fl-web-tier" \
--workspace $LA_WORKSPACE_ID \
--interval 10 \
--traffic-analytics true
Purpose: Enables Traffic Analytics for advanced flow log analysis. Traffic Analytics processes raw flow logs to provide insights into traffic patterns, top talkers, blocked traffic, and security threats.
Interpreting Flow Logs
graph LR
subgraph "Flow Log Entry Components"
A[Timestamp] --> B[Source IP]
B --> C[Destination IP]
C --> D[Source Port]
D --> E[Destination Port]
E --> F[Protocol]
F --> G[Traffic Decision]
G --> H[Flow State]
end
subgraph "Analysis Perspectives"
I[Security Analysis]
J[Performance Analysis]
K[Compliance Audit]
end
A --> I
B --> I
C --> I
G --> I
F --> J
H --> J
A --> K
G --> K
style I fill:#ffebee
style J fill:#e8f5e8
style K fill:#fff3e0
Flow Log Analysis Dimensions:
Flow logs provide multiple analysis perspectives:
- Security Analysis - Identify blocked traffic, failed connections, and potential threats
- Performance Analysis - Monitor flow states, connection patterns, and throughput
- Compliance Audit - Track access patterns and verify security policy compliance
Query Flow Logs with KQL
// Query blocked traffic in Log Analytics
AzureNetworkAnalytics_CL
| where FlowStatus_s == "D" // Denied traffic
| where TimeGenerated > ago(1h)
| summarize Count = count() by SrcIP_s, DestIP_s, DestPort_d
| order by Count desc
| take 10
// Query top talking hosts
AzureNetworkAnalytics_CL
| where TimeGenerated > ago(24h)
| summarize TotalBytes = sum(OutboundBytes_d + InboundBytes_d) by SrcIP_s
| order by TotalBytes desc
| take 20
Purpose: Demonstrates KQL queries for analyzing flow log data. These queries help identify security issues (blocked traffic) and performance patterns (high-volume communications).
8. Remote Server Administration with Azure Bastion
graph TB
subgraph "Traditional Access (Insecure)"
Internet1[Internet]
PublicIP[Public IP + NSG Rules]
VM1[Virtual Machine]
Internet1 --> PublicIP
PublicIP --> VM1
end
subgraph "Azure Bastion Access (Secure)"
Internet2[Internet]
Bastion[Azure Bastion]
BastionSubnet[AzureBastionSubnet]
PrivateVM[Private Virtual Machine]
Internet2 -->|HTTPS/SSL| Bastion
Bastion --> BastionSubnet
BastionSubnet -->|RDP/SSH over Private IP| PrivateVM
end
style PublicIP fill:#ffebee
style VM1 fill:#ffebee
style Bastion fill:#e8f5e8
style PrivateVM fill:#e8f5e8
Bastion vs Traditional Remote Access:
This comparison shows the security benefits of Azure Bastion:
- Traditional Method - Requires public IPs and open RDP/SSH ports, creating attack surface
- Azure Bastion - Provides secure access over HTTPS without public IPs on target VMs
- Network Isolation - VMs remain completely private while still accessible for administration
- Protocol Security - All traffic encrypted and authenticated through Azure portal
Create Azure Bastion Subnet
# Create dedicated subnet for Azure Bastion (must be named AzureBastionSubnet)
az network vnet subnet create \
--resource-group "rg-network-security" \
--vnet-name "vnet-security-demo" \
--name "AzureBastionSubnet" \
--address-prefix "10.0.100.0/24"
Subnet Requirements:
Requirement | Value | Reason |
Name | AzureBastionSubnet | Required by Azure platform |
Minimum Size | /27 (32 addresses) | Azure Bastion service requirements |
Dedicated Use | Bastion only | No other resources allowed |
Purpose: Creates the dedicated subnet required for Azure Bastion deployment. This subnet must follow strict naming and sizing requirements and cannot host any other resources.
Create Public IP for Bastion
# Create Public IP for Azure Bastion
az network public-ip create \
--resource-group "rg-network-security" \
--name "pip-bastion" \
--sku "Standard" \
--allocation-method "Static" \
--location "East US"
Purpose: Creates the public IP address required for Azure Bastion. This is the only public IP needed for secure access to all private VMs in the VNet.
Deploy Azure Bastion
# Create Azure Bastion
az network bastion create \
--resource-group "rg-network-security" \
--name "bastion-security-demo" \
--public-ip-address "pip-bastion" \
--vnet-name "vnet-security-demo" \
--location "East US" \
--sku "Standard"
Parameters Explanation:
Parameter | Description | Options |
--sku | Bastion service tier | Basic, Standard (Standard enables features like file transfer) |
--public-ip-address | Associated public IP | Must be Standard SKU, static allocation |
Purpose: Deploys the Azure Bastion service that provides secure RDP/SSH connectivity to VMs without exposing them to the internet. This significantly reduces the attack surface while maintaining administrative access.
Deployment Time: Azure Bastion deployment typically takes 10-15 minutes. The service must be fully deployed before it can be used for VM connections.
Configure NSG Rules for Bastion
# Create NSG for Bastion Subnet
az network nsg create \
--resource-group "rg-network-security" \
--name "nsg-bastion-subnet" \
--location "East US"
# Allow HTTPS inbound from Internet to Bastion
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-bastion-subnet" \
--name "Allow-HTTPS-Inbound" \
--priority 100 \
--source-address-prefixes "Internet" \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges "443" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
# Allow Gateway Manager inbound
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-bastion-subnet" \
--name "Allow-GatewayManager-Inbound" \
--priority 110 \
--source-address-prefixes "GatewayManager" \
--source-port-ranges "*" \
--destination-address-prefixes "*" \
--destination-port-ranges "443" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
# Allow Bastion to reach target VMs
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-bastion-subnet" \
--name "Allow-SSH-RDP-Outbound" \
--priority 100 \
--source-address-prefixes "*" \
--source-port-ranges "*" \
--destination-address-prefixes "VirtualNetwork" \
--destination-port-ranges "22" "3389" \
--protocol "Tcp" \
--access "Allow" \
--direction "Outbound"
# Associate NSG to Bastion Subnet
az network vnet subnet update \
--resource-group "rg-network-security" \
--vnet-name "vnet-security-demo" \
--name "AzureBastionSubnet" \
--network-security-group "nsg-bastion-subnet"
Purpose: Configures the required NSG rules for Azure Bastion operation. These rules allow the Bastion service to receive HTTPS connections from users and establish RDP/SSH connections to target VMs.
Required Rules: Azure Bastion requires specific NSG rules to function properly. Missing rules will prevent the service from connecting to target VMs.
Update Target VM NSG for Bastion Access
# Allow RDP/SSH from Bastion subnet to target VMs
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-web-tier" \
--name "Allow-Bastion-RDP-SSH" \
--priority 150 \
--source-address-prefixes "10.0.100.0/24" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-web-servers" \
--destination-port-ranges "22" "3389" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
# Repeat for other tiers
az network nsg rule create \
--resource-group "rg-network-security" \
--nsg-name "nsg-app-tier" \
--name "Allow-Bastion-RDP-SSH" \
--priority 150 \
--source-address-prefixes "10.0.100.0/24" \
--source-port-ranges "*" \
--destination-application-security-groups "asg-app-servers" \
--destination-port-ranges "22" "3389" \
--protocol "Tcp" \
--access "Allow" \
--direction "Inbound"
Purpose: Enables Azure Bastion to connect to target VMs by allowing RDP/SSH traffic from the Bastion subnet. This rule is added to each tier's NSG to enable administrative access through Bastion.
9. Azure Virtual Network Manager Implementation
graph TB
subgraph "Azure Virtual Network Manager"
AVNM[VNet Manager Instance]
subgraph "Network Groups"
NG1[Production Group]
NG2[Development Group]
NG3[DMZ Group]
end
subgraph "Configurations"
SC[Security Configuration]
CC[Connectivity Configuration]
end
subgraph "Managed VNets"
VNet1[Production VNet]
VNet2[Development VNet]
VNet3[DMZ VNet]
end
end
AVNM --> NG1
AVNM --> NG2
AVNM --> NG3
AVNM --> SC
AVNM --> CC
NG1 --> VNet1
NG2 --> VNet2
NG3 --> VNet3
SC --> VNet1
SC --> VNet2
SC --> VNet3
CC --> VNet1
CC --> VNet2
CC --> VNet3
style AVNM fill:#e3f2fd
style SC fill:#ffebee
style CC fill:#e8f5e8
Azure Virtual Network Manager Architecture:
This diagram shows how Azure VNet Manager provides centralized network management:
- Network Groups - Logical collections of VNets for policy application
- Security Configurations - Centrally managed security rules applied across network groups
- Connectivity Configurations - Hub-spoke or mesh connectivity patterns
- Centralized Management - Single point of control for multiple VNets across subscriptions
Create Azure Virtual Network Manager
# Create Azure Virtual Network Manager
az network manager create \
--resource-group "rg-network-security" \
--name "avnm-enterprise-security" \
--location "East US" \
--description "Enterprise Network Security Management" \
--scope-accesses "SecurityAdmin" "Connectivity" \
--network-manager-scopes subscriptions="/subscriptions/$(az account show --query id -o tsv)"
Parameters Explanation:
Parameter | Description | Options |
--scope-accesses | Management capabilities | SecurityAdmin, Connectivity |
--network-manager-scopes | Management scope | Subscription, Management Group, or specific resources |
Purpose: Creates the central Azure Virtual Network Manager instance that will manage security and connectivity across multiple VNets. The scope defines which subscriptions and management groups this instance can manage.
Create Network Groups
# Create Network Group for Production VNets
az network manager group create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--name "ng-production" \
--description "Production Virtual Networks" \
--group-members '[{
"resourceId": "/subscriptions/'$(az account show --query id -o tsv)'/resourceGroups/rg-network-security/providers/Microsoft.Network/virtualNetworks/vnet-security-demo"
}]'
# Create Network Group for Management VNets
az network manager group create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--name "ng-management" \
--description "Management and Bastion Networks"
Purpose: Creates logical groupings of VNets that will be managed together. Network groups enable you to apply consistent policies across multiple VNets without managing each individually.
Create Security Admin Configuration
# Create Security Admin Configuration
az network manager security-admin-config create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--name "sec-admin-config-enterprise" \
--description "Enterprise Security Administration Rules" \
--apply-on-network-intent-policy-based-services "AllowRulesOnly"
Parameters Explanation:
Parameter | Description | Options |
--apply-on-network-intent-policy-based-services | Policy enforcement mode | AllowRulesOnly, All |
Purpose: Creates a security configuration that can enforce security rules across all VNets in the managed scope. This provides centralized security policy management.
Create Security Admin Rule Collection
# Create Rule Collection for Production Security
az network manager security-admin-config rule-collection create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--configuration-name "sec-admin-config-enterprise" \
--name "rc-production-security" \
--description "Production Environment Security Rules" \
--applies-to-groups '[{
"networkGroupId": "/subscriptions/'$(az account show --query id -o tsv)'/resourceGroups/rg-network-security/providers/Microsoft.Network/networkManagers/avnm-enterprise-security/networkGroups/ng-production"
}]'
Purpose: Creates a container for security rules that will be applied to specific network groups. Rule collections allow for organized management of related security policies.
Create Admin Security Rules
# Create high-priority security rule to block malicious traffic
az network manager security-admin-config rule-collection rule create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--configuration-name "sec-admin-config-enterprise" \
--rule-collection-name "rc-production-security" \
--name "rule-block-malicious-ips" \
--description "Block Known Malicious IP Ranges" \
--access "Deny" \
--direction "Inbound" \
--priority 10 \
--protocol "Any" \
--sources '[{
"addressPrefixType": "IPPrefix",
"addressPrefix": "192.0.2.0/24"
}]' \
--destinations '[{
"addressPrefixType": "IPPrefix",
"addressPrefix": "*"
}]'
# Create rule to enforce HTTPS only for web traffic
az network manager security-admin-config rule-collection rule create \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--configuration-name "sec-admin-config-enterprise" \
--rule-collection-name "rc-production-security" \
--name "rule-https-only" \
--description "Deny HTTP Traffic, Enforce HTTPS" \
--access "Deny" \
--direction "Inbound" \
--priority 20 \
--protocol "Tcp" \
--sources '[{
"addressPrefixType": "ServiceTag",
"addressPrefix": "Internet"
}]' \
--destinations '[{
"addressPrefixType": "IPPrefix",
"addressPrefix": "*"
}]' \
--destination-ports '["80"]'
Purpose: Creates high-priority security rules that override local NSG rules. These admin rules can enforce organization-wide security policies that cannot be modified at the local level, ensuring consistent security posture.
Admin Rule Priority: Security admin rules always take precedence over local NSG rules. Use them carefully to avoid unintended blocking of legitimate traffic.
Deploy Configuration
# Deploy the security configuration
az network manager post-commit \
--resource-group "rg-network-security" \
--network-manager-name "avnm-enterprise-security" \
--target-locations "East US" \
--configuration-ids '/subscriptions/'$(az account show --query id -o tsv)'/resourceGroups/rg-network-security/providers/Microsoft.Network/networkManagers/avnm-enterprise-security/securityAdminConfigurations/sec-admin-config-enterprise' \
--commit-type "SecurityAdmin"
Purpose: Deploys the security configuration to the target regions. This action applies the security admin rules to all VNets in the specified network groups within those regions.
10. Command Execution Flow and Dependencies
graph TD
A[1. Create Resource Group] --> B[2. Create VNet]
B --> C[3. Create Subnets]
C --> D[4. Create NSGs]
C --> E[5. Create ASGs]
D --> F[6. Create NSG Rules]
E --> F
D --> G[7. Associate NSGs to Subnets]
F --> H[8. Create VMs]
G --> H
E --> I[9. Associate ASGs to NICs]
H --> I
J[10. Create Storage Account] --> K[11. Create Log Analytics]
K --> L[12. Enable Flow Logs]
C --> M[13. Create Bastion Subnet]
M --> N[14. Create Bastion Public IP]
N --> O[15. Deploy Azure Bastion]
O --> P[16. Configure Bastion NSG Rules]
Q[17. Create VNet Manager] --> R[18. Create Network Groups]
R --> S[19. Create Security Config]
S --> T[20. Create Rule Collections]
T --> U[21. Create Admin Rules]
U --> V[22. Deploy Configuration]
style A fill:#e3f2fd
style B fill:#e3f2fd
style C fill:#e3f2fd
style F fill:#e8f5e8
style I fill:#e8f5e8
style L fill:#fff3e0
style O fill:#ffebee
style V fill:#f3e5f5
Command Execution Dependencies:
This flowchart shows the required order for implementing the complete solution:
- Foundation (1-3) - Basic infrastructure must be created first
- Security Groups (4-5) - NSGs and ASGs can be created in parallel
- Rule Configuration (6-9) - Rules and associations require existing infrastructure
- Monitoring (10-12) - Flow logs require storage and can be configured independently
- Remote Access (13-16) - Bastion requires dedicated subnet and specific configuration
- Centralized Management (17-22) - VNet Manager can be implemented after basic infrastructure
Complete Implementation Script
Phase 1 Foundation Infrastructure
Phase 2 Security Configuration
Phase 3 Monitoring and Logging
Phase 4 Remote Access
Phase 5 Centralized Management
#!/bin/bash
# Complete Azure Network Security Implementation Script
# Phase 1: Foundation Infrastructure
echo "Phase 1: Creating Foundation Infrastructure..."
# Set variables
RG_NAME="rg-network-security"
LOCATION="East US"
VNET_NAME="vnet-security-demo"
# Create Resource Group
az group create --name $RG_NAME --location "$LOCATION"
# Create VNet and Subnets
az network vnet create --resource-group $RG_NAME --name $VNET_NAME --address-prefix "10.0.0.0/16"
az network vnet subnet create --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-web" --address-prefix "10.0.1.0/24"
az network vnet subnet create --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-app" --address-prefix "10.0.2.0/24"
az network vnet subnet create --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-db" --address-prefix "10.0.3.0/24"
# Phase 2: Security Configuration
echo "Phase 2: Configuring Security Groups and Rules..."
# Create NSGs
az network nsg create --resource-group $RG_NAME --name "nsg-web-tier"
az network nsg create --resource-group $RG_NAME --name "nsg-app-tier"
az network nsg create --resource-group $RG_NAME --name "nsg-db-tier"
# Create ASGs
az network asg create --resource-group $RG_NAME --name "asg-web-servers"
az network asg create --resource-group $RG_NAME --name "asg-app-servers"
az network asg create --resource-group $RG_NAME --name "asg-db-servers"
# Associate NSGs to Subnets
az network vnet subnet update --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-web" --network-security-group "nsg-web-tier"
az network vnet subnet update --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-app" --network-security-group "nsg-app-tier"
az network vnet subnet update --resource-group $RG_NAME --vnet-name $VNET_NAME --name "subnet-db" --network-security-group "nsg-db-tier"
# Create comprehensive NSG rules
# [Include all the NSG rules from previous sections]
echo "Implementation complete! Verify resources in Azure Portal."
Purpose: Provides a complete automation script that implements the entire solution in the correct sequence. This script can be used for consistent deployments across environments.
Validation and Testing Commands
# Validate NSG effective rules
az network nic list-effective-nsg \
--resource-group "rg-network-security" \
--name "vm-web-01VMNic"
# Test IP flow verification
az network watcher test-ip-flow \
--resource-group "NetworkWatcherRG" \
--vm "vm-web-01" \
--direction "Inbound" \
--protocol "TCP" \
--local "10.0.1.4:80" \
--remote "0.0.0.0:12345"
# Verify flow logs status
az network watcher flow-log show \
--resource-group "NetworkWatcherRG" \
--name "fl-web-tier"
# Check Network Security Group associations
az network nsg show \
--resource-group "rg-network-security" \
--name "nsg-web-tier" \
--query "{Name:name, Subnets:subnets[].id, NetworkInterfaces:networkInterfaces[].id}"
Purpose: Provides essential validation commands to verify that the configuration is working as expected. These commands help troubleshoot connectivity issues and confirm security policy effectiveness.
Summary and Best Practices
Key Implementation Points:
- Defense in Depth - Use both subnet-level and NIC-level NSGs where appropriate
- Least Privilege - Start with deny-all and add only necessary allow rules
- Application Security Groups - Use ASGs for scalable, maintainable rule management
- Flow Logs - Enable comprehensive logging for security analysis and compliance
- Azure Bastion - Eliminate public IPs on VMs while maintaining administrative access
- Centralized Management - Use Azure VNet Manager for enterprise-scale security governance
Common Pitfalls to Avoid:
- Not planning IP address spaces carefully before implementation
- Forgetting to enable Network Watcher before configuring flow logs
- Using overly permissive rules instead of specific port and protocol restrictions
- Not testing connectivity after implementing security rules
- Failing to monitor and analyze flow logs for security insights