From 0c2d9e98afd773e186c8203f15a1751a71d51857 Mon Sep 17 00:00:00 2001 From: Jim Madge Date: Wed, 17 Apr 2024 11:10:50 +0100 Subject: [PATCH 1/4] Create Enum for ports --- .../infrastructure/common/__init__.py | 3 +- .../infrastructure/common/enums.py | 22 +++++++ .../infrastructure/stacks/shm/firewall.py | 5 +- .../infrastructure/stacks/shm/networking.py | 34 +++++----- .../infrastructure/stacks/sre/dns_server.py | 5 +- .../stacks/sre/hedgedoc_server.py | 3 +- .../infrastructure/stacks/sre/networking.py | 63 ++++++++++--------- .../stacks/sre/software_repositories.py | 3 +- 8 files changed, 86 insertions(+), 52 deletions(-) diff --git a/data_safe_haven/infrastructure/common/__init__.py b/data_safe_haven/infrastructure/common/__init__.py index a8c8f4e650..ffc414932d 100644 --- a/data_safe_haven/infrastructure/common/__init__.py +++ b/data_safe_haven/infrastructure/common/__init__.py @@ -1,4 +1,4 @@ -from .enums import FirewallPriorities, NetworkingPriorities +from .enums import FirewallPriorities, NetworkingPriorities, Ports from .ip_ranges import SREDnsIpRanges, SREIpRanges from .transformations import ( get_available_ips_from_subnet, @@ -26,6 +26,7 @@ "get_name_from_vnet", "get_subscription_id_from_rg", "NetworkingPriorities", + "Ports", "SREDnsIpRanges", "SREIpRanges", ] diff --git a/data_safe_haven/infrastructure/common/enums.py b/data_safe_haven/infrastructure/common/enums.py index 8d0373e656..c5838fc1e0 100644 --- a/data_safe_haven/infrastructure/common/enums.py +++ b/data_safe_haven/infrastructure/common/enums.py @@ -57,3 +57,25 @@ class NetworkingPriorities(int, Enum): EXTERNAL_INTERNET = 3999 # Deny all other: 4096 ALL_OTHER = 4096 + + +@verify(UNIQUE) +class Ports(str, Enum): + AZURE_BASTIAN_1 = ( + "8080" # https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg + ) + AZURE_BASTIAN_2 = "5701" + DNS = "53" + HTTP = "80" + HTTPS = "443" + LDAP = "389" + LDAPS = "636" + LDAP_APRICOT = "1389" + LINUX_UPDATE = "8000" + MSSQL = "1433" + NEXUS = "8081" + NTP = "123" + POSTGRESQL = "5432" + RDP = "3389" + SSH = "22" + SQUID = "3128" diff --git a/data_safe_haven/infrastructure/stacks/shm/firewall.py b/data_safe_haven/infrastructure/stacks/shm/firewall.py index 2ba2476056..661efaea07 100644 --- a/data_safe_haven/infrastructure/stacks/shm/firewall.py +++ b/data_safe_haven/infrastructure/stacks/shm/firewall.py @@ -7,6 +7,7 @@ from data_safe_haven.infrastructure.common import ( FirewallPriorities, + Ports, SREIpRanges, get_id_from_subnet, ) @@ -513,7 +514,7 @@ def __init__( network.AzureFirewallNetworkRuleArgs( description="Allow external DNS resolver", destination_addresses=[external_dns_resolver], - destination_ports=["53"], + destination_ports=[Ports.DNS], name="AllowExternalDnsResolver", protocols=[ network.AzureFirewallNetworkRuleProtocol.TCP, @@ -542,7 +543,7 @@ def __init__( network.AzureFirewallNetworkRuleArgs( description="Allow external NTP requests", destination_addresses=ntp_ip_addresses, - destination_ports=["123"], + destination_ports=[Ports.NTP], name="AllowExternalNTP", protocols=[network.AzureFirewallNetworkRuleProtocol.UDP], source_addresses=["*"], diff --git a/data_safe_haven/infrastructure/stacks/shm/networking.py b/data_safe_haven/infrastructure/stacks/shm/networking.py index f0271e50fc..580c2359fc 100644 --- a/data_safe_haven/infrastructure/stacks/shm/networking.py +++ b/data_safe_haven/infrastructure/stacks/shm/networking.py @@ -7,7 +7,7 @@ from data_safe_haven.external import AzureIPv4Range from data_safe_haven.functions import ordered_private_dns_zones -from data_safe_haven.infrastructure.common import NetworkingPriorities +from data_safe_haven.infrastructure.common import NetworkingPriorities, Ports class SHMNetworkingProps: @@ -72,7 +72,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound https connections from admins connecting from approved IP addresses.", destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowAdminHttpsInbound", priority=NetworkingPriorities.AUTHORISED_EXTERNAL_ADMIN_IPS, @@ -84,7 +84,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound gateway management service traffic.", destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowGatewayManagerServiceInbound", priority=NetworkingPriorities.AZURE_GATEWAY_MANAGER, @@ -96,7 +96,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound load balancer service traffic.", destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowLoadBalancerServiceInbound", priority=NetworkingPriorities.AZURE_LOAD_BALANCER, @@ -108,7 +108,10 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound internal bastion host communication.", destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["5701", "8080"], + destination_port_ranges=[ + Ports.AZURE_BASTIAN_1, + Ports.AZURE_BASTIAN_2, + ], direction=network.SecurityRuleDirection.INBOUND, name="AllowBastionHostInbound", priority=NetworkingPriorities.INTERNAL_SELF, @@ -133,7 +136,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DSH VMs.", destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["22", "3389"], + destination_port_ranges=[Ports.SSH, Ports.RDP], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowRdpOutbound", priority=NetworkingPriorities.INTERNAL_SHM_BASTION, @@ -145,7 +148,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to Azure public endpoints.", destination_address_prefix="AzureCloud", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowAzureCloudOutbound", priority=NetworkingPriorities.AZURE_CLOUD, @@ -157,7 +160,10 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound internal bastion host communication.", destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=["5701", "8080"], + destination_port_ranges=[ + Ports.AZURE_BASTIAN_1, + Ports.AZURE_BASTIAN_2, + ], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowBastionHostOutbound", priority=NetworkingPriorities.INTERNAL_SELF, @@ -169,7 +175,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections for session and certificate validation.", destination_address_prefix="Internet", - destination_port_ranges=["80"], + destination_port_ranges=[Ports.HTTP], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowCertificateValidationOutbound", priority=NetworkingPriorities.EXTERNAL_INTERNET, @@ -205,7 +211,7 @@ def __init__( destination_address_prefix=str( props.subnet_identity_servers_iprange ), - destination_port_ranges=["389", "636"], + destination_port_ranges=[Ports.LDAP, Ports.LDAPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowLDAPClientUDPInbound", priority=NetworkingPriorities.INTERNAL_SHM_LDAP_UDP, @@ -219,7 +225,7 @@ def __init__( destination_address_prefix=str( props.subnet_identity_servers_iprange ), - destination_port_ranges=["389", "636"], + destination_port_ranges=[Ports.LDAP, Ports.LDAPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowLDAPClientTCPInbound", priority=NetworkingPriorities.INTERNAL_SHM_LDAP_TCP, @@ -233,7 +239,7 @@ def __init__( destination_address_prefix=str( props.subnet_identity_servers_iprange ), - destination_port_ranges=["3389"], + destination_port_ranges=[Ports.RDP], direction=network.SecurityRuleDirection.INBOUND, name="AllowBastionAdminsInbound", priority=NetworkingPriorities.INTERNAL_SHM_BASTION, @@ -288,7 +294,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to local monitoring tools.", destination_address_prefix=str(props.subnet_monitoring_iprange), - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowMonitoringToolsOutbound", priority=NetworkingPriorities.INTERNAL_SHM_MONITORING_TOOLS, @@ -300,7 +306,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to Linux update servers.", destination_address_prefix="Internet", - destination_port_ranges=["80", "443"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowLinuxUpdatesOutbound", priority=NetworkingPriorities.EXTERNAL_LINUX_UPDATES, diff --git a/data_safe_haven/infrastructure/stacks/sre/dns_server.py b/data_safe_haven/infrastructure/stacks/sre/dns_server.py index b9a820e785..03ef98c894 100644 --- a/data_safe_haven/infrastructure/stacks/sre/dns_server.py +++ b/data_safe_haven/infrastructure/stacks/sre/dns_server.py @@ -13,6 +13,7 @@ ) from data_safe_haven.infrastructure.common import ( NetworkingPriorities, + Ports, SREDnsIpRanges, SREIpRanges, get_ip_address_from_container_group, @@ -107,7 +108,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from attached.", destination_address_prefix=props.ip_range_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.INBOUND, name="AllowSREInbound", priority=NetworkingPriorities.INTERNAL_SRE_ANY, @@ -132,7 +133,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound DNS traffic over the internet.", destination_address_prefix="Internet", - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDnsInternetOutbound", priority=NetworkingPriorities.EXTERNAL_INTERNET, diff --git a/data_safe_haven/infrastructure/stacks/sre/hedgedoc_server.py b/data_safe_haven/infrastructure/stacks/sre/hedgedoc_server.py index 836b85407c..a4ab65d12d 100644 --- a/data_safe_haven/infrastructure/stacks/sre/hedgedoc_server.py +++ b/data_safe_haven/infrastructure/stacks/sre/hedgedoc_server.py @@ -5,6 +5,7 @@ from data_safe_haven.functions import b64encode from data_safe_haven.infrastructure.common import ( + Ports, get_ip_address_from_container_group, ) from data_safe_haven.infrastructure.components import ( @@ -188,7 +189,7 @@ def __init__( ), containerinstance.EnvironmentVariableArgs( name="CMD_DB_PORT", - value="5432", + value=Ports.POSTGRESQL, ), containerinstance.EnvironmentVariableArgs( name="CMD_DB_USERNAME", diff --git a/data_safe_haven/infrastructure/stacks/sre/networking.py b/data_safe_haven/infrastructure/stacks/sre/networking.py index 49ac113875..661f39ac46 100644 --- a/data_safe_haven/infrastructure/stacks/sre/networking.py +++ b/data_safe_haven/infrastructure/stacks/sre/networking.py @@ -8,6 +8,7 @@ from data_safe_haven.functions import alphanumeric, ordered_private_dns_zones from data_safe_haven.infrastructure.common import ( NetworkingPriorities, + Ports, SREDnsIpRanges, SREIpRanges, get_id_from_vnet, @@ -206,7 +207,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from users over the internet.", destination_address_prefix=subnet_application_gateway_prefix, - destination_port_ranges=["80", "443"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowUsersInternetInbound", priority=NetworkingPriorities.AUTHORISED_EXTERNAL_USER_IPS, @@ -218,7 +219,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from from ssllabs.com for SSL quality reporting.", destination_address_prefix=subnet_application_gateway_prefix, - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowSslLabsInternetInbound", priority=NetworkingPriorities.AUTHORISED_EXTERNAL_SSL_LABS_IPS, @@ -243,7 +244,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -255,7 +256,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to the Guacamole remote desktop gateway.", destination_address_prefix=subnet_guacamole_containers_prefix, - destination_port_ranges=["80"], + destination_port_ranges=[Ports.HTTP], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowGuacamoleContainersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_GUACAMOLE_CONTAINERS, @@ -433,7 +434,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from the Application Gateway.", destination_address_prefix=subnet_guacamole_containers_prefix, - destination_port_ranges=["80"], + destination_port_ranges=[Ports.HTTP], direction=network.SecurityRuleDirection.INBOUND, name="AllowApplicationGatewayInbound", priority=NetworkingPriorities.INTERNAL_SRE_APPLICATION_GATEWAY, @@ -470,7 +471,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -494,7 +495,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to Guacamole support services.", destination_address_prefix=subnet_guacamole_containers_support_prefix, - destination_port_ranges=["5432"], + destination_port_ranges=[Ports.POSTGRESQL], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowGuacamoleContainersSupportOutbound", priority=NetworkingPriorities.INTERNAL_SRE_GUACAMOLE_CONTAINERS_SUPPORT, @@ -506,7 +507,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowIdentityServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_IDENTITY_CONTAINERS, @@ -518,7 +519,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to SRE workspaces.", destination_address_prefix=subnet_workspaces_prefix, - destination_port_ranges=["22", "3389"], + destination_port_ranges=[Ports.SSH, Ports.RDP], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowWorkspacesOutbound", priority=NetworkingPriorities.INTERNAL_SRE_WORKSPACES, @@ -530,7 +531,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound OAuth connections over the internet.", destination_address_prefix="Internet", - destination_port_ranges=["80", "443"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowOAuthInternetOutbound", priority=NetworkingPriorities.EXTERNAL_INTERNET, @@ -623,7 +624,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests from Guacamole over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.INBOUND, name="AllowGuacamoleLDAPClientTCPInbound", priority=NetworkingPriorities.INTERNAL_SRE_GUACAMOLE_CONTAINERS, @@ -635,7 +636,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests from user services over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.INBOUND, name="AllowUserServicesLDAPClientTCPInbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_CONTAINERS, @@ -647,7 +648,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests from workspaces over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.INBOUND, name="AllowWorkspaceLDAPClientTCPInbound", priority=NetworkingPriorities.INTERNAL_SRE_WORKSPACES, @@ -670,7 +671,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from SRE workspaces.", destination_address_prefix=subnet_user_services_containers_prefix, - destination_port_ranges=["22", "80", "443"], + destination_port_ranges=[Ports.SSH, Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.INBOUND, name="AllowWorkspacesInbound", priority=NetworkingPriorities.INTERNAL_SRE_WORKSPACES, @@ -707,7 +708,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -731,7 +732,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowIdentityServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_IDENTITY_CONTAINERS, @@ -743,7 +744,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to container support services.", destination_address_prefix=subnet_user_services_containers_support_prefix, - destination_port_ranges=["5432"], + destination_port_ranges=[Ports.POSTGRESQL], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowUserServicesContainersSupportOutbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_CONTAINERS_SUPPORT, @@ -777,7 +778,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from user services containers.", destination_address_prefix=subnet_user_services_containers_support_prefix, - destination_port_ranges=["5432"], + destination_port_ranges=[Ports.POSTGRESQL], direction=network.SecurityRuleDirection.INBOUND, name="AllowUserServicesContainersInbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_CONTAINERS, @@ -836,7 +837,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from SRE workspaces.", destination_address_prefix=subnet_user_services_databases_prefix, - destination_port_ranges=["1433", "5432"], + destination_port_ranges=[Ports.MSSQL, Ports.POSTGRESQL], direction=network.SecurityRuleDirection.INBOUND, name="AllowWorkspacesInbound", priority=NetworkingPriorities.INTERNAL_SRE_WORKSPACES, @@ -873,7 +874,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -919,7 +920,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from SRE workspaces.", destination_address_prefix=subnet_user_services_software_repositories_prefix, - destination_port_ranges=["80", "443", "3128"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS, Ports.SQUID], direction=network.SecurityRuleDirection.INBOUND, name="AllowWorkspacesInbound", priority=NetworkingPriorities.INTERNAL_SRE_WORKSPACES, @@ -956,7 +957,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -980,7 +981,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to external repositories over the internet.", destination_address_prefix="Internet", - destination_port_ranges=["80", "443"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowPackagesInternetOutbound", priority=NetworkingPriorities.EXTERNAL_INTERNET, @@ -1014,7 +1015,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow inbound connections from Guacamole remote desktop gateway.", destination_address_prefix=subnet_workspaces_prefix, - destination_port_ranges=["22", "3389"], + destination_port_ranges=[Ports.SSH, Ports.RDP], direction=network.SecurityRuleDirection.INBOUND, name="AllowGuacamoleContainersInbound", priority=NetworkingPriorities.INTERNAL_SRE_GUACAMOLE_CONTAINERS, @@ -1051,7 +1052,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow LDAP client requests over TCP.", destination_address_prefix=subnet_identity_containers_prefix, - destination_port_ranges=["1389"], + destination_port_ranges=[Ports.LDAP_APRICOT], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowIdentityServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_IDENTITY_CONTAINERS, @@ -1063,7 +1064,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to SHM monitoring tools.", destination_address_prefix=str(props.shm_subnet_monitoring_prefix), - destination_port_ranges=["443"], + destination_port_ranges=[Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowMonitoringToolsOutbound", priority=NetworkingPriorities.INTERNAL_SHM_MONITORING_TOOLS, @@ -1075,7 +1076,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to Linux update servers.", destination_address_prefix=props.shm_subnet_update_servers_prefix, - destination_port_ranges=["8000"], + destination_port_ranges=[Ports.LINUX_UPDATE], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowLinuxUpdatesOutbound", priority=NetworkingPriorities.INTERNAL_SHM_UPDATE_SERVERS, @@ -1087,7 +1088,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to DNS servers.", destination_address_prefix=dns_servers_prefix, - destination_port_ranges=["53"], + destination_port_ranges=[Ports.DNS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowDNSServersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_DNS_SERVERS, @@ -1111,7 +1112,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to user services containers.", destination_address_prefix=subnet_user_services_containers_prefix, - destination_port_ranges=["22", "80", "443"], + destination_port_ranges=[Ports.SSH, Ports.HTTP, Ports.HTTPS], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowUserServicesContainersOutbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_CONTAINERS, @@ -1123,7 +1124,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to user services databases.", destination_address_prefix=subnet_user_services_databases_prefix, - destination_port_ranges=["1433", "5432"], + destination_port_ranges=[Ports.MSSQL, Ports.POSTGRESQL], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowUserServicesDatabasesOutbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_DATABASES, @@ -1135,7 +1136,7 @@ def __init__( access=network.SecurityRuleAccess.ALLOW, description="Allow outbound connections to user services software repositories.", destination_address_prefix=subnet_user_services_software_repositories_prefix, - destination_port_ranges=["80", "443", "3128"], + destination_port_ranges=[Ports.HTTP, Ports.HTTPS, Ports.SQUID], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowUserServicesSoftwareRepositoriesOutbound", priority=NetworkingPriorities.INTERNAL_SRE_USER_SERVICES_SOFTWARE_REPOSITORIES, diff --git a/data_safe_haven/infrastructure/stacks/sre/software_repositories.py b/data_safe_haven/infrastructure/stacks/sre/software_repositories.py index a1e55052bb..62eeabb0ff 100644 --- a/data_safe_haven/infrastructure/stacks/sre/software_repositories.py +++ b/data_safe_haven/infrastructure/stacks/sre/software_repositories.py @@ -6,6 +6,7 @@ from pulumi_azure_native import containerinstance, storage from data_safe_haven.infrastructure.common import ( + Ports, get_ip_address_from_container_group, ) from data_safe_haven.infrastructure.components import ( @@ -219,7 +220,7 @@ def __init__( ), containerinstance.EnvironmentVariableArgs( name="NEXUS_PORT", - value="8081", + value=Ports.NEXUS, ), # Use fallback updating method due to issue with changes to # files on Azure storage mount not being recognised by entr From 4f187d01f37e8c6382d9f48a40635167c64db0c5 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Fri, 19 Apr 2024 10:37:37 +0100 Subject: [PATCH 2/4] :pencil2: Fix minor typo --- data_safe_haven/infrastructure/common/enums.py | 4 ++-- data_safe_haven/infrastructure/stacks/shm/networking.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data_safe_haven/infrastructure/common/enums.py b/data_safe_haven/infrastructure/common/enums.py index c5838fc1e0..2891d60cac 100644 --- a/data_safe_haven/infrastructure/common/enums.py +++ b/data_safe_haven/infrastructure/common/enums.py @@ -61,10 +61,10 @@ class NetworkingPriorities(int, Enum): @verify(UNIQUE) class Ports(str, Enum): - AZURE_BASTIAN_1 = ( + AZURE_BASTION_1 = ( "8080" # https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg ) - AZURE_BASTIAN_2 = "5701" + AZURE_BASTION_2 = "5701" DNS = "53" HTTP = "80" HTTPS = "443" diff --git a/data_safe_haven/infrastructure/stacks/shm/networking.py b/data_safe_haven/infrastructure/stacks/shm/networking.py index 580c2359fc..09e24868e9 100644 --- a/data_safe_haven/infrastructure/stacks/shm/networking.py +++ b/data_safe_haven/infrastructure/stacks/shm/networking.py @@ -109,8 +109,8 @@ def __init__( description="Allow inbound internal bastion host communication.", destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg destination_port_ranges=[ - Ports.AZURE_BASTIAN_1, - Ports.AZURE_BASTIAN_2, + Ports.AZURE_BASTION_1, + Ports.AZURE_BASTION_2, ], direction=network.SecurityRuleDirection.INBOUND, name="AllowBastionHostInbound", @@ -161,8 +161,8 @@ def __init__( description="Allow outbound internal bastion host communication.", destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg destination_port_ranges=[ - Ports.AZURE_BASTIAN_1, - Ports.AZURE_BASTIAN_2, + Ports.AZURE_BASTION_1, + Ports.AZURE_BASTION_2, ], direction=network.SecurityRuleDirection.OUTBOUND, name="AllowBastionHostOutbound", From 1b5b2a17de1f576abe03126a0abf6698dfb27713 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Fri, 19 Apr 2024 10:46:09 +0100 Subject: [PATCH 3/4] :coffin: Remove rules relating to Azure Bastion --- .../infrastructure/common/enums.py | 5 - .../infrastructure/stacks/shm/networking.py | 157 ------------------ 2 files changed, 162 deletions(-) diff --git a/data_safe_haven/infrastructure/common/enums.py b/data_safe_haven/infrastructure/common/enums.py index 2891d60cac..54705b2577 100644 --- a/data_safe_haven/infrastructure/common/enums.py +++ b/data_safe_haven/infrastructure/common/enums.py @@ -28,7 +28,6 @@ class NetworkingPriorities(int, Enum): AZURE_PLATFORM_DNS = 400 # SHM connections: 1000-1399 INTERNAL_SELF = 1000 - INTERNAL_SHM_BASTION = 1100 INTERNAL_SHM_LDAP_TCP = 1200 INTERNAL_SHM_LDAP_UDP = 1250 INTERNAL_SHM_MONITORING_TOOLS = 1300 @@ -61,10 +60,6 @@ class NetworkingPriorities(int, Enum): @verify(UNIQUE) class Ports(str, Enum): - AZURE_BASTION_1 = ( - "8080" # https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - ) - AZURE_BASTION_2 = "5701" DNS = "53" HTTP = "80" HTTPS = "443" diff --git a/data_safe_haven/infrastructure/stacks/shm/networking.py b/data_safe_haven/infrastructure/stacks/shm/networking.py index 4aed72f924..874ea81cda 100644 --- a/data_safe_haven/infrastructure/stacks/shm/networking.py +++ b/data_safe_haven/infrastructure/stacks/shm/networking.py @@ -22,8 +22,6 @@ def __init__( ) -> None: # Virtual network and subnet IP ranges self.vnet_iprange = AzureIPv4Range("10.0.0.0", "10.0.255.255") - # Bastion subnet must be at least /26 in size (64 addresses) - self.subnet_bastion_iprange = self.vnet_iprange.next_subnet(64) # Firewall subnet must be at least /26 in size (64 addresses) self.subnet_firewall_iprange = self.vnet_iprange.next_subnet(64) # Monitoring subnet needs 2 IP addresses for automation and 13 for log analytics @@ -61,143 +59,6 @@ def __init__( ) # Define NSGs - nsg_bastion = network.NetworkSecurityGroup( - f"{self._name}_nsg_bastion", - network_security_group_name=f"{stack_name}-nsg-bastion", - resource_group_name=resource_group.name, - security_rules=[ - # Inbound - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow inbound https connections from admins connecting from approved IP addresses.", - destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[Ports.HTTPS], - direction=network.SecurityRuleDirection.INBOUND, - name="AllowAdminHttpsInbound", - priority=NetworkingPriorities.AUTHORISED_EXTERNAL_ADMIN_IPS, - protocol=network.SecurityRuleProtocol.TCP, - source_address_prefixes=props.admin_ip_addresses, - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow inbound gateway management service traffic.", - destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[Ports.HTTPS], - direction=network.SecurityRuleDirection.INBOUND, - name="AllowGatewayManagerServiceInbound", - priority=NetworkingPriorities.AZURE_GATEWAY_MANAGER, - protocol=network.SecurityRuleProtocol.TCP, - source_address_prefix="GatewayManager", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow inbound load balancer service traffic.", - destination_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[Ports.HTTPS], - direction=network.SecurityRuleDirection.INBOUND, - name="AllowLoadBalancerServiceInbound", - priority=NetworkingPriorities.AZURE_LOAD_BALANCER, - protocol=network.SecurityRuleProtocol.TCP, - source_address_prefix="AzureLoadBalancer", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow inbound internal bastion host communication.", - destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[ - Ports.AZURE_BASTION_1, - Ports.AZURE_BASTION_2, - ], - direction=network.SecurityRuleDirection.INBOUND, - name="AllowBastionHostInbound", - priority=NetworkingPriorities.INTERNAL_SELF, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.DENY, - description="Deny all other inbound traffic.", - destination_address_prefix="*", - destination_port_range="*", - direction=network.SecurityRuleDirection.INBOUND, - name="DenyAllOtherInbound", - priority=NetworkingPriorities.ALL_OTHER, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="*", - source_port_range="*", - ), - # Outbound - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow outbound connections to DSH VMs.", - destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[Ports.SSH, Ports.RDP], - direction=network.SecurityRuleDirection.OUTBOUND, - name="AllowRdpOutbound", - priority=NetworkingPriorities.INTERNAL_SHM_BASTION, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow outbound connections to Azure public endpoints.", - destination_address_prefix="AzureCloud", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[Ports.HTTPS], - direction=network.SecurityRuleDirection.OUTBOUND, - name="AllowAzureCloudOutbound", - priority=NetworkingPriorities.AZURE_CLOUD, - protocol=network.SecurityRuleProtocol.TCP, - source_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow outbound internal bastion host communication.", - destination_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - destination_port_ranges=[ - Ports.AZURE_BASTION_1, - Ports.AZURE_BASTION_2, - ], - direction=network.SecurityRuleDirection.OUTBOUND, - name="AllowBastionHostOutbound", - priority=NetworkingPriorities.INTERNAL_SELF, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="VirtualNetwork", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.ALLOW, - description="Allow outbound connections for session and certificate validation.", - destination_address_prefix="Internet", - destination_port_ranges=[Ports.HTTP], - direction=network.SecurityRuleDirection.OUTBOUND, - name="AllowCertificateValidationOutbound", - priority=NetworkingPriorities.EXTERNAL_INTERNET, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="*", # required by https://learn.microsoft.com/en-us/azure/bastion/bastion-nsg - source_port_range="*", - ), - network.SecurityRuleArgs( - access=network.SecurityRuleAccess.DENY, - description="Deny all other outbound traffic.", - destination_address_prefix="*", - destination_port_range="*", - direction=network.SecurityRuleDirection.OUTBOUND, - name="DenyAllOtherOutbound", - priority=NetworkingPriorities.ALL_OTHER, - protocol=network.SecurityRuleProtocol.ASTERISK, - source_address_prefix="*", - source_port_range="*", - ), - ], - opts=child_opts, - tags=child_tags, - ) nsg_monitoring = network.NetworkSecurityGroup( f"{self._name}_nsg_monitoring", network_security_group_name=f"{stack_name}-nsg-monitoring", @@ -296,7 +157,6 @@ def __init__( # Define the virtual network and its subnets subnet_firewall_name = "AzureFirewallSubnet" # this name is forced by https://docs.microsoft.com/en-us/azure/firewall/tutorial-firewall-deploy-portal - subnet_bastion_name = "AzureBastionSubnet" # this name is forced by https://learn.microsoft.com/en-us/azure/bastion/configuration-settings#subnet subnet_monitoring_name = "MonitoringSubnet" subnet_update_servers_name = "UpdateServersSubnet" virtual_network = network.VirtualNetwork( @@ -306,15 +166,6 @@ def __init__( ), resource_group_name=resource_group.name, subnets=[ # Note that we define subnets inline to avoid creation order issues - # Bastion subnet - network.SubnetArgs( - address_prefix=str(props.subnet_bastion_iprange), - name=subnet_bastion_name, - network_security_group=network.NetworkSecurityGroupArgs( - id=nsg_bastion.id - ), - route_table=None, # the bastion subnet must NOT be attached to the route table - ), # AzureFirewall subnet network.SubnetArgs( address_prefix=str(props.subnet_firewall_iprange), @@ -433,11 +284,6 @@ def __init__( self.private_dns_zone_base_id = private_zone_ids[0] self.resource_group_name = Output.from_input(resource_group.name) self.route_table = route_table - self.subnet_bastion = network.get_subnet_output( - subnet_name=subnet_bastion_name, - resource_group_name=resource_group.name, - virtual_network_name=virtual_network.name, - ) self.subnet_firewall = network.get_subnet_output( subnet_name=subnet_firewall_name, resource_group_name=resource_group.name, @@ -460,9 +306,6 @@ def __init__( "fqdn_nameservers": self.dns_zone.name_servers, "private_dns_zone_base_id": self.private_dns_zone_base_id, "resource_group_name": resource_group.name, - "subnet_bastion_prefix": self.subnet_bastion.apply( - lambda s: str(s.address_prefix) if s.address_prefix else "" - ), "subnet_monitoring_prefix": self.subnet_monitoring.apply( lambda s: str(s.address_prefix) if s.address_prefix else "" ), From c83df18e4586111489cbf4fae18993bee4ae8f95 Mon Sep 17 00:00:00 2001 From: James Robinson Date: Fri, 19 Apr 2024 10:53:51 +0100 Subject: [PATCH 4/4] :coffin: Remove unused rule/port enums --- .../infrastructure/common/enums.py | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/data_safe_haven/infrastructure/common/enums.py b/data_safe_haven/infrastructure/common/enums.py index 54705b2577..f8fcc5ea54 100644 --- a/data_safe_haven/infrastructure/common/enums.py +++ b/data_safe_haven/infrastructure/common/enums.py @@ -21,34 +21,30 @@ class FirewallPriorities(int, Enum): class NetworkingPriorities(int, Enum): """Priorities for network security group rules.""" - # Azure services: 0 - 999 - AZURE_CLOUD = 100 - AZURE_GATEWAY_MANAGER = 200 - AZURE_LOAD_BALANCER = 300 - AZURE_PLATFORM_DNS = 400 - # SHM connections: 1000-1399 + # Azure services: 100 - 999 + AZURE_GATEWAY_MANAGER = 100 + AZURE_LOAD_BALANCER = 200 + AZURE_PLATFORM_DNS = 300 + # SHM connections: 1000-1299 INTERNAL_SELF = 1000 - INTERNAL_SHM_LDAP_TCP = 1200 - INTERNAL_SHM_LDAP_UDP = 1250 - INTERNAL_SHM_MONITORING_TOOLS = 1300 - INTERNAL_SHM_UPDATE_SERVERS = 1400 + INTERNAL_SHM_MONITORING_TOOLS = 1100 + INTERNAL_SHM_UPDATE_SERVERS = 1200 # DNS connections: 1400-1499 - INTERNAL_SRE_DNS_SERVERS = 1499 + INTERNAL_SRE_DNS_SERVERS = 1400 # SRE connections: 1500-2999 INTERNAL_SRE_APPLICATION_GATEWAY = 1500 INTERNAL_SRE_DATA_CONFIGURATION = 1600 INTERNAL_SRE_DATA_PRIVATE = 1700 INTERNAL_SRE_GUACAMOLE_CONTAINERS = 1800 INTERNAL_SRE_GUACAMOLE_CONTAINERS_SUPPORT = 1900 - INTERNAL_SRE_IDENTITY_CONTAINERS = 1950 - INTERNAL_SRE_USER_SERVICES_CONTAINERS = 2000 - INTERNAL_SRE_USER_SERVICES_CONTAINERS_SUPPORT = 2100 - INTERNAL_SRE_USER_SERVICES_DATABASES = 2200 - INTERNAL_SRE_USER_SERVICES_SOFTWARE_REPOSITORIES = 2300 - INTERNAL_SRE_WORKSPACES = 2400 + INTERNAL_SRE_IDENTITY_CONTAINERS = 2000 + INTERNAL_SRE_USER_SERVICES_CONTAINERS = 2100 + INTERNAL_SRE_USER_SERVICES_CONTAINERS_SUPPORT = 2200 + INTERNAL_SRE_USER_SERVICES_DATABASES = 2300 + INTERNAL_SRE_USER_SERVICES_SOFTWARE_REPOSITORIES = 2400 + INTERNAL_SRE_WORKSPACES = 2500 INTERNAL_SRE_ANY = 2999 # Authorised external IPs: 3000-3499 - AUTHORISED_EXTERNAL_ADMIN_IPS = 3000 AUTHORISED_EXTERNAL_USER_IPS = 3100 AUTHORISED_EXTERNAL_SSL_LABS_IPS = 3200 # Wider internet: 3500-3999 @@ -63,8 +59,6 @@ class Ports(str, Enum): DNS = "53" HTTP = "80" HTTPS = "443" - LDAP = "389" - LDAPS = "636" LDAP_APRICOT = "1389" LINUX_UPDATE = "8000" MSSQL = "1433"