Lab 1. Protecting the network perimeter - neilhamshaw/azure-security-workshop GitHub Wiki
Network security groups filter traffic to and from resources in an Azure virtual network based on a set of applied rules. They can be created at subnet or virtual machine level. If created at subnet level, the NSG will attach itself to every network interface in the subnet applying the rules set against each and every virtual machine. If set at virtual machine level, the rules apply only to that virtual machine.
Further information on network security groups (NSG) can be found in the Azure documentation:
https://docs.microsoft.com/en-us/azure/virtual-network/security-overview
The infrastructure as it has been deployed is wide open for access, and poses a security risk...
- All traffic can flow between all subnets and all servers
- Anybody can attempt to remotely access the web server using Remote Desktop tools if they know the server public IP address
- If a user gained remote access to the web server, they can attempt to get further remote access to additional resources, such as the API or SQL database server or run remote services
The only thing currently preventing access to uncommon ports on the Windows servers is the Windows Firewall.
Network security groups can be used as a first-step method to protect/restrict traffic to resources. For example, in the N-tier architecture shown, none of the web servers deployed in the web tier should be able to communicate directly with any resource in the database tier. This should all happen via the deployed API. To enforce this, security needs to be put in place which blocks all but the necessary incoming traffic to the database subnet. This can be done using network security groups.
This section creates the security group and the relevant rules to protect the database tier.
In the Azure Portal Cloud Shell, enter the following CLI command to create a network security group named SQLServer-NSG in the resource group created earlier. NSGs are considered a networking resource, so the network element of the Azure CLI is used:
Parameters:
- --name: The name of the security group. In this case, SQLServer-NSG
- --resource-group: Your resource group created during the initial setup
- --location: The region to deploy the resource in. Enter westeurope
Command:
az network nsg create --name SQLServer-NSG --resource-group <resource-group-name> --location <location>
When the command completes, the terminal will output all properties of the security group (too many to list here), and the new NSG will be viewable in the Azure Portal. There are one or two ways to locate resources quickly:
- In the search bar at the top of the Azure Portal, search for SQLServer-NSG and click on the resource when displayed.
- Click All resources from the menu bar on the left, and locate the resource in the list. If the resource list is too long, apply filters to the list in the All resources pane:
Checking the Overview details of the SQLServer-NSG group will show that, by default, a network security group will be pre-populated with three inbound rules (in order of execution):
- allow any VNet to VNet traffic
- allow any traffic from the Azure load balancer to the VNet
- deny all inbound traffic (that does not match any other rule)
There are also three outbound rules:
- allow any traffic outbound to the VNet
- allow all traffic outbound to the Internet
- deny all outbound traffic
These rules can also be shown by running this CLI command (notice the show parameter which fetches the resource details rather than create used above):
Parameters:
- --resource-group: Your resource group created during the initial setup
- --name: The name of the security group, SQLServer-NSG
- --query: The CLI has a query function/parameter which filters the output of the command to a specific property. Adding defaultSecurityRules[] will show all of the default rules in the output.
-
--output: This parameter describes how to format the output. The default output is in JSON format but allowed values are:
json, jsonc, table, tsv, yaml or none
Command (multi-line):
az network nsg show --resource-group <resource-group-name> \
--name SQLServer-NSG \
--query "defaultSecurityRules[]" \
--output table
Command (single line):
az network nsg show --resource-group <resource-group-name> --name SQLServer-NSG --query "defaultSecurityRules[]" --output table
These rules cannot be deleted. What we can do however, is create a new series of rules in the security group with a higher priority (a higher execution order) to filter the traffic before the default rules are evaluated. The next steps will cover this.
With the network security group created, the required rules can be added to secure the target resources. Similar to firewall rules, security group rules are based on information about the source, destination, protocol, port and action (allow/deny).
-
Allow inbound traffic from the API Subnet.
The first rule will allow any traffic into the database tier from the API tier. This is done by specifying the subnet address space (or CIDR) of the API Subnet (10.0.2.0/24) as the source. Any resources/VMs created within this subnet will be able to communicate with the database tier. Please note that this can be further tied down to specific VMs and this is covered later in this section.
Parameters:
- --resource-group: The resource group created during the initial setup
- --name: The name of the security group rule
- --priority: Sets the rule priority number. Lower numbers have a higher priority
- --description: Text string which users can add to describe the purpose of the rule
- --access: Set to either Allow or Deny to describe the rule action.
- --direction: This parameter determines whether the rule is for Inbound or Outbound traffic
- --source-address-prefix: Set to either an IP address or use 0.0.0.0/0 to allow any addresses. This example will use the entire address space of the API Subnet, 10.0.2.0/24
- --source-port-ranges: If traffic is coming from a known TCP/IP port, it can be set here. Alternatively, use the asterisk for all ports
- --protocol: Used to set as Any (*), TCP, UDP, ICMP or ESP
- --destination-address-prefix: Sets the destination address. More important for outbound rules, this can be set to any address (asterisk) for this session as the destination will be the virtual machine the security group will be attached to.
- --destination-port-ranges: Specifies the target TCP/IP address ports for the rule. Whilst this can be set to 'Any', this specific rule is to allow database traffic from the API, so it should be set to the default SQL Server port, 1433
Command:
az network nsg rule create --resource-group <resource-group-name> \ --name Allow1433FromAPI \ --nsg-name SQLServer-NSG \ --priority 110 \ --description "Allow all traffic from the API Subnet" \ --access Allow \ --direction Inbound \ --source-address-prefix 10.0.2.0/24 \ --source-port-ranges "*" \ --protocol "*" \ --destination-address-prefix "*" \ --destination-port-ranges 1433
Command (single line):
az network nsg rule create --resource-group <resource-group-name> --name Allow1433FromAPI --nsg-name SQLServer-NSG --priority 110 --description "Allow all traffic from the API Subnet" --access Allow --direction Inbound --source-address-prefix 10.0.2.0/24 --source-port-ranges "*" --protocol "*" --destination-address-prefix "*" --destination-port-ranges 1433
Reviewing the SQLServer-NSG resource will show the new rule appearing in the Inbound security rules list.
The command above appears to be quite extensive with a large number of parameters. In fact, only four are compulsory parameters: --name, --nsg-name, --priority and --resource-group. Other parameters are not needed depending on the properties of the rule, or have implied defaults so they can be left off. Examples of these parameters include --direction which defaults to Inbound, and --protocol which defaults to Any (*).
Review the list of parameters for NSG rule creation by running the following command:
az network nsg rule create --help
Use the pattern above for the remaining rules (below).
-
Allow inbound traffic from the database tier subnet itself.
This rule allows communication between the database virtual machines, which is needed for database replication and failover. Use the database (SQL) subnet range 10.0.3.0/24 as the source address. Some parameters with defaults could be dropped and the default values allowed:
az network nsg rule create --name AllowAllFromSQL \ --nsg-name SQLServer-NSG \ --priority 120 \ --resource-group <resource-group-name> \ --description "Allow all intra SQL traffic within the database tier" \ --source-address-prefix 10.0.3.0/24 \ --destination-port-ranges "*"
However, the full parameter set adds clarity in their intent:
az network nsg rule create --name AllowAllFromSQL --nsg-name SQLServer-NSG --priority 120 --resource-group <resource-group-name> --description "Allow all intra SQL traffic within the database tier" --access Allow --direction Inbound --source-address-prefix 10.0.3.0/24 --source-port-ranges "*" --protocol "*" --destination-address-prefix "*" --destination-port-ranges "*"
-
Allow RDP access from the Jump Box.
Allowing RDP traffic on the RDP port (3389) from the Jump Box allows remote administrators to connect to the database servers from the Jump Box. This rule has two key benefits:
- By only specifying the RDP port, users of the Jump Box will not be able to connect via any other method, port or protocol
- Locking the RDP protocol to only the Jump Box IP address will prevent Remote Desktop access from any other server within the deployment.
Use the internal IP address of the Jump Box as the source address. In the example deployment, this will be 10.0.0.132/32 (the /32 suffix specifies a single address). Note that this command also specifies the TCP protocol:
az network nsg rule create --name AllowRDPFromJumpBox \ --nsg-name SQLServer-NSG \ --priority 130 \ --resource-group <resource-group-name> \ --description "Allow RDP traffic from the Jump Box" \ --access Allow \ --direction Inbound \ --source-address-prefix 10.0.0.132/32 \ --source-port-ranges "*" \ --protocol TCP \ --destination-address-prefix "*" \ --destination-port-ranges 3389
-
Deny all other inbound traffic.
Now that the base access requirements have been configured, all other traffic within the virtual network must be prevented from reaching the SQL servers. Instead of a source address, the Virtualnetwork tag can be used in the rule to:
az network nsg rule create --name DenyFromVNet \ --nsg-name SQLServer-NSG \ --priority 140 \ --resource-group <resource-group-name> \ --description "Deny general VNet traffic" \ --access Deny \ --direction Inbound \ --source-address-prefix Virtualnetwork \ --destination-port-ranges "*"
-
Deny all inbound traffic from the Internet.
Create the final rule yourself using the commands above as the pattern. Set your own description, and use these properties:
- Name: DenyFromInternet
- Priority: 150
- Source Address: Internet
Consider the following when creating security group rules...
- security group rules run in priority order, with the rule given the lowest priority number being evaluated first.
- Leave a reasonable gap between your rule numbers. It makes for a lot of work to try and retro-fit a new rule with a higher priority in between rules (for example) numbered 4,5 and 6 than it does with numbers 140, 150 and 160.
- The first Deny rule encountered by the evaluation instantly denies the access.
Follow these steps to attach the new network security group to the network interface of the SQL server virtual machine. A security group attachment to a virtual network interface is a logical association, and can take place from both sides of the attachment (associating a NIC to security group, or adding a security group to a NIC). This section details how to to both methods, and also provides the CLI command (if required).
The first method of attaching the network security group to the virtual NIC of a server is by making the association from the security group properties. To do this:
-
In the Azure Portal, locate the SQLServer-NSG resource.
-
Under Settings, click network interfaces
-
The network interfaces list should simply be showing No results. Click Associate near the top of the screen.
-
From the list of network Interfaces available, choose the SQLServer-NIC to make the association. Clicking the NIC will action the change.
-
Once saved, the SQLServer-NIC will appear as an associated network Interface for the network security group.
Clicking on the SQLServer-NIC object will switch the view to the properties of the network Interface, and clicking network security group under Settings will show the same association but from the network interface viewpoint.
The alternative method method of attaching the network security group to the virtual NIC of a server is by making the association from the network interface itself. Follow these steps...
Please note: If the security group and network interface have been associated in step 1.4.1 (above), move on to section 1.5.
-
In the Azure Portal, locate the SQLServer-NIC resource.
-
Click the Network security group option under Settings. This displays the associated security group to the network interface.
-
Click Edit and then click the bar beneath labelled Network Security Group: None.
-
A list of available network security groups will be shown. Select SQLServer-NSG.
-
Click Save. This will save the association of the NSG to the network interface.
Use the following Azure CLI command to associate the SQLServer-NIC and SQLServer-NSG resources. The command references the NIC resource and attaches the security group to the NIC.
Note: The name of the NIC for the SQL server is sql-vm1-nic1
az network nic update --resource-group <resource-group-name> \
--name SQLServer-NIC \
--network-security-group SQLServer-NSG
Once complete, the assocoation between the network interface and the network security group will be visible from either resource by selecting Network security group from the SQLServer-NIC overview page, or Network interfaces from the SQLServer-NSG overview page.
The SQLServerNSG rule set should look similar to this...
Try some final steps to test the new security:
-
Open a Remote Desktop session to the Jump Box.
-
Confirm that is is still possible to open a remote desktop session from the Jump Box to the SQL server (remember to use the internal IP address of the SQL server).
-
Try and ping the SQL server from the jump box. Before the security was configured, this was possible as the ICMP (ping) protocol was allowed on the Windows Firewall of the SQL server, but the NSG rules do not allow ping, so the test should fail.
-
No rules were specified to allow Remote Desktop Protocol (RDP) from any other servers in the network security group. As such, RDP should now be blocked from the web server.
-
Any ping response between the web server and the SQL server should also fail.
The next lab is Lab 2 - Networking Logs.