Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Adding a toggleable additional Gitea external mirror #2071

Draft
wants to merge 48 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e4a00ae
add gitea_external_server
craddm Aug 1, 2024
ce965cf
add additional files for external gitea
craddm Aug 1, 2024
fa62af6
Add gitea_external_mirror config flag
craddm Aug 1, 2024
cb70be7
Create enum for GiteaServerAvailability
craddm Aug 1, 2024
73259e4
Create GiteaServerAvailability type
craddm Aug 1, 2024
34b25cd
Add gitea_external_mirror to config template
craddm Aug 1, 2024
b218499
add gitea_server field to GiteaServerProps
craddm Aug 1, 2024
15dcbf0
change gitea_external_mirror field entry to list
craddm Aug 1, 2024
7f5c04c
add gitea_servers field to SREUserServiceProps
craddm Aug 1, 2024
2acba92
change gitea enum name and possible responses
craddm Aug 1, 2024
39845fe
change GiteaServer type
craddm Aug 1, 2024
700f6f2
Change use of GiteaServers enum
craddm Aug 1, 2024
4042d1e
Change GiteaServer Enum possible values
craddm Aug 1, 2024
27f0c00
Iterate over gitea_servers to deploy multiple types
craddm Aug 1, 2024
26b5f47
Modify config template
craddm Aug 1, 2024
ebcc502
Remove seperate gitea component for external mirror
craddm Aug 1, 2024
a9643f1
Switch to boolean toggle for external mirror
craddm Aug 1, 2024
5fa097b
Remove GiteaServers enum
craddm Aug 2, 2024
3adc136
Change gitea flag to boolean
craddm Aug 2, 2024
3a20cc8
Use new fieldname
craddm Aug 2, 2024
dfbaf54
Switch to boolean toggle for external mirror
craddm Aug 2, 2024
d9067f9
Run lint:fmt
craddm Aug 2, 2024
4705e22
Switch to boolean toggle and change logic for deploying multiple servers
craddm Aug 2, 2024
5ab174d
Merge branch 'alan-turing-institute:develop' into gitea_external_mirror
craddm Aug 2, 2024
b6f3a50
remove deprecated enum
craddm Aug 2, 2024
d8e7ee5
switch to external_git_mirror
craddm Aug 2, 2024
486261e
rename gitea property
craddm Aug 2, 2024
da2b231
comment out external subnet while testing
craddm Aug 2, 2024
cb242ac
comment out external subnet while testing
craddm Aug 2, 2024
d499684
use separate fileshares for external and internal gitea servers
craddm Aug 2, 2024
599f771
don't setup ldap on external gitea server
craddm Aug 2, 2024
a575e71
Merge remote-tracking branch 'upstream/develop' into gitea_external_m…
craddm Sep 13, 2024
0d32339
fix linting error
craddm Sep 13, 2024
426c6d6
Add ip range for external git mirror
craddm Sep 13, 2024
424b18b
add subnet and nsg for external git mirror
craddm Sep 13, 2024
c86beec
add enum for git mirror nsg rule
craddm Sep 16, 2024
52badd4
differentiate between internal and external gitea hosts
craddm Sep 16, 2024
92669fc
add some test NSG rules
craddm Sep 16, 2024
343b20c
differentiate between internal and external gitea servers
craddm Sep 16, 2024
3b7e1f9
create list of gitea servers
craddm Sep 16, 2024
e8d3488
add type hint
craddm Sep 16, 2024
72e7cc1
swap gitea over
craddm Sep 16, 2024
638982b
Merge remote-tracking branch 'upstream/develop' into gitea_external_m…
craddm Sep 23, 2024
cf31e76
Capture gitea hostnames correctly
craddm Sep 23, 2024
dfb6d7e
Use dicts rather than lists for gitea server related variables
craddm Sep 23, 2024
b53ac70
Fix setting hostnames for external and internal gitea
craddm Sep 24, 2024
36a8cd6
populate gitea_hostnames
craddm Sep 24, 2024
53c88a7
Merge branch 'alan-turing-institute:develop' into gitea_external_mirror
craddm Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data_safe_haven/config/config_sections.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class ConfigSectionSRE(BaseModel, validate_assignment=True):
# Mutable objects can be used as default arguments in Pydantic:
# https://docs.pydantic.dev/latest/concepts/models/#fields-with-non-hashable-default-values
admin_email_address: EmailAddress
external_git_mirror: bool = False
admin_ip_addresses: list[IpAddress] = []
databases: UniqueList[DatabaseSystem] = []
data_provider_ip_addresses: list[IpAddress] = []
Expand Down
1 change: 1 addition & 0 deletions data_safe_haven/config/sre_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def template(cls: type[Self], tier: int | None = None) -> SREConfig:
data_provider_ip_addresses=[
"List of IP addresses belonging to data providers"
],
external_git_mirror="True/False: whether to deploy an external mirror git server (True), or only an internal server", # type: ignore
remote_desktop=ConfigSubsectionRemoteDesktopOpts.model_construct(
allow_copy=remote_desktop_allow_copy,
allow_paste=remote_desktop_allow_paste,
Expand Down
1 change: 1 addition & 0 deletions data_safe_haven/infrastructure/common/ip_ranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class SREIpRanges:
data_configuration = vnet.next_subnet(8)
data_private = vnet.next_subnet(8)
desired_state = vnet.next_subnet(8)
external_git_mirror = vnet.next_subnet(8)
firewall = vnet.next_subnet(64) # 64 address minimum
firewall_management = vnet.next_subnet(64) # 64 address minimum
guacamole_containers = vnet.next_subnet(8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ def __call__(self) -> None:
dns_server_ip=dns.ip_address,
dockerhub_credentials=dockerhub_credentials,
gitea_database_password=data.password_gitea_database_admin,
external_git_mirror=self.config.sre.external_git_mirror,
hedgedoc_database_password=data.password_hedgedoc_database_admin,
ldap_server_hostname=identity.hostname,
ldap_server_port=identity.server_port,
Expand All @@ -334,6 +335,7 @@ def __call__(self) -> None:
subnet_containers=networking.subnet_user_services_containers,
subnet_containers_support=networking.subnet_user_services_containers_support,
subnet_databases=networking.subnet_user_services_databases,
subnet_external_git_mirror=networking.subnet_external_git_mirror,
subnet_software_repositories=networking.subnet_user_services_software_repositories,
),
tags=self.tags,
Expand Down Expand Up @@ -362,7 +364,10 @@ def __call__(self) -> None:
clamav_mirror_hostname=clamav_mirror.hostname,
database_service_admin_password=data.password_database_service_admin,
dns_private_zones=dns.private_zones,
gitea_hostname=user_services.gitea_server.hostname,
gitea_hostnames={
availability: server.hostname
for (availability, server) in user_services.gitea_server.items()
},
hedgedoc_hostname=user_services.hedgedoc_server.hostname,
ldap_group_filter=ldap_group_filter,
ldap_group_search_base=ldap_group_search_base,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(
clamav_mirror_hostname: Input[str],
database_service_admin_password: Input[str],
dns_private_zones: Input[dict[str, network.PrivateZone]],
gitea_hostname: Input[str],
gitea_hostnames: Input[dict[str, str]],
hedgedoc_hostname: Input[str],
ldap_group_filter: Input[str],
ldap_group_search_base: Input[str],
Expand All @@ -64,7 +64,8 @@ def __init__(
self.clamav_mirror_hostname = clamav_mirror_hostname
self.database_service_admin_password = database_service_admin_password
self.dns_private_zones = dns_private_zones
self.gitea_hostname = gitea_hostname
self.internal_gitea_hostname = gitea_hostnames.get("internal")
self.external_gitea_hostname = gitea_hostnames.get("external")
self.hedgedoc_hostname = hedgedoc_hostname
self.ldap_group_filter = ldap_group_filter
self.ldap_group_search_base = ldap_group_search_base
Expand Down Expand Up @@ -161,7 +162,7 @@ def __init__(
source=Output.all(
clamav_mirror_hostname=props.clamav_mirror_hostname,
database_service_admin_password=props.database_service_admin_password,
gitea_hostname=props.gitea_hostname,
gitea_hostname=props.internal_gitea_hostname,
hedgedoc_hostname=props.hedgedoc_hostname,
ldap_group_filter=props.ldap_group_filter,
ldap_group_search_base=props.ldap_group_search_base,
Expand Down
27 changes: 17 additions & 10 deletions data_safe_haven/infrastructure/programs/sre/gitea_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def __init__(
database_subnet_id: Input[str],
dns_server_ip: Input[str],
dockerhub_credentials: DockerHubCredentials,
gitea_server: Input[str],
ldap_server_hostname: Input[str],
ldap_server_port: Input[int],
ldap_username_attribute: Input[str],
Expand All @@ -49,6 +50,7 @@ def __init__(
)
self.dns_server_ip = dns_server_ip
self.dockerhub_credentials = dockerhub_credentials
self.gitea_server = gitea_server
self.ldap_server_hostname = ldap_server_hostname
self.ldap_server_port = ldap_server_port
self.ldap_username_attribute = ldap_username_attribute
Expand Down Expand Up @@ -82,7 +84,7 @@ def __init__(
access_tier=storage.ShareAccessTier.TRANSACTION_OPTIMIZED,
account_name=props.storage_account_name,
resource_group_name=props.resource_group_name,
share_name="gitea-caddy",
share_name=f"{props.gitea_server}-gitea-caddy",
share_quota=1,
signed_identifiers=[],
opts=child_opts,
Expand All @@ -92,7 +94,7 @@ def __init__(
access_tier=storage.ShareAccessTier.TRANSACTION_OPTIMIZED,
account_name=props.storage_account_name,
resource_group_name=props.resource_group_name,
share_name="gitea-gitea",
share_name=f"{props.gitea_server}-gitea-gitea",
share_quota=1,
signed_identifiers=[],
opts=child_opts,
Expand All @@ -117,9 +119,14 @@ def __init__(
)

# Upload Gitea configuration script
gitea_configure_sh_reader = FileReader(
resources_path / "gitea" / "gitea" / "configure.mustache.sh"
)
if props.gitea_server == "external":
gitea_configure_sh_reader = FileReader(
resources_path / "gitea_external" / "gitea" / "configure.mustache.sh"
)
else:
gitea_configure_sh_reader = FileReader(
resources_path / "gitea" / "gitea" / "configure.mustache.sh"
)
gitea_configure_sh = Output.all(
admin_email="[email protected]",
admin_username="dshadmin",
Expand Down Expand Up @@ -167,12 +174,12 @@ def __init__(
# Define a PostgreSQL server and default database
db_gitea_repository_name = "gitea"
db_server_gitea = PostgresqlDatabaseComponent(
f"{self._name}_db_gitea",
f"{self._name}_db_gitea_{props.gitea_server}",
PostgresqlDatabaseProps(
database_names=[db_gitea_repository_name],
database_password=props.database_password,
database_resource_group_name=props.resource_group_name,
database_server_name=f"{stack_name}-db-server-gitea",
database_server_name=f"{stack_name}-db-server-gitea-{props.gitea_server}",
database_subnet_id=props.database_subnet_id,
database_username=props.database_username,
disable_secure_transport=False,
Expand All @@ -182,10 +189,10 @@ def __init__(
tags=child_tags,
)

# Define the container group with guacd, guacamole and caddy
# Define the container group with gitea and caddy
container_group = containerinstance.ContainerGroup(
f"{self._name}_container_group",
container_group_name=f"{stack_name}-container-group-gitea",
container_group_name=f"{stack_name}-container-group-gitea-{props.gitea_server}",
containers=[
containerinstance.ContainerArgs(
image="caddy:2.8.4",
Expand Down Expand Up @@ -341,7 +348,7 @@ def __init__(
LocalDnsRecordProps(
base_fqdn=props.sre_fqdn,
private_ip_address=get_ip_address_from_container_group(container_group),
record_name="gitea",
record_name=f"{props.gitea_server}-gitea",
resource_group_name=props.resource_group_name,
),
opts=ResourceOptions.merge(
Expand Down
57 changes: 57 additions & 0 deletions data_safe_haven/infrastructure/programs/sre/networking.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,41 @@ def __init__(
)

# Define NSGs
nsg_external_git_mirror = network.NetworkSecurityGroup(
f"{self._name}_nsg_external_git_mirror",
location=props.location,
network_security_group_name=f"{stack_name}-nsg-external-git-mirror",
resource_group_name=props.resource_group_name,
security_rules=[
# Inbound
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="*",
),
network.SecurityRuleArgs(
access=network.SecurityRuleAccess.ALLOW,
description="Allow inbound connections from user container services.",
destination_address_prefix=SREIpRanges.external_git_mirror.prefix,
destination_port_range="*",
direction=network.SecurityRuleDirection.INBOUND,
name="AllowGitServersInbound",
priority=NetworkingPriorities.INTERNAL_SRE_EXTERNAL_GIT_MIRROR,
protocol=network.SecurityRuleProtocol.ASTERISK,
source_address_prefix=SREIpRanges.user_services_containers.prefix,
source_port_range="*",
),
],
opts=child_opts,
tags=child_tags,
)
nsg_application_gateway = network.NetworkSecurityGroup(
f"{self._name}_nsg_application_gateway",
location=props.location,
Expand Down Expand Up @@ -1564,6 +1599,7 @@ def __init__(
subnet_data_configuration_name = "DataConfigurationSubnet"
subnet_desired_state_name = "DataDesiredStateSubnet"
subnet_data_private_name = "DataPrivateSubnet"
subnet_external_git_mirror_name = "ExternalGitMirrorSubnet"
subnet_firewall_name = "AzureFirewallSubnet"
subnet_firewall_management_name = "AzureFirewallManagementSubnet"
subnet_guacamole_containers_name = "GuacamoleContainersSubnet"
Expand Down Expand Up @@ -1754,6 +1790,22 @@ def __init__(
),
route_table=network.RouteTableArgs(id=route_table.id),
),
# User services external git mirror
network.SubnetArgs(
address_prefix=SREIpRanges.external_git_mirror.prefix,
delegations=[
network.DelegationArgs(
name="SubnetDelegationContainerGroups",
service_name="Microsoft.ContainerInstance/containerGroups",
type="Microsoft.Network/virtualNetworks/subnets/delegations",
),
],
name=subnet_external_git_mirror_name,
network_security_group=network.NetworkSecurityGroupArgs(
id=nsg_external_git_mirror.id
),
route_table=network.RouteTableArgs(id=route_table.id),
),
# User services containers support
network.SubnetArgs(
address_prefix=SREIpRanges.user_services_containers_support.prefix,
Expand Down Expand Up @@ -1999,6 +2051,11 @@ def __init__(
resource_group_name=props.resource_group_name,
virtual_network_name=sre_virtual_network.name,
)
self.subnet_external_git_mirror = network.get_subnet_output(
subnet_name=subnet_external_git_mirror_name,
resource_group_name=props.resource_group_name,
virtual_network_name=sre_virtual_network.name,
)
self.subnet_firewall = network.get_subnet_output(
subnet_name=subnet_firewall_name,
resource_group_name=props.resource_group_name,
Expand Down
67 changes: 43 additions & 24 deletions data_safe_haven/infrastructure/programs/sre/user_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(
dns_server_ip: Input[str],
dockerhub_credentials: DockerHubCredentials,
gitea_database_password: Input[str],
external_git_mirror: Input[bool],
hedgedoc_database_password: Input[str],
ldap_server_hostname: Input[str],
ldap_server_port: Input[int],
Expand All @@ -44,13 +45,15 @@ def __init__(
subnet_containers: Input[network.GetSubnetResult],
subnet_containers_support: Input[network.GetSubnetResult],
subnet_databases: Input[network.GetSubnetResult],
subnet_external_git_mirror: Input[network.GetSubnetResult],
subnet_software_repositories: Input[network.GetSubnetResult],
) -> None:
self.database_service_admin_password = database_service_admin_password
self.databases = databases
self.dns_server_ip = dns_server_ip
self.dockerhub_credentials = dockerhub_credentials
self.gitea_database_password = gitea_database_password
self.external_git_mirror = external_git_mirror
self.hedgedoc_database_password = hedgedoc_database_password
self.ldap_server_hostname = ldap_server_hostname
self.ldap_server_port = ldap_server_port
Expand All @@ -73,6 +76,9 @@ def __init__(
self.subnet_databases_id = Output.from_input(subnet_databases).apply(
get_id_from_subnet
)
self.subnet_external_git_mirror_id = Output.from_input(
subnet_external_git_mirror
).apply(get_id_from_subnet)
self.subnet_software_repositories_id = Output.from_input(
subnet_software_repositories
).apply(get_id_from_subnet)
Expand All @@ -93,30 +99,43 @@ def __init__(
child_opts = ResourceOptions.merge(opts, ResourceOptions(parent=self))
child_tags = {"component": "user services"} | (tags if tags else {})

# Deploy the Gitea server
self.gitea_server = SREGiteaServerComponent(
"sre_gitea_server",
stack_name,
SREGiteaServerProps(
containers_subnet_id=props.subnet_containers_id,
database_subnet_id=props.subnet_containers_support_id,
database_password=props.gitea_database_password,
dns_server_ip=props.dns_server_ip,
dockerhub_credentials=props.dockerhub_credentials,
ldap_server_hostname=props.ldap_server_hostname,
ldap_server_port=props.ldap_server_port,
ldap_username_attribute=props.ldap_username_attribute,
ldap_user_filter=props.ldap_user_filter,
ldap_user_search_base=props.ldap_user_search_base,
location=props.location,
resource_group_name=props.resource_group_name,
sre_fqdn=props.sre_fqdn,
storage_account_key=props.storage_account_key,
storage_account_name=props.storage_account_name,
),
opts=child_opts,
tags=child_tags,
)
# Deploy the Gitea servers
self.gitea_server = {} # type: dict[str, SREGiteaServerComponent]
if props.external_git_mirror:
gitea_servers = ["internal", "external"]
subnet = {
"internal": props.subnet_containers_id,
"external": props.subnet_external_git_mirror_id,
}
else:
gitea_servers = ["internal"]
subnet = {"internal": props.subnet_containers_id}

for gitea_server in gitea_servers:
self.gitea_server[gitea_server] = SREGiteaServerComponent(
f"sre_{gitea_server}_gitea_server",
stack_name,
SREGiteaServerProps(
containers_subnet_id=subnet[gitea_server],
database_subnet_id=props.subnet_containers_support_id,
database_password=props.gitea_database_password,
dns_server_ip=props.dns_server_ip,
dockerhub_credentials=props.dockerhub_credentials,
gitea_server=gitea_server,
ldap_server_hostname=props.ldap_server_hostname,
ldap_server_port=props.ldap_server_port,
ldap_username_attribute=props.ldap_username_attribute,
ldap_user_filter=props.ldap_user_filter,
ldap_user_search_base=props.ldap_user_search_base,
Comment on lines +125 to +129
Copy link
Member

@jemrobinson jemrobinson Aug 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't want don't need the external server to plug in to our LDAP directory.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some notes on Gitea configuration here

location=props.location,
resource_group_name=props.resource_group_name,
sre_fqdn=props.sre_fqdn,
storage_account_key=props.storage_account_key,
storage_account_name=props.storage_account_name,
),
opts=child_opts,
tags=child_tags,
)

# Deploy the HedgeDoc server
self.hedgedoc_server = SREHedgeDocServerComponent(
Expand Down
14 changes: 14 additions & 0 deletions data_safe_haven/resources/gitea_external/caddy/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile
{
log {
format console {
level_format upper
}
level DEBUG
}
}

:80 {
reverse_proxy http://localhost:3000
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#! /usr/bin/env bash

# Ensure that default admin user exists
until su-exec "$USER" /usr/local/bin/gitea admin user list --admin | grep "{{admin_username}}" > /dev/null 2>&1; do
echo "$(date -Iseconds) Attempting to create default admin user '{{admin_username}}'..." | tee -a /var/log/configuration
su-exec "$USER" /usr/local/bin/gitea admin user create --admin --username "{{admin_username}}" --random-password --random-password-length 20 --email "{{admin_email}}" 2> /dev/null
sleep 1
done
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#! /usr/bin/env sh

# Add configuration as an s6 target
mkdir -p /etc/s6/setup
rm /etc/s6/setup/run 2> /dev/null
ln -s /app/custom/configure.sh /etc/s6/setup/run

# Run the usual entrypoint
/usr/bin/entrypoint
1 change: 1 addition & 0 deletions data_safe_haven/types/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class NetworkingPriorities(int, Enum):
INTERNAL_SRE_DATA_CONFIGURATION = 1900
INTERNAL_SRE_DATA_DESIRED_STATE = 1910
INTERNAL_SRE_DATA_PRIVATE = 1920
INTERNAL_SRE_EXTERNAL_GIT_MIRROR = 1930
INTERNAL_SRE_GUACAMOLE_CONTAINERS = 2000
INTERNAL_SRE_GUACAMOLE_CONTAINERS_SUPPORT = 2100
INTERNAL_SRE_IDENTITY_CONTAINERS = 2200
Expand Down
Loading