Microservice Security


Introduction

Microservice architectures distribute application functionality across multiple independent services, each with its own data store, API, and deployment lifecycle. This distribution increases the attack surface — intra-service communication must be secured, secrets must be distributed without exposure, and visibility must span service boundaries.

Service Mesh mTLS

A service mesh provides a dedicated infrastructure layer for handling service-to-service communication. It transparently encrypts traffic between services using mutual TLS (mTLS).

Istio mTLS Configuration




# Enable mTLS across the mesh


apiVersion: security.istio.io/v1beta1


kind: PeerAuthentication


metadata:


name: default


namespace: istio-system


spec:


mtls:


mode: STRICT # Reject plain-text traffic








# Per-namespace mTLS policy


apiVersion: security.istio.io/v1beta1


kind: PeerAuthentication


metadata:


name: payment-service


namespace: production


spec:


selector:


matchLabels:


app: payment-service


mtls:


mode: STRICT


portLevelMtls:


8080:


mode: DISABLE # Allow plaintext for health checks only








# Authorization policy for service-to-service access


apiVersion: security.istio.io/v1beta1


kind: AuthorizationPolicy


metadata:


name: payment-service-authz


namespace: production


spec:


selector:


matchLabels:


app: payment-service


rules:


- from:


- source:


principals: ["cluster.local/ns/production/sa/order-service"]


namespaces: ["production"]


to:


- operation:


methods: ["POST", "GET"]


paths: ["/api/v1/charges"]





Envoy Sidecar Configuration




# Envoy TLS configuration (used under the hood by Istio)


static_resources:


listeners:


- name: service_listener


address:


socket_address: { address: 0.0.0.0, port_value: 8443 }


filter_chains:


- filters:


- name: envoy.filters.network.http_connection_manager


typed_config:


"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager


codec_type: AUTO


stat_prefix: ingress_http


route_config:


virtual_hosts:


- name: backend


domains: ["*"]


routes:


- match: { prefix: "/" }


route: { cluster: service_cluster }


http_filters:


- name: envoy.filters.http.router


transport_socket:


name: envoy.transport_sockets.tls


typed_config:


"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext


common_tls_context:


tls_certificates:


- certificate_chain: { filename: "/etc/certs/cert.pem" }


private_key: { filename: "/etc/certs/key.pem" }


validation_context:


trusted_ca: { filename: "/etc/certs/ca.pem" }





API Gateway Security

The API gateway is the ingress point for external traffic and performs authentication, rate limiting, and request validation.




# Kong API Gateway security configuration


_format_version: "3.0"


services:


- name: order-service


host: order-service.production.svc.cluster.local


port: 8080


protocol: http


routes:


- name: order-route


paths:


- /api/v1/orders


methods: [GET, POST]




plugins:


- name: oauth2


config:


scopes: ["read:orders", "write:orders"]


mandatory_scope: true


token_expiration: 3600




- name: rate-limiting


config:


minute: 100


hour: 1000


policy: local




- name: ip-restriction


config:


allow:


- 10.0.0.0/8




- name: cors


config:


origins: ["https://app.example.com"]


methods: ["GET", "POST"]


headers: ["Authorization", "Content-Type"]





Secret Distribution

Never store secrets in code or configuration files. Use a dedicated secret management system.




# Kubernetes External Secrets Operator


apiVersion: external-secrets.io/v1beta1


kind: ExternalSecret


metadata:


name: database-credentials


namespace: production


spec:


secretStoreRef:


name: aws-secret-store


kind: ClusterSecretStore


target:


name: database-credentials


creationPolicy: Owner


data:


- secretKey: username


remoteRef:


key: production/database/credentials


property: username


- secretKey: password


remoteRef:


key: production/database/credentials


property: password








# HashiCorp Vault integration


import hvac




class VaultSecretManager:


def __init__(self):


self.client = hvac.Client(


url='https://vault.example.com:8200',


token=self._get_vault_token()


)




def get_database_credentials(self, role_name):


"""Get dynamic database credentials from Vault."""


creds = self.client.secrets.database.generate_credentials(


name=role_name,


mount_point='database'


)


return {


'username': creds['data']['username'],


'password': creds['data']['password']


}




def rotate_secret(self, path):


"""Force rotation of a static secret."""


self.client.secrets.kv.v2.delete_metadata_and_all_versions(


path=path,


mount_point='secret'


)





Observability

Distributed tracing correlates requests across service boundaries, enabling security incident reconstruction.




from opentelemetry import trace


from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter


from opentelemetry.sdk.trace import TracerProvider


from opentelemetry.sdk.trace.export import BatchSpanProcessor




# Initialize distributed tracing


provider = TracerProvider()


processor = BatchSpanProcessor(OTLPSpanExporter())


provider.add_span_processor(processor)


trace.set_tracer_provider(provider)




tracer = trace.get_tracer(__name__)




def process_order(request):


with tracer.start_as_current_span("process_order") as span:


span.set_attribute("order_id", request.order_id)


span.set_attribute("user_id", request.user_id)




# Add security-relevant attributes


span.set_attribute("auth.method", "oauth2")


span.set_attribute("ip_address", request.client_ip)




# Call downstream service


with tracer.start_as_current_span("validate_payment") as child_span:


child_span.set_attribute("payment_provider", "stripe")


result = payment_service.validate(request)





Defense in Depth for Microservices




microservice_security_layers:


network:


- service_mesh_mtls: strict


- network_policies: default_deny


- api_gateway_authentication




identity:


- service_accounts_per_pod


- jwt_token_validation


- oauth2_for_external_apis




data:


- encryption_at_rest


- encrypted_service_communication


- dynamic_secret_rotation




runtime:


- pod_security_policies


- container_immutable_filesystem


- resource_limits




observability:


- distributed_tracing


- centralized_logging


- anomaly_detection





Conclusion

Microservice security requires shifting from perimeter-based defense to identity-based security. Use a service mesh for automatic mTLS between services, enforce authorization at the API gateway, distribute secrets through dedicated systems like Vault or External Secrets Operator, and implement distributed tracing for cross-service visibility. Each service should be treated as an untrusted external system — authenticate and authorize every request, regardless of source.