Skip to content

coplane/planar-deploy-infra-azure

Repository files navigation

Azure Terraform Project to deploy Planar Apps

Deploy to Azure

This Terraform project creates a simple Azure infrastructure with:

  • Resource Group
  • Virtual Network (VNet) with subnets
  • Azure Container App with configurable Docker images
  • Key Vault for secure credential storage
  • PostgreSQL Flexible Server database
  • Storage Account with blob container
  • Azure OpenAI Service with private networking
  • HTTPS access from the internet

Architecture

                    AZURE SIMPLE TERRAFORM INFRASTRUCTURE
                    ======================================

┌─────────────────────────────────────────────────────────────────────────────┐
│                           AZURE RESOURCE GROUP                              │
│                         (rg-simple-terraform)                               │
│                              East US Region                                 │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                          VIRTUAL NETWORK                                    │
│                    (simple-terraform-vnet)                                  │
│                        10.0.0.0/16 CIDR                                     │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                        CONTAINER APP ENVIRONMENT                            │
│                    (simple-terraform-env)                                   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    CONTAINER APP                                    │    │
│  │              (simple-terraform-app)                                 │    │
│  │                                                                     │    │
│  │  ┌─────────────────────────────────────────────────────────────┐    │    │
│  │  │                CONTAINER                                    │    │    │
│  │  │              (nginx:latest)                                 │    │    │
│  │  │                                                             │    │    │
│  │  │  • CPU: 1 cores                                             │    │    │
│  │  │  • Memory: 2Gi                                              │    │    │
│  │  │  • Port: 8000                                               │    │    │
│  │  │  • Min Replicas: 1                                          │    │    │
│  │  │  • Max Replicas: 3                                          │    │    │
│  │  └─────────────────────────────────────────────────────────────┘    │    │
│  │                                                                     │    │
│  │  ┌─────────────────────────────────────────────────────────────┐    │    │
│  │  │              INGRESS CONFIGURATION                          │    │    │
│  │  │                                                             │    │    │
│  │  │  • External Access: Enabled                                 │    │    │
│  │  │  • HTTPS Only: Yes                                          │    │    │
│  │  │  • Target Port: 8000                                        │    │    │
│  │  │  • URL: https://[app].azurecontainerapps.io                 │    │    │
│  │  └─────────────────────────────────────────────────────────────┘    │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌────────────────────────────────────────────────────────────────────────────┐
│                        LOG ANALYTICS WORKSPACE                             │
│                    (simple-terraform-logs)                                 │
│                                                                            │
│  • SKU: PerGB2018                                                          │
│  • Retention: 30 days                                                      │
│  • Container App Logs                                                      │
└────────────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────────────────┐
│                        POSTGRESQL FLEXIBLE SERVER                          │
│                    (simple-terraform-postgres)                             │
│                                                                            │
│  • Version: PostgreSQL 16                                                  │
│  • SKU: "GP_Standard_D2s_v3"  #2 vCores, 8GB RAM                           │
│  • Storage: 32GB (auto-grow enabled)                                       │
│  • Zone: 2                                                                 │
│  • Backup: 7 days retention                                                │
│  • Public Access: Disabled (private subnets plus firewall rules)           │
│                                                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    DATABASE                                         │   │
│  │                    (appdb)                                          │   │
│  │                                                                     │   │
│  │  • Collation: en_US.utf8                                            │   │
│  │  • Charset: utf8                                                    │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                  FIREWALL RULES                                     │   │
│  │                                                                     │   │
│  │  • Allow Azure Services (0.0.0.0 - 0.0.0.0)                         │   │
│  │  • Allow Container App (10.0.0.0/16)                                │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                            │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                    USERS                                            │   │
│  │                                                                     │   │
│  │  • Admin: postgresadmin (random password)                           │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                        STORAGE ACCOUNT                                      │
│                    (simpleterraformstor)                                    │
│                                                                             │
│  • Tier: Standard                                                           │
│  • Replication: LRS                                                         │
│  • Kind: StorageV2                                                          │
│  • Public Access: Disabled                                                  │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                  BLOB CONTAINER                                     │    │
│  │                    (data)                                           │    │
│  │                                                                     │    │
│  │  • Access Type: Private                                             │    │
│  │  • CORS: Configured for *                                           │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                          KEY VAULT                                          │
│                    (kv-[random-suffix])                                     │
│                                                                             │
│  • SKU: Standard                                                            │
│  • Soft Delete: 7 days                                                      │
│  • Purge Protection: Disabled                                               │
│  • Network Access: Allow Azure Services                                     │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    SECRETS                                          │    │
│  │                                                                     │    │
│  │  • docker-registry-username (if provided)                           │    │
│  │  • docker-registry-password (if provided)                           │    │
│  │  • postgresql-password (if provided)                                │    │
│  │  • openai-api-secret (if provided)                                  │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                  ACCESS POLICIES                                    │    │
│  │                                                                     │    │
│  │  • Current User: Full access                                        │    │
│  │  • Container App Identity: Get/List secrets                         │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘

┌────────────────────────────────────────────────────────────────────────-─────┐
│                      MANAGED IDENTITY                                        │
│              (simple-terraform-container-identity)                           │
│                                                                              │
│  • Type: System Assigned                                                     │
│  • Assigned to: Container App                                                │
│  • Permissions: Storage Blob Data Contributor, KeyVault Get/List, OpenAI User│
└────────────────────────────────────────────────────────────────────────────-─┘

┌─────────────────────────────────────────────────────────────────────────────┐
│                        AZURE OPENAI SERVICE                                 │
│                    (simple-terraform-openai)                                │
│                                                                             │
│  • Kind: OpenAI                                                             │
│  • SKU: S0                                                                  │
│  • Public Access: Disabled (private endpoint only)                          │
│  • Custom Subdomain: [project-name]-openai                                  │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    MODEL DEPLOYMENT                                 │    │
│  │                    (GPT-4.1-[stage])                                │    │
│  │                                                                     │    │
│  │  • Model: GPT-4.1 (configurable)                                    │    │
│  │  • Version: Latest (configurable)                                   │    │
│  │  • SKU: GlobalStandard                                              │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    PRIVATE ENDPOINT                                 │    │
│  │                    (10.0.3.0/24 subnet)                             │    │
│  │                                                                     │    │
│  │  • Private DNS Zone: privatelink.openai.azure.com                   │    │
│  │  • Network Access: VNet only                                        │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘

                    CONNECTION FLOWS
                    ================

Container App ──────────────┐
                            │
                            ▼
                    ┌───────────────┐
                    │   Database    │
                    │ (PostgreSQL)  │
                    └───────────────┘

Container App ──────────────┐
                            │
                            ▼
                    ┌───────────────┐
                    │   Storage     │
                    │ (Blob Store)  │
                    └───────────────┘

Container App ──────────────┐
                            │
                            ▼
                    ┌───────────────┐
                    │   Key Vault   │
                    │   (Secrets)   │
                    └───────────────┘


Container App ──────────────┐
                            │
                            ▼
                    ┌───────────────┐
                    │ Azure OpenAI  │
                    │   (Private)   │
                    └───────────────┘
                            ▲
                            │
Container App ──────────────┘

=====================================
                    ┌───────────────┐
                    │ Container App │
                    │   (HTTPS)     │
                    └───────────────┘
                            ▲
                            │
External Users  ────────────┘

Prerequisites

  1. Azure CLI installed and configured
  2. Terraform installed (>= 1.0)
  3. Azure subscription with appropriate permissions

Quick Start

  1. Login to Azure:

    az login
  2. Set your subscription:

    az account set --subscription "your-subscription-id"
  3. Copy and customize variables:

    cp terraform.tfvars.example terraform.tfvars
    # Edit terraform.tfvars with your preferred values
  4. Initialize Terraform:

    terraform init -var-file terraform.tfvars -backend-config=backend.hcl
  5. Plan the deployment:

    terraform plan
  6. Apply the configuration:

    terraform apply
  7. Access your Planar App: After deployment, the output will show the HTTPS URL where your nginx container is accessible.

Resources Created

  • Resource Group: Contains all resources
  • Virtual Network: 10.0.0.0/16 with three subnets (app, database, OpenAI)
  • Log Analytics Workspace: For container app monitoring
  • Container App Environment: Managed environment for container apps
  • Container App: Configurable container with HTTPS ingress and database environment variables
  • Key Vault: Secure storage for Docker registry credentials and other secrets
  • PostgreSQL Flexible Server: Managed PostgreSQL database (B_Standard_B1ms SKU)
  • PostgreSQL Database: Application database with dedicated user
  • Storage Account: Blob storage with private container
  • Azure OpenAI Service: Private OpenAI service with GPT model deployment
  • Private Endpoint: Secure private access to Azure OpenAI service
  • Private DNS Zone: DNS resolution for OpenAI private endpoint
  • Managed Identity: For secure access to Azure resources

Configuration

Key variables you can customize in terraform.tfvars:

  • resource_group_name: Name of the Azure resource group
  • location: Azure region (default: "East US")
  • project_name: Prefix for all resource names
  • tags: Tags applied to all resources
  • container_image: Docker image to deploy (default: "nginx:latest")
  • container_name: Name of the container within the app
  • container_port: Port the container listens on (default: 80)
  • docker_registry_server: Private registry server URL (optional)
  • docker_registry_username: Registry username (optional, stored in Key Vault)
  • docker_registry_password: Registry password (optional, stored in Key Vault)
  • azure_openai_model: Azure OpenAI model name (default: "gpt-4.1")
  • azure_openai_version: Azure OpenAI model version (default: "2025-04-14")
  • PostgreSQL passwords are automatically generated for security

Cleanup

To destroy all resources:

terraform destroy

Database Access

The container app has the following environment variables for database connectivity:

  • DATABASE_URL: Complete PostgreSQL connection string
  • DB_HOST: Database server hostname
  • DB_PORT: Database port (5432)
  • DB_NAME: Database name
  • DB_USER: Application database user
  • DB_PASSWORD: Application database password

Azure OpenAI Access

The Azure OpenAI service is configured with:

  • Private Networking: Accessible only from within the VNet via private endpoint
  • Model Deployment: GPT-4.1 model deployed with GlobalStandard SKU
  • Authentication: Container app has "Cognitive Services OpenAI User" role
  • Endpoint: Available at https://[project-name]-openai.openai.azure.com/

The container app can access Azure OpenAI using the managed identity for authentication, eliminating the need to manage API keys in your application code.

Using Private Docker Registries

To deploy containers from private Docker registries (like Azure Container Registry):

  1. Configure registry credentials in terraform.tfvars:

    docker_registry_server   = "myregistry.azurecr.io"
    docker_registry_username = "myregistry"
    docker_registry_password = "your-access-key"
  2. Update the container image:

    container_image = "myregistry.azurecr.io/myapp:v1.0"
  3. Deploy with Terraform:

    terraform apply

    Note: you might neet to export ARM_SUBSCRIPTION_ID= with your Azure Subscription id.

The credentials are securely stored in Azure Key Vault and automatically used by the container app for registry authentication.

Notes

  • The container app is configured with HTTPS only (no insecure connections)
  • The container runs on the specified port internally and is exposed via HTTPS
  • Auto-scaling is configured (1-3 replicas based on load)
  • PostgreSQL server uses minimal standard SKU
  • Passwords are randomly generated and stored securely in Key Vault
  • Docker registry credentials are stored securely in Key Vault when provided
  • All resources are tagged for easy identification and cost tracking

About

Terraform stack to deploy Planar App on Azure Cloud.

Topics

Resources

License

Stars

Watchers

Forks