← Back to DevBytes

NGINX Service Mesh Security Hardening and Best Practices

Introduction to NGINX Service Mesh Security Hardening

NGINX Service Mesh is a lightweight, high-performance service mesh that provides advanced traffic management, security, and observability for microservices running in Kubernetes. It leverages NGINX Plus as a sidecar proxy to handle east-west traffic between services. Security hardening in this context means configuring the mesh to enforce strict identity verification, encrypt all inter-service communication, and limit access to only what is explicitly permitted. This tutorial walks you through the essential security hardening configurations and best practices to protect your service mesh deployment from common threats and misconfigurations.

Why Security Hardening Matters in a Service Mesh

A service mesh introduces a new layer to your infrastructure. While it abstracts away networking complexity, it also expands the attack surface if not properly secured. Without hardening, you risk:

Security hardening addresses these risks by implementing defense-in-depth at the network, transport, and application layers. In NGINX Service Mesh, this translates to mandatory mTLS, fine-grained access control, secure ingress configuration, and continuous policy validation.

Core Security Pillars of NGINX Service Mesh

NGINX Service Mesh security rests on four interconnected pillars. Understanding each is critical before you begin hardening your deployment.

1. Mutual TLS (mTLS) Enforcement

mTLS ensures that every service in the mesh authenticates itself to every other service using X.509 certificates. Both the client and server present certificates, cryptographically proving their identities before any application data is exchanged. NGINX Service Mesh uses SPIRE (the SPIFFE Runtime Environment) as its identity provider, issuing SPIFFE-compliant identities to each workload.

2. Role-Based Access Control (RBAC)

NGINX Service Mesh allows you to define fine-grained access policies that specify which services may communicate with one another, which HTTP methods and paths are allowed, and from which namespaces requests may originate. These policies are enforced at the sidecar proxy level, meaning a request is denied before it ever reaches the application.

3. Secure Ingress Gateway Configuration

The ingress gateway is the entry point for external traffic into the mesh. Hardening the ingress gateway involves TLS termination with strong cipher suites, strict SNI validation, rate limiting, and Web Application Firewall (WAF) integration to filter malicious payloads before they enter the mesh.

4. Observability and Audit Logging

Comprehensive logging and metrics provide visibility into all security events. NGINX Service Mesh exports access logs, security policy violation metrics, and certificate expiry data that enable SOC teams to detect anomalies and respond to incidents quickly.

Step-by-Step: Hardening a Fresh NGINX Service Mesh Deployment

Let's walk through a practical hardening process. We assume you have a Kubernetes cluster and the NGINX Service Mesh CLI installed. The steps progress from foundational security to advanced policy enforcement.

Step 1: Deploy the Mesh with Strict mTLS Mode

By default, NGINX Service Mesh operates in permissive mTLS mode, which allows both encrypted and unencrypted traffic during migration. For a hardened production environment, you must enable strict mode from the start.

# Deploy NGINX Service Mesh with strict mTLS
nginx-meshctl deploy \
  --mtls-mode strict \
  --mtls-ca-ttl 168h \
  --mtls-svid-ttl 1h \
  --image-version latest

Key parameters explained:

Step 2: Verify Certificate Issuance and Rotation

After deployment, confirm that SPIRE is issuing certificates correctly and that automatic rotation functions as expected.

# Check SPIRE agent status across nodes
kubectl get pods -n nginx-mesh -l app=spire-agent -o wide

# Inspect the SVID of a specific service
kubectl exec -it deployment/my-service -c nginx-mesh-sidecar -- \
  openssl s_client -connect localhost:443 -showcerts 2>&1 | \
  grep -A 20 "BEGIN CERTIFICATE"

# Force certificate rotation for testing
kubectl exec -it deployment/my-service -c nginx-mesh-sidecar -- \
  curl -X POST http://localhost:8080/spire-agent/api/v1/svid/rotate

Automated rotation happens transparently. The mesh sidecar fetches a new SVID before the current one expires, ensuring zero-downtime credential refresh.

Step 3: Create a Namespace-Level Traffic Policy

Begin RBAC hardening by isolating namespaces. This policy prevents services in the default namespace from calling services in payments unless explicitly allowed.

# traffic-policy-isolation.yaml
apiVersion: nginx.com/v1alpha1
kind: TrafficPolicy
metadata:
  name: namespace-isolation
  namespace: payments
spec:
  accessControl:
    allow:
      - source:
          namespace: "payments"
      - source:
          namespace: "gateway"
    deny:
      - source:
          namespace: "*"
  defaultAction: deny

Apply the policy:

kubectl apply -f traffic-policy-isolation.yaml

Now any service from default or other namespaces attempting to reach payments services will receive a 403 Forbidden response at the proxy level.

Step 4: Define Service-Specific Access Control Lists

Namespace isolation is coarse-grained. Next, create per-service ACLs that restrict HTTP methods and paths. The following example protects a payment processing endpoint.

# payment-acl.yaml
apiVersion: nginx.com/v1alpha1
kind: AccessControlPolicy
metadata:
  name: payment-service-acl
  namespace: payments
spec:
  rules:
    - match:
        methods: ["POST"]
        paths: ["/api/v1/process"]
      allow:
        - sourceService: "order-service.payments.svc.cluster.local"
        - sourceService: "gateway-service.gateway.svc.cluster.local"
      deny:
        - sourceService: "*"
    - match:
        methods: ["GET"]
        paths: ["/health", "/metrics"]
      allow:
        - sourceService: "*"

Apply and verify:

kubectl apply -f payment-acl.yaml

# Test allowed access from order-service
kubectl exec -it deployment/order-service -c nginx-mesh-sidecar -- \
  curl -X POST https://payment-service.payments.svc.cluster.local/api/v1/process \
  -H "Content-Type: application/json" -d '{"amount": 100}'

# Test denied access from an unauthorized service
kubectl exec -it deployment/analytics-service -c nginx-mesh-sidecar -- \
  curl -X POST https://payment-service.payments.svc.cluster.local/api/v1/process \
  -H "Content-Type: application/json" -d '{"amount": 100}'
# Expected: 403 Forbidden

Hardening the Ingress Gateway

The ingress gateway is the most exposed component. A hardened configuration follows these principles: terminate TLS with modern ciphers, enforce SNI host matching, apply rate limiting, and integrate a WAF.

Configuring TLS Termination with Strong Cipher Suites

# ingress-gateway-tls.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-tls-config
  namespace: nginx-mesh
data:
  ssl-ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
  ssl-protocols: "TLSv1.2 TLSv1.3"
  ssl-prefer-server-ciphers: "on"
  ssl-session-tickets: "off"
  ssl-stapling: "on"
  ssl-stapling-verify: "on"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: secure-ingress
  annotations:
    nginx.org/ssl-services: "backend-service"
    nginx.org/ssl-ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384"
    nginx.org/ssl-prefer-server-ciphers: "true"
    nginx.org/proxy-ssl-protocols: "TLSv1.2 TLSv1.3"
spec:
  tls:
    - hosts:
        - api.example.com
      secretName: api-tls-secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gateway-service
                port:
                  number: 443

This configuration disables legacy TLS versions, removes weak ciphers, enables OCSP stapling for faster certificate revocation checks, and disables session tickets to prevent session resumption attacks.

Adding Rate Limiting to Prevent DDoS

# rate-limit-policy.yaml
apiVersion: nginx.com/v1alpha1
kind: RateLimitPolicy
metadata:
  name: ingress-rate-limit
  namespace: gateway
spec:
  rules:
    - match:
        host: "api.example.com"
        paths: ["/api/v1/*"]
      rateLimit:
        rate: 100
        burst: 20
        key: "${remote_addr}"
        delay: 5
    - match:
        paths: ["/health"]
      rateLimit:
        rate: 1000
        burst: 50
        key: "${remote_addr}"

Apply the rate limit policy to the ingress gateway deployment:

kubectl apply -f rate-limit-policy.yaml

# Verify the rate limit is active
for i in $(seq 1 150); do
  curl -s -o /dev/null -w "%{http_code}" https://api.example.com/api/v1/test
  echo ""
done
# After burst limit, you will see 503 Service Unavailable responses

WAF Integration with NGINX App Protect

For production hardening, integrate NGINX App Protect (NAAP) as a WAF module in the ingress gateway. This requires an NGINX Plus subscription with the App Protect module enabled.

# app-protect-policy.yaml
apiVersion: k8s.nginx.org/v1alpha1
kind: APPolicy
metadata:
  name: waf-policy
spec:
  policy:
    signature-settings:
      signature-inclusion-policy: "strict"
    threat-campaigns:
      - name: "command-execution"
        action: "block"
      - name: "sql-injection"
        action: "block"
      - name: "cross-site-scripting"
        action: "block"
    enforcement-mode: "blocking"
    blocking-settings:
      violations:
        - name: "VIOL_ASM_PARAMETER_TYPE_MISMATCH"
          alarm: true
          block: true
---
apiVersion: k8s.nginx.org/v1alpha1
kind: APLogConf
metadata:
  name: waf-logging
spec:
  filter:
    request_type: "all"
    minimum_severity: "critical"
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: waf-protected-ingress
  annotations:
    nginx.org/app-protect-policy: "waf-policy"
    nginx.org/app-protect-logconf: "waf-logging"
    nginx.org/app-protect-enable: "true"
spec:
  tls:
    - hosts:
        - api.example.com
      secretName: api-tls-secret
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: gateway-service
                port:
                  number: 443

The WAF blocks SQL injection, cross-site scripting, command execution, and parameter type mismatch attacks at the ingress boundary before they ever reach backend services.

Sidecar Security Hardening

The NGINX sidecar proxy itself must be hardened to prevent container escapes and privilege escalation. Apply Kubernetes Pod Security Standards and network policies to restrict the sidecar's capabilities.

Applying Pod Security Context

# secure-sidecar-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  namespace: payments
spec:
  replicas: 3
  selector:
    matchLabels:
      app: payment-service
  template:
    metadata:
      labels:
        app: payment-service
    spec:
      serviceAccountName: payment-service-sa
      securityContext:
        runAsNonRoot: true
        runAsUser: 101
        fsGroup: 101
      containers:
        - name: app
          image: my-app:latest
          securityContext:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
        - name: nginx-mesh-sidecar
          image: nginx-mesh-sidecar:latest
          securityContext:
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
              add:
                - NET_BIND_SERVICE

This configuration ensures the sidecar runs as a non-root user, has a read-only root filesystem, drops all Linux capabilities except the minimum required to bind to network ports, and prevents privilege escalation.

Network Policies to Isolate Sidecar Communication

# mesh-network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sidecar-isolation
  namespace: payments
spec:
  podSelector:
    matchLabels:
      app: payment-service
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              mesh-enabled: "true"
        - podSelector:
            matchLabels:
              app: order-service
      ports:
        - protocol: TCP
          port: 443
    - from:
        - namespaceSelector:
            matchLabels:
              name: nginx-mesh
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              mesh-enabled: "true"
      ports:
        - protocol: TCP
          port: 443
    - to:
        - namespaceSelector:
            matchLabels:
              name: nginx-mesh
      ports:
        - protocol: TCP
          port: 8443

Apply the network policy:

kubectl apply -f mesh-network-policy.yaml

# Verify the policy is enforced
kubectl describe networkpolicy sidecar-isolation -n payments

This restricts the sidecar to communicate only with other mesh-enabled pods on port 443 (mTLS data plane) and the NGINX Service Mesh control plane on designated ports. Any attempt to reach external endpoints from the sidecar is blocked.

Certificate and SPIFFE Identity Best Practices

The SPIFFE identity system underpins all authentication in NGINX Service Mesh. Hardening this subsystem requires careful attention to trust domain configuration, certificate lifetimes, and federation boundaries.

Configuring Trust Domain and Identity Templates

# spire-server-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: spire-server-config
  namespace: nginx-mesh
data:
  server.conf: |
    server:
      bind_address: 0.0.0.0
      bind_port: 8081
      trust_domain: "production.example.com"
      ca_ttl: 168h
      ca_subject:
        country: "US"
        organization: "Example Corp"
        common_name: "production.example.com"
    plugins:
      DataStore:
        sql:
          plugin_data:
            database_type: "sqlite3"
            connection_string: "/var/lib/spire/data/datastore.sqlite3"
      NodeAttestor:
        k8s_psat:
          plugin_data:
            cluster: "prod-cluster"
      KeyManager:
        memory:
          plugin_data: {}
      UpstreamAuthority:
        disk:
          plugin_data:
            key_file_path: "/etc/spire/keys/privkey.pem"
            cert_file_path: "/etc/spire/keys/cacert.pem"

Set the trust domain to a unique, organization-specific value like production.example.com. This prevents cross-mesh identity spoofing if multiple meshes exist in your infrastructure.

Rotating the SPIRE CA Regularly

# Manual CA rotation script
#!/bin/bash
# rotate-spire-ca.sh

# Generate new CA key and certificate
openssl req -new -x509 -days 365 -nodes \
  -subj "/C=US/O=Example Corp/CN=production.example.com" \
  -keyout new-ca-key.pem \
  -out new-ca-cert.pem \
  -addext "subjectAltName=DNS:production.example.com"

# Create a ConfigMap with the new CA certificate
kubectl create configmap spire-ca-cert \
  --from-file=cacert.pem=new-ca-cert.pem \
  --namespace nginx-mesh \
  --dry-run=client -o yaml | kubectl apply -f -

# Restart SPIRE server to pick up the new CA
kubectl rollout restart deployment/spire-server -n nginx-mesh

# Verify all agents have reconnected
kubectl wait --for=condition=ready pod \
  -l app=spire-agent -n nginx-mesh \
  --timeout=300s

Automate CA rotation with a cron job that runs every 30 days. Always keep the previous CA valid for a transition period (e.g., 24 hours) to allow all SVIDs to rotate gracefully.

Audit Logging and Security Monitoring

Even with all hardening measures in place, you need continuous visibility. NGINX Service Mesh provides detailed access logs and Prometheus metrics that feed into your SIEM and monitoring stack.

Enabling Comprehensive Access Logging

# access-log-config.yaml
apiVersion: nginx.com/v1alpha1
kind: AccessLogPolicy
metadata:
  name: full-access-logging
  namespace: payments
spec:
  filters:
    - paths: ["/api/*"]
      logFormat: |
        "$time_iso8601" "$remote_addr" "$ssl_client_fingerprint"
        "$server_name" "$request_method" "$request_uri"
        "$status" "$body_bytes_sent" "$request_time"
        "$upstream_addr" "$upstream_status"
        "$spiffe_id" "$request_id"
  destinations:
    - syslog:
        host: "siem-collector.monitoring.svc.cluster.local"
        port: 514
        protocol: "tcp"
        facility: "local0"
        severity: "info"
    - stdout:
        format: "json"

Apply the logging policy:

kubectl apply -f access-log-config.yaml

# Verify logs are flowing to your SIEM collector
kubectl logs deployment/siem-collector -n monitoring | grep "spiffe_id"

Prometheus Metrics for Security Events

NGINX Service Mesh exports metrics that can be scraped by Prometheus. Key security metrics include:

# Prometheus scrape configuration snippet
scrape_configs:
  - job_name: 'nginx-mesh-sidecars'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_container_name]
        action: keep
        regex: nginx-mesh-sidecar
    metric_relabel_configs:
      - source_labels: [__name__]
        action: keep
        regex: 'nginx_mesh_(auth|ssl|request)_(.*)'

Key metrics to alert on:

Sample Prometheus Alert Rules

# prometheus-alerts.yaml
groups:
  - name: nginx-mesh-security
    rules:
      - alert: HighAuthFailures
        expr: rate(nginx_mesh_auth_failures_total[5m]) > 10
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "High rate of mTLS authentication failures"
          description: "Service {{ $labels.pod }} in namespace {{ $labels.namespace }} has elevated auth failures. Investigate possible certificate issue or unauthorized access attempt."

      - alert: CertificateExpiryCritical
        expr: nginx_mesh_svid_expiry_seconds < 300
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "SVID certificate expiring in less than 5 minutes"
          description: "Pod {{ $labels.pod }} SVID expires soon. Check SPIRE agent connectivity."

      - alert: PolicyBlockRateIncrease
        expr: rate(nginx_mesh_request_blocked_by_policy_total[10m]) > 20
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Increased rate of policy-blocked requests"
          description: "Possible misconfiguration or active reconnaissance against namespace {{ $labels.namespace }}."

Best Practices Summary

The following checklist consolidates the most critical security hardening practices for NGINX Service Mesh. Use it as a reference during deployment and periodic audits.

Deployment-Time Hardening

Runtime Hardening

Operational Hardening

Secrets Management

Disaster Recovery and Incident Response

Despite best efforts, security incidents can occur. Prepare response procedures specifically for mesh-level compromises.

Isolating a Compromised Service

# Immediately apply a deny-all policy for the compromised service
cat <

Revoking and Reissuing Mesh-Wide Certificates

# Emergency certificate revocation procedure
# 1. Rotate the SPIRE CA immediately
kubectl delete configmap spire-ca-cert -n nginx-mesh
kubectl create configmap spire-ca-cert \
  --from-file=cacert.pem=emergency-ca-cert.pem \
  --namespace nginx-mesh

# 2. Restart SPIRE server and all agents
kubectl rollout restart deployment/spire-server -n nginx-mesh
kubectl delete pods -l app=spire-agent -n nginx-mesh

# 3. Force all sidecars to fetch new SVIDs
for deployment in $(kubectl get deployments -A -o json | \
  jq -r '.items[] | select(.spec.template.metadata.labels["nginx-mesh-sidecar"] == "true") | "\(.metadata.namespace)/\(.metadata.name)"'); do
  kubectl rollout restart deployment -n "${deployment%/*}" "${deployment#*/}"
done

# 4. Verify all pods are healthy with new certificates
kubectl wait --for=condition=ready pod -A \
  -l nginx-mesh-sidecar=true --timeout=600s

Validation and Testing Your Hardened Mesh

After applying hardening configurations, validate that security controls work as expected. Automated testing catches regressions during future changes.

Automated Security Test Suite

# security-validation.sh
#!/bin/bash

echo "=== NGINX Service Mesh Security Validation ==="

# Test 1: Verify strict mTLS - unauthenticated request should fail
echo "[Test 1] Testing mTLS enforcement..."
AUTH_FAIL=$(kubectl exec deployment/test-runner -- \
  curl -k -s -o /dev/null -w "%{http_code}" \
  https://payment-service.payments.svc.cluster.local/health)
if [ "$AUTH_FAIL" -eq "403" ] || [ "$AUTH_FAIL" -eq "000" ]; then
  echo "PASS: Unauthenticated requests blocked ($AUTH_FAIL)"
else
  echo "FAIL: mTLS not enforced, got HTTP $AUTH_FAIL"
  exit 1
fi

# Test 2: Verify namespace isolation
echo "[Test 2] Testing namespace isolation..."
NS_ISO=$(kubectl exec deployment/default-service -n default -- \
  curl -k -s -o /dev/null -w "%{http_code}" \
  https://payment-service.payments.svc.cluster.local/api/v1/status)
if [ "$NS_ISO" -eq "403" ]; then
  echo "PASS: Cross-namespace access denied"
else
  echo "FAIL: Namespace isolation not enforced, got HTTP $NS_ISO"
  exit 1
fi

# Test 3: Verify ACL path restrictions
echo "[Test 3] Testing ACL path restrictions..."
ACL_TEST=$(kubectl exec deployment/order-service -n payments -- \
  curl -k -s -o /dev/null -w "%{http_code}" \
  https://payment-service.payments.svc.cluster.local/api/v1/admin)
if [ "$ACL_TEST" -eq "403" ]; then
  echo "PASS: Unauthorized path blocked"
else
  echo "FAIL: ACL not enforced, got HTTP $ACL_TEST"
  exit 1
fi

# Test 4: Verify ingress WAF blocking
echo "[Test 4] Testing WAF SQL injection blocking..."
WAF_TEST=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Host: api.example.com" \
  "https://ingress-gateway/api/v1/search?q=1'+OR+'1'='1")
if [ "$WAF_TEST" -eq "403" ] || [ "$WAF_TEST" -eq "406" ]; then
  echo "PASS: SQL injection blocked by WAF"
else
  echo "FAIL: WAF did not block SQL injection, got HTTP $WAF_TEST"
  exit 1
fi

# Test 5: Verify rate limiting
echo "[Test 5] Testing rate limiting..."
RATE_LIMIT_COUNT=0
for i in $(seq 1 150); do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
    -H "Host: api.example.com" \
    "https://ingress-gateway/api/v1/test" 2>/dev/null)
  if [ "$STATUS" -eq "503" ]; then
    RATE_LIMIT_COUNT=$((RATE_LIMIT_COUNT + 1))
  fi
done
if [ "$RATE_LIMIT_COUNT" -gt 0 ]; then
  echo "PASS: Rate limiting active ($RATE_LIMIT_COUNT requests blocked)"
else
  echo "FAIL: Rate limiting not enforced"
  exit 1
fi

echo ""
echo "=== All security tests passed ==="

Run this test suite as part of your CI/CD pipeline after any mesh configuration change. A failing test blocks deployment to production.

Continuous Compliance with OPA Gatekeeper

# gatekeeper-constraint.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: require-mesh-security-labels
spec:
  match:
    kinds:
      - apiGroups: ["apps"]
        kinds: ["Deployment"]
  parameters:
    labels:
      - key: "nginx-mesh-security-policy"
        allowedRegex: "^((strict)|(permissive-test-only))$"
---
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | input.parameters.labels[label].key}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("Missing required labels: %v", [missing])
        }

This Gatekeeper policy ensures every deployment in the mesh carries a security policy label, preventing accidental deployment of services without mesh security configurations.

Conclusion

NGINX Service Mesh security hardening is not a one-time effort but an ongoing discipline. By enforcing strict mTLS, implementing fine-grained RBAC policies, hardening ingress gateways with WAF protection, restricting sidecar privileges, and establishing continuous monitoring and automated testing, you create a defense-in-depth architecture that protects microservices at every layer. The practices outlined in this tutorial—from deployment-time strict mode to emergency isolation procedures—form a comprehensive security framework. Regularly review your policies, rotate certificates on schedule, and keep the mesh control plane updated. A hardened service mesh becomes a powerful security asset rather than an additional attack surface, giving your organization confidence that inter-service communication remains authenticated, authorized, encrypted, and continuously audited.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles