Skip to main content
Version: 4.5.x

MTE Relay Server on Azure

Introduction

MTE Relay Server is an end-to-end encryption system that protects all network requests with next-generation application data security. It acts as a proxy server in front of your backend, communicating with an MTE Relay Client to encode and decode all network traffic. The server is highly customizable and supports integration with other services through custom adapters.

Below is a typical architecture where a client application communicates with an MTE Relay Server, which then proxies decoded traffic to backend services:

Example MTE Relay Example diagram

info

MTE Relay Servers can only communicate with MTE Relay Clients. An MTE API Relay cannot communicate with an MTE Relay Server or an MTE Relay Client SDK. MTE Relay Servers are strictly for client-to-server communications.


Prerequisites

Technical Requirements

  • A web or mobile application project that communicates with a backend API over HTTP.

Skills and Knowledge

  • Familiarity with AKS and Kubernetes.
  • Ability to manage deployments with kubectl.

Deployment Options

MTE Relay Server is provided as a Docker image and is typically run on Azure Kubernetes Service (AKS).

Azure Kubernetes Service (AKS)

Assuming kubectl is configured for your AKS cluster:

Example Deployment (deployment.yaml)

apiVersion: apps/v1
kind: Deployment
metadata:
name: azure-mte-relay-deployment
spec:
replicas: 1
selector:
matchLabels:
app: azure-mte-relay
template:
metadata:
labels:
app: azure-mte-relay
spec:
containers:
- name: azure-mte-relay
image: <CONTAINER_IMAGE>
ports:
- containerPort: 8080
env:
- name: CLIENT_ID_SECRET
value: <YOUR CLIENT ID SECRET HERE>
- name: CORS_ORIGINS
value: <YOUR CORS ORIGINS HERE>
- name: UPSTREAM
value: <UPSTREAM VALUE HERE>

Deploy:

kubectl apply -f deployment.yaml

Example Service (service.yaml)

Expose the deployment via a load balancer:

apiVersion: v1
kind: Service
metadata:
name: azure-mte-relay-service
spec:
type: LoadBalancer
selector:
app: azure-mte-relay
ports:
- protocol: TCP
port: 80
targetPort: 8080

Deploy:

kubectl apply -f service.yaml
kubectl get services

Remove Deployment and Service

kubectl delete -f deployment.yaml
kubectl delete -f service.yaml

Server Configuration

MTE Relay Server is configured using environment variables.

DOMAIN_MAP is a JSON object keyed by the Host header that arrives with each request.
The value for each key is a settings object that tells the proxy how to process the request.

Settings

FieldTypePurpose
upstreamstringFull URL (http://localhost:8080, https://api.internal)
pass_through_routesstring[]Paths that use standard HTTP proxy, without MTE encryption
client_id_secretstringLegacy shared secret used by some auth layers
cors_originsstring[]List of allowed CORS origins for preflight requests
cors_methodsstring[]List of allowed CORS methods for preflight requests
headersstringA JSON object of additional headers to add to proxied requests

Examples

  1. Single Proxy: Requests with Host header mte-api.company.com are decrypted and forwarded to http://internal-service. The /health route is proxied without MTE encoding/decoding.
{
"mte-api.company.com": {
"upstream": "http://internal-service",
"client_id_secret": "8KeJmtuKweUhymNJmGHvGMrJCUtHxhQG",
"pass_through_routes": ["/health"],
"cors_origins": ["https://app.company.com"]
}
}
  1. Multi-service proxy that handles:
  • Incoming encoded requests for billing.company.io, forwarding to http://billing-service with /ready and /live routes unencoded.
  • Request to auth.company.io, forwarding to http://auth-service with /health route unencoded.
  • All other requests (any Host) are proxied to http://default-backend:8080 without encoding.
{
"billing.company.io": {
"upstream": "http://billing-service",
"pass_through_routes": ["/ready", "/live"],
"client_id_secret": "8KeJmtuKweUhymNJmGHvGMrJCUtHxhQG",
"cors_origins": ["https://app.company.com"]
},
"auth.company.io": {
"upstream": "http://auth-service:3000",
"pass_through_routes": ["/health"],
"client_id_secret": "heYBRbTr3QNBgQFV6x6YpfWqyEs2Tj8F",
"cors_origins": ["https://app.company.com"],
"cors_methods": ["GET", "POST", "OPTIONS"]
},
"*": {
"upstream": "http://default-backend:8080",
"client_id_secret": "PmNPtWJMzz46S9k8cY7du5Z6XYc9B5Ad",
"cors_origins": ["https://app.company.com", "http://localhost:3000"]
}
}

Export as one-line env var:

export DOMAIN_MAP='{ "billing.company.io": { "upstream": "http://billing-service", "pass_through_routes": ["/ready", "/live"], "client_id_secret": "8KeJmtuKweUhymNJmGHvGMrJCUtHxhQG" }, "auth.company.io": { "upstream": "http://auth-service", "pass_through_routes": ["/health"], "client_id_secret": "heYBRbTr3QNBgQFV6x6YpfWqyEs2Tj8F" }, "*": { "upstream": "http://default-backend:8080", "client_id_secret": "PmNPtWJMzz46S9k8cY7du5Z6XYc9B5Ad" } }'

Host header derivation

The Host header is taken directly from the authority component of the absolute URL used in the request.
For example, https://api.example.com/users/1 the authority is api.example.com (port 443 is implicit for HTTPS), so the Host header sent by the client is exactly:

Host: api.example.com

If the URL contains an explicit port (https://api.example.com:8443/users/1) the header becomes:

Host: api.example.com:8443

DOMAIN_MAP must therefore use the exact same string—domain only, or domain:port—to match the incoming Host header. Or, use a wildcard "*" to match any host.

Host Matching

MTE Relay Server performs an exact match against the Host header (case-insensitive).
If an exact match is not found, it checks for a wildcard ("*").
If no match is found, the request is rejected with 404.

Using individual Environment Variables (Legacy)

Using these environment variables will result in the MTE Relay Server being configured to only handle a single domain. This method is deprecated in favor of using the DOMAIN_MAP variable. If both are provided, DOMAIN_MAP will take precedence.

Example:

  • UPSTREAM - Upstream API or service URL.
  • CLIENT_ID_SECRET - Secret for signing client IDs (minimum 32 characters).
  • PASS_THROUGH_ROUTES - Comma-separated list of routes proxied without encoding/decoding.
  • CORS_ORIGINS - Comma-separated list of allowed origins.
  • CORS_METHODS - Comma-separated list of allowed methods. Default: GET, POST, PUT, DELETE.
UPSTREAM='https://api.my-company.com'
CLIENT_ID_SECRET='2DkV4DDabehO8cifDktdF9elKJL0CKrk'
PASS_THROUGH_ROUTES='/health,/version'
OUTBOUND_TOKEN='s3cr3tT0k3nV4lu3'

Additional Environment Variables

  • PORT - Default: 8080.
  • LOG_LEVEL - One of trace, debug, info, warning, error, panic, disabled. Default: info.

Client-Side Setup

Eclypses provides client-side SDKs to integrate with MTE Relay Server:

Client-side integration typically requires less than one day of effort.


Testing & Health Checks

  • Monitor container logs for startup messages
  • Use the default or custom echo routes to test container responsiveness:
    • Default: /api/mte-echo
    • Custom Message: /api/mte-echo?msg=test

Expected response:

{
"message": "test",
"timestamp": "<timestamp>"
}

Monitoring

Azure Monitor and Grafana

Grafana Dashboard Configuration

Import the provided Grafana dashboard:
Download Grafana Dashboard

Dashboard Metrics:

  • Requests Processed [req/sec]
  • Request Time [ms]
  • Upstream Proxy Time [ms]
  • Average Decode Time [ms]
  • Average Encode Time [ms]

Performance Metrics

Performance was measured with ~1 kb request/response payloads:

ConcurrencyReq/Sec RelayReq/Sec APIRelay %Extra Latency (Median)
40018518898.5%+10 ms
50029830597.8%+17 ms
55033835595.1%+45 ms
60033940284.3%+202 ms

Note: At higher volumes (≥550 concurrent), scale using multiple Relay pods and Azure load balancing.


Troubleshooting

  1. Invalid Configuration
    • Check logs for missing/invalid environment variables.
  2. Relay unreachable
    • Verify AKS service and NSG rules.
  3. Redis connection issues
    • Ensure Redis is reachable with valid credentials.

Security

  • No sensitive data is stored in the container.
  • No root privileges required.

Maintenance

Routine Updates

  • Updated container images are distributed through the Azure Marketplace.

Fault Recovery

  • Restart the Relay container pod; clients will re-pair automatically.

Support

For assistance, contact Eclypses Support:
📧 customer_support@eclypses.com
🕒 Monday–Friday, 8:00 AM–5:00 PM MST (excluding holidays)