APIs (Application Programming Interfaces) have become an integral part of modern software development. They allow different applications to communicate and exchange data, enabling developers to create complex systems that integrate multiple services and technologies. APIs are used by companies of all sizes to power their digital products and services, from social media platforms to financial systems.
However, APIs can also be complex and challenging to manage, particularly when it comes to security and scalability. As APIs are exposed to the internet, they are vulnerable to attacks such as injection, denial of service, and man-in-the-middle attacks. Furthermore, as API usage grows, it becomes increasingly challenging to scale them to meet the demands of growing user bases and increasing traffic. This article aims to demonstrate the use of open source technologies, such as Envoy Proxy, to build a secure, scalable, and resilient Application Programming Interface (API) layer for organizations that depend heavily on APIs.
The following design will be implemented within the scope of this article to demonstrate the creation of a secure and scalable API layer.

First, let’s start with the external authentication service and the related proxy configuration, as it is the first service that Envoy Proxy calls when a request is received.
Rate limiting with Envoy ratelimit gRPC service
Envoy Proxy offers multiple rate limiting strategies, including local rate limiting, circuit breaking, and global rate limiting. For this article, we will focus on global rate limiting using the Envoy External Rate Limit Service. Local rate limiting and circuit breakers can also be used in cases where network connection level rate limiting is needed, in addition to application level rate limiting enforced by the global rate limit service.
Add ratelimit filter to the HTTP filter chain
Similar to external authorization, we need to add the Envoy Rate Limit filter to the filter chain to enable the Envoy Proxy to call the global rate limit service. It’s important to add the Rate Limit filter after the External Authorization filter to reduce the load on the external ratelimit service.
http_filters:
- name: envoy.filters.http.ext_authz
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
grpc_service:
envoy_grpc:
cluster_name: ext_authz
timeout: 2s
transport_api_version: V3
- name: envoy.filters.http.ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
domain: default
failure_mode_deny: true
enable_x_ratelimit_headers: DRAFT_VERSION_03
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: ratelimit
transport_api_version: V3Provide ratelimit configuration to the external ratelimit service
Envoy Rate Limit Service uses descriptors which are basically key, value pairs to perform rate limiting. In order to use the Envoy Rate Limit Service, we need to provide rate limits related to the descriptors as configuration to the Rate Limit Service.
---
domain: default
descriptors:
- key: version
value: v1
rate_limit:
unit: second
requests_per_unit: 5
- key: version
value: v2
rate_limit:
unit: second
requests_per_unit: 10Add ratelimit descriptors to the routes
Additionally, we need a mechanism for Envoy Proxy to inform the External Rate Limit Service to increment a specific descriptor when a resource is accessed. To achieve this, we need to define descriptors for each resource.
route_config:
name: local_route
virtual_hosts:
- name: upstream
domains:
- "*"
routes:
- match:
prefix: "/api/v1"
route:
cluster: upstream_service
rate_limits:
- actions:
- generic_key:
descriptor_key: version
descriptor_value: v1
- match:
prefix: "/api/v2"
route:
cluster: upstream_service
rate_limits:
- actions:
- generic_key:
descriptor_key: version
descriptor_value: v2 In this scenario, we have defined two rate limit keys. When resources with prefix /api/v1 are accessed, the rate limit policy with descriptor value v1 is applied. Similarly, for resources with prefix /api/v2, the rate limit policy with descriptor value v2 is applied. This means that API v1 can be accessed 5 times per minute, while API v2 can be accessed 10 times per minute. If the quota is exceeded, Envoy Proxy returns a 429 error response without processing the request any further.
Collecting telemetry data for distributed tracing
As demonstrated in the above scenario, Envoy Proxy makes multiple gRPC/HTTP requests to external services during request processing. Therefore, it’s important to have better visibility into what’s happening behind the scenes for debugging errors or monitoring purposes. In the above scenario, we can configure Envoy Proxy, External Authorization Service, and Rate Limit Service to publish telemetry data to a telemetry backend. For this example, we use Jaeger as the telemetry backend and OpenTelemetry to generate telemetry data.
Envoy proxy tracer configuration
- 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
generate_request_id: true
tracing:
provider:
name: envoy.tracers.opentelemetry
typed_config:
"@type": type.googleapis.com/envoy.config.trace.v3.OpenTelemetryConfig
grpc_service:
envoy_grpc:
cluster_name: jaeger
timeout: 1s
service_name: proxySummary
This article mainly focuses on the application-level security and scalability of the API layer. We achieve application-level security using the External Authorization Service, which deals with identity verification and authorization, and the External Rate Limit Service, which ensures the availability of upstream services by performing the configured rate limits.
Scalability can be achieved by scaling the necessary components based on requirements. It’s recommended to identify the bottleneck and scale the components accordingly. For example, if the rate limit service is causing a bottleneck in request processing and adding high latency, the external rate limit service can be scaled independently without scaling other components.
This kind of API layer helps application developers focus on writing business logic in their microservices without worrying about security and scalability.
Complete source code for the above setup with a docker-compose deployment: secure-scalable-api-layer