From 344fb27dd0de65a47a35e76f500b9b7f9828d7eb Mon Sep 17 00:00:00 2001 From: Hallie Swan <26949006+hallieswan@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:05:01 -0800 Subject: [PATCH 1/9] update CODEOWNERS per Khai --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d5f46d0..362d627 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @Sage-Bionetworks-IT/sagebio-it @Sage-Bionetworks-IT/infra-oversight-committee @Sage-Bionetworks-IT/agora-admin +* @Sage-Bionetworks-IT/infra-oversight-committee @Sage-Bionetworks-IT/agora-admin From 45b5ed8f793de076ecca72540a6f1f1ccc4751a2 Mon Sep 17 00:00:00 2001 From: Hallie Swan <26949006+hallieswan@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:45:34 -0800 Subject: [PATCH 2/9] AG-1592: point agora-api at existing DocumentDB instances --- app.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index e905319..e92d1a6 100644 --- a/app.py +++ b/app.py @@ -5,7 +5,7 @@ from src.ecs_stack import EcsStack from src.load_balancer_stack import LoadBalancerStack from src.network_stack import NetworkStack -from src.service_props import ServiceProps, ContainerVolume +from src.service_props import ServiceProps, ContainerVolume, ServiceSecret from src.service_stack import LoadBalancedServiceStack, ServiceStack # get the environment and set environment specific variables @@ -148,9 +148,24 @@ container_port=3333, container_memory=1024, container_env_vars={ - "MONGODB_URI": "mongodb://root:changeme@agora-mongo:27017/agora?authSource=admin", - "NODE_ENV": "development", + "NODE_ENV": "development" + "MONGODB_PORT": "27017", + "MONGODB_NAME": "agora" }, + container_secrets=[ + ServiceSecret( + secret_name=f"{stack_name_prefix}/MongodbUsername", + environment_key="MONGODB_USER", + ), + ServiceSecret( + secret_name=f"{stack_name_prefix}/MongodbPassword", + environment_key="MONGODB_PASS", + ), + ServiceSecret( + secret_name=f"{stack_name_prefix}/MongodbHost", + environment_key="MONGODB_HOST", + ), + ] ) api_stack = ServiceStack( scope=cdk_app, From 9456101c74c6f55997fee8c477bbbf0aaed7948f Mon Sep 17 00:00:00 2001 From: Hallie Swan <26949006+hallieswan@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:46:23 -0800 Subject: [PATCH 3/9] AG-1591: only deploy containers required for agora --- app.py | 69 ---------------------------------------------------------- 1 file changed, 69 deletions(-) diff --git a/app.py b/app.py index e92d1a6..bbeb122 100644 --- a/app.py +++ b/app.py @@ -75,73 +75,6 @@ vpc=network_stack.vpc, ) -api_docs_props = ServiceProps( - container_name="agora-api-docs", - container_location=f"ghcr.io/sage-bionetworks/agora-api-docs:{agora_version}", - container_port=8010, - container_memory=200, - container_env_vars={"PORT": "8010"}, -) -api_docs_stack = ServiceStack( - scope=cdk_app, - construct_id=f"{stack_name_prefix}-api-docs", - vpc=network_stack.vpc, - cluster=ecs_stack.cluster, - props=api_docs_props, -) - -mongo_props = ServiceProps( - container_name="agora-mongo", - container_location=f"ghcr.io/sage-bionetworks/agora-mongo:{agora_version}", - container_port=27017, - container_memory=500, - container_env_vars={ - "MONGO_INITDB_ROOT_USERNAME": "root", - "MONGO_INITDB_ROOT_PASSWORD": "changeme", - "MONGO_INITDB_DATABASE": "agora", - }, - container_volumes=[ - ContainerVolume( - path="/data/db", - size=30, - ) - ], -) -mongo_stack = ServiceStack( - scope=cdk_app, - construct_id=f"{stack_name_prefix}-mongo", - vpc=network_stack.vpc, - cluster=ecs_stack.cluster, - props=mongo_props, -) - -# It is probably not appropriate host this container in ECS -# data_props = ServiceProps( -# container_name="agora-data", -# container_location=f"ghcr.io/sage-bionetworks/agora-data:{agora_version}", -# container_port=9999, # Not used -# container_memory=2048, -# ) -# data_stack = ServiceStack( -# scope=cdk_app, -# construct_id=f"{stack_name_prefix}-data", -# vpc=network_stack.vpc, -# cluster=ecs_stack.cluster, -# props=data_props, -# container_env_vars={ -# "DB_USER": "root", -# "DB_PASS": "changeme", -# "DB_NAME": "agora", -# "DB_PORT": "27017", -# "DB_HOST": "agora-mongo", -# "DATA_FILE": "syn13363290", -# "DATA_VERSION": "68", -# "TEAM_IMAGES_ID": "syn12861877", -# "SYNAPSE_AUTH_TOKEN": "agora-service-user-pat-here", -# }, -# ) -# data_stack.add_dependency(mongo_stack) - api_props = ServiceProps( container_name="agora-api", container_location=f"ghcr.io/sage-bionetworks/agora-api:{agora_version}", @@ -174,7 +107,6 @@ cluster=ecs_stack.cluster, props=api_props, ) -api_stack.add_dependency(mongo_stack) app_props = ServiceProps( container_name="agora-app", @@ -222,7 +154,6 @@ health_check_path="/health", ) apex_stack.add_dependency(app_stack) -apex_stack.add_dependency(api_docs_stack) apex_stack.add_dependency(api_stack) cdk_app.synth() From fb5b2febbd52d61569f04236010101347e54d78a Mon Sep 17 00:00:00 2001 From: Hallie Swan <26949006+hallieswan@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:47:32 -0800 Subject: [PATCH 4/9] add missing environment variables --- app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app.py b/app.py index bbeb122..63cd438 100644 --- a/app.py +++ b/app.py @@ -118,6 +118,8 @@ "APP_VERSION": f"{agora_version}", "CSR_API_URL": f"http://{fully_qualified_domain_name}/api/v1", "SSR_API_URL": "http://agora-api:3333/v1", + "ROLLBAR_TOKEN"="e788198867474855a996485580b08d03" + "TAG_NAME"=f"agora/v${agora_version}" }, ) app_stack = ServiceStack( From 6b898bbc9b075c248898c3f83e344491c0b3c723 Mon Sep 17 00:00:00 2001 From: Hallie Swan <26949006+hallieswan@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:54:04 -0800 Subject: [PATCH 5/9] fix lint errors --- app.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app.py b/app.py index 63cd438..a5de542 100644 --- a/app.py +++ b/app.py @@ -5,7 +5,7 @@ from src.ecs_stack import EcsStack from src.load_balancer_stack import LoadBalancerStack from src.network_stack import NetworkStack -from src.service_props import ServiceProps, ContainerVolume, ServiceSecret +from src.service_props import ServiceProps, ServiceSecret from src.service_stack import LoadBalancedServiceStack, ServiceStack # get the environment and set environment specific variables @@ -81,9 +81,9 @@ container_port=3333, container_memory=1024, container_env_vars={ - "NODE_ENV": "development" + "NODE_ENV": "development", "MONGODB_PORT": "27017", - "MONGODB_NAME": "agora" + "MONGODB_NAME": "agora", }, container_secrets=[ ServiceSecret( @@ -98,7 +98,7 @@ secret_name=f"{stack_name_prefix}/MongodbHost", environment_key="MONGODB_HOST", ), - ] + ], ) api_stack = ServiceStack( scope=cdk_app, @@ -118,8 +118,8 @@ "APP_VERSION": f"{agora_version}", "CSR_API_URL": f"http://{fully_qualified_domain_name}/api/v1", "SSR_API_URL": "http://agora-api:3333/v1", - "ROLLBAR_TOKEN"="e788198867474855a996485580b08d03" - "TAG_NAME"=f"agora/v${agora_version}" + "ROLLBAR_TOKEN": "e788198867474855a996485580b08d03", + "TAG_NAME": f"agora/v${agora_version}", }, ) app_stack = ServiceStack( From 1f1bb235c379c1dfc30cd1c65d9b0d99d486f98d Mon Sep 17 00:00:00 2001 From: Hallie Swan Date: Wed, 22 Jan 2025 22:42:08 +0000 Subject: [PATCH 6/9] IT-4241: create documentDB instance and allow connection from ECS API container --- app.py | 34 ++++++++---- requirements.txt | 2 +- src/docdb_props.py | 14 +++++ src/docdb_stack.py | 94 ++++++++++++++++++++++++++++++++++ src/service_props.py | 9 +++- src/service_stack.py | 4 +- tests/unit/test_docdb_stack.py | 62 ++++++++++++++++++++++ tools/setup.sh | 2 +- 8 files changed, 206 insertions(+), 15 deletions(-) create mode 100644 src/docdb_props.py create mode 100644 src/docdb_stack.py create mode 100644 tests/unit/test_docdb_stack.py diff --git a/app.py b/app.py index a5de542..3825233 100644 --- a/app.py +++ b/app.py @@ -1,12 +1,15 @@ from os import environ import aws_cdk as cdk +from aws_cdk import aws_ec2 as ec2 from src.ecs_stack import EcsStack from src.load_balancer_stack import LoadBalancerStack from src.network_stack import NetworkStack from src.service_props import ServiceProps, ServiceSecret from src.service_stack import LoadBalancedServiceStack, ServiceStack +from src.docdb_props import DocdbProps +from src.docdb_stack import DocdbStack # get the environment and set environment specific variables VALID_ENVIRONMENTS = ["dev", "stage", "prod"] @@ -43,6 +46,7 @@ fully_qualified_domain_name = environment_variables["FQDN"] environment_tags = environment_variables["TAGS"] agora_version = "4.0.0-rc1" +docdb_master_username = "master" # Define stacks cdk_app = cdk.App() @@ -58,6 +62,19 @@ vpc_cidr=environment_variables["VPC_CIDR"], ) +docdb_props = DocdbProps( + instance_type=ec2.InstanceType.of( + ec2.InstanceClass.MEMORY5, ec2.InstanceSize.LARGE + ), + master_username=docdb_master_username, +) +docdb_stack = DocdbStack( + scope=cdk_app, + construct_id=f"{stack_name_prefix}-docdb", + vpc=network_stack.vpc, + props=docdb_props, +) + ecs_stack = EcsStack( scope=cdk_app, construct_id=f"{stack_name_prefix}-ecs", @@ -84,21 +101,16 @@ "NODE_ENV": "development", "MONGODB_PORT": "27017", "MONGODB_NAME": "agora", + "MONDODB_USER": docdb_master_username, + "MONGODB_HOST": docdb_stack.cluster.cluster_endpoint.hostname, }, container_secrets=[ ServiceSecret( - secret_name=f"{stack_name_prefix}/MongodbUsername", - environment_key="MONGODB_USER", - ), - ServiceSecret( - secret_name=f"{stack_name_prefix}/MongodbPassword", + secret_name=docdb_stack.master_password_secret.secret_name, environment_key="MONGODB_PASS", - ), - ServiceSecret( - secret_name=f"{stack_name_prefix}/MongodbHost", - environment_key="MONGODB_HOST", - ), + ) ], + container_security_groups=[docdb_stack.access_docdb_security_group], ) api_stack = ServiceStack( scope=cdk_app, @@ -107,6 +119,7 @@ cluster=ecs_stack.cluster, props=api_props, ) +api_stack.add_dependency(docdb_stack) app_props = ServiceProps( container_name="agora-app", @@ -118,7 +131,6 @@ "APP_VERSION": f"{agora_version}", "CSR_API_URL": f"http://{fully_qualified_domain_name}/api/v1", "SSR_API_URL": "http://agora-api:3333/v1", - "ROLLBAR_TOKEN": "e788198867474855a996485580b08d03", "TAG_NAME": f"agora/v${agora_version}", }, ) diff --git a/requirements.txt b/requirements.txt index 0246ca6..f2bf95d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ -aws-cdk-lib~=2.139 +aws-cdk-lib~=2.176 constructs~=10.0 boto3~=1.34 diff --git a/src/docdb_props.py b/src/docdb_props.py new file mode 100644 index 0000000..0bccce5 --- /dev/null +++ b/src/docdb_props.py @@ -0,0 +1,14 @@ +from aws_cdk import aws_ec2 as ec2 + + +class DocdbProps: + """ + DocumentDB properties + + instance_type: What type of instance to start for the replicas + master_username: The database admin account username + """ + + def __init__(self, instance_type: ec2.InstanceType, master_username: str) -> None: + self.instance_type = instance_type + self.master_username = master_username diff --git a/src/docdb_stack.py b/src/docdb_stack.py new file mode 100644 index 0000000..b2774b4 --- /dev/null +++ b/src/docdb_stack.py @@ -0,0 +1,94 @@ +import aws_cdk as cdk +from aws_cdk import ( + aws_docdb as docdb, + aws_ec2 as ec2, + aws_secretsmanager as sm, +) +from src.docdb_props import DocdbProps + +from constructs import Construct + + +class DocdbStack(cdk.Stack): + """ + DocumentDB cluster + """ + + def __init__( + self, + scope: Construct, + construct_id: str, + vpc: ec2.Vpc, + props: DocdbProps, + **kwargs, + ) -> None: + super().__init__(scope, construct_id, **kwargs) + + self.master_password_secret = sm.Secret( + self, + f"{construct_id}-master-password", + generate_secret_string=sm.SecretStringGenerator( + password_length=32, exclude_punctuation=True + ), + ) + + self.access_docdb_security_group = ec2.SecurityGroup( + self, + f"{construct_id}-access-docdb-sg", + vpc=vpc, + description="Instances with access to document DB servers", + ) + self.docdb_security_group = ec2.SecurityGroup( + self, + f"{construct_id}-docdb-sg", + vpc=vpc, + description="Document DB server management and access ports", + ) + self.docdb_security_group.add_ingress_rule( + peer=self.access_docdb_security_group, + connection=ec2.Port.tcp_range(27017, 27030), + ) + self.docdb_security_group.add_ingress_rule( + peer=self.access_docdb_security_group, connection=ec2.Port.tcp(28017) + ) + + cluster_parameter_group = docdb.ClusterParameterGroup( + self, + "ClusterParameterGroup", + family="docdb5.0", + parameters={ + "audit_logs": "disabled", + "audit_logs": "disabled", + "profiler": "enabled", + "profiler_sampling_rate": "1.0", + "profiler_threshold_ms": "50", + "change_stream_log_retention_duration": "10800", + "tls": "disabled", + "ttl_monitor": "disabled", + }, + db_cluster_parameter_group_name=f"{construct_id}-cluster-parameter-group", + ) + + # https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_docdb/DatabaseCluster.html + self.cluster = docdb.DatabaseCluster( + self, + "Database", + master_user=docdb.Login( + username=props.master_username, + password=self.master_password_secret.secret_value, + ), + instance_type=props.instance_type, + vpc=vpc, + vpc_subnets=ec2.SubnetSelection( + subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS + ), + parameter_group=cluster_parameter_group, + removal_policy=cdk.RemovalPolicy.DESTROY, + storage_encrypted=True, + preferred_maintenance_window="sat:06:54-sat:07:24", + port=27017, + export_profiler_logs_to_cloud_watch=True, + security_group=self.docdb_security_group, + ) + + self.cluster.add_security_groups(self.access_docdb_security_group) diff --git a/src/service_props.py b/src/service_props.py index 496fe8d..fbbd464 100644 --- a/src/service_props.py +++ b/src/service_props.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import List, Optional, Sequence -from aws_cdk import aws_ecs as ecs +from aws_cdk import aws_ecs as ecs, aws_ec2 as ec2 CONTAINER_LOCATION_PATH_ID = "path://" @@ -62,6 +62,7 @@ class ServiceProps: auto_scale_max_capacity: the fargate auto scaling maximum capacity container_command: Optional commands to run during the container startup container_healthcheck: Optional health check configuration for the container + container_security_groups: Optional List of security groups for the container """ def __init__( @@ -77,6 +78,7 @@ def __init__( auto_scale_max_capacity: int = 1, container_command: Optional[Sequence[str]] = None, container_healthcheck: Optional[ecs.HealthCheck] = None, + container_security_groups: Optional[List[ec2.SecurityGroup]] = None, ) -> None: self.container_name = container_name self.container_port = container_port @@ -106,3 +108,8 @@ def __init__( self.auto_scale_max_capacity = auto_scale_max_capacity self.container_command = container_command self.container_healthcheck = container_healthcheck + + if container_security_groups is None: + self.container_security_groups = [] + else: + self.container_security_groups = container_security_groups diff --git a/src/service_stack.py b/src/service_stack.py index f029392..addda38 100644 --- a/src/service_stack.py +++ b/src/service_stack.py @@ -132,6 +132,8 @@ def _get_secret(scope: Construct, id: str, name: str) -> sm.Secret: peer=ec2.Peer.ipv4("0.0.0.0/0"), connection=ec2.Port.tcp(props.container_port), ) + self.security_groups = props.container_security_groups.copy() + self.security_groups.append(self.security_group) # attach ECS task to ECS cluster self.service = ecs.FargateService( @@ -141,7 +143,7 @@ def _get_secret(scope: Construct, id: str, name: str) -> sm.Secret: task_definition=self.task_definition, enable_execute_command=True, circuit_breaker=ecs.DeploymentCircuitBreaker(enable=True, rollback=True), - security_groups=([self.security_group]), + security_groups=self.security_groups, service_connect_configuration=ecs.ServiceConnectProps( log_driver=ecs.LogDrivers.aws_logs(stream_prefix=f"{construct_id}"), services=[ diff --git a/tests/unit/test_docdb_stack.py b/tests/unit/test_docdb_stack.py new file mode 100644 index 0000000..95fd593 --- /dev/null +++ b/tests/unit/test_docdb_stack.py @@ -0,0 +1,62 @@ +import aws_cdk as cdk +from aws_cdk import aws_ec2 as ec2, assertions as assertions + +from src.network_stack import NetworkStack +from src.docdb_stack import DocdbStack +from src.docdb_props import DocdbProps + + +def test_docdb_created(): + cdk_app = cdk.App() + master_username = "myuser" + vpc_cidr = "10.254.192.0/24" + network_stack = NetworkStack(cdk_app, "NetworkStack", vpc_cidr=vpc_cidr) + + docdb_props = DocdbProps( + instance_type=ec2.InstanceType.of( + ec2.InstanceClass.MEMORY5, ec2.InstanceSize.LARGE + ), + master_username=master_username, + ) + docdb_stack = DocdbStack( + scope=cdk_app, + construct_id="docdb", + vpc=network_stack.vpc, + props=docdb_props, + ) + + template = assertions.Template.from_stack(docdb_stack) + template.has_resource_properties( + "AWS::DocDB::DBClusterParameterGroup", + { + "Parameters": { + "audit_logs": "disabled", + "profiler": "enabled", + "profiler_sampling_rate": "1.0", + "profiler_threshold_ms": "50", + "change_stream_log_retention_duration": "10800", + "tls": "disabled", + "ttl_monitor": "disabled", + } + }, + ) + template.has_resource_properties( + "AWS::DocDB::DBCluster", + { + "MasterUsername": master_username, + "MasterUserPassword": assertions.Match.any_value(), + "DBSubnetGroupName": assertions.Match.any_value(), + "DBClusterParameterGroupName": assertions.Match.any_value(), + "StorageEncrypted": True, + "PreferredMaintenanceWindow": "sat:06:54-sat:07:24", + "Port": 27017, + "EnableCloudwatchLogsExports": ["profiler"], + "VpcSecurityGroupIds": [ + assertions.Match.any_value(), + assertions.Match.any_value(), + ], + }, + ) + template.resource_properties_count_is( + "AWS::EC2::SecurityGroup", assertions.Match.any_value(), 2 + ) diff --git a/tools/setup.sh b/tools/setup.sh index f92cf9b..0671d6f 100755 --- a/tools/setup.sh +++ b/tools/setup.sh @@ -4,7 +4,7 @@ set -euxo pipefail # Install Node.js dependencies -npm install -g aws-cdk@2.151.0 +npm install -g aws-cdk@2.176.0 # Install Python dependencies python -m venv .venv From 4e98df5cfb85ef9c152490eb95b357360529e881 Mon Sep 17 00:00:00 2001 From: Hallie Swan Date: Fri, 24 Jan 2025 00:08:27 +0000 Subject: [PATCH 7/9] IT-4241: improvements from review --- app.py | 6 +++--- src/docdb_stack.py | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app.py b/app.py index 3825233..c28c491 100644 --- a/app.py +++ b/app.py @@ -127,10 +127,10 @@ container_port=4200, container_memory=200, container_env_vars={ - "API_DOCS_URL": f"http://{fully_qualified_domain_name}/api-docs", + "API_DOCS_URL": f"https://{fully_qualified_domain_name}/api-docs", "APP_VERSION": f"{agora_version}", - "CSR_API_URL": f"http://{fully_qualified_domain_name}/api/v1", - "SSR_API_URL": "http://agora-api:3333/v1", + "CSR_API_URL": f"https://{fully_qualified_domain_name}/api/v1", + "SSR_API_URL": "https://agora-api:3333/v1", "TAG_NAME": f"agora/v${agora_version}", }, ) diff --git a/src/docdb_stack.py b/src/docdb_stack.py index b2774b4..6546b7e 100644 --- a/src/docdb_stack.py +++ b/src/docdb_stack.py @@ -8,6 +8,8 @@ from constructs import Construct +MONGODB_PORT = 27017 + class DocdbStack(cdk.Stack): """ @@ -26,7 +28,7 @@ def __init__( self.master_password_secret = sm.Secret( self, - f"{construct_id}-master-password", + "DocDbMasterPassword", generate_secret_string=sm.SecretStringGenerator( password_length=32, exclude_punctuation=True ), @@ -34,19 +36,19 @@ def __init__( self.access_docdb_security_group = ec2.SecurityGroup( self, - f"{construct_id}-access-docdb-sg", + "DocDbAccessSecurityGroup", vpc=vpc, description="Instances with access to document DB servers", ) self.docdb_security_group = ec2.SecurityGroup( self, - f"{construct_id}-docdb-sg", + "DocDbSecurityGroup", vpc=vpc, description="Document DB server management and access ports", ) self.docdb_security_group.add_ingress_rule( peer=self.access_docdb_security_group, - connection=ec2.Port.tcp_range(27017, 27030), + connection=ec2.Port.tcp_range(MONGODB_PORT, 27030), ) self.docdb_security_group.add_ingress_rule( peer=self.access_docdb_security_group, connection=ec2.Port.tcp(28017) @@ -54,10 +56,9 @@ def __init__( cluster_parameter_group = docdb.ClusterParameterGroup( self, - "ClusterParameterGroup", + "DocDbClusterParameterGroup", family="docdb5.0", parameters={ - "audit_logs": "disabled", "audit_logs": "disabled", "profiler": "enabled", "profiler_sampling_rate": "1.0", @@ -66,13 +67,12 @@ def __init__( "tls": "disabled", "ttl_monitor": "disabled", }, - db_cluster_parameter_group_name=f"{construct_id}-cluster-parameter-group", ) # https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_docdb/DatabaseCluster.html self.cluster = docdb.DatabaseCluster( self, - "Database", + "DocDbCluster", master_user=docdb.Login( username=props.master_username, password=self.master_password_secret.secret_value, @@ -86,7 +86,7 @@ def __init__( removal_policy=cdk.RemovalPolicy.DESTROY, storage_encrypted=True, preferred_maintenance_window="sat:06:54-sat:07:24", - port=27017, + port=MONGODB_PORT, export_profiler_logs_to_cloud_watch=True, security_group=self.docdb_security_group, ) From 298aea953b6db7d8a2e21f79f94539c13fa1ee6c Mon Sep 17 00:00:00 2001 From: Hallie Swan Date: Fri, 24 Jan 2025 19:45:41 +0000 Subject: [PATCH 8/9] IT-4241: use connections rather than directly manipulating security groups --- app.py | 9 +++++++-- src/docdb_props.py | 6 +++++- src/docdb_stack.py | 27 +-------------------------- src/service_props.py | 9 +-------- src/service_stack.py | 10 +--------- tests/unit/test_docdb_stack.py | 7 ++++--- 6 files changed, 19 insertions(+), 49 deletions(-) diff --git a/app.py b/app.py index c28c491..3f510f4 100644 --- a/app.py +++ b/app.py @@ -47,6 +47,7 @@ environment_tags = environment_variables["TAGS"] agora_version = "4.0.0-rc1" docdb_master_username = "master" +mongodb_port = 27017 # Define stacks cdk_app = cdk.App() @@ -67,6 +68,7 @@ ec2.InstanceClass.MEMORY5, ec2.InstanceSize.LARGE ), master_username=docdb_master_username, + port=mongodb_port, ) docdb_stack = DocdbStack( scope=cdk_app, @@ -99,7 +101,7 @@ container_memory=1024, container_env_vars={ "NODE_ENV": "development", - "MONGODB_PORT": "27017", + "MONGODB_PORT": f"{mongodb_port}", "MONGODB_NAME": "agora", "MONDODB_USER": docdb_master_username, "MONGODB_HOST": docdb_stack.cluster.cluster_endpoint.hostname, @@ -110,7 +112,6 @@ environment_key="MONGODB_PASS", ) ], - container_security_groups=[docdb_stack.access_docdb_security_group], ) api_stack = ServiceStack( scope=cdk_app, @@ -120,6 +121,10 @@ props=api_props, ) api_stack.add_dependency(docdb_stack) +api_stack.service.connections.allow_to_default_port( + docdb_stack.cluster, + "Allow API container to connect to DocumentDB cluster", +) app_props = ServiceProps( container_name="agora-app", diff --git a/src/docdb_props.py b/src/docdb_props.py index 0bccce5..3dd8a2b 100644 --- a/src/docdb_props.py +++ b/src/docdb_props.py @@ -7,8 +7,12 @@ class DocdbProps: instance_type: What type of instance to start for the replicas master_username: The database admin account username + port: The MongoDB port """ - def __init__(self, instance_type: ec2.InstanceType, master_username: str) -> None: + def __init__( + self, instance_type: ec2.InstanceType, master_username: str, port: int + ) -> None: self.instance_type = instance_type self.master_username = master_username + self.port = port diff --git a/src/docdb_stack.py b/src/docdb_stack.py index 6546b7e..be7a5b3 100644 --- a/src/docdb_stack.py +++ b/src/docdb_stack.py @@ -8,8 +8,6 @@ from constructs import Construct -MONGODB_PORT = 27017 - class DocdbStack(cdk.Stack): """ @@ -34,26 +32,6 @@ def __init__( ), ) - self.access_docdb_security_group = ec2.SecurityGroup( - self, - "DocDbAccessSecurityGroup", - vpc=vpc, - description="Instances with access to document DB servers", - ) - self.docdb_security_group = ec2.SecurityGroup( - self, - "DocDbSecurityGroup", - vpc=vpc, - description="Document DB server management and access ports", - ) - self.docdb_security_group.add_ingress_rule( - peer=self.access_docdb_security_group, - connection=ec2.Port.tcp_range(MONGODB_PORT, 27030), - ) - self.docdb_security_group.add_ingress_rule( - peer=self.access_docdb_security_group, connection=ec2.Port.tcp(28017) - ) - cluster_parameter_group = docdb.ClusterParameterGroup( self, "DocDbClusterParameterGroup", @@ -86,9 +64,6 @@ def __init__( removal_policy=cdk.RemovalPolicy.DESTROY, storage_encrypted=True, preferred_maintenance_window="sat:06:54-sat:07:24", - port=MONGODB_PORT, + port=props.port, export_profiler_logs_to_cloud_watch=True, - security_group=self.docdb_security_group, ) - - self.cluster.add_security_groups(self.access_docdb_security_group) diff --git a/src/service_props.py b/src/service_props.py index fbbd464..496fe8d 100644 --- a/src/service_props.py +++ b/src/service_props.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import List, Optional, Sequence -from aws_cdk import aws_ecs as ecs, aws_ec2 as ec2 +from aws_cdk import aws_ecs as ecs CONTAINER_LOCATION_PATH_ID = "path://" @@ -62,7 +62,6 @@ class ServiceProps: auto_scale_max_capacity: the fargate auto scaling maximum capacity container_command: Optional commands to run during the container startup container_healthcheck: Optional health check configuration for the container - container_security_groups: Optional List of security groups for the container """ def __init__( @@ -78,7 +77,6 @@ def __init__( auto_scale_max_capacity: int = 1, container_command: Optional[Sequence[str]] = None, container_healthcheck: Optional[ecs.HealthCheck] = None, - container_security_groups: Optional[List[ec2.SecurityGroup]] = None, ) -> None: self.container_name = container_name self.container_port = container_port @@ -108,8 +106,3 @@ def __init__( self.auto_scale_max_capacity = auto_scale_max_capacity self.container_command = container_command self.container_healthcheck = container_healthcheck - - if container_security_groups is None: - self.container_security_groups = [] - else: - self.container_security_groups = container_security_groups diff --git a/src/service_stack.py b/src/service_stack.py index addda38..fd35eda 100644 --- a/src/service_stack.py +++ b/src/service_stack.py @@ -127,14 +127,6 @@ def _get_secret(scope: Construct, id: str, name: str) -> sm.Secret: health_check=props.container_healthcheck, ) - self.security_group = ec2.SecurityGroup(self, "SecurityGroup", vpc=vpc) - self.security_group.add_ingress_rule( - peer=ec2.Peer.ipv4("0.0.0.0/0"), - connection=ec2.Port.tcp(props.container_port), - ) - self.security_groups = props.container_security_groups.copy() - self.security_groups.append(self.security_group) - # attach ECS task to ECS cluster self.service = ecs.FargateService( self, @@ -143,7 +135,6 @@ def _get_secret(scope: Construct, id: str, name: str) -> sm.Secret: task_definition=self.task_definition, enable_execute_command=True, circuit_breaker=ecs.DeploymentCircuitBreaker(enable=True, rollback=True), - security_groups=self.security_groups, service_connect_configuration=ecs.ServiceConnectProps( log_driver=ecs.LogDrivers.aws_logs(stream_prefix=f"{construct_id}"), services=[ @@ -166,6 +157,7 @@ def _get_secret(scope: Construct, id: str, name: str) -> sm.Secret: ), ], ) + self.service.connections.allow_from_any_ipv4(ec2.Port.tcp(props.container_port)) # Setup AutoScaling policy scaling = self.service.auto_scale_task_count( diff --git a/tests/unit/test_docdb_stack.py b/tests/unit/test_docdb_stack.py index 95fd593..8754c50 100644 --- a/tests/unit/test_docdb_stack.py +++ b/tests/unit/test_docdb_stack.py @@ -9,6 +9,7 @@ def test_docdb_created(): cdk_app = cdk.App() master_username = "myuser" + port = 27017 vpc_cidr = "10.254.192.0/24" network_stack = NetworkStack(cdk_app, "NetworkStack", vpc_cidr=vpc_cidr) @@ -17,6 +18,7 @@ def test_docdb_created(): ec2.InstanceClass.MEMORY5, ec2.InstanceSize.LARGE ), master_username=master_username, + port=port, ) docdb_stack = DocdbStack( scope=cdk_app, @@ -49,14 +51,13 @@ def test_docdb_created(): "DBClusterParameterGroupName": assertions.Match.any_value(), "StorageEncrypted": True, "PreferredMaintenanceWindow": "sat:06:54-sat:07:24", - "Port": 27017, + "Port": port, "EnableCloudwatchLogsExports": ["profiler"], "VpcSecurityGroupIds": [ assertions.Match.any_value(), - assertions.Match.any_value(), ], }, ) template.resource_properties_count_is( - "AWS::EC2::SecurityGroup", assertions.Match.any_value(), 2 + "AWS::EC2::SecurityGroup", assertions.Match.any_value(), 1 ) From 526d54c38cc3bb61cdfff8756f93a0b83f04085d Mon Sep 17 00:00:00 2001 From: Hallie Swan Date: Fri, 24 Jan 2025 19:46:12 +0000 Subject: [PATCH 9/9] IT-4241: change back to http per review --- app.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app.py b/app.py index 3f510f4..e1c3602 100644 --- a/app.py +++ b/app.py @@ -132,10 +132,10 @@ container_port=4200, container_memory=200, container_env_vars={ - "API_DOCS_URL": f"https://{fully_qualified_domain_name}/api-docs", + "API_DOCS_URL": f"http://{fully_qualified_domain_name}/api-docs", "APP_VERSION": f"{agora_version}", - "CSR_API_URL": f"https://{fully_qualified_domain_name}/api/v1", - "SSR_API_URL": "https://agora-api:3333/v1", + "CSR_API_URL": f"http://{fully_qualified_domain_name}/api/v1", + "SSR_API_URL": "http://agora-api:3333/v1", "TAG_NAME": f"agora/v${agora_version}", }, )