Skip to content

Commit

Permalink
Merge pull request #1555 from jemrobinson/1495-sre-nsg-rules
Browse files Browse the repository at this point in the history
Update SRE networking
  • Loading branch information
jemrobinson authored Aug 16, 2023
2 parents 0d100c0 + 814290e commit 9a530e3
Show file tree
Hide file tree
Showing 13 changed files with 986 additions and 302 deletions.
3 changes: 2 additions & 1 deletion data_safe_haven/commands/deploy_shm.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ def deploy_shm(

# Add the SHM domain as a custom domain in AzureAD
graph_api.verify_custom_domain(
config.shm.fqdn, stack.output("fqdn_nameservers")
config.shm.fqdn,
stack.output("networking")["fqdn_nameservers"],
)

# Add Pulumi infrastructure information to the config file
Expand Down
15 changes: 10 additions & 5 deletions data_safe_haven/pulumi/common/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,16 @@ class NetworkingPriorities(int, Enum):
INTERNAL_SHM_LDAP_UDP = 1250
INTERNAL_SHM_MONITORING_TOOLS = 1300
INTERNAL_SHM_UPDATE_SERVERS = 1400
INTERNAL_SRE_PRIVATE_DATA = 1500
INTERNAL_SRE_REMOTE_DESKTOP = 1600
INTERNAL_SRE_USER_SERVICES_CONTAINERS = 1700
INTERNAL_SRE_USER_SERVICES_DATABASES = 1800
INTERNAL_DSH_VIRTUAL_NETWORK = 1999
INTERNAL_SRE_APPLICATION_GATEWAY = 1500
INTERNAL_SRE_DATA_CONFIGURATION = 1600
INTERNAL_SRE_DATA_PRIVATE = 1650
INTERNAL_SRE_GUACAMOLE_CONTAINERS = 1700
INTERNAL_SRE_GUACAMOLE_CONTAINERS_SUPPORT = 1750
INTERNAL_SRE_USER_SERVICES_CONTAINERS = 1800
INTERNAL_SRE_USER_SERVICES_CONTAINERS_SUPPORT = 1825
INTERNAL_SRE_USER_SERVICES_DATABASES = 1850
INTERNAL_SRE_USER_SERVICES_SOFTWARE_REPOSITORIES = 1875
INTERNAL_SRE_WORKSPACES = 1900
# Authorised external IPs: 2000-2999
AUTHORISED_EXTERNAL_ADMIN_IPS = 2000
AUTHORISED_EXTERNAL_USER_IPS = 2100
Expand Down
155 changes: 78 additions & 77 deletions data_safe_haven/pulumi/components/shm_networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ def __init__(
) -> None:
# Virtual network and subnet IP ranges
self.vnet_iprange = AzureIPv4Range("10.0.0.0", "10.0.255.255")
# Firewall subnet must be at least /26 in size (64 addresses)
self.subnet_firewall_iprange = self.vnet_iprange.next_subnet(64)
# 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)
self.subnet_identity_servers_iprange = self.vnet_iprange.next_subnet(8)
# Monitoring subnet needs 2 IP addresses for automation and 13 for log analytics
self.subnet_monitoring_iprange = self.vnet_iprange.next_subnet(32)
self.subnet_update_servers_iprange = self.vnet_iprange.next_subnet(8)
self.subnet_identity_servers_iprange = self.vnet_iprange.next_subnet(8)
# Other variables
self.admin_ip_addresses = admin_ip_addresses
self.fqdn = fqdn
Expand Down Expand Up @@ -58,13 +58,6 @@ def __init__(
)

# Define NSGs
nsg_monitoring = network.NetworkSecurityGroup(
f"{self._name}_nsg_monitoring",
network_security_group_name=f"{stack_name}-nsg-monitoring",
resource_group_name=resource_group.name,
security_rules=[],
opts=child_opts,
)
nsg_bastion = network.NetworkSecurityGroup(
f"{self._name}_nsg_bastion",
network_security_group_name=f"{stack_name}-nsg-bastion",
Expand Down Expand Up @@ -195,6 +188,64 @@ def __init__(
],
opts=child_opts,
)
nsg_identity_servers = network.NetworkSecurityGroup(
f"{self._name}_nsg_identity",
network_security_group_name=f"{stack_name}-nsg-identity",
resource_group_name=resource_group.name,
security_rules=[
# Inbound
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound LDAP to domain controllers.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["389", "636"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowLDAPClientUDPInbound",
priority=NetworkingPriorities.INTERNAL_SHM_LDAP_UDP,
protocol=network.SecurityRuleProtocol.UDP,
source_address_prefix="VirtualNetwork",
source_port_range="*",
),
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound LDAP to domain controllers.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["389", "636"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowLDAPClientTCPInbound",
priority=NetworkingPriorities.INTERNAL_SHM_LDAP_TCP,
protocol=network.SecurityRuleProtocol.TCP,
source_address_prefix="VirtualNetwork",
source_port_range="*",
),
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound RDP connections from admins using AzureBastion.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["3389"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowBastionAdminsInbound",
priority=NetworkingPriorities.INTERNAL_SHM_BASTION,
protocol=network.SecurityRuleProtocol.TCP,
source_address_prefix=str(props.subnet_bastion_iprange),
source_port_range="*",
),
],
opts=child_opts,
)
nsg_monitoring = network.NetworkSecurityGroup(
f"{self._name}_nsg_monitoring",
network_security_group_name=f"{stack_name}-nsg-monitoring",
resource_group_name=resource_group.name,
security_rules=[],
opts=child_opts,
)
nsg_update_servers = network.NetworkSecurityGroup(
f"{self._name}_nsg_update_servers",
network_security_group_name=f"{stack_name}-nsg-update-servers",
Expand All @@ -208,7 +259,7 @@ def __init__(
destination_port_range="*",
direction=network.SecurityRuleDirection.INBOUND,
name="AllowVirtualNetworkInbound",
priority=NetworkingPriorities.INTERNAL_DSH_VIRTUAL_NETWORK,
priority=NetworkingPriorities.INTERNAL_SELF,
protocol=network.SecurityRuleProtocol.ASTERISK,
source_address_prefix="VirtualNetwork",
source_port_range="*",
Expand Down Expand Up @@ -265,57 +316,6 @@ def __init__(
],
opts=child_opts,
)
nsg_identity_servers = network.NetworkSecurityGroup(
f"{self._name}_nsg_identity",
network_security_group_name=f"{stack_name}-nsg-identity",
resource_group_name=resource_group.name,
security_rules=[
# Inbound
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound LDAP to domain controllers.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["389", "636"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowLDAPClientUDPInbound",
priority=NetworkingPriorities.INTERNAL_SHM_LDAP_UDP,
protocol=network.SecurityRuleProtocol.UDP,
source_address_prefix="*",
source_port_range="*",
),
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound LDAP to domain controllers.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["389", "636"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowLDAPClientTCPInbound",
priority=NetworkingPriorities.INTERNAL_SHM_LDAP_TCP,
protocol=network.SecurityRuleProtocol.TCP,
source_address_prefix="*",
source_port_range="*",
),
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound RDP connections from admins using AzureBastion.",
destination_address_prefix=str(
props.subnet_identity_servers_iprange
),
destination_port_ranges=["3389"],
direction=network.SecurityRuleDirection.INBOUND,
name="AllowBastionAdminsInbound",
priority=NetworkingPriorities.INTERNAL_SHM_BASTION,
protocol=network.SecurityRuleProtocol.TCP,
source_address_prefix=str(props.subnet_bastion_iprange),
source_port_range="*",
),
],
opts=child_opts,
)

# Define route table
route_table = network.RouteTable(
Expand All @@ -335,31 +335,40 @@ 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_identity_servers_name = "IdentityServersSubnet"
subnet_monitoring_name = "MonitoringSubnet"
subnet_update_servers_name = "UpdateServersSubnet"
subnet_identity_servers_name = "IdentityServersSubnet"
virtual_network = network.VirtualNetwork(
f"{self._name}_virtual_network",
address_space=network.AddressSpaceArgs(
address_prefixes=[str(props.vnet_iprange)],
),
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),
name=subnet_firewall_name,
network_security_group=None, # the firewall subnet must NOT have an NSG
route_table=None, # the firewall subnet must NOT be attached to the route table
),
# Bastion subnet
# Identity servers subnet
network.SubnetArgs(
address_prefix=str(props.subnet_bastion_iprange),
name=subnet_bastion_name,
address_prefix=str(props.subnet_identity_servers_iprange),
name=subnet_identity_servers_name,
network_security_group=network.NetworkSecurityGroupArgs(
id=nsg_bastion.id
id=nsg_identity_servers.id
),
route_table=None, # the bastion subnet must NOT be attached to the route table
route_table=network.RouteTableArgs(id=route_table.id),
),
# Monitoring subnet
network.SubnetArgs(
Expand All @@ -379,15 +388,6 @@ def __init__(
),
route_table=network.RouteTableArgs(id=route_table.id),
),
# Identity servers subnet
network.SubnetArgs(
address_prefix=str(props.subnet_identity_servers_iprange),
name=subnet_identity_servers_name,
network_security_group=network.NetworkSecurityGroupArgs(
id=nsg_identity_servers.id
),
route_table=network.RouteTableArgs(id=route_table.id),
),
],
virtual_network_name=f"{stack_name}-vnet",
virtual_network_peerings=[],
Expand Down Expand Up @@ -502,6 +502,7 @@ def __init__(

# Register exports
self.exports = {
"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(
Expand Down
22 changes: 13 additions & 9 deletions data_safe_haven/pulumi/components/sre_backup.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Pulumi component for SRE state"""
"""Pulumi component for SRE backup"""
from pulumi import ComponentResource, Input, ResourceOptions
from pulumi_azure_native import dataprotection, resources

Expand All @@ -9,12 +9,16 @@ class SREBackupProps:
def __init__(
self,
location: Input[str],
storage_account_securedata_id: Input[str],
storage_account_securedata_name: Input[str],
storage_account_data_private_sensitive_id: Input[str],
storage_account_data_private_sensitive_name: Input[str],
) -> None:
self.location = location
self.storage_account_securedata_id = storage_account_securedata_id
self.storage_account_securedata_name = storage_account_securedata_name
self.storage_account_data_private_sensitive_id = (
storage_account_data_private_sensitive_id
)
self.storage_account_data_private_sensitive_name = (
storage_account_data_private_sensitive_name
)


class SREBackupComponent(ComponentResource):
Expand Down Expand Up @@ -164,19 +168,19 @@ def __init__(
backup_instance_name="backup-instance-blobs",
properties=dataprotection.BackupInstanceArgs(
data_source_info=dataprotection.DatasourceArgs(
resource_id=props.storage_account_securedata_id,
resource_id=props.storage_account_data_private_sensitive_id,
datasource_type="Microsoft.Storage/storageAccounts/blobServices",
object_type="Datasource",
resource_location=props.location,
resource_name=props.storage_account_securedata_name,
resource_name=props.storage_account_data_private_sensitive_name,
resource_type="Microsoft.Storage/storageAccounts",
resource_uri=props.storage_account_securedata_id,
resource_uri=props.storage_account_data_private_sensitive_id,
),
object_type="BackupInstance",
policy_info=dataprotection.PolicyInfoArgs(
policy_id=backup_policy_blobs.id,
),
friendly_name="BlobBackupSecureData",
friendly_name="BlobBackupSensitiveData",
),
resource_group_name=resource_group.name,
vault_name=backup_vault.name,
Expand Down
Loading

0 comments on commit 9a530e3

Please sign in to comment.