diff --git a/streamlit-server/iam.tf b/streamlit-server/iam.tf new file mode 100644 index 0000000..0d04cad --- /dev/null +++ b/streamlit-server/iam.tf @@ -0,0 +1,132 @@ +resource "aws_iam_role" "ec2_role" { + name = local.ec2_role_name + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + } + ] + }) +} + +# Attached all policies created here to the ec2 role + + + +# Combine all policy documents into a single document +data "aws_iam_policy_document" "combined_policy_document" { + statement { + sid = "S3Permissions" + effect = "Allow" + actions = [ + "s3:ListBucket", + "s3:ListAllMyBuckets", + "s3:GetObject", + "s3:PutObject", + "s3:GetObjectTagging", + "s3:PutObjectTagging" + ] + resources = ["*"] + } + + statement { + sid = "SecretsManagerOperations" + effect = "Allow" + actions = [ + "secretsmanager:GetResourcePolicy", + "secretsmanager:GetSecretValue", + "secretsmanager:DescribeSecret", + "secretsmanager:PutSecretValue", + "secretsmanager:ListSecretVersionIds", + "secretsmanager:GetRandomPassword", + "secretsmanager:ListSecrets", + "secretsmanager:BatchGetSecretValue" + ] + # Need to restrict this to ARN of the secrets later + resources = ["*"] + } + + statement { + sid = "SSMUpdateInstanceInformation" + effect = "Allow" + actions = ["ssm:UpdateInstanceInformation"] + # Refernce the instance by its instance id + resources = ["${aws_instance.streamlit_server.arn}"] + } + statement { + sid = "BedrockPermissions" + effect = "Allow" + actions = [ + "bedrock:InvokeAgent", + "bedrock:InvokeModel", + "bedrock:InvokeModelWithResponseStream", + "bedrock:ListFoundationModels" + ] + resources = ["*"] + } + + statement { + sid = "APIGatewayInvokeFullAccess" + effect = "Allow" + actions = ["execute-api:Invoke", + "execute-api:ManageConnections"] + resources = ["arn:aws:execute-api:*:*:*"] + } + statement { + sid = "AmazonSSMManagedInstanceCore" + effect = "Allow" + actions = [ + "ssm:DescribeAssociation", + "ssm:GetDeployablePatchSnapshotForInstance", + "ssm:GetDocument", + "ssm:DescribeDocument", + "ssm:GetManifest", + "ssm:GetParameter", + "ssm:GetParameters", + "ssm:ListAssociations", + "ssm:ListInstanceAssociations", + "ssm:PutInventory", + "ssm:PutComplianceItems", + "ssm:PutConfigurePackageResult", + "ssm:UpdateAssociationStatus", + "ssm:UpdateInstanceAssociationStatus", + "ssm:UpdateInstanceInformation", + "ssmmessages:CreateControlChannel", + "ssmmessages:CreateDataChannel", + "ssmmessages:OpenControlChannel", + "ssmmessages:OpenDataChannel", + "ec2messages:AcknowledgeMessage", + "ec2messages:DeleteMessage", + "ec2messages:FailMessage", + "ec2messages:GetEndpoint", + "ec2messages:GetMessages", + "ec2messages:SendReply" + ] + resources = ["*"] + } + # statement for cli policy + statement { + effect = "Allow" + actions = ["airflow:CreateCliToken"] + resources = ["*"] + } +} + +# Attached the combined document to the ec2 role +resource "aws_iam_policy" "combined_policy" { + name = "${local.ec2_role_name}-combined-policy" + description = "Combined policy for Bedrock, Secrets Manager, SSM, and S3" + policy = data.aws_iam_policy_document.combined_policy_document.json +} + +resource "aws_iam_role_policy_attachment" "combined_policy_attachment" { + role = aws_iam_role.ec2_role.name + policy_arn = aws_iam_policy.combined_policy.arn +} diff --git a/streamlit-server/main.tf b/streamlit-server/main.tf new file mode 100644 index 0000000..e9e4dcf --- /dev/null +++ b/streamlit-server/main.tf @@ -0,0 +1,188 @@ +provider "aws" { + region = "us-east-2" + profile = "temp_cred" +} + +# data "aws_acm_certificate" "cert_global" { +# domain = "doczy.aarete.com" +# statuses = ["ISSUED"] +# } + +locals { + region_map = { + us-east-1 = "use1" + us-east-2 = "use2" + us-west-1 = "usw1" + us-west-2 = "usw2" + } + environment_map = { + prod = "p" + uat = "u" + qa = "q" + dev = "d" + } + + # region abbreviation + region_short_name = local.region_map[var.aws_region] + + # environment abbreviation + environment_short_name = local.environment_map[var.environment] + + # global prefix + global_prefix = "${var.project_name}-${local.region_short_name}-${local.environment_short_name}" + + # Resource prefix + iam_policy_prefix = "${local.global_prefix}-pol" + + # # Resource prefix + iam_role_prefix = "${local.global_prefix}-rol" + + # IAM role name + ec2_role_name = "${local.iam_role_prefix}-streamlit" + + ec2_instance_name = "${local.global_prefix}-ec2-infra-streamlit-server" + +} + + +# get the subnet id using data source +data "aws_subnets" "subnets" { + filter { + name = "vpc-id" + values = [var.vpc_id] + } +} + +# vpc security groups +data "aws_security_groups" "security_groups" { + filter { + name = "group-name" + values = ["*default*"] + } + + filter { + name = "vpc-id" + values = [var.vpc_id] + } +} + +# instance profile for ec2 using the ec2_role +resource "aws_iam_instance_profile" "ec2_instance_profile" { + name = "${local.ec2_role_name}-instance-profile" + role = aws_iam_role.ec2_role.name +} + +resource "aws_instance" "streamlit_server" { + ami = var.ubuntu_ami + instance_type = var.ec2_instance_type + subnet_id = data.aws_subnets.subnets.ids[0] + vpc_security_group_ids = data.aws_security_groups.security_groups.ids + iam_instance_profile = aws_iam_instance_profile.ec2_instance_profile.name + associate_public_ip_address = false + key_name = "tf-test-key" # Created using TF and uploaded to S3. Prerequisite + + root_block_device { + volume_size = 30 # Variable + encrypted = true # Mandatory + } +# Setup SSH authentication for bitbucket access to pull code +# Setup SSL certificate for HTTPS access for SSO to work + user_data = <<-EOF + #!/bin/bash + echo '${file("${path.module}/requirements.txt")}' > /tmp/requirements.txt + apt-get update + apt-get install -y python3 python3-pip + pip3 install $(cat /tmp/requirements.txt) + sudo apt install openssh-client + + # Create UI0 systemd service + cat < /etc/systemd/system/streamlit-ui0.service + [Unit] + Description=Streamlit Server Service + + [Service] + User=ubuntu + Type=simple + Restart=always + WorkingDirectory=/home/ubuntu/doczy.ai/streamlit + ExecStart=/home/ubuntu/.local/bin/streamlit run /home/ubuntu/doczy.ai/streamlit/interface_0.py --server.port 8500 + + [Install] + WantedBy=multi-user.target + EOT + + # Enable and start the service + systemctl enable streamlit-ui0.service + systemctl start streamlit-ui0.service + + # Create UI1 systemd service + cat < /etc/systemd/system/streamlit-ui1.service + [Unit] + Description=Streamlit Server Service + + [Service] + User=ubuntu + Type=simple + Restart=always + WorkingDirectory=/home/ubuntu/doczy.ai/streamlit + ExecStart=/home/ubuntu/.local/bin/streamlit run /home/ubuntu/doczy.ai/streamlit/interface_1.py --server.port 8501 + + [Install] + WantedBy=multi-user.target + EOT + # Enable and start the service + systemctl enable streamlit-ui1.service + systemctl start streamlit-ui1.service + + # Create UI2 systemd service + cat < /etc/systemd/system/streamlit-ui2.service + [Unit] + Description=Streamlit Server Service + + [Service] + User=ubuntu + Type=simple + Restart=always + WorkingDirectory=/home/ubuntu/doczy.ai/streamlit + ExecStart=/home/ubuntu/.local/bin/streamlit run /home/ubuntu/doczy.ai/streamlit/interface_2.py --server.port 8502 + + [Install] + WantedBy=multi-user.target + EOT + # Enable and start the service + systemctl enable streamlit-ui2.service + systemctl start streamlit-ui2.service + + # Create UI3 systemd service + cat < /etc/systemd/system/streamlit-ui3.service + [Unit] + Description=Streamlit Server Service + + [Service] + User=ubuntu + Type=simple + Restart=always + WorkingDirectory=/home/ubuntu/doczy.ai/streamlit + ExecStart=/home/ubuntu/.local/bin/streamlit run /home/ubuntu/doczy.ai/streamlit/interface_3.py --server.port 8503 + + [Install] + WantedBy=multi-user.target + EOT + # Enable and start the service + systemctl enable streamlit-ui3.service + systemctl start streamlit-ui3.service + + EOF + + metadata_options { + http_endpoint = "enabled" + http_put_response_hop_limit = 2 + http_tokens = "required" + } + + tags = { + Terraform = "true" + Environment = "dev" + } +} + diff --git a/streamlit-server/requirements.txt b/streamlit-server/requirements.txt new file mode 100644 index 0000000..c8ec80f --- /dev/null +++ b/streamlit-server/requirements.txt @@ -0,0 +1,38 @@ +# Natural Language Processing +langchain==0.0.267 +chromadb==0.4.6 +pdfminer.six==20221105 +InstructorEmbedding +sentence-transformers==2.2.2 +faiss-cpu +huggingface_hub +transformers +autoawq +protobuf==3.20.2; sys_platform != 'darwin' +protobuf==3.20.2; sys_platform == 'darwin' and platform_machine != 'arm64' +protobuf==3.20.3; sys_platform == 'darwin' and platform_machine == 'arm64' +auto-gptq==0.2.2 +docx2txt +unstructured +unstructured[pdf] + +# Utilities +urllib3==1.26.6 +accelerate +bitsandbytes ; sys_platform != 'win32' +bitsandbytes-windows ; sys_platform == 'win32' +click +flask +requests + +# Streamlit related +streamlit +Streamlit-extras + +# Excel File Manipulation +openpyxl +numpy>=1.22.2 + +# AWS related +boto3 +awscli \ No newline at end of file diff --git a/streamlit-server/variables.tf b/streamlit-server/variables.tf new file mode 100644 index 0000000..08071d0 --- /dev/null +++ b/streamlit-server/variables.tf @@ -0,0 +1,55 @@ + +# required +variable "aws_region" { + type = string + default = "us-east-2" +} +# required +variable "project_name" { + type = string + default = "doczyai" +} +# required +variable "environment" { + type = string + default = "dev" +} + + +variable "client_list" { + type = map(object({ + client_name = string + })) + default = { + client1 = { + client_name = "cn1" + } + } +} + +variable "vpc_id" { + type = string +} + +variable "ubuntu_ami" { + type = string + default = "ami-0b8b44ec9a8f90422" + +} + +variable "ec2_instance_type" { + type = string + default = "t2.small" +} + +# EC2 iam role name +variable "ec2_iam_role_name" { + type = string + default = "ec2-iam-role" +} + +# Cerate an array of ARNS +variable "SecretsNames"{ + type = list(string) + default = [] +} \ No newline at end of file