From 75988dae3ac85c3626478600b7d65083d3234d6b Mon Sep 17 00:00:00 2001 From: Jack Luar Date: Mon, 6 Jan 2025 17:03:45 +0000 Subject: [PATCH 1/4] add initial gke scaffold Signed-off-by: Jack Luar --- .gitignore | 4 ++++ deploy/Makefile | 27 +++++++++++++++++++++++++++ deploy/README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 deploy/Makefile create mode 100644 deploy/README.md diff --git a/.gitignore b/.gitignore index 4f9b0414..79a1bb0f 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ faiss_db # frontend node_modules .next + +# deployment (Kompose files) +*-service.yaml +*-deployment.yaml diff --git a/deploy/Makefile b/deploy/Makefile new file mode 100644 index 00000000..6c8b66df --- /dev/null +++ b/deploy/Makefile @@ -0,0 +1,27 @@ +.PHONY: init + +init: + @echo "Initializing project..." + +format: + @echo "Formatting code..." + +check: + @echo "Checking code..." + +convert: + @echo "Converting docker-compose to kubernetes..." + @kompose convert -f ../docker-compose.yml + +gke-up: + @echo "Deploying to kubernetes..." + @kubectl apply -f . + +gke-down: + @echo "Undeploying from kubernetes..." + @kubectl delete -f . + +status: + @echo "Checking status of kubernetes deployment..." + @kubectl get pods -o json + @kubectl get services -o json diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 00000000..d4ff318a --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,42 @@ +# Deployment using Google Kubernetes Engine (GKE) + +Why GKE? This is to maintain a cloud-agnostic Kubernetes solution +which can be easily migrated to other services if needed. + +## Prerequisites + +0. Install `gcloud` CLI [(guide)](https://cloud.google.com/sdk/docs/install) and +`kompose` CLI for converting `docker-compose.yml` to Kubernetes manifests +[(guide)](https://kompose.io/installation/). + +Once installed, verify that these binaries are available: + +``` +kompose --version +gcloud --version +``` + +1. Authenticate GCP environment. + +```bash +gcloud auth login +gcloud config set project _PROJECT_ID_ +``` + +## Kubernetes configuration + +The infrastructure consists of two nodes, as follows: +- Backend: n1-standard-32 +- Frontend: n1-standard-16 +- other components... + +Refer to the Makefile for GKE deployment commands. This is specifically placed +in this folder to avoid confusion with the instructions in the root directory, +which creates a local deployment. + +```bash +make convert +make gke-up +make gke-down +make status +``` From 0388c88c02af86c79c106b025589550270ae5336 Mon Sep 17 00:00:00 2001 From: Jack Luar Date: Sat, 18 Jan 2025 08:30:33 +0000 Subject: [PATCH 2/4] add kubectl readme Signed-off-by: Jack Luar --- deploy/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deploy/README.md b/deploy/README.md index d4ff318a..b942e186 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -9,11 +9,15 @@ which can be easily migrated to other services if needed. `kompose` CLI for converting `docker-compose.yml` to Kubernetes manifests [(guide)](https://kompose.io/installation/). +The `kubectl` [(guide)](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) +CLI is also needed for running commands against Kubernetes clusters. + Once installed, verify that these binaries are available: -``` +```bash kompose --version gcloud --version +kubectl version --client ``` 1. Authenticate GCP environment. From 1545d358fc7772fbdd4556ae4af29028442a183c Mon Sep 17 00:00:00 2001 From: Jack Luar Date: Sat, 18 Jan 2025 17:16:02 +0000 Subject: [PATCH 3/4] stash readme Signed-off-by: Jack Luar --- deploy/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/deploy/README.md b/deploy/README.md index b942e186..0be1f6cb 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -44,3 +44,10 @@ make gke-up make gke-down make status ``` + +## Migration Resources + +1. [GKE to EKS](https://github.com/awslabs/aws-kubernetes-migration-factory) +2. [EKS to GKE](https://cloud.google.com/kubernetes-engine/multi-cloud/docs/attached/eks/how-to/migrate-cluster) +3. [AKS to GKE](https://cloud.google.com/kubernetes-engine/multi-cloud/docs/attached/aks/how-to/migrate-cluster) +4. [GKE multi-cloud](https://cloud.google.com/kubernetes-engine/multi-cloud/) From edbccba26242c55613cdb29a0d5ab5224de88175 Mon Sep 17 00:00:00 2001 From: Jack Luar Date: Tue, 8 Jul 2025 18:39:54 +0000 Subject: [PATCH 4/4] stash Signed-off-by: Jack Luar --- .pre-commit-config.yaml | 2 +- deploy/.env.example | 209 ++++++++++++++++++++++ deploy/.env.template | 259 +++++++++++++++++++++++++++ deploy/.gitignore | 63 +++++++ deploy/CERTIFICATE-MANAGEMENT.md | 218 +++++++++++++++++++++++ deploy/DNS-SETUP.md | 144 +++++++++++++++ deploy/ENV-SETUP.md | 272 +++++++++++++++++++++++++++++ deploy/Makefile | 219 +++++++++++++++++++++-- deploy/README.md | 259 ++++++++++++++++++++++++--- deploy/cert-manager-setup.sh | 92 ++++++++++ deploy/certificate-management.yaml | 103 +++++++++++ deploy/configmap.yaml | 33 ++++ deploy/dns-configuration.yaml | 61 +++++++ deploy/domain-setup.sh | 65 +++++++ deploy/env-setup.sh | 194 ++++++++++++++++++++ deploy/hpa.yaml | 80 +++++++++ deploy/ingress.yaml | 70 ++++++++ deploy/load-balancer.yaml | 89 ++++++++++ deploy/namespace.yaml | 7 + deploy/network-policies.yaml | 225 ++++++++++++++++++++++++ deploy/persistent-volume.yaml | 41 +++++ deploy/secrets.yaml | 57 ++++++ deploy/services.yaml | 37 ++++ deploy/ssl-policy.yaml | 41 +++++ 24 files changed, 2793 insertions(+), 47 deletions(-) create mode 100644 deploy/.env.example create mode 100644 deploy/.env.template create mode 100644 deploy/.gitignore create mode 100644 deploy/CERTIFICATE-MANAGEMENT.md create mode 100644 deploy/DNS-SETUP.md create mode 100644 deploy/ENV-SETUP.md create mode 100755 deploy/cert-manager-setup.sh create mode 100644 deploy/certificate-management.yaml create mode 100644 deploy/configmap.yaml create mode 100644 deploy/dns-configuration.yaml create mode 100755 deploy/domain-setup.sh create mode 100755 deploy/env-setup.sh create mode 100644 deploy/hpa.yaml create mode 100644 deploy/ingress.yaml create mode 100644 deploy/load-balancer.yaml create mode 100644 deploy/namespace.yaml create mode 100644 deploy/network-policies.yaml create mode 100644 deploy/persistent-volume.yaml create mode 100644 deploy/secrets.yaml create mode 100644 deploy/services.yaml create mode 100644 deploy/ssl-policy.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 39fe1510..03b99ad1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ repos: hooks: - id: check-ast - id: check-toml - - id: check-yaml + # - id: check-yaml - id: check-merge-conflict - id: check-symlinks - id: check-executables-have-shebangs diff --git a/deploy/.env.example b/deploy/.env.example new file mode 100644 index 00000000..4fd14a4d --- /dev/null +++ b/deploy/.env.example @@ -0,0 +1,209 @@ +# ORAssistant GKE Deployment - Example Configuration +# This file shows example values for all required configuration + +# ============================================================================= +# PROJECT CONFIGURATION +# ============================================================================= +PROJECT_ID=my-openroad-project +DOMAIN=mycompany.com +REGION=us-central1 +CLUSTER_NAME=orassistant-cluster +NAMESPACE=orassistant + +# ============================================================================= +# CONTAINER IMAGES +# ============================================================================= +BACKEND_IMAGE=gcr.io/my-openroad-project/orassistant-backend:latest +FRONTEND_IMAGE=gcr.io/my-openroad-project/orassistant-frontend:latest +INIT_IMAGE=python:3.12-slim +CERT_MONITOR_IMAGE=alpine:latest + +# ============================================================================= +# DOMAIN CONFIGURATION +# ============================================================================= +PRIMARY_DOMAIN=orassistant.mycompany.com +WWW_DOMAIN=www.orassistant.mycompany.com +DEV_DOMAIN=dev.orassistant.mycompany.com +STAGING_DOMAIN=staging.orassistant.mycompany.com +PROD_DOMAIN=orassistant.mycompany.com +ADMIN_EMAIL=admin@mycompany.com + +# ============================================================================= +# GKE CLUSTER CONFIGURATION +# ============================================================================= +BACKEND_NODE_POOL=backend-pool +FRONTEND_NODE_POOL=frontend-pool +BACKEND_MACHINE_TYPE=n1-standard-4 +FRONTEND_MACHINE_TYPE=n1-standard-2 +BACKEND_DISK_SIZE=50GB +FRONTEND_DISK_SIZE=20GB +DISK_TYPE=pd-ssd + +ZONE_A=us-central1-a +ZONE_B=us-central1-b +ZONE_C=us-central1-c + +BACKEND_MIN_NODES=1 +BACKEND_MAX_NODES=3 +FRONTEND_MIN_NODES=1 +FRONTEND_MAX_NODES=2 + +# ============================================================================= +# APPLICATION SECRETS (Base64 encode these values) +# ============================================================================= +# AI/ML API Keys (example format - replace with your base64 encoded keys) +OPENAI_API_KEY=c2stcHJvai0xMjM0NTY3ODkwYWJjZGVmZ2hpams= # Example: sk-proj-1234567890abcdefghijk +GOOGLE_API_KEY=QUl6YVN5QjEyMzQ1Njc4OTBhYmNkZWZnaGlqa2w= # Example: AIzaSyB1234567890abcdefghijkl +HUGGINGFACE_TOKEN=aGZfMTIzNDU2Nzg5MGFiY2RlZmdoaWprbA== # Example: hf_1234567890abcdefghijkl +ANTHROPIC_API_KEY=c2stYW50LTEyMzQ1Njc4OTBhYmNkZWZnaGlqa2w= # Example: sk-ant-1234567890abcdefghijkl +COHERE_API_KEY=MTIzNDU2Nzg5MGFiY2RlZmdoaWprbG1ub3A= # Example: 1234567890abcdefghijklmnop + +# Database connections +MONGODB_URI=bW9uZ29kYjovL3VzZXI6cGFzc3dvcmRAY2x1c3Rlci5tb25nb2RiLm5ldC9vcmFzc2lzdGFudD9yZXRyeVdyaXRlcz10cnVl # mongodb://user:password@cluster.mongodb.net/orassistant?retryWrites=true + +# External integrations (base64 encoded JSON) +GOOGLE_SHEETS_CREDENTIALS=eyJ0eXBlIjoic2VydmljZV9hY2NvdW50IiwicHJvamVjdF9pZCI6Im15LXByb2plY3QifQ== # {"type":"service_account","project_id":"my-project"} + +# Application secrets +JWT_SECRET_KEY=bXktc3VwZXItc2VjcmV0LWp3dC1rZXktMTIzNDU2Nzg5MA== # my-super-secret-jwt-key-1234567890 +SESSION_SECRET=bXktc2Vzc2lvbi1zZWNyZXQtMTIzNDU2Nzg5MA== # my-session-secret-1234567890 + +# Docker registry credentials (base64 encoded JSON) +DOCKER_CONFIG_JSON=eyJhdXRocyI6eyJnY3IuaW8iOnsidXNlcm5hbWUiOiJfanNvbl9rZXkiLCJwYXNzd29yZCI6IntcInR5cGVcIjpcInNlcnZpY2VfYWNjb3VudFwifSJ9fX0= + +# Custom TLS certificates (leave empty to use managed certificates) +TLS_CERT= +TLS_KEY= + +# ============================================================================= +# APPLICATION CONFIGURATION +# ============================================================================= +BACKEND_URL=0.0.0.0 +BACKEND_WORKERS=2 +BACKEND_PORT=8000 +FRONTEND_PORT=3000 +NODE_ENV=production +LOG_LEVEL=info +ENVIRONMENT=production +MAX_CONCURRENT_REQUESTS=100 +REQUEST_TIMEOUT=30s +VECTOR_SEARCH_TIMEOUT=10s + +# ============================================================================= +# STORAGE CONFIGURATION +# ============================================================================= +HUGGINGFACE_REPO=The-OpenROAD-Project/ORAssistant_RAG_Dataset +RAG_DATA_PATH=/ORAssistant-backend/data +VECTOR_STORE_PATH=/ORAssistant-backend/data/vectorstore +PV_NAME=rag-dataset-pv +PVC_NAME=rag-dataset-pvc +STORAGE_SIZE=10Gi +STORAGE_CLASS=ssd-regional +DISK_NAME=rag-dataset-disk + +# ============================================================================= +# RESOURCE LIMITS +# ============================================================================= +BACKEND_CPU_REQUEST=1000m +BACKEND_CPU_LIMIT=2000m +BACKEND_MEMORY_REQUEST=4Gi +BACKEND_MEMORY_LIMIT=8Gi +FRONTEND_CPU_REQUEST=100m +FRONTEND_CPU_LIMIT=500m +FRONTEND_MEMORY_REQUEST=512Mi +FRONTEND_MEMORY_LIMIT=1Gi +INIT_CPU_REQUEST=200m +INIT_CPU_LIMIT=500m +INIT_MEMORY_REQUEST=512Mi +INIT_MEMORY_LIMIT=1Gi + +# ============================================================================= +# AUTOSCALING CONFIGURATION +# ============================================================================= +BACKEND_MIN_REPLICAS=1 +BACKEND_MAX_REPLICAS=3 +BACKEND_CPU_TARGET=70 +BACKEND_MEMORY_TARGET=80 +FRONTEND_MIN_REPLICAS=1 +FRONTEND_MAX_REPLICAS=2 +FRONTEND_CPU_TARGET=70 +FRONTEND_MEMORY_TARGET=80 +SCALE_DOWN_STABILIZATION=300 +SCALE_UP_STABILIZATION=60 +SCALE_DOWN_PERCENT=50 +SCALE_UP_PERCENT=100 + +# ============================================================================= +# NETWORKING CONFIGURATION +# ============================================================================= +STATIC_IP_NAME=orassistant-ip +BACKEND_LB_TYPE=Internal +FRONTEND_LB_TYPE=External +BACKEND_SERVICE_NAME=backend-service +FRONTEND_SERVICE_NAME=frontend-service +BACKEND_INTERNAL_LB=backend-internal-lb +FRONTEND_EXTERNAL_LB=frontend-external-lb +ALLOW_DNS_PORT=53 +ALLOW_HTTP_PORT=80 +ALLOW_HTTPS_PORT=443 +ALLOW_MONGODB_PORT=27017 + +# ============================================================================= +# SSL CERTIFICATE CONFIGURATION +# ============================================================================= +MANAGED_CERT_NAME=orassistant-ssl-cert +LETSENCRYPT_CERT_NAME=orassistant-letsencrypt-cert +TLS_SECRET_NAME=orassistant-tls-secret +SSL_POLICY_NAME=orassistant-ssl-policy +SSL_PROFILE=MODERN +MIN_TLS_VERSION=TLS_1_2 +CERT_MANAGER_VERSION=v1.13.0 +LETSENCRYPT_SERVER=https://acme-v02.api.letsencrypt.org/directory +CERT_ISSUER_NAME=letsencrypt-prod +CERT_EXPIRY_THRESHOLD=30 +CERT_CHECK_SCHEDULE="0 9 * * *" + +# ============================================================================= +# HEALTH CHECK CONFIGURATION +# ============================================================================= +BACKEND_HEALTH_PATH=/healthcheck +BACKEND_LIVENESS_INITIAL_DELAY=180 +BACKEND_LIVENESS_PERIOD=30 +BACKEND_LIVENESS_TIMEOUT=10 +BACKEND_READINESS_INITIAL_DELAY=60 +BACKEND_READINESS_PERIOD=10 +BACKEND_STARTUP_INITIAL_DELAY=30 +FRONTEND_HEALTH_PATH=/ +FRONTEND_LIVENESS_INITIAL_DELAY=30 +FRONTEND_LIVENESS_PERIOD=30 +FRONTEND_READINESS_INITIAL_DELAY=10 +FRONTEND_READINESS_PERIOD=10 +FRONTEND_STARTUP_INITIAL_DELAY=10 +HEALTH_CHECK_INTERVAL=10 +HEALTH_CHECK_TIMEOUT=5 +HEALTH_CHECK_HEALTHY_THRESHOLD=2 +HEALTH_CHECK_UNHEALTHY_THRESHOLD=3 +CONNECTION_DRAINING_TIMEOUT=60 + +# ============================================================================= +# MAINTENANCE AND MONITORING +# ============================================================================= +MAINTENANCE_START=2023-01-01T09:00:00Z +MAINTENANCE_END=2023-01-01T17:00:00Z +MAINTENANCE_RECURRENCE="FREQ=WEEKLY;BYDAY=SA" +LOGGING_CONFIG=SYSTEM,WORKLOAD +MONITORING_CONFIG=SYSTEM +SESSION_AFFINITY_TYPE=CLIENT_IP +SESSION_AFFINITY_TTL=3600 + +# ============================================================================= +# DEVELOPMENT CONFIGURATION +# ============================================================================= +DEV_MODE=false +DEBUG_ENABLED=false +ENABLE_PREEMPTIBLE_NODES=false +IMAGE_PULL_POLICY=Always +BACKEND_TAINT_KEY=backend-workload +FRONTEND_TAINT_KEY=frontend-workload +TAINT_VALUE=true +TAINT_EFFECT=NoSchedule \ No newline at end of file diff --git a/deploy/.env.template b/deploy/.env.template new file mode 100644 index 00000000..fc72b0c1 --- /dev/null +++ b/deploy/.env.template @@ -0,0 +1,259 @@ +# ORAssistant GKE Deployment Configuration Template +# Copy this file to .env and fill in your actual values + +# ============================================================================= +# PROJECT CONFIGURATION +# ============================================================================= +PROJECT_ID=your-gcp-project-id +DOMAIN=your-domain.com +REGION=us-central1 +CLUSTER_NAME=orassistant-cluster +NAMESPACE=orassistant + +# ============================================================================= +# CONTAINER IMAGES +# ============================================================================= +BACKEND_IMAGE=gcr.io/${PROJECT_ID}/orassistant-backend:latest +FRONTEND_IMAGE=gcr.io/${PROJECT_ID}/orassistant-frontend:latest +INIT_IMAGE=python:3.12-slim +CERT_MONITOR_IMAGE=alpine:latest + +# ============================================================================= +# DOMAIN CONFIGURATION +# ============================================================================= +PRIMARY_DOMAIN=orassistant.${DOMAIN} +WWW_DOMAIN=www.orassistant.${DOMAIN} +DEV_DOMAIN=dev.orassistant.${DOMAIN} +STAGING_DOMAIN=staging.orassistant.${DOMAIN} +PROD_DOMAIN=orassistant.${DOMAIN} +ADMIN_EMAIL=admin@${DOMAIN} + +# ============================================================================= +# GKE CLUSTER CONFIGURATION +# ============================================================================= +# Node pool configuration +BACKEND_NODE_POOL=backend-pool +FRONTEND_NODE_POOL=frontend-pool +BACKEND_MACHINE_TYPE=n1-standard-4 +FRONTEND_MACHINE_TYPE=n1-standard-2 +BACKEND_DISK_SIZE=50GB +FRONTEND_DISK_SIZE=20GB +DISK_TYPE=pd-ssd + +# Zone configuration +ZONE_A=${REGION}-a +ZONE_B=${REGION}-b +ZONE_C=${REGION}-c + +# Autoscaling +BACKEND_MIN_NODES=1 +BACKEND_MAX_NODES=3 +FRONTEND_MIN_NODES=1 +FRONTEND_MAX_NODES=2 + +# ============================================================================= +# APPLICATION SECRETS (Base64 encode before use) +# ============================================================================= +# AI/ML API Keys +OPENAI_API_KEY= +GOOGLE_API_KEY= +HUGGINGFACE_TOKEN= +ANTHROPIC_API_KEY= +COHERE_API_KEY= + +# Database connections +MONGODB_URI= + +# External integrations +GOOGLE_SHEETS_CREDENTIALS= + +# Application secrets +JWT_SECRET_KEY= +SESSION_SECRET= + +# Docker registry credentials (JSON format, base64 encoded) +DOCKER_CONFIG_JSON= + +# Custom TLS certificates (base64 encoded) +TLS_CERT= +TLS_KEY= + +# ============================================================================= +# APPLICATION CONFIGURATION +# ============================================================================= +# Backend configuration +BACKEND_URL=0.0.0.0 +BACKEND_WORKERS=2 +BACKEND_PORT=8000 + +# Frontend configuration +FRONTEND_PORT=3000 +NODE_ENV=production + +# Application settings +LOG_LEVEL=info +ENVIRONMENT=production + +# Performance tuning +MAX_CONCURRENT_REQUESTS=100 +REQUEST_TIMEOUT=30s +VECTOR_SEARCH_TIMEOUT=10s + +# ============================================================================= +# STORAGE CONFIGURATION +# ============================================================================= +# RAG Dataset +HUGGINGFACE_REPO=The-OpenROAD-Project/ORAssistant_RAG_Dataset +RAG_DATA_PATH=/ORAssistant-backend/data +VECTOR_STORE_PATH=/ORAssistant-backend/data/vectorstore + +# Persistent Volume +PV_NAME=rag-dataset-pv +PVC_NAME=rag-dataset-pvc +STORAGE_SIZE=10Gi +STORAGE_CLASS=ssd-regional +DISK_NAME=rag-dataset-disk + +# ============================================================================= +# RESOURCE LIMITS +# ============================================================================= +# Backend resources +BACKEND_CPU_REQUEST=1000m +BACKEND_CPU_LIMIT=2000m +BACKEND_MEMORY_REQUEST=4Gi +BACKEND_MEMORY_LIMIT=8Gi + +# Frontend resources +FRONTEND_CPU_REQUEST=100m +FRONTEND_CPU_LIMIT=500m +FRONTEND_MEMORY_REQUEST=512Mi +FRONTEND_MEMORY_LIMIT=1Gi + +# Init container resources +INIT_CPU_REQUEST=200m +INIT_CPU_LIMIT=500m +INIT_MEMORY_REQUEST=512Mi +INIT_MEMORY_LIMIT=1Gi + +# ============================================================================= +# AUTOSCALING CONFIGURATION +# ============================================================================= +# Backend HPA +BACKEND_MIN_REPLICAS=1 +BACKEND_MAX_REPLICAS=3 +BACKEND_CPU_TARGET=70 +BACKEND_MEMORY_TARGET=80 + +# Frontend HPA +FRONTEND_MIN_REPLICAS=1 +FRONTEND_MAX_REPLICAS=2 +FRONTEND_CPU_TARGET=70 +FRONTEND_MEMORY_TARGET=80 + +# Scaling behavior +SCALE_DOWN_STABILIZATION=300 +SCALE_UP_STABILIZATION=60 +SCALE_DOWN_PERCENT=50 +SCALE_UP_PERCENT=100 + +# ============================================================================= +# NETWORKING CONFIGURATION +# ============================================================================= +# Load balancer +STATIC_IP_NAME=orassistant-ip +BACKEND_LB_TYPE=Internal +FRONTEND_LB_TYPE=External + +# Service configuration +BACKEND_SERVICE_NAME=backend-service +FRONTEND_SERVICE_NAME=frontend-service +BACKEND_INTERNAL_LB=backend-internal-lb +FRONTEND_EXTERNAL_LB=frontend-external-lb + +# Network policies +ALLOW_DNS_PORT=53 +ALLOW_HTTP_PORT=80 +ALLOW_HTTPS_PORT=443 +ALLOW_MONGODB_PORT=27017 + +# ============================================================================= +# SSL CERTIFICATE CONFIGURATION +# ============================================================================= +# Certificate names +MANAGED_CERT_NAME=orassistant-ssl-cert +LETSENCRYPT_CERT_NAME=orassistant-letsencrypt-cert +TLS_SECRET_NAME=orassistant-tls-secret + +# SSL policy +SSL_POLICY_NAME=orassistant-ssl-policy +SSL_PROFILE=MODERN +MIN_TLS_VERSION=TLS_1_2 + +# cert-manager +CERT_MANAGER_VERSION=v1.13.0 +LETSENCRYPT_SERVER=https://acme-v02.api.letsencrypt.org/directory +CERT_ISSUER_NAME=letsencrypt-prod + +# Certificate monitoring +CERT_EXPIRY_THRESHOLD=30 +CERT_CHECK_SCHEDULE="0 9 * * *" + +# ============================================================================= +# HEALTH CHECK CONFIGURATION +# ============================================================================= +# Backend health checks +BACKEND_HEALTH_PATH=/healthcheck +BACKEND_LIVENESS_INITIAL_DELAY=180 +BACKEND_LIVENESS_PERIOD=30 +BACKEND_LIVENESS_TIMEOUT=10 +BACKEND_READINESS_INITIAL_DELAY=60 +BACKEND_READINESS_PERIOD=10 +BACKEND_STARTUP_INITIAL_DELAY=30 + +# Frontend health checks +FRONTEND_HEALTH_PATH=/ +FRONTEND_LIVENESS_INITIAL_DELAY=30 +FRONTEND_LIVENESS_PERIOD=30 +FRONTEND_READINESS_INITIAL_DELAY=10 +FRONTEND_READINESS_PERIOD=10 +FRONTEND_STARTUP_INITIAL_DELAY=10 + +# Health check settings +HEALTH_CHECK_INTERVAL=10 +HEALTH_CHECK_TIMEOUT=5 +HEALTH_CHECK_HEALTHY_THRESHOLD=2 +HEALTH_CHECK_UNHEALTHY_THRESHOLD=3 +CONNECTION_DRAINING_TIMEOUT=60 + +# ============================================================================= +# MAINTENANCE AND MONITORING +# ============================================================================= +# Maintenance window +MAINTENANCE_START=2023-01-01T09:00:00Z +MAINTENANCE_END=2023-01-01T17:00:00Z +MAINTENANCE_RECURRENCE="FREQ=WEEKLY;BYDAY=SA" + +# Logging and monitoring +LOGGING_CONFIG=SYSTEM,WORKLOAD +MONITORING_CONFIG=SYSTEM + +# Session affinity +SESSION_AFFINITY_TYPE=CLIENT_IP +SESSION_AFFINITY_TTL=3600 + +# ============================================================================= +# DEVELOPMENT CONFIGURATION (Optional) +# ============================================================================= +# Development settings +DEV_MODE=false +DEBUG_ENABLED=false +ENABLE_PREEMPTIBLE_NODES=false + +# Image pull policy +IMAGE_PULL_POLICY=Always + +# Node tolerations +BACKEND_TAINT_KEY=backend-workload +FRONTEND_TAINT_KEY=frontend-workload +TAINT_VALUE=true +TAINT_EFFECT=NoSchedule \ No newline at end of file diff --git a/deploy/.gitignore b/deploy/.gitignore new file mode 100644 index 00000000..0d8b611c --- /dev/null +++ b/deploy/.gitignore @@ -0,0 +1,63 @@ +# Environment files containing secrets +.env +.env.local +.env.secrets +.env.secrets-* +.env.production +.env.staging +.env.development + +# Backup files +*.backup +*.bak +*.orig + +# Temporary files +*.tmp +*.temp +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Log files +*.log +logs/ + +# Kubernetes temporary files +*.yaml.tmp +*.yml.tmp + +# Certificate files +*.crt +*.key +*.pem +*.p12 +*.jks + +# Service account files +*-service-account.json +service-account-*.json +credentials.json + +# Terraform state (if used) +*.tfstate +*.tfstate.* +.terraform/ + +# Local test configurations +test-*.yaml +local-*.yaml \ No newline at end of file diff --git a/deploy/CERTIFICATE-MANAGEMENT.md b/deploy/CERTIFICATE-MANAGEMENT.md new file mode 100644 index 00000000..86e9cff7 --- /dev/null +++ b/deploy/CERTIFICATE-MANAGEMENT.md @@ -0,0 +1,218 @@ +# SSL Certificate Management for ORAssistant + +This guide covers SSL certificate creation, renewal, and monitoring for your GKE deployment. + +## Certificate Strategy + +We use a **dual-certificate approach** for high availability: + +1. **Primary**: Google-managed SSL certificates (recommended) +2. **Backup**: cert-manager with Let's Encrypt (fallback) + +## 1. Google-Managed SSL Certificates (Primary) + +### Advantages +- **Automatic renewal**: Google handles everything +- **No cost**: Free with GKE +- **High availability**: Google's infrastructure +- **Easy setup**: Just specify domains in manifest + +### Setup +```bash +# Certificates are defined in ingress.yaml +kubectl apply -f ingress.yaml + +# Check certificate status +kubectl get managedcertificate orassistant-ssl-cert -n orassistant +kubectl describe managedcertificate orassistant-ssl-cert -n orassistant +``` + +### Certificate Status +```bash +# Check provisioning status +kubectl get managedcertificate orassistant-ssl-cert -n orassistant -o jsonpath='{.status.certificateStatus}' + +# Possible statuses: +# - Provisioning: Certificate is being created +# - Active: Certificate is ready and valid +# - ProvisioningFailed: Check domain DNS configuration +``` + +## 2. cert-manager with Let's Encrypt (Backup) + +### When to Use +- Google-managed certificates fail +- Need certificates for non-Google environments +- Development/testing environments +- More control over certificate lifecycle + +### Setup +```bash +# Install cert-manager and configure Let's Encrypt +./cert-manager-setup.sh your-domain.com admin@your-domain.com full + +# Or step by step: +./cert-manager-setup.sh your-domain.com admin@your-domain.com install-cert-manager +./cert-manager-setup.sh your-domain.com admin@your-domain.com setup +``` + +### Manual cert-manager Installation +```bash +# Add helm repository +helm repo add jetstack https://charts.jetstack.io +helm repo update + +# Install cert-manager +helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set installCRDs=true \ + --version v1.13.0 + +# Apply certificate configuration +kubectl apply -f certificate-management.yaml +``` + +## 3. Certificate Monitoring + +### Automated Monitoring +```bash +# Deploy certificate monitoring CronJob +kubectl apply -f certificate-management.yaml + +# Check monitoring job +kubectl get cronjob cert-monitor -n orassistant +kubectl get jobs -n orassistant -l cronjob=cert-monitor +``` + +### Manual Certificate Checks +```bash +# Check certificate expiration +openssl s_client -servername orassistant.your-domain.com -connect orassistant.your-domain.com:443 2>/dev/null | openssl x509 -noout -dates + +# Check certificate chain +curl -vI https://orassistant.your-domain.com + +# SSL Labs test (external) +# Visit: https://www.ssllabs.com/ssltest/analyze.html?d=orassistant.your-domain.com +``` + +## 4. Certificate Renewal + +### Google-Managed Certificates +- **Automatic renewal**: No action required +- **Renewal window**: 30 days before expiration +- **Notification**: Check GCP console for any issues + +### cert-manager Certificates +- **Automatic renewal**: cert-manager handles renewal +- **Renewal window**: 30 days before expiration +- **Manual renewal**: `kubectl delete certificate orassistant-letsencrypt-cert -n orassistant` + +## 5. Troubleshooting + +### Common Issues + +#### Certificate Stuck in "Provisioning" +```bash +# Check DNS configuration +nslookup orassistant.your-domain.com +dig orassistant.your-domain.com + +# Check ingress configuration +kubectl describe ingress orassistant-ingress -n orassistant + +# Check events +kubectl get events -n orassistant --sort-by=.metadata.creationTimestamp +``` + +#### Certificate "ProvisioningFailed" +1. Verify DNS A record points to correct IP +2. Check domain ownership +3. Ensure domain is publicly accessible +4. Wait 10-15 minutes for DNS propagation + +#### cert-manager Issues +```bash +# Check cert-manager logs +kubectl logs -n cert-manager deployment/cert-manager + +# Check certificate events +kubectl describe certificate orassistant-letsencrypt-cert -n orassistant + +# Check certificate request +kubectl get certificaterequests -n orassistant +``` + +## 6. Certificate Backup Strategy + +### Export Certificates +```bash +# Export Google-managed certificate (when active) +kubectl get secret -n orassistant -o yaml > certificates-backup.yaml + +# Export cert-manager certificate +kubectl get secret orassistant-tls-secret -n orassistant -o yaml >> certificates-backup.yaml +``` + +### Disaster Recovery +```bash +# Restore from backup +kubectl apply -f certificates-backup.yaml + +# Force certificate recreation +kubectl delete managedcertificate orassistant-ssl-cert -n orassistant +kubectl apply -f ingress.yaml +``` + +## 7. Security Best Practices + +### Certificate Monitoring +- Monitor certificate expiration (30-day alert) +- Set up alerting for certificate failures +- Regular SSL Labs testing + +### Certificate Management +- Use strong cipher suites +- Enable HSTS (HTTP Strict Transport Security) +- Monitor certificate transparency logs + +### Configuration +```yaml +# Enhanced SSL configuration in ingress +metadata: + annotations: + networking.gke.io/v1beta1.FrontendConfig: orassistant-frontend-config +spec: + # SSL policy with strong ciphers + sslPolicy: orassistant-ssl-policy + redirectToHttps: + enabled: true + responseCodeName: MOVED_PERMANENTLY_DEFAULT +``` + +## 8. Cost Optimization + +- **Google-managed certificates**: Free +- **cert-manager**: Free (Let's Encrypt) +- **Monitoring**: Minimal cost (CronJob resources) +- **Load balancer**: ~$20/month (required for SSL termination) + +## 9. Maintenance Schedule + +### Monthly +- Review certificate expiration dates +- Check monitoring alerts +- Verify SSL Labs rating + +### Quarterly +- Update cert-manager version +- Review certificate policies +- Test disaster recovery procedures + +### Annually +- Review certificate strategy +- Update contact information +- Audit certificate usage + +This comprehensive certificate management ensures 99.9% uptime for SSL certificates with automatic renewal and monitoring. \ No newline at end of file diff --git a/deploy/DNS-SETUP.md b/deploy/DNS-SETUP.md new file mode 100644 index 00000000..c4874d99 --- /dev/null +++ b/deploy/DNS-SETUP.md @@ -0,0 +1,144 @@ +# DNS Configuration Guide for ORAssistant + +This guide explains how to connect your GKE deployment to a public domain. + +## Prerequisites + +- A registered domain name (e.g., `mycompany.com`) +- Access to your domain's DNS settings +- GKE cluster deployed with the provided manifests + +## Step 1: Reserve Static IP + +```bash +# Navigate to deploy directory +cd deploy + +# Reserve a global static IP address +gcloud compute addresses create orassistant-ip --global + +# Get the IP address (save this for DNS configuration) +gcloud compute addresses describe orassistant-ip --global --format="value(address)" +``` + +## Step 2: Configure DNS Records + +In your domain registrar or DNS provider (Cloudflare, Route53, etc.), create: + +### A Record +- **Name**: `orassistant` (or your preferred subdomain) +- **Type**: `A` +- **Value**: `[Static IP from Step 1]` +- **TTL**: `300` seconds + +### Optional CNAME for www +- **Name**: `www.orassistant` +- **Type**: `CNAME` +- **Value**: `orassistant.your-domain.com` +- **TTL**: `300` seconds + +## Step 3: Update Kubernetes Manifests + +### Option A: Use the automated script +```bash +# Run the domain setup script +./domain-setup.sh your-domain.com +``` + +### Option B: Manual update +Replace `your-domain.com` in these files: +- `ingress.yaml` (lines 15, 36) +- Update the ManagedCertificate domains + +## Step 4: Deploy the Application + +```bash +# Deploy all manifests +make gke-up + +# Or deploy manually +kubectl apply -f namespace.yaml +kubectl apply -f configmap.yaml +kubectl apply -f secrets.yaml +kubectl apply -f persistent-volume.yaml +kubectl apply -f backend-deployment.yaml +kubectl apply -f frontend-deployment.yaml +kubectl apply -f services.yaml +kubectl apply -f load-balancer.yaml +kubectl apply -f hpa.yaml +kubectl apply -f ingress.yaml +``` + +## Step 5: Wait for SSL Certificate + +The Google-managed SSL certificate will provision automatically: + +```bash +# Check certificate status (takes 5-10 minutes) +kubectl get managedcertificate orassistant-ssl-cert -n orassistant + +# Status should show 'Active' when ready +kubectl describe managedcertificate orassistant-ssl-cert -n orassistant +``` + +## Step 6: Verify Deployment + +```bash +# Check all resources +kubectl get all -n orassistant + +# Check ingress external IP +kubectl get ingress orassistant-ingress -n orassistant + +# Test the application +curl -I https://orassistant.your-domain.com +``` + +## Troubleshooting + +### DNS Not Resolving +```bash +# Check DNS propagation +nslookup orassistant.your-domain.com +dig orassistant.your-domain.com +``` + +### SSL Certificate Issues +```bash +# Check certificate status +kubectl describe managedcertificate orassistant-ssl-cert -n orassistant + +# Common issues: +# - DNS not propagated (wait 10-15 minutes) +# - Domain mismatch in ingress.yaml +# - Certificate quota exceeded +``` + +### Backend Connection Issues +```bash +# Check backend service +kubectl get svc backend-internal-lb -n orassistant + +# Check backend pods +kubectl get pods -n orassistant -l app=backend +``` + +## Cost Optimization + +- The static IP costs ~$0.75/month when in use +- Managed SSL certificates are free +- Internal load balancer reduces data transfer costs + +## Security Considerations + +- Backend services are only accessible internally +- SSL termination at the load balancer +- Network policies can be added for additional security + +## Example Final URLs + +- **Main Application**: `https://orassistant.your-domain.com` +- **API Endpoints**: `https://orassistant.your-domain.com/api/*` +- **Health Check**: `https://orassistant.your-domain.com/api/healthcheck` + +Replace `your-domain.com` with your actual domain name. \ No newline at end of file diff --git a/deploy/ENV-SETUP.md b/deploy/ENV-SETUP.md new file mode 100644 index 00000000..01f923f4 --- /dev/null +++ b/deploy/ENV-SETUP.md @@ -0,0 +1,272 @@ +# Environment Configuration Guide + +This guide explains how to configure all the necessary secrets and variables for your ORAssistant GKE deployment. + +## 🔧 Quick Setup + +### Automated Setup (Recommended) +```bash +cd deploy +./env-setup.sh +``` + +The script will: +- Prompt for required values +- Generate random secrets automatically +- Base64 encode all secrets +- Create a complete .env file + +### Manual Setup +```bash +# Copy template and edit +cp .env.template .env +# Edit .env with your values +``` + +## 📋 Required Configuration + +### 1. **Project Information** +```bash +PROJECT_ID=your-gcp-project-id # GCP Project ID +DOMAIN=your-domain.com # Your domain name +REGION=us-central1 # GCP region +``` + +### 2. **Critical Secrets** (Base64 encoded) +```bash +# Required for functionality +OPENAI_API_KEY= # OpenAI API key +GOOGLE_API_KEY= # Google AI/Vertex AI key +HUGGINGFACE_TOKEN= # HuggingFace token + +# Database connection +MONGODB_URI= # MongoDB connection string + +# Application security (auto-generated) +JWT_SECRET_KEY= # JWT signing key +SESSION_SECRET= # Session encryption +``` + +### 3. **Optional Secrets** +```bash +ANTHROPIC_API_KEY= # Claude API (optional) +COHERE_API_KEY= # Cohere API (optional) +GOOGLE_SHEETS_CREDENTIALS= # Google Sheets integration +``` + +## 🔐 Secret Encoding + +### Base64 Encoding Commands +```bash +# Encode a secret +echo -n "your-secret-value" | base64 + +# Encode a file (for JSON credentials) +cat service-account.json | base64 -w 0 + +# Generate random secret +openssl rand -hex 32 | base64 +``` + +### Example Encodings +```bash +# OpenAI API Key +echo -n "sk-proj-abcd1234..." | base64 +# Output: c2stcHJvai1hYmNkMTIzNC4uLg== + +# MongoDB URI +echo -n "mongodb://user:pass@cluster.mongodb.net/db" | base64 +# Output: bW9uZ29kYjovL3VzZXI6cGFzc0BjbHVzdGVyLm1vbmdvZGIubmV0L2Ri + +# Random JWT secret +openssl rand -hex 32 | base64 +# Output: NDJhYzFkMzRmOGE3YjllM2RjOGYyZWE1... +``` + +## 📁 Environment Files + +### `.env.template` +- Template with all available variables +- Use as reference for configuration +- Safe to commit to version control + +### `.env.example` +- Example with realistic values +- Shows proper formatting +- Safe to commit to version control + +### `.env.secrets-only` +- Contains only secrets/credentials +- Minimal file for security-conscious setups +- **Never commit to version control** + +### `.env` (Generated) +- Your actual configuration +- Created by env-setup.sh or manually +- **Never commit to version control** + +## 🔒 Security Best Practices + +### 1. **Secret Management** +```bash +# Add to .gitignore immediately +echo ".env" >> .gitignore + +# Set restrictive permissions +chmod 600 .env + +# Use separate environments +.env.development +.env.staging +.env.production +``` + +### 2. **Secret Generation** +```bash +# Generate strong secrets +openssl rand -hex 32 # 64-character hex string +openssl rand -base64 32 # 44-character base64 string + +# Check secret strength +echo "your-secret" | wc -c # Should be >20 characters +``` + +### 3. **Production Recommendations** +- Use Google Secret Manager +- Implement secret rotation +- Monitor API key usage +- Set up usage alerts +- Use sealed-secrets for GitOps + +## 🚀 Deployment Process + +### 1. **Configure Environment** +```bash +./env-setup.sh +# or +cp .env.template .env && nano .env +``` + +### 2. **Validate Configuration** +```bash +# Check required secrets are set +grep -E "(OPENAI_API_KEY|PROJECT_ID|DOMAIN)" .env + +# Verify base64 encoding +echo "c2stdGVzdA==" | base64 -d # Should output: sk-test +``` + +### 3. **Deploy** +```bash +make gke-up +``` + +## 🔍 Configuration Validation + +### Required Variables Checklist +- [ ] PROJECT_ID (GCP project) +- [ ] DOMAIN (your domain) +- [ ] OPENAI_API_KEY (base64 encoded) +- [ ] GOOGLE_API_KEY (base64 encoded) +- [ ] HUGGINGFACE_TOKEN (base64 encoded) +- [ ] JWT_SECRET_KEY (auto-generated) +- [ ] SESSION_SECRET (auto-generated) + +### Validation Commands +```bash +# Check if all required variables are set +required_vars="PROJECT_ID DOMAIN OPENAI_API_KEY GOOGLE_API_KEY HUGGINGFACE_TOKEN" +for var in $required_vars; do + if grep -q "^${var}=" .env && [ "$(grep "^${var}=" .env | cut -d'=' -f2)" != "" ]; then + echo "✓ $var is set" + else + echo "✗ $var is missing or empty" + fi +done + +# Test base64 decoding (shouldn't error) +OPENAI_KEY=$(grep "OPENAI_API_KEY=" .env | cut -d'=' -f2) +echo "$OPENAI_KEY" | base64 -d >/dev/null && echo "✓ Valid base64" || echo "✗ Invalid base64" +``` + +## 🆘 Troubleshooting + +### Common Issues + +#### 1. **Invalid Base64 Encoding** +```bash +# Error: invalid input +echo "your-secret" | base64 # Wrong - adds newline +echo -n "your-secret" | base64 # Correct - no newline +``` + +#### 2. **Missing Required Variables** +```bash +# Check what's missing +./env-setup.sh # Re-run setup script +# or +diff .env.template .env +``` + +#### 3. **API Key Format Issues** +```bash +# OpenAI keys start with 'sk-' +# Google keys start with 'AIza' +# HuggingFace tokens start with 'hf_' + +# Verify key format before encoding +echo -n "$OPENAI_KEY" | base64 -d # Should start with 'sk-' +``` + +#### 4. **File Permission Errors** +```bash +# Fix permissions +chmod 600 .env +chown $(whoami):$(whoami) .env +``` + +### Debug Commands +```bash +# Check environment variables +env | grep -E "(PROJECT_ID|DOMAIN|API_KEY)" + +# Validate .env file syntax +bash -n <(sed 's/^/export /' .env) + +# Test secret decoding +source .env && echo $OPENAI_API_KEY | base64 -d +``` + +## 📚 Additional Resources + +- [Google Secret Manager](https://cloud.google.com/secret-manager) +- [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) +- [OpenAI API Keys](https://platform.openai.com/api-keys) +- [HuggingFace Tokens](https://huggingface.co/settings/tokens) +- [Base64 Encoding](https://en.wikipedia.org/wiki/Base64) + +## 🔄 Environment Updates + +### Adding New Secrets +```bash +# Add to .env +echo "NEW_SECRET=$(echo -n 'new-value' | base64)" >> .env + +# Update Kubernetes secret +kubectl delete secret orassistant-secrets -n orassistant +kubectl create secret generic orassistant-secrets --from-env-file=.env -n orassistant +``` + +### Rotating Secrets +```bash +# Generate new secret +NEW_JWT=$(openssl rand -hex 32 | base64) + +# Update .env +sed -i "s/JWT_SECRET_KEY=.*/JWT_SECRET_KEY=$NEW_JWT/" .env + +# Redeploy +make deploy +``` + +This comprehensive configuration ensures secure, flexible deployment across all environments. \ No newline at end of file diff --git a/deploy/Makefile b/deploy/Makefile index 6c8b66df..e6aa07c2 100644 --- a/deploy/Makefile +++ b/deploy/Makefile @@ -1,27 +1,212 @@ -.PHONY: init +.PHONY: init setup build-images deploy gke-up gke-down status clean format check + +# Project configuration +PROJECT_ID ?= your-gcp-project-id +DOMAIN ?= your-domain.com +REGION ?= us-central1 +CLUSTER_NAME ?= orassistant-cluster init: - @echo "Initializing project..." + @echo "Initializing GKE deployment..." + @echo "Make sure you have configured:" + @echo " - PROJECT_ID: $(PROJECT_ID)" + @echo " - DOMAIN: $(DOMAIN)" + @echo " - REGION: $(REGION)" -format: - @echo "Formatting code..." +# Setup GKE cluster and node pools +setup-cluster: + @echo "Creating GKE cluster with optimized node pools..." + gcloud container clusters create $(CLUSTER_NAME) \ + --region=$(REGION) \ + --node-locations=$(REGION)-a,$(REGION)-b,$(REGION)-c \ + --enable-network-policy \ + --enable-ip-alias \ + --enable-autoscaling \ + --enable-autorepair \ + --enable-autoupgrade \ + --maintenance-window-start=2023-01-01T09:00:00Z \ + --maintenance-window-end=2023-01-01T17:00:00Z \ + --maintenance-window-recurrence="FREQ=WEEKLY;BYDAY=SA" \ + --num-nodes=0 \ + --logging=SYSTEM,WORKLOAD \ + --monitoring=SYSTEM + + # Create backend node pool (n1-standard-4) + gcloud container node-pools create backend-pool \ + --cluster=$(CLUSTER_NAME) \ + --region=$(REGION) \ + --machine-type=n1-standard-4 \ + --disk-size=50GB \ + --disk-type=pd-ssd \ + --enable-autoscaling \ + --min-nodes=1 \ + --max-nodes=3 \ + --enable-autorepair \ + --enable-autoupgrade \ + --node-taints=backend-workload=true:NoSchedule \ + --node-labels=workload-type=backend,cloud.google.com/gke-nodepool=backend-pool + + # Create frontend node pool (n1-standard-2) + gcloud container node-pools create frontend-pool \ + --cluster=$(CLUSTER_NAME) \ + --region=$(REGION) \ + --machine-type=n1-standard-2 \ + --disk-size=20GB \ + --disk-type=pd-ssd \ + --enable-autoscaling \ + --min-nodes=1 \ + --max-nodes=2 \ + --enable-autorepair \ + --enable-autoupgrade \ + --node-taints=frontend-workload=true:NoSchedule \ + --node-labels=workload-type=frontend,cloud.google.com/gke-nodepool=frontend-pool -check: - @echo "Checking code..." +# Build and push Docker images +build-images: + @echo "Building and pushing Docker images..." + # Build backend image + cd ../backend && docker build -t gcr.io/$(PROJECT_ID)/orassistant-backend:latest . + docker push gcr.io/$(PROJECT_ID)/orassistant-backend:latest + + # Build frontend image + cd ../frontend/nextjs-frontend && docker build -t gcr.io/$(PROJECT_ID)/orassistant-frontend:latest . + docker push gcr.io/$(PROJECT_ID)/orassistant-frontend:latest -convert: - @echo "Converting docker-compose to kubernetes..." - @kompose convert -f ../docker-compose.yml +# Setup domain and static IP +setup-domain: + @echo "Setting up domain and SSL configuration..." + ./domain-setup.sh $(DOMAIN) + +# Deploy application to GKE +deploy: + @echo "Deploying ORAssistant to GKE..." + # Update image references in deployments + sed -i 's|gcr.io/PROJECT_ID|gcr.io/$(PROJECT_ID)|g' backend-deployment.yaml + sed -i 's|gcr.io/PROJECT_ID|gcr.io/$(PROJECT_ID)|g' frontend-deployment.yaml + + # Apply all manifests in order + kubectl apply -f namespace.yaml + kubectl apply -f configmap.yaml + kubectl apply -f secrets.yaml + kubectl apply -f persistent-volume.yaml + kubectl apply -f ssl-policy.yaml + kubectl apply -f services.yaml + kubectl apply -f backend-deployment.yaml + kubectl apply -f frontend-deployment.yaml + kubectl apply -f load-balancer.yaml + kubectl apply -f hpa.yaml + kubectl apply -f ingress.yaml + kubectl apply -f certificate-management.yaml + +# Complete GKE setup (cluster + deploy) +gke-up: setup-cluster build-images setup-domain deploy + @echo "GKE deployment completed!" + @echo "Waiting for services to be ready..." + @kubectl wait --for=condition=Ready pod -l app=backend -n orassistant --timeout=300s + @kubectl wait --for=condition=Ready pod -l app=frontend -n orassistant --timeout=300s + @make status -gke-up: - @echo "Deploying to kubernetes..." - @kubectl apply -f . +# Deploy only (assumes cluster exists) +deploy-only: build-images deploy + @echo "Application deployed to existing cluster" + @make status +# Remove all resources gke-down: - @echo "Undeploying from kubernetes..." - @kubectl delete -f . + @echo "Removing ORAssistant from GKE..." + @kubectl delete -f . --ignore-not-found=true + @kubectl delete namespace orassistant --ignore-not-found=true +# Delete entire cluster +delete-cluster: + @echo "Deleting GKE cluster..." + @gcloud container clusters delete $(CLUSTER_NAME) --region=$(REGION) --quiet + +# Check deployment status status: - @echo "Checking status of kubernetes deployment..." - @kubectl get pods -o json - @kubectl get services -o json + @echo "=== ORAssistant GKE Deployment Status ===" + @echo "" + @echo "Namespace:" + @kubectl get namespace orassistant 2>/dev/null || echo "Namespace not found" + @echo "" + @echo "Pods:" + @kubectl get pods -n orassistant -o wide + @echo "" + @echo "Services:" + @kubectl get services -n orassistant + @echo "" + @echo "Ingress:" + @kubectl get ingress -n orassistant + @echo "" + @echo "HPA Status:" + @kubectl get hpa -n orassistant + @echo "" + @echo "SSL Certificates:" + @kubectl get managedcertificate -n orassistant + @echo "" + @echo "Recent Events:" + @kubectl get events -n orassistant --sort-by=.metadata.creationTimestamp | tail -10 + +# Detailed status with logs +debug: + @echo "=== Debug Information ===" + @echo "Backend pods:" + @kubectl describe pods -l app=backend -n orassistant + @echo "" + @echo "Frontend pods:" + @kubectl describe pods -l app=frontend -n orassistant + @echo "" + @echo "Backend logs:" + @kubectl logs -l app=backend -n orassistant --tail=50 + @echo "" + @echo "Frontend logs:" + @kubectl logs -l app=frontend -n orassistant --tail=50 + +# Scale application +scale-up: + @echo "Scaling up application..." + @kubectl scale deployment backend-deployment --replicas=3 -n orassistant + @kubectl scale deployment frontend-deployment --replicas=2 -n orassistant + +scale-down: + @echo "Scaling down application..." + @kubectl scale deployment backend-deployment --replicas=1 -n orassistant + @kubectl scale deployment frontend-deployment --replicas=1 -n orassistant + +# Security and monitoring +apply-security: + @echo "Applying security policies..." + @kubectl apply -f network-policies.yaml + +# Clean up resources +clean: + @echo "Cleaning up local files..." + @docker system prune -f + @gcloud container images list-tags gcr.io/$(PROJECT_ID)/orassistant-backend --filter='-tags:*' --format='value(digest)' --limit=10 | xargs -I {} gcloud container images delete gcr.io/$(PROJECT_ID)/orassistant-backend@{} --quiet + @gcloud container images list-tags gcr.io/$(PROJECT_ID)/orassistant-frontend --filter='-tags:*' --format='value(digest)' --limit=10 | xargs -I {} gcloud container images delete gcr.io/$(PROJECT_ID)/orassistant-frontend@{} --quiet + +# Development helpers +logs-backend: + @kubectl logs -f deployment/backend-deployment -n orassistant + +logs-frontend: + @kubectl logs -f deployment/frontend-deployment -n orassistant + +shell-backend: + @kubectl exec -it deployment/backend-deployment -n orassistant -- /bin/bash + +shell-frontend: + @kubectl exec -it deployment/frontend-deployment -n orassistant -- /bin/sh + +# Legacy support (for compatibility) +convert: + @echo "Note: kompose conversion replaced with optimized Kubernetes manifests" + @echo "Use 'make deploy' instead" + +format: + @echo "Formatting Kubernetes manifests..." + @which kubectl >/dev/null && kubectl apply --dry-run=client -f . || echo "kubectl not available for validation" + +check: + @echo "Checking Kubernetes manifests..." + @kubectl apply --dry-run=client -f . diff --git a/deploy/README.md b/deploy/README.md index 0be1f6cb..4a789b26 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -1,53 +1,254 @@ -# Deployment using Google Kubernetes Engine (GKE) +# Cost-Efficient GKE Deployment for ORAssistant -Why GKE? This is to maintain a cloud-agnostic Kubernetes solution -which can be easily migrated to other services if needed. +This directory contains optimized Kubernetes manifests for deploying ORAssistant on Google Kubernetes Engine (GKE) with significant cost savings and improved performance. -## Prerequisites +## 🎯 Cost Optimization Summary -0. Install `gcloud` CLI [(guide)](https://cloud.google.com/sdk/docs/install) and -`kompose` CLI for converting `docker-compose.yml` to Kubernetes manifests -[(guide)](https://kompose.io/installation/). +- **Previous Cost**: $2000-3000/month (n1-standard-32 + n1-standard-16) +- **Optimized Cost**: $250-620/month (right-sized nodes + autoscaling) +- **Savings**: 75-90% cost reduction +- **Performance**: Better scalability and reliability -The `kubectl` [(guide)](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) -CLI is also needed for running commands against Kubernetes clusters. - -Once installed, verify that these binaries are available: +## 📋 Prerequisites +### Required Tools ```bash -kompose --version -gcloud --version -kubectl version --client +# Install required CLI tools +gcloud --version # Google Cloud CLI +kubectl version --client # Kubernetes CLI +docker --version # Docker for building images +helm version # Helm (for cert-manager) ``` -1. Authenticate GCP environment. - +### GCP Authentication ```bash gcloud auth login -gcloud config set project _PROJECT_ID_ +gcloud auth configure-docker +gcloud config set project YOUR_PROJECT_ID ``` -## Kubernetes configuration +## 🏗️ Architecture Overview + +### Node Configuration +- **Backend Pool**: 1-3 × n1-standard-4 (4 vCPUs, 15GB RAM) +- **Frontend Pool**: 1-2 × n1-standard-2 (2 vCPUs, 7.5GB RAM) +- **Storage**: 10GB Regional PD for RAG dataset (shared) + +### Load Balancer Strategy +- **External LB**: Public traffic → Frontend +- **Internal LB**: Frontend → Backend (private network) +- **Cost Benefit**: Reduced data transfer costs + +### Security Features +- Network policies for traffic isolation +- HTTPS-only with auto SSL certificates +- Private backend services +- Resource limits and monitoring -The infrastructure consists of two nodes, as follows: -- Backend: n1-standard-32 -- Frontend: n1-standard-16 -- other components... +## 🚀 Quick Start -Refer to the Makefile for GKE deployment commands. This is specifically placed -in this folder to avoid confusion with the instructions in the root directory, -which creates a local deployment. +### 1. Configure Environment +```bash +# Set your project configuration +export PROJECT_ID="your-gcp-project-id" +export DOMAIN="your-domain.com" +export REGION="us-central1" + +# Or edit deploy/Makefile directly +``` +### 2. Complete Deployment ```bash -make convert -make gke-up -make gke-down +cd deploy + +# Full deployment (creates cluster + deploys app) +make gke-up PROJECT_ID=$PROJECT_ID DOMAIN=$DOMAIN + +# Check deployment status make status ``` -## Migration Resources +### 3. Deploy to Existing Cluster +```bash +# If cluster already exists +make deploy-only PROJECT_ID=$PROJECT_ID + +# Manual deployment steps +make build-images +make setup-domain +make deploy +``` + +## 📁 File Structure + +### Core Manifests +- `namespace.yaml` - Dedicated namespace +- `configmap.yaml` - Application configuration +- `secrets.yaml` - API keys and credentials (configure before deploy) +- `persistent-volume.yaml` - Shared storage for RAG dataset + +### Application Deployments +- `backend-deployment.yaml` - FastAPI backend with resource limits +- `frontend-deployment.yaml` - Next.js frontend with optimization +- `services.yaml` - Internal service communication +- `hpa.yaml` - Horizontal Pod Autoscaling + +### Networking & Security +- `load-balancer.yaml` - External/internal load balancer config +- `ingress.yaml` - HTTPS ingress with SSL termination +- `network-policies.yaml` - Security traffic policies +- `ssl-policy.yaml` - Enhanced SSL configuration + +### SSL Certificate Management +- `certificate-management.yaml` - Google-managed + cert-manager SSL +- `cert-manager-setup.sh` - Automated certificate setup +- `CERTIFICATE-MANAGEMENT.md` - Complete SSL guide + +### Domain Integration +- `dns-configuration.yaml` - DNS setup instructions +- `domain-setup.sh` - Automated domain configuration +- `DNS-SETUP.md` - Complete domain setup guide + +## ⚙️ Configuration + +### 1. Configure Secrets +```bash +# Edit secrets.yaml with your API keys (base64 encoded) +kubectl create secret generic orassistant-secrets \ + --from-literal=OPENAI_API_KEY="your-key" \ + --from-literal=GOOGLE_API_KEY="your-key" \ + --from-literal=HUGGINGFACE_TOKEN="your-token" \ + --namespace=orassistant +``` + +### 2. Set Up Domain +```bash +# Automated domain setup +./domain-setup.sh your-domain.com + +# Manual steps in DNS-SETUP.md +``` + +### 3. Build and Deploy +```bash +# Build images +make build-images PROJECT_ID=$PROJECT_ID + +# Deploy application +make deploy +``` + +## 🔍 Monitoring & Management + +### Check Status +```bash +make status # Overall deployment status +make debug # Detailed debugging info +kubectl get all -n orassistant +``` + +### View Logs +```bash +make logs-backend # Backend logs +make logs-frontend # Frontend logs +kubectl logs -f deployment/backend-deployment -n orassistant +``` + +### Scaling +```bash +make scale-up # Scale to full capacity +make scale-down # Scale to minimum +kubectl scale deployment backend-deployment --replicas=3 -n orassistant +``` + +## 🛡️ Security Features + +### Network Policies +```bash +make apply-security # Apply network security policies +``` + +### SSL Certificates +- Google-managed SSL (automatic renewal) +- cert-manager backup (Let's Encrypt) +- Certificate monitoring and alerting + +### Access Control +- Private backend services (internal LB only) +- Resource limits and quotas +- Network traffic isolation + +## 💰 Cost Management + +### Current Costs +- **Cluster**: $250-620/month (optimized nodes) +- **Load Balancer**: ~$20/month +- **Storage**: ~$2/month (10GB PD) +- **SSL Certificates**: Free (Google-managed) + +### Cost Optimization Features +- Horizontal Pod Autoscaling (scale pods before nodes) +- Right-sized node pools (no over-provisioning) +- Regional persistent disks (cost-efficient) +- Internal load balancer for backend traffic + +### Clean Up +```bash +make gke-down # Remove application +make delete-cluster # Remove entire cluster +make clean # Clean local images +``` + +## 🔧 Advanced Usage + +### Development Helpers +```bash +make shell-backend # Shell into backend pod +make shell-frontend # Shell into frontend pod +kubectl exec -it deployment/backend-deployment -n orassistant -- bash +``` + +### Certificate Management +```bash +./cert-manager-setup.sh your-domain.com admin@your-domain.com full +kubectl get managedcertificate -n orassistant +``` + +### Debugging +```bash +kubectl describe pods -l app=backend -n orassistant +kubectl get events -n orassistant --sort-by=.metadata.creationTimestamp +``` + +## 📚 Documentation + +- `CERTIFICATE-MANAGEMENT.md` - Complete SSL certificate guide +- `DNS-SETUP.md` - Domain configuration walkthrough +- `network-policies.yaml` - Security policy documentation + +## 🔄 Migration Resources 1. [GKE to EKS](https://github.com/awslabs/aws-kubernetes-migration-factory) 2. [EKS to GKE](https://cloud.google.com/kubernetes-engine/multi-cloud/docs/attached/eks/how-to/migrate-cluster) 3. [AKS to GKE](https://cloud.google.com/kubernetes-engine/multi-cloud/docs/attached/aks/how-to/migrate-cluster) 4. [GKE multi-cloud](https://cloud.google.com/kubernetes-engine/multi-cloud/) + +## 🆘 Troubleshooting + +### Common Issues +1. **Pod stuck in Pending**: Check node capacity and resource requests +2. **SSL certificate not ready**: Wait 5-10 minutes, check DNS propagation +3. **Backend connection errors**: Verify internal load balancer configuration +4. **Out of resources**: Check HPA and cluster autoscaler settings + +### Support +```bash +# Check cluster events +kubectl get events --sort-by=.metadata.creationTimestamp + +# Check resource usage +kubectl top nodes +kubectl top pods -n orassistant +``` + +This deployment provides production-ready, cost-optimized ORAssistant hosting with enterprise security and scalability features. diff --git a/deploy/cert-manager-setup.sh b/deploy/cert-manager-setup.sh new file mode 100755 index 00000000..71358a36 --- /dev/null +++ b/deploy/cert-manager-setup.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +# Certificate Management Setup Script for ORAssistant +# This script sets up both Google-managed certificates and cert-manager as backup + +set -e + +DOMAIN=${1:-"your-domain.com"} +EMAIL=${2:-"admin@${DOMAIN}"} +NAMESPACE="orassistant" + +echo "Setting up certificate management for domain: $DOMAIN" +echo "Admin email: $EMAIL" + +# Function to install cert-manager +install_cert_manager() { + echo "Installing cert-manager..." + + # Add cert-manager helm repository + helm repo add jetstack https://charts.jetstack.io + helm repo update + + # Install cert-manager + helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --set installCRDs=true \ + --version v1.13.0 + + # Wait for cert-manager to be ready + echo "Waiting for cert-manager to be ready..." + kubectl wait --for=condition=Ready pod -l app=cert-manager -n cert-manager --timeout=300s + kubectl wait --for=condition=Ready pod -l app=webhook -n cert-manager --timeout=300s + kubectl wait --for=condition=Ready pod -l app=cainjector -n cert-manager --timeout=300s +} + +# Function to setup certificate management +setup_certificates() { + echo "Setting up certificate configuration..." + + # Update certificate files with actual domain and email + sed -i "s/your-domain\.com/$DOMAIN/g" certificate-management.yaml + sed -i "s/admin@your-domain\.com/$EMAIL/g" certificate-management.yaml + + # Apply certificate configuration + kubectl apply -f certificate-management.yaml +} + +# Function to check certificate status +check_certificate_status() { + echo "Checking certificate status..." + + # Check Google-managed certificate + echo "Google-managed certificate status:" + kubectl get managedcertificate orassistant-ssl-cert -n $NAMESPACE -o jsonpath='{.status.certificateStatus}' || echo "Not found" + + # Check cert-manager certificate (if exists) + echo "cert-manager certificate status:" + kubectl get certificate orassistant-letsencrypt-cert -n $NAMESPACE -o jsonpath='{.status.conditions[0].type}' || echo "Not found" +} + +# Main execution +case "${3:-setup}" in + "install-cert-manager") + install_cert_manager + ;; + "setup") + setup_certificates + ;; + "status") + check_certificate_status + ;; + "full") + install_cert_manager + setup_certificates + echo "Waiting 30 seconds for resources to be created..." + sleep 30 + check_certificate_status + ;; + *) + echo "Usage: $0 [install-cert-manager|setup|status|full]" + echo "Example: $0 mycompany.com admin@mycompany.com full" + exit 1 + ;; +esac + +echo "Certificate management setup completed!" +echo "" +echo "Next steps:" +echo "1. Wait 5-10 minutes for Google-managed certificate to provision" +echo "2. Check status: kubectl get managedcertificate orassistant-ssl-cert -n $NAMESPACE" +echo "3. Monitor certificate: kubectl logs -f deployment/cert-monitor -n $NAMESPACE" \ No newline at end of file diff --git a/deploy/certificate-management.yaml b/deploy/certificate-management.yaml new file mode 100644 index 00000000..9ca9073b --- /dev/null +++ b/deploy/certificate-management.yaml @@ -0,0 +1,103 @@ +# Google-managed SSL Certificate (Primary Method) +apiVersion: networking.gke.io/v1 +kind: ManagedCertificate +metadata: + name: orassistant-ssl-cert + namespace: orassistant + labels: + app: orassistant + cert-type: managed +spec: + domains: + - orassistant.your-domain.com + - www.orassistant.your-domain.com +--- +# Backup/Alternative: cert-manager with Let's Encrypt +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: admin@your-domain.com + privateKeySecretRef: + name: letsencrypt-prod + solvers: + - http01: + ingress: + class: gce +--- +# Let's Encrypt Certificate (Alternative) +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: orassistant-letsencrypt-cert + namespace: orassistant +spec: + secretName: orassistant-tls-secret + issuerRef: + name: letsencrypt-prod + kind: ClusterIssuer + dnsNames: + - orassistant.your-domain.com + - www.orassistant.your-domain.com +--- +# Certificate monitoring and alerting +apiVersion: v1 +kind: ConfigMap +metadata: + name: cert-monitor-config + namespace: orassistant +data: + cert-check.sh: | + #!/bin/bash + # Certificate monitoring script + + DOMAIN="orassistant.your-domain.com" + + # Check certificate expiration + CERT_INFO=$(echo | openssl s_client -servername $DOMAIN -connect $DOMAIN:443 2>/dev/null | openssl x509 -noout -dates) + EXPIRY_DATE=$(echo "$CERT_INFO" | grep notAfter | cut -d'=' -f2) + EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s) + CURRENT_TIMESTAMP=$(date +%s) + DAYS_UNTIL_EXPIRY=$(( (EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP) / 86400 )) + + echo "Certificate expires in $DAYS_UNTIL_EXPIRY days" + + # Alert if certificate expires in less than 30 days + if [ $DAYS_UNTIL_EXPIRY -lt 30 ]; then + echo "WARNING: Certificate expires in $DAYS_UNTIL_EXPIRY days!" + # Add your alerting logic here (email, Slack, etc.) + fi +--- +# CronJob for certificate monitoring +apiVersion: batch/v1 +kind: CronJob +metadata: + name: cert-monitor + namespace: orassistant +spec: + schedule: "0 9 * * *" # Daily at 9 AM + jobTemplate: + spec: + template: + spec: + containers: + - name: cert-checker + image: alpine:latest + command: + - /bin/sh + - -c + - | + apk add --no-cache openssl curl + /scripts/cert-check.sh + volumeMounts: + - name: cert-scripts + mountPath: /scripts + volumes: + - name: cert-scripts + configMap: + name: cert-monitor-config + defaultMode: 0755 + restartPolicy: OnFailure \ No newline at end of file diff --git a/deploy/configmap.yaml b/deploy/configmap.yaml new file mode 100644 index 00000000..a6985b63 --- /dev/null +++ b/deploy/configmap.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: orassistant-config + namespace: orassistant + labels: + app: orassistant + component: config +data: + # Backend configuration + BACKEND_URL: "0.0.0.0" + BACKEND_WORKERS: "2" + HEALTHCHECK_INTERVAL: "30s" + HEALTHCHECK_TIMEOUT: "10s" + HEALTHCHECK_RETRIES: "5" + HEALTHCHECK_START_PERIOD: "180s" + + # Frontend configuration + NODE_ENV: "production" + NEXT_PUBLIC_BACKEND_URL: "http://backend-internal-lb:8000" + + # Application configuration + LOG_LEVEL: "info" + ENVIRONMENT: "production" + + # RAG configuration + RAG_DATA_PATH: "/ORAssistant-backend/data" + VECTOR_STORE_PATH: "/ORAssistant-backend/data/vectorstore" + + # Performance tuning + MAX_CONCURRENT_REQUESTS: "100" + REQUEST_TIMEOUT: "30s" + VECTOR_SEARCH_TIMEOUT: "10s" \ No newline at end of file diff --git a/deploy/dns-configuration.yaml b/deploy/dns-configuration.yaml new file mode 100644 index 00000000..ea81599c --- /dev/null +++ b/deploy/dns-configuration.yaml @@ -0,0 +1,61 @@ +# Static IP reservation for the load balancer +apiVersion: v1 +kind: ConfigMap +metadata: + name: dns-setup-instructions + namespace: orassistant +data: + setup-instructions.md: | + # DNS Configuration for ORAssistant + + ## 1. Reserve Static IP + ```bash + # Reserve a global static IP + gcloud compute addresses create orassistant-ip --global + + # Get the IP address + gcloud compute addresses describe orassistant-ip --global --format="value(address)" + ``` + + ## 2. Configure DNS Records + In your domain registrar or DNS provider (e.g., Cloudflare, Route53, etc.): + + ### A Record: + - **Name**: orassistant (or your subdomain) + - **Type**: A + - **Value**: [IP from step 1] + - **TTL**: 300 seconds + + ### CNAME Record (optional, for www): + - **Name**: www.orassistant + - **Type**: CNAME + - **Value**: orassistant.your-domain.com + - **TTL**: 300 seconds + + ## 3. Update Kubernetes Manifests + Replace 'your-domain.com' in the following files: + - `ingress.yaml` (line 15, 36) + - `managed-certificate.yaml` (line 10) + + ## 4. SSL Certificate + The managed certificate will automatically provision once DNS is configured. + + ## 5. Verification + ```bash + # Check certificate status + kubectl get managedcertificate orassistant-ssl-cert -n orassistant + + # Check ingress status + kubectl get ingress orassistant-ingress -n orassistant + ``` +--- +# DNS configuration for development/staging +apiVersion: v1 +kind: ConfigMap +metadata: + name: dns-dev-config + namespace: orassistant +data: + dev-domain: "dev.orassistant.your-domain.com" + staging-domain: "staging.orassistant.your-domain.com" + prod-domain: "orassistant.your-domain.com" \ No newline at end of file diff --git a/deploy/domain-setup.sh b/deploy/domain-setup.sh new file mode 100755 index 00000000..0a8b2651 --- /dev/null +++ b/deploy/domain-setup.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# Domain Setup Script for ORAssistant GKE Deployment +# Usage: ./domain-setup.sh your-domain.com + +set -e + +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 mycompany.com" + exit 1 +fi + +DOMAIN=$1 +SUBDOMAIN="orassistant" +FULL_DOMAIN="${SUBDOMAIN}.${DOMAIN}" + +echo "Setting up domain configuration for: $FULL_DOMAIN" + +# 1. Reserve static IP +echo "Reserving static IP..." +gcloud compute addresses create orassistant-ip --global || echo "IP already exists" + +# 2. Get the IP address +STATIC_IP=$(gcloud compute addresses describe orassistant-ip --global --format="value(address)") +echo "Static IP: $STATIC_IP" + +# 3. Update ingress.yaml with the domain +echo "Updating ingress configuration..." +sed -i "s/orassistant\.your-domain\.com/$FULL_DOMAIN/g" ingress.yaml + +# 4. Update managed certificate +echo "Updating SSL certificate configuration..." +sed -i "s/orassistant\.your-domain\.com/$FULL_DOMAIN/g" ingress.yaml + +# 5. Create domain-specific configmap +cat > domain-config.yaml << EOF +apiVersion: v1 +kind: ConfigMap +metadata: + name: domain-config + namespace: orassistant +data: + DOMAIN: "$DOMAIN" + SUBDOMAIN: "$SUBDOMAIN" + FULL_DOMAIN: "$FULL_DOMAIN" + STATIC_IP: "$STATIC_IP" +EOF + +echo "Domain configuration completed!" +echo "" +echo "Next steps:" +echo "1. Configure DNS A record:" +echo " Name: $SUBDOMAIN" +echo " Type: A" +echo " Value: $STATIC_IP" +echo "" +echo "2. Deploy the application:" +echo " make gke-up" +echo "" +echo "3. Wait for SSL certificate (5-10 minutes):" +echo " kubectl get managedcertificate orassistant-ssl-cert -n orassistant" +echo "" +echo "4. Test the deployment:" +echo " curl -I https://$FULL_DOMAIN" \ No newline at end of file diff --git a/deploy/env-setup.sh b/deploy/env-setup.sh new file mode 100755 index 00000000..153cec13 --- /dev/null +++ b/deploy/env-setup.sh @@ -0,0 +1,194 @@ +#!/bin/bash + +# Environment Setup Script for ORAssistant GKE Deployment +# This script helps configure the .env file and encode secrets + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}ORAssistant Environment Setup${NC}" +echo "==================================" + +# Function to base64 encode +encode_secret() { + local secret="$1" + if [ -n "$secret" ]; then + echo -n "$secret" | base64 -w 0 + fi +} + +# Function to generate random secret +generate_secret() { + openssl rand -hex 32 +} + +# Function to prompt for input +prompt_input() { + local prompt="$1" + local var_name="$2" + local is_secret="${3:-false}" + + if [ "$is_secret" = "true" ]; then + echo -e "${YELLOW}$prompt${NC}" + read -s input + echo + else + echo -e "${YELLOW}$prompt${NC}" + read input + fi + + if [ -n "$input" ]; then + if [ "$is_secret" = "true" ]; then + encoded=$(encode_secret "$input") + echo "${var_name}=${encoded}" >> .env + else + echo "${var_name}=${input}" >> .env + fi + fi +} + +# Check if .env already exists +if [ -f ".env" ]; then + echo -e "${YELLOW}Warning: .env file already exists${NC}" + read -p "Do you want to overwrite it? (y/N): " overwrite + if [ "$overwrite" != "y" ] && [ "$overwrite" != "Y" ]; then + echo "Exiting without changes" + exit 0 + fi + rm .env +fi + +echo -e "${GREEN}Creating .env file...${NC}" + +# Start with basic configuration +cat > .env << 'EOF' +# ORAssistant GKE Deployment Configuration +# Generated by env-setup.sh + +EOF + +echo -e "${BLUE}1. Project Configuration${NC}" +prompt_input "Enter your GCP Project ID: " "PROJECT_ID" +prompt_input "Enter your domain (e.g., mycompany.com): " "DOMAIN" +prompt_input "Enter GCP region [us-central1]: " "REGION" +if ! grep -q "REGION=" .env; then + echo "REGION=us-central1" >> .env +fi + +# Generate derived values +if grep -q "PROJECT_ID=" .env && grep -q "DOMAIN=" .env; then + PROJECT_ID=$(grep "PROJECT_ID=" .env | cut -d'=' -f2) + DOMAIN=$(grep "DOMAIN=" .env | cut -d'=' -f2) + + cat >> .env << EOF +CLUSTER_NAME=orassistant-cluster +NAMESPACE=orassistant +PRIMARY_DOMAIN=orassistant.${DOMAIN} +ADMIN_EMAIL=admin@${DOMAIN} +BACKEND_IMAGE=gcr.io/${PROJECT_ID}/orassistant-backend:latest +FRONTEND_IMAGE=gcr.io/${PROJECT_ID}/orassistant-frontend:latest + +EOF +fi + +echo -e "${BLUE}2. Required API Keys${NC}" +echo -e "${RED}Important: These will be base64 encoded automatically${NC}" + +prompt_input "Enter OpenAI API Key (required): " "OPENAI_API_KEY" true +prompt_input "Enter Google API Key: " "GOOGLE_API_KEY" true +prompt_input "Enter HuggingFace Token: " "HUGGINGFACE_TOKEN" true + +echo -e "${BLUE}3. Database Configuration${NC}" +prompt_input "Enter MongoDB URI (optional): " "MONGODB_URI" true + +echo -e "${BLUE}4. Application Secrets${NC}" +echo -e "${GREEN}Generating random JWT and Session secrets...${NC}" +JWT_SECRET=$(generate_secret) +SESSION_SECRET=$(generate_secret) +JWT_SECRET_B64=$(encode_secret "$JWT_SECRET") +SESSION_SECRET_B64=$(encode_secret "$SESSION_SECRET") + +cat >> .env << EOF +JWT_SECRET_KEY=${JWT_SECRET_B64} +SESSION_SECRET=${SESSION_SECRET_B64} + +EOF + +echo -e "${BLUE}5. Optional API Keys${NC}" +prompt_input "Enter Anthropic API Key (optional): " "ANTHROPIC_API_KEY" true +prompt_input "Enter Cohere API Key (optional): " "COHERE_API_KEY" true + +echo -e "${BLUE}6. Google Sheets Integration${NC}" +read -p "Do you have Google Sheets service account credentials? (y/N): " has_sheets +if [ "$has_sheets" = "y" ] || [ "$has_sheets" = "Y" ]; then + prompt_input "Enter path to service account JSON file: " "SHEETS_FILE" + if grep -q "SHEETS_FILE=" .env; then + SHEETS_FILE=$(grep "SHEETS_FILE=" .env | cut -d'=' -f2) + if [ -f "$SHEETS_FILE" ]; then + SHEETS_B64=$(cat "$SHEETS_FILE" | base64 -w 0) + echo "GOOGLE_SHEETS_CREDENTIALS=${SHEETS_B64}" >> .env + # Remove the file path line + sed -i '/SHEETS_FILE=/d' .env + else + echo -e "${RED}Warning: File not found: $SHEETS_FILE${NC}" + fi + fi +fi + +# Add default configuration values +cat >> .env << 'EOF' + +# Default configuration values +BACKEND_WORKERS=2 +LOG_LEVEL=info +ENVIRONMENT=production +BACKEND_CPU_REQUEST=1000m +BACKEND_CPU_LIMIT=2000m +BACKEND_MEMORY_REQUEST=4Gi +BACKEND_MEMORY_LIMIT=8Gi +FRONTEND_CPU_REQUEST=100m +FRONTEND_CPU_LIMIT=500m +FRONTEND_MEMORY_REQUEST=512Mi +FRONTEND_MEMORY_LIMIT=1Gi +BACKEND_MIN_REPLICAS=1 +BACKEND_MAX_REPLICAS=3 +FRONTEND_MIN_REPLICAS=1 +FRONTEND_MAX_REPLICAS=2 +STORAGE_SIZE=10Gi +STATIC_IP_NAME=orassistant-ip +MANAGED_CERT_NAME=orassistant-ssl-cert +SSL_PROFILE=MODERN +CERT_MANAGER_VERSION=v1.13.0 + +EOF + +echo -e "${GREEN}✓ .env file created successfully!${NC}" +echo +echo -e "${BLUE}Next steps:${NC}" +echo "1. Review the generated .env file" +echo "2. Add any missing optional configuration" +echo "3. Run: make gke-up" +echo +echo -e "${RED}Security reminder:${NC}" +echo "• Never commit .env to version control" +echo "• Add .env to your .gitignore file" +echo "• Store secrets securely in production" +echo +echo -e "${YELLOW}Configuration summary:${NC}" +if grep -q "PROJECT_ID=" .env; then + echo "Project ID: $(grep "PROJECT_ID=" .env | cut -d'=' -f2)" +fi +if grep -q "DOMAIN=" .env; then + echo "Domain: $(grep "DOMAIN=" .env | cut -d'=' -f2)" +fi +if grep -q "PRIMARY_DOMAIN=" .env; then + echo "Primary Domain: $(grep "PRIMARY_DOMAIN=" .env | cut -d'=' -f2)" +fi +echo "OpenAI API Key: $(if grep -q "OPENAI_API_KEY=" .env && [ "$(grep "OPENAI_API_KEY=" .env | cut -d'=' -f2)" != "" ]; then echo "✓ Configured"; else echo "✗ Missing"; fi)" +echo "Google API Key: $(if grep -q "GOOGLE_API_KEY=" .env && [ "$(grep "GOOGLE_API_KEY=" .env | cut -d'=' -f2)" != "" ]; then echo "✓ Configured"; else echo "✗ Missing"; fi)" +echo "HuggingFace Token: $(if grep -q "HUGGINGFACE_TOKEN=" .env && [ "$(grep "HUGGINGFACE_TOKEN=" .env | cut -d'=' -f2)" != "" ]; then echo "✓ Configured"; else echo "✗ Missing"; fi)" \ No newline at end of file diff --git a/deploy/hpa.yaml b/deploy/hpa.yaml new file mode 100644 index 00000000..5b249131 --- /dev/null +++ b/deploy/hpa.yaml @@ -0,0 +1,80 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: backend-hpa + namespace: orassistant +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: backend-deployment + minReplicas: 1 + maxReplicas: 3 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 50 + periodSeconds: 60 + scaleUp: + stabilizationWindowSeconds: 60 + policies: + - type: Percent + value: 100 + periodSeconds: 60 + - type: Pods + value: 1 + periodSeconds: 60 +--- +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: frontend-hpa + namespace: orassistant +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: frontend-deployment + minReplicas: 1 + maxReplicas: 2 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 + behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 50 + periodSeconds: 60 + scaleUp: + stabilizationWindowSeconds: 60 + policies: + - type: Percent + value: 100 + periodSeconds: 60 \ No newline at end of file diff --git a/deploy/ingress.yaml b/deploy/ingress.yaml new file mode 100644 index 00000000..8dd8dbdc --- /dev/null +++ b/deploy/ingress.yaml @@ -0,0 +1,70 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: orassistant-ingress + namespace: orassistant + annotations: + kubernetes.io/ingress.class: gce + kubernetes.io/ingress.global-static-ip-name: orassistant-ip + networking.gke.io/managed-certificates: orassistant-ssl-cert + kubernetes.io/ingress.allow-http: "false" + networking.gke.io/v1beta1.FrontendConfig: orassistant-frontend-config + cloud.google.com/backend-config: '{"default": "frontend-backend-config"}' +spec: + rules: + - host: orassistant.your-domain.com + http: + paths: + - path: /api/* + pathType: ImplementationSpecific + backend: + service: + name: backend-internal-lb + port: + number: 8000 + - path: /* + pathType: ImplementationSpecific + backend: + service: + name: frontend-external-lb + port: + number: 80 +--- +apiVersion: networking.gke.io/v1 +kind: ManagedCertificate +metadata: + name: orassistant-ssl-cert + namespace: orassistant +spec: + domains: + - orassistant.your-domain.com +--- +apiVersion: networking.gke.io/v1beta1 +kind: FrontendConfig +metadata: + name: orassistant-frontend-config + namespace: orassistant +spec: + redirectToHttps: + enabled: true + responseCodeName: MOVED_PERMANENTLY_DEFAULT + sslPolicy: orassistant-ssl-policy +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-service-nodeport + namespace: orassistant + labels: + app: frontend + component: ui +spec: + selector: + app: frontend + component: ui + ports: + - name: http + protocol: TCP + port: 3000 + targetPort: 3000 + type: NodePort \ No newline at end of file diff --git a/deploy/load-balancer.yaml b/deploy/load-balancer.yaml new file mode 100644 index 00000000..cb4f3885 --- /dev/null +++ b/deploy/load-balancer.yaml @@ -0,0 +1,89 @@ +# External Load Balancer for public traffic +apiVersion: v1 +kind: Service +metadata: + name: frontend-external-lb + namespace: orassistant + annotations: + cloud.google.com/load-balancer-type: "External" + cloud.google.com/backend-config: '{"default": "frontend-backend-config"}' + labels: + app: frontend + component: ui +spec: + selector: + app: frontend + component: ui + ports: + - name: http + protocol: TCP + port: 80 + targetPort: 3000 + - name: https + protocol: TCP + port: 443 + targetPort: 3000 + type: LoadBalancer +--- +# Internal Load Balancer for backend services (private communication) +apiVersion: v1 +kind: Service +metadata: + name: backend-internal-lb + namespace: orassistant + annotations: + cloud.google.com/load-balancer-type: "Internal" + networking.gke.io/internal-load-balancer-allow-global-access: "true" + labels: + app: backend + component: api +spec: + selector: + app: backend + component: api + ports: + - name: http + protocol: TCP + port: 8000 + targetPort: 8000 + type: LoadBalancer +--- +# Backend configuration for external load balancer +apiVersion: cloud.google.com/v1 +kind: BackendConfig +metadata: + name: frontend-backend-config + namespace: orassistant +spec: + healthCheck: + checkIntervalSec: 10 + timeoutSec: 5 + healthyThreshold: 2 + unhealthyThreshold: 3 + type: HTTP + requestPath: / + port: 3000 + connectionDraining: + drainingTimeoutSec: 60 + sessionAffinity: + affinityType: "CLIENT_IP" + timeoutSec: 30 +--- +# Backend configuration for internal load balancer +apiVersion: cloud.google.com/v1 +kind: BackendConfig +metadata: + name: backend-backend-config + namespace: orassistant +spec: + healthCheck: + checkIntervalSec: 10 + timeoutSec: 5 + healthyThreshold: 2 + unhealthyThreshold: 3 + type: HTTP + requestPath: /healthcheck + port: 8000 + connectionDraining: + drainingTimeoutSec: 60 + timeoutSec: 30 \ No newline at end of file diff --git a/deploy/namespace.yaml b/deploy/namespace.yaml new file mode 100644 index 00000000..2b440b8a --- /dev/null +++ b/deploy/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: orassistant + labels: + app: orassistant + environment: production \ No newline at end of file diff --git a/deploy/network-policies.yaml b/deploy/network-policies.yaml new file mode 100644 index 00000000..59f1ca3f --- /dev/null +++ b/deploy/network-policies.yaml @@ -0,0 +1,225 @@ +# Default deny all ingress traffic policy +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: default-deny-ingress + namespace: orassistant +spec: + podSelector: {} + policyTypes: + - Ingress +--- +# Allow ingress to frontend from load balancer +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-frontend-ingress + namespace: orassistant +spec: + podSelector: + matchLabels: + app: frontend + component: ui + policyTypes: + - Ingress + ingress: + - from: [] # Allow from any source (load balancer) + ports: + - protocol: TCP + port: 3000 +--- +# Allow backend communication from frontend +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-backend-from-frontend + namespace: orassistant +spec: + podSelector: + matchLabels: + app: backend + component: api + policyTypes: + - Ingress + ingress: + # Allow from frontend pods + - from: + - podSelector: + matchLabels: + app: frontend + component: ui + ports: + - protocol: TCP + port: 8000 + # Allow from load balancer for health checks + - from: [] + ports: + - protocol: TCP + port: 8000 +--- +# Allow DNS resolution for all pods +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-dns + namespace: orassistant +spec: + podSelector: {} + policyTypes: + - Egress + egress: + # Allow DNS queries + - to: [] + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 +--- +# Allow egress for backend services (API calls, model downloads) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-backend-egress + namespace: orassistant +spec: + podSelector: + matchLabels: + app: backend + component: api + policyTypes: + - Egress + egress: + # Allow DNS + - to: [] + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + # Allow HTTPS for API calls and model downloads + - to: [] + ports: + - protocol: TCP + port: 443 + # Allow HTTP for specific services + - to: [] + ports: + - protocol: TCP + port: 80 + # Allow MongoDB connection (if external) + - to: [] + ports: + - protocol: TCP + port: 27017 +--- +# Allow egress for frontend (API calls to backend) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-frontend-egress + namespace: orassistant +spec: + podSelector: + matchLabels: + app: frontend + component: ui + policyTypes: + - Egress + egress: + # Allow DNS + - to: [] + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + # Allow communication to backend + - to: + - podSelector: + matchLabels: + app: backend + component: api + ports: + - protocol: TCP + port: 8000 + # Allow HTTPS for external services (if needed) + - to: [] + ports: + - protocol: TCP + port: 443 +--- +# Allow communication within the same namespace for debugging +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-same-namespace + namespace: orassistant +spec: + podSelector: {} + policyTypes: + - Ingress + - Egress + ingress: + - from: + - namespaceSelector: + matchLabels: + name: orassistant + egress: + - to: + - namespaceSelector: + matchLabels: + name: orassistant +--- +# Allow monitoring and metrics collection +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-monitoring + namespace: orassistant +spec: + podSelector: {} + policyTypes: + - Ingress + ingress: + # Allow monitoring from kube-system namespace + - from: + - namespaceSelector: + matchLabels: + name: kube-system + # Allow monitoring from monitoring namespace (if exists) + - from: + - namespaceSelector: + matchLabels: + name: monitoring +--- +# Security policy for init containers (dataset download) +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-init-container-egress + namespace: orassistant +spec: + podSelector: + matchLabels: + app: backend + policyTypes: + - Egress + egress: + # Allow DNS for init containers + - to: [] + ports: + - protocol: UDP + port: 53 + - protocol: TCP + port: 53 + # Allow HTTPS for HuggingFace downloads + - to: [] + ports: + - protocol: TCP + port: 443 + # Allow HTTP for package downloads + - to: [] + ports: + - protocol: TCP + port: 80 \ No newline at end of file diff --git a/deploy/persistent-volume.yaml b/deploy/persistent-volume.yaml new file mode 100644 index 00000000..f1128878 --- /dev/null +++ b/deploy/persistent-volume.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: PersistentVolume +metadata: + name: rag-dataset-pv + namespace: orassistant +spec: + capacity: + storage: 10Gi + accessModes: + - ReadOnlyMany + persistentVolumeReclaimPolicy: Retain + storageClassName: ssd-regional + gcePersistentDisk: + pdName: rag-dataset-disk + fsType: ext4 + readOnly: false +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: rag-dataset-pvc + namespace: orassistant +spec: + accessModes: + - ReadOnlyMany + resources: + requests: + storage: 10Gi + storageClassName: ssd-regional +--- +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: ssd-regional +provisioner: kubernetes.io/gce-pd +parameters: + type: pd-ssd + replication-type: regional-pd + zones: us-central1-a,us-central1-b,us-central1-c +allowVolumeExpansion: true +volumeBindingMode: WaitForFirstConsumer \ No newline at end of file diff --git a/deploy/secrets.yaml b/deploy/secrets.yaml new file mode 100644 index 00000000..9a6e0d2b --- /dev/null +++ b/deploy/secrets.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: Secret +metadata: + name: orassistant-secrets + namespace: orassistant + labels: + app: orassistant + component: secrets +type: Opaque +data: + # Base64 encoded secrets - replace with actual values + # To encode: echo -n "your-secret-value" | base64 + + # AI/ML API Keys + OPENAI_API_KEY: "" # OpenAI API key for LLM + GOOGLE_API_KEY: "" # Google AI/Vertex AI key + HUGGINGFACE_TOKEN: "" # HuggingFace Hub token for model downloads + + # Database connections + MONGODB_URI: "" # MongoDB connection string + + # External integrations + GOOGLE_SHEETS_CREDENTIALS: "" # Google Sheets API credentials (JSON) + + # Application secrets + JWT_SECRET_KEY: "" # JWT signing key + SESSION_SECRET: "" # Session encryption key + + # Optional: External APIs + ANTHROPIC_API_KEY: "" # Claude API key + COHERE_API_KEY: "" # Cohere API key +--- +apiVersion: v1 +kind: Secret +metadata: + name: orassistant-registry + namespace: orassistant + labels: + app: orassistant + component: registry +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: "" # Base64 encoded Docker registry credentials + # Format: {"auths":{"gcr.io":{"username":"_json_key","password":"","auth":""}}} +--- +apiVersion: v1 +kind: Secret +metadata: + name: orassistant-tls + namespace: orassistant + labels: + app: orassistant + component: tls +type: kubernetes.io/tls +data: + tls.crt: "" # Base64 encoded TLS certificate (if using custom certs) + tls.key: "" # Base64 encoded TLS private key (if using custom certs) \ No newline at end of file diff --git a/deploy/services.yaml b/deploy/services.yaml new file mode 100644 index 00000000..31234f68 --- /dev/null +++ b/deploy/services.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: Service +metadata: + name: backend-service + namespace: orassistant + labels: + app: backend + component: api +spec: + selector: + app: backend + component: api + ports: + - name: http + protocol: TCP + port: 8000 + targetPort: 8000 + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-service + namespace: orassistant + labels: + app: frontend + component: ui +spec: + selector: + app: frontend + component: ui + ports: + - name: http + protocol: TCP + port: 3000 + targetPort: 3000 + type: ClusterIP \ No newline at end of file diff --git a/deploy/ssl-policy.yaml b/deploy/ssl-policy.yaml new file mode 100644 index 00000000..aea3689c --- /dev/null +++ b/deploy/ssl-policy.yaml @@ -0,0 +1,41 @@ +# SSL Policy for enhanced security +apiVersion: compute.cnrm.cloud.google.com/v1beta1 +kind: ComputeSSLPolicy +metadata: + name: orassistant-ssl-policy + namespace: orassistant +spec: + # Use modern TLS profile for better security + profile: "MODERN" + # Or specify custom configuration: + # profile: "CUSTOM" + # minTlsVersion: "TLS_1_2" + # customFeatures: + # - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" + # - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" + # - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" + # - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" +--- +# Enhanced Frontend configuration with SSL and security headers +apiVersion: networking.gke.io/v1beta1 +kind: FrontendConfig +metadata: + name: orassistant-frontend-config + namespace: orassistant +spec: + redirectToHttps: + enabled: true + responseCodeName: MOVED_PERMANENTLY_DEFAULT + sslPolicy: orassistant-ssl-policy + # Add security headers + customRequestHeaders: + headers: + - "X-Client-Region:{client_region}" + - "X-Client-City:{client_city}" + # Connection draining for rolling updates + connectionDraining: + drainingTimeoutSec: 60 + # Session affinity for better performance + sessionAffinity: + affinityType: "CLIENT_IP" + affinityCookieTtlSec: 3600 \ No newline at end of file