Microservices Security Testing: Architecture, API Gateways, and Service Mesh
Microservices architectures distribute an application across dozens or hundreds of independently deployable services. Each service has its own API. Each communicates with others over the network. Authentication happens at multiple layers. This is not a monolith with one attack surface — it is a distributed system where each connection point is a potential vulnerability.
Security testing microservices is different from testing a traditional web application. The perimeter is not well-defined. The trust model between services is critical. And standard web application scanners that assume a single application miss entire categories of microservices-specific vulnerabilities.
This guide covers how to approach security testing for microservices architectures systematically.
Understanding the Attack Surface
Map the attack surface before testing. In microservices, this includes:
| Layer | Components | Key Risks |
|---|---|---|
| External edge | API gateway, load balancer, CDN | Gateway bypass, routing issues |
| Service-to-service | Internal APIs, message queues | Broken service auth, lateral movement |
| Service mesh | Istio, Linkerd, Envoy sidecars | mTLS misconfig, policy bypass |
| Orchestration | Kubernetes API server, etcd | Privilege escalation, secret access |
| Runtime | Container images, registries | Vulnerable images, container escape |
| Data | Databases, caches, queues | Cross-service data leakage |
Test 1: API Gateway Bypass
The API gateway is the intended entry point for external traffic. It handles authentication, rate limiting, and routing. If individual microservices are reachable directly without going through the gateway, all gateway controls are bypassed.
# Enumerate exposed services
# Check for direct service exposure on non-standard ports
nmap -sV -p 8000-9999 target.example.com
# Look for services exposed via cloud load balancers, ingress, or DNS
# In AWS: check security groups for inbound rules on EC2/ECS ports
# In k8s: check for NodePort or LoadBalancer type Services
# Attempt direct service access (skip gateway auth):
curl http://internal-service.target.com:8081/api/users
# vs
curl -H "Authorization: Bearer $TOKEN" https://api.target.com/users
# If the direct call succeeds without auth: gateway bypass confirmed
Cloud environments often expose services unintentionally through misconfigured security groups or Kubernetes service types. Check:
- AWS: security groups allowing 0.0.0.0/0 inbound on non-80/443 ports
- Kubernetes: services of type
NodePortorLoadBalancerthat should beClusterIP - Docker: containers with published ports on the host that bypass network segmentation
Test 2: Service-to-Service Authentication
How do services authenticate to each other? Common patterns have common weaknesses:
Shared secrets / API keys
# Test: can you call internal service APIs with no auth or known shared secrets?
curl -H "X-Service-Token: internal-service-key" \
http://internal-payment-service/api/process-payment
# Look for service credentials in:
# - Environment variables (inspect via SSRF or compromised service)
# - Kubernetes secrets (kubectl get secrets if you have cluster access)
# - Application config files in container images
JWT-based service identity
# Internal JWTs are often signed with weaker keys than customer-facing ones
# Test for:
# - None algorithm bypass (alg:none)
# - Same key used for internal + external tokens
# - Service tokens with broader claims than necessary
# Decode internal service JWT and look at:
# - iss (issuer) — is it validated?
# - scope — what permissions does this token grant?
# - exp — does it expire?
mTLS (mutual TLS)
# If using service mesh with mTLS:
# Test if services accept plaintext connections (mTLS may not be enforced)
curl http://internal-service:8080/api/data # No TLS
# Test if mTLS validation is permissive
# Some setups accept any valid client cert, not specific service identities
Test 3: Service Mesh Security (Istio / Linkerd)
Service meshes add a security layer through sidecar proxies (Envoy in Istio). They enforce traffic policies, mTLS, and authorization rules. Misconfigurations are common.
# Istio: check authorization policies
kubectl get authorizationpolicies --all-namespaces
# A policy that allows all traffic from any source:
# spec:
# action: ALLOW
# rules:
# - {} # Empty rule = allow everything
# PeerAuthentication mode should be STRICT, not PERMISSIVE
kubectl get peerauthentication --all-namespaces -o yaml | grep mode
# PERMISSIVE allows both mTLS and plaintext = mTLS provides no security
Istio authorization policy mistakes to check:
- Wildcard namespace selectors (
namespaceSelector: {}) granting access from any namespace - Missing default-deny policy — Istio allows all traffic by default; explicit allow-all is the same as no policy
- Header-based trust in authorization rules — if the rule trusts
X-Forwarded-Foror custom service identity headers that can be spoofed
Test 4: Kubernetes RBAC and API Server Exposure
# Check if the Kubernetes API server is accessible from your test position
curl -k https://kubernetes.default.svc/api/v1/namespaces
# Check service account token permissions (from within a pod)
cat /var/run/secrets/kubernetes.io/serviceaccount/token | jwt decode -
# Test what the current service account can do:
kubectl auth can-i --list --namespace=default
# Overprivileged service accounts can:
# - Read secrets from other namespaces
# - Create/modify pods (potential container escape path)
# - Access etcd data directly
Test 5: Cross-Service Authorization (Broken Object-Level Auth)
In microservices, user A's request to Service A might trigger Service A to call Service B on behalf of user A. Does Service B verify that user A is authorized to access the resource it's fetching? Often not — it trusts that Service A already checked.
# Scenario: User A requests their order history
GET /api/orders/12345
# Service A (Orders) validates user owns order 12345, then calls:
GET /internal/payments/order/12345
# Service B (Payments) assumes Service A already validated ownership
# Test: Call Service A with user A's credentials but for user B's resource ID
GET /api/orders/67890 # user B's order, user A's token
# Expected: 403 Forbidden (Service A checks ownership)
# Then test Service B directly if accessible:
GET /internal/payments/order/67890 # same user A's token
# Vulnerable: Service B returns user B's payment data assuming Service A validated
Test 6: Message Queue Injection and Consumer Spoofing
Microservices often communicate via message queues (Kafka, RabbitMQ, SQS). Messages may not be authenticated or validated by consumers.
# If you can publish to a queue (via SSRF, compromised service, or exposed management UI):
# Test message injection with:
# - Elevated privilege claims in message payload
# - User ID spoofing in event data
# - Command injection in message fields processed by consumers
# RabbitMQ management UI often exposed on port 15672
# Default credentials: guest/guest
curl http://target.com:15672/api/queues
# Kafka without authentication:
# List topics:
kafka-topics --list --bootstrap-server target.com:9092
# Produce a malicious message:
echo '{"user_id": "admin", "action": "grant_admin"}' | \
kafka-console-producer --bootstrap-server target.com:9092 --topic user-events
Test 7: SSRF as Lateral Movement
Server-Side Request Forgery is significantly more damaging in microservices than in monolithic applications. A successful SSRF in one service becomes a pivot point to reach all internal services.
# From an SSRF in the public-facing service:
# Probe internal services:
http://internal-user-service/api/users
http://internal-payment-service/api/transactions
http://169.254.169.254/latest/meta-data/ # AWS metadata (IAM role credentials)
http://kubernetes.default.svc/api/v1/secrets
# Service discovery — scan internal network
http://10.0.0.1/
http://10.0.0.2/
# etc.
SSRF is covered in our SSRF testing guide, but the internal network topology of a microservices deployment makes SSRF findings critical priority.
Test 8: Container Image Vulnerabilities
# Scan container images for known CVEs
# Pull image and scan locally:
docker pull target-service:latest
trivy image target-service:latest
grype target-service:latest
# Check for secrets baked into images:
docker history target-service:latest
docker run --rm target-service:latest env # Environment variables
docker run --rm --entrypoint cat target-service:latest /app/.env
# Running with excessive privileges:
docker inspect target-container | grep -i privileged
docker inspect target-container | grep -i cap # Check capabilities
Test 9: Service Discovery and Internal API Documentation
Many microservices expose Swagger/OpenAPI documentation internally, intended for other services. If these are reachable externally or via SSRF:
# Look for internal API docs:
GET /internal/swagger.json
GET /internal/openapi.yaml
GET /api-docs
GET /__docs/
# Common internal management endpoints:
GET /actuator # Spring Boot — exposes health, metrics, env, beans
GET /actuator/env # Environment variables including secrets
GET /actuator/httptrace # Recent HTTP requests
GET /metrics # Prometheus metrics endpoint
GET /debug/vars # Go pprof/expvar
GET /.well-known/
A Testing Framework for Microservices Engagements
Structure microservices security assessments in three phases:
- Architecture mapping — document all services, their exposure (external/internal), communication patterns, and auth mechanisms before testing
- Perimeter testing — API gateway, load balancers, exposed ports, TLS configuration
- Internal testing — service-to-service auth, RBAC, cross-service authorization, message queues, service mesh policies
Without architecture mapping first, you will miss services and test the wrong things. Get the architecture diagram. If there isn't one, build it during reconnaissance.
Microservices expand your attack surface with every new service. Ironimo provides continuous security scanning across your web-facing APIs and services — built on Kali Linux tools, running on schedule or on demand. Catch configuration drift before it becomes a breach.
Start free scanKey Takeaways
- Map the architecture before testing — know what services exist, which are internet-facing, and how they communicate
- API gateway bypass is the highest-impact finding: direct service access skips all perimeter controls
- Service-to-service authentication is often weaker than external auth — test internal APIs as a first-class target
- Kubernetes RBAC misconfigurations turn a compromised pod into a cluster-wide pivot
- SSRF in microservices is not just SSRF — it is lateral movement through the entire internal network
- Message queues are trusted channels that rarely validate message authenticity