diff --git a/keyserver/src/user/checks.js b/keyserver/src/user/checks.js --- a/keyserver/src/user/checks.js +++ b/keyserver/src/user/checks.js @@ -1,6 +1,9 @@ // @flow import { getCommConfig } from 'lib/utils/comm-config.js'; + +// changes here should be reflected for keyserver_user_credentials in +// services/terraform/self-host/variables.tf export type UserCredentials = { +username: string, +password: string, diff --git a/services/terraform/self-host/aws_db.tf b/services/terraform/self-host/aws_db.tf --- a/services/terraform/self-host/aws_db.tf +++ b/services/terraform/self-host/aws_db.tf @@ -5,6 +5,13 @@ vpc_id = local.vpc_id # Inbound rules + ingress { + from_port = 3307 + to_port = 3307 + protocol = "tcp" + security_groups = [aws_security_group.keyserver_service.id] + } + ingress { from_port = 3307 to_port = 3307 diff --git a/services/terraform/self-host/aws_ecs.tf b/services/terraform/self-host/aws_ecs.tf new file mode 100644 --- /dev/null +++ b/services/terraform/self-host/aws_ecs.tf @@ -0,0 +1,23 @@ +resource "aws_ecs_cluster" "keyserver_cluster" { + name = "keyserver-cluster" + + configuration { + execute_command_configuration { + logging = "DEFAULT" + } + } +} + +# Namespace for services to be able to communicate with each other +# by their hostnames. Similar to docker compose network. +resource "aws_service_discovery_http_namespace" "keyserver_cluster" { + name = "keyserver-cluster-http-namespace" + tags = { + "AmazonECSManaged" = "true" + } +} + +resource "aws_ecs_cluster_capacity_providers" "keyserver_cluster" { + cluster_name = aws_ecs_cluster.keyserver_cluster.name + capacity_providers = ["FARGATE"] +} diff --git a/services/terraform/self-host/aws_iam.tf b/services/terraform/self-host/aws_iam.tf new file mode 100644 --- /dev/null +++ b/services/terraform/self-host/aws_iam.tf @@ -0,0 +1,87 @@ +resource "aws_iam_role" "ecs_task_role" { + name = "ecs-iam_role" + description = "Allows to SSH into ECS containers" + assume_role_policy = data.aws_iam_policy_document.assume_role_ecs_ec2.json + + managed_policy_arns = [ + aws_iam_policy.allow_ecs_exec.arn, + ] +} + +data "aws_iam_policy_document" "assume_role_ecs_ec2" { + statement { + effect = "Allow" + actions = [ + "sts:AssumeRole", + ] + principals { + type = "Service" + identifiers = [ + "ec2.amazonaws.com", + "ecs-tasks.amazonaws.com" + ] + } + } +} + +resource "aws_iam_policy" "allow_ecs_exec" { + name = "allow-ecs-exec" + description = "Adds SSM permissions to enable ECS Exec" + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "ssmmessages:CreateControlChannel", + "ssmmessages:CreateDataChannel", + "ssmmessages:OpenControlChannel", + "ssmmessages:OpenDataChannel" + ] + Resource = "*" + } + ] + }) +} + +resource "aws_iam_role" "fargate_execution_role" { + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + Action = "sts:AssumeRole" + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "fargate_execution_role" { + role = aws_iam_role.fargate_execution_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +resource "aws_iam_role" "ecs_task_execution" { + name = "ecsTaskExecutionRole" + assume_role_policy = jsonencode({ + Version = "2008-10-17" + Statement = [ + { + Sid = "" + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + } + ] + }) + + managed_policy_arns = [ + "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy", + "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess", + ] +} diff --git a/services/terraform/self-host/keyserver_primary.tf b/services/terraform/self-host/keyserver_primary.tf new file mode 100644 --- /dev/null +++ b/services/terraform/self-host/keyserver_primary.tf @@ -0,0 +1,155 @@ +locals { + keyserver_service_image_tag = "0.1" + keyserver_service_server_image = "commapp/keyserver:${local.keyserver_service_image_tag}" + keyserver_service_container_name = "keyserver-primary" +} + +resource "aws_cloudwatch_log_group" "ecs_log_group" { + name = "/ecs/keyserver-primary-task-def" + retention_in_days = 7 +} + +output "mariadb_address" { + value = aws_db_instance.mariadb.address +} + +resource "aws_ecs_task_definition" "keyserver_service" { + network_mode = "awsvpc" + family = "keyserver-primary-task-def" + requires_compatibilities = ["FARGATE"] + task_role_arn = aws_iam_role.ecs_task_role.arn + execution_role_arn = aws_iam_role.ecs_task_execution.arn + cpu = "1024" + memory = "3072" + + ephemeral_storage { + size_in_gib = 40 + } + + container_definitions = jsonencode([ + { + name = local.keyserver_service_container_name + image = local.keyserver_service_server_image + essential = true + portMappings = [ + { + name = "keyserver-port" + containerPort = 3000 + protocol = "tcp" + }, + { + name = "http-port" + containerPort = 80 + protocol = "tcp" + appProtocol = "http" + }, + ] + environment = [ + { + name = "COMM_DATABASE_HOST" + value = "${aws_db_instance.mariadb.address}" + }, + { + name = "COMM_DATABASE_DATABASE" + value = "comm" + }, + { + name = "COMM_DATABASE_PORT" + value = "3307" + }, + { + name = "COMM_DATABASE_USER" + value = "${var.mariadb_username}" + }, + { + name = "COMM_DATABASE_PASSWORD" + value = "${var.mariadb_password}" + }, + { + name = "COMM_JSONCONFIG_secrets_user_credentials" + value = jsonencode(var.keyserver_user_credentials) + }, + { + name = "COMM_JSONCONFIG_facts_webapp_cors" + value = jsonencode({ + "domain" : "https://web.comm.app" + }) + }, + { + name = "COMM_JSONCONFIG_secrets_identity_service_config", + value = jsonencode({ + "identitySocketAddr" : "${var.identity_socket_address}" + }) + }, + ] + logConfiguration = { + "logDriver" = "awslogs" + "options" = { + "awslogs-create-group" = "true" + "awslogs-group" = aws_cloudwatch_log_group.ecs_log_group.name + "awslogs-stream-prefix" = "ecs" + "awslogs-region" = "${var.region}" + } + } + linuxParameters = { + initProcessEnabled = true + } + } + ]) + + runtime_platform { + cpu_architecture = "ARM64" + operating_system_family = "LINUX" + } + + skip_destroy = false +} + +resource "aws_ecs_service" "keyserver_primary_service" { + name = "keyserver-primary-service" + cluster = aws_ecs_cluster.keyserver_cluster.id + task_definition = aws_ecs_task_definition.keyserver_service.arn + launch_type = "FARGATE" + enable_execute_command = true + enable_ecs_managed_tags = true + force_new_deployment = true + desired_count = 1 + + network_configuration { + subnets = local.vpc_subnets + security_groups = [aws_security_group.keyserver_service.id] + assign_public_ip = true + } + + deployment_circuit_breaker { + enable = true + rollback = true + } +} + +resource "aws_security_group" "keyserver_service" { + name = "keyserver-service-ecs-sg" + vpc_id = local.vpc_id + + # Allow all inbound traffic. This is temporary until load balancer is configured + ingress { + from_port = 0 + to_port = 65535 + protocol = "tcp" + cidr_blocks = ["0.0.0.0/0"] + } + + # Allow all outbound traffic + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + + lifecycle { + create_before_destroy = true + } +} + + diff --git a/services/terraform/self-host/variables.tf b/services/terraform/self-host/variables.tf --- a/services/terraform/self-host/variables.tf +++ b/services/terraform/self-host/variables.tf @@ -1,3 +1,13 @@ +variable "keyserver_user_credentials" { + description = "Credentials for user authentication" + type = object({ + username = string + password = string + usingIdentityCredentials = optional(bool) + force = optional(bool) + }) +} + variable "mariadb_username" { description = "MariaDB username" type = string @@ -23,8 +33,6 @@ variable "user_created_vpc" { description = "Use non-default vpc and subnets" - type = bool - default = false } variable "availability_zone_1" { @@ -38,3 +46,9 @@ type = string default = "us-west-1c" } + +variable "identity_socket_address" { + description = "The socket address to access the identity service" + type = string + default = "https://identity.commtechnologies.org:50054" +}