Multi-Cloud Infrastructure-as-Code for Azure, AWS & GCP
Enterprise-grade cloud infrastructure with security-first design and cloud-native identity management.
Built with zero-trust principles and Azure security best practices.
Storage Account access exclusively via Azure AD authentication. No shared keys or SAS tokens.
SQL Server configured for Azure AD authentication only. No SQL authentication available.
Azure Managed Identity, AWS IAM Roles, or GCP Service Accounts for secure resource access without credentials.
Backend services accessible only through private networking (Azure Private Endpoints, AWS PrivateLink, GCP Private Service Connect).
Cloud-agnostic JWT tokens for API authentication without dependency on Azure AD, AWS Cognito, or Google Identity Platform.
Service access restricted to configured IP addresses only.
All services enforce TLS 1.2 as the minimum protocol version.
Multi-provider authentication: OAuth2 (Azure AD, Self-Hosted JWT) or API Keys for Document API.
OAuth2 ONLY - Requires admin_client_id configuration (Azure AD or Self-Hosted JWT). API keys cannot access admin endpoints.
API Key OR OAuth2 - For systems that don't support OAuth2 (e.g., Salesforce Outbound Messages).
Via Admin REST API - Keys are created, rotated, and stored securely in Azure Key Vault.
For Document API (non-OAuth2 systems)
API Keys are managed via the Admin REST API, not in configuration files:
curl -X GET "https://app-docservice-dev.azurewebsites.net/api/documents" \
-H "X-API-Key: your-api-key-here" \
-H "Content-Type: application/json"
API Keys cannot access Admin endpoints. Use OAuth2 (Azure AD or Self-Hosted JWT) with admin_client_id for administrative operations.
OAuth 2.0 / Bearer Token authentication
Azure AD is always enabled when TenantId is configured. Only AdminClientId needs to be set:
Additional OAuth2 clients are registered via the Admin API, not configuration files.
curl -X GET "https://app-docservice-dev.azurewebsites.net/api/documents" \
-H "Authorization: Bearer eyJ0eXAiOiJKV1Q..." \
-H "Content-Type: application/json"
Clients obtain tokens via OAuth 2.0 Client Credentials flow or user authentication, depending on the client type.
Cloud-agnostic OAuth 2.0 authentication
Perfect for multi-cloud scenarios or when you don't want dependency on cloud-specific identity providers (Azure AD, AWS Cognito, Google Identity Platform).
curl -X POST "https://your-api.com/api/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=your-client-id" \
-d "client_secret=your-client-secret"
Multi-cloud deployments, on-premises installations, or when you need full control over the authentication flow without external dependencies.
Follow these steps to configure Azure AD authentication for the Document Service API.
DocumentService-API-{env} (e.g., DocumentService-API-Dev)ClientIdTenantIdapi://{client-id}access_as_applicationAccess Document Service APIAllows the app to access Document Service APIFor each service that needs to call the API (e.g., Salesforce), create a separate App Registration:
DocumentService-Client-Salesforceaccess_as_application scopePOST https://login.microsoftonline.com/{tenant-id}/oauth2/v2.0/token
client_id={client-app-id}
&client_secret={client-secret}
&scope=api://{api-client-id}/.default
&grant_type=client_credentials
Set authentication environment variables in your container runtime (Docker -e, Azure App Settings, AWS ECS Task Definition, GCP Cloud Run Variables):
# Authentication Mode (Both = Azure AD + API Key)
Authentication__Mode=Both
# Azure Entra ID (REQUIRED for Admin endpoints)
Authentication__AzureAd__Instance=https://login.microsoftonline.com/
Authentication__AzureAd__TenantId=YOUR_TENANT_ID
Authentication__AzureAd__AdminClientId=YOUR_ADMIN_CLIENT_ID
Authentication__AzureAd__IsEnabled=true
# API Key (for Document API, managed via Admin REST API)
Authentication__ApiKey__Enabled=true
Authentication__ApiKey__HeaderName=X-API-Key
# NOTE: API Keys are created via POST /api/admin/clients
Use double-underscore (__) as section separator for environment variables. Example: Authentication__AzureAd__TenantId=...
API keys are created and managed through the Admin REST API using OAuth2 authentication.
Authenticate with the Admin Client ID and create a new API client:
curl -X POST "https://your-api.azurewebsites.net/api/admin/clients" \
-H "Authorization: Bearer {admin-token}" \
-H "Content-Type: application/json" \
-d '{
"name": "Salesforce-Integration",
"description": "API client for Salesforce",
"generateApiKey": true,
"keyVaultStorage": {
"storeInKeyVault": true,
"secretName": "apikey-salesforce"
},
"permissions": ["Documents.Read", "Documents.Write"]
}'
The API key is returned once in the response. Store it securely! If storeInKeyVault is true, you can retrieve it later from Key Vault.
If the key was stored in Key Vault, retrieve it via the Admin API:
curl -X GET "https://your-api.azurewebsites.net/api/admin/clients/{client-guid}/key" \
-H "Authorization: Bearer {admin-token}"
Generate a new key (old key becomes invalid immediately):
curl -X POST "https://your-api.azurewebsites.net/api/admin/clients/{client-guid}/rotate-key" \
-H "Authorization: Bearer {admin-token}"
Backend services like Salesforce, Azure Functions, or other APIs that call the Document Service without user interaction.
Client Credentials FlowWeb apps or SPAs where users log in with their Azure AD credentials to access documents on their behalf.
Authorization Code FlowFor systems that cannot use OAuth2 (e.g., Salesforce Outbound Messages). API keys created via Admin API and stored in Key Vault.
API Key (X-API-Key Header)Configure network isolation per resource type based on environment requirements.
Access from all IP addresses allowed. Azure AD authentication still required.
Access only from IP whitelist, VNet, and Azure Services.
No public access. Only accessible via Private Endpoints.
Each cloud resource can be configured with its own network access mode.
| Resource | Available Modes | Description |
|---|---|---|
| App Service / Container | public restricted |
Controls inbound access to the web application (Landing Page, APIs, API Docs).
public: Allow connections from ANY IP address restricted: Only allow connections from configured IP whitelist |
| SQL Database | public restricted private |
Controls access to the database server.
public: Allow connections from ANY IP address restricted: Only whitelisted IPs + VNet subnets + cloud services private: Only via Private Endpoint / PrivateLink (no public access) |
| Storage Account | public restricted private |
Controls access to Blob / Object Storage.
public: Allow connections from ANY IP address restricted: Only whitelisted IPs + VNet subnets + cloud services private: Only via Private Endpoint / PrivateLink (no public access) |
When set to public:
When set to restricted:
When set to restricted:
When set to private:
Deploy the Document Service container in your cloud environment.
Pull the latest Document Service container from your configured container registry.
# Azure Container Registry
docker pull yourregistry.azurecr.io/documentservice:latest
# AWS ECR
docker pull 123456789012.dkr.ecr.eu-central-1.amazonaws.com/documentservice:latest
# GCP Artifact Registry
docker pull europe-docker.pkg.dev/project-id/repo/documentservice:latest
Set all required environment variables for your cloud provider. See the Configuration Guide for all available settings.
# Database (required)
Database__Provider=PostgreSQL
ConnectionStrings__DefaultConnection=Host=...;Database=documentservice;...
# Storage (required)
BlobStorage__AccountName=yourstorageaccount
BlobStorage__ContainerName=documents
# Authentication (required)
Authentication__Mode=Both
Authentication__AzureAd__TenantId=YOUR_TENANT_ID
Authentication__AzureAd__AdminClientId=YOUR_ADMIN_CLIENT_ID
# Branding (optional)
Branding__LandingPageRedirectUrl=https://portal.yourcompany.com
Branding__ShowApiDocs=false
Start the container with your environment variables. The service runs on port 8080 by default.
docker run -d \
-p 8080:8080 \
-e "Database__Provider=PostgreSQL" \
-e "ConnectionStrings__DefaultConnection=Host=..." \
-e "BlobStorage__AccountName=yourstorageaccount" \
-e "Authentication__Mode=Both" \
-e "Authentication__AzureAd__TenantId=YOUR_TENANT_ID" \
-e "Authentication__AzureAd__AdminClientId=YOUR_ADMIN_CLIENT_ID" \
yourregistry.azurecr.io/documentservice:latest
Check the health endpoint and validate the cloud configuration.
# Health check
curl https://your-service-url/health
# Validate cloud configuration (requires Admin token)
curl -X POST https://your-service-url/api/admin/system/validate-config \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"
Monthly cost estimation for the basic development configuration.
| Service | SKU | ~Cost/Month |
|---|---|---|
| App Service Plan | B1 (Basic) | ~13 EUR |
| Azure SQL Database | Basic (5 DTU) | ~5 EUR |
| Storage Account | Standard LRS | ~1-5 EUR |
| Key Vault | Standard | ~0.03 EUR/10k ops |
| Private Endpoints | 3x Endpoints | ~22 EUR |
| Total (Dev) | ~45-50 EUR |
*Prices vary by region and actual usage. Private Endpoints optional in dev.
Recommended settings for different deployment stages.
Common issues and their solutions.
Cause: SQL database user for Managed Identity not created.
Solution: Run the SQL script from Post-Deployment Step 5 to create the database user.
Cause: Key Vault RBAC assignment missing for App Service.
Solution: Verify the "Key Vault Secrets User" role is assigned to the App Service Managed Identity.
Cause: VNet integration, DNS, or NSG misconfiguration.
Solution:
Cause: Deployer doesn't have Storage Blob Data Contributor role.
Solution: Wait for RBAC propagation (~2 minutes) or manually assign the role.