Skip to content

Instantly share code, notes, and snippets.

@mohashari
Created July 25, 2026 01:04
Show Gist options
  • Select an option

  • Save mohashari/a872f63d3e3963d4fbc975cbf440bb02 to your computer and use it in GitHub Desktop.

Select an option

Save mohashari/a872f63d3e3963d4fbc975cbf440bb02 to your computer and use it in GitHub Desktop.
Implementing Zero-Trust Service-to-Service Authorization Using Envoy Proxies and Open Policy Agent (OPA) — code snippets
# Envoy HTTP filter configuration for OPA external authorization
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-opa
timeout: 0.15s
transport_api_version: V3
with_request_body:
max_request_bytes: 1024
pack_as_bytes: true
failure_mode_allow: false
status_on_error:
code: ServiceUnavailable
include_peer_certificate: true
# The corresponding Envoy cluster definition pointing to local OPA
clusters:
- name: ext-authz-opa
type: STATIC
connect_timeout: 0.25s
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: ext-authz-opa
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 9001
# OPA Daemon configuration for Envoy gRPC ext_authz plugin
services:
control-plane-service:
url: https://control-plane.internal.net
credentials:
bearer:
token: "env-var-expanded-token"
keys:
my-key:
key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0G4P9Kz1r8bXpLzWwQID
-----END PUBLIC KEY-----
bundles:
authz:
service: control-plane-service
resource: /v1/bundles/service-authz
signing:
keyid: my-key
polling:
min_delay_seconds: 10
max_delay_seconds: 30
plugins:
envoy_ext_authz_grpc:
addr: 127.0.0.1:9001
path: envoy/authz/allow
query: data.envoy.authz.allow
package envoy.authz
import rego.v1
# Default deny all traffic
default allow = false
# Main entry point specified in OPA config
allow if {
client_identity_allowed
jwt_claims_validated
endpoint_permissions_allowed
}
# 1. Parse client certificate SPIFFE identity from Envoy source principal
spiffe_id := input.attributes.source.principal
client_identity_allowed if {
# Ensure client identity presents a valid SPIFFE ID within our trust domain
startswith(spiffe_id, "spiffe://prod.internal/ns/core-services/sa/")
}
# 2. Extract and validate JWT bearer token passed in authorization header
jwt_token := token if {
auth_header := input.attributes.request.http.headers.authorization
startswith(auth_header, "Bearer ")
token := substring(auth_header, 7, -1)
}
# Helper to decode the JWT payload
jwt_payload := payload if {
[_, payload, _] := io.jwt.decode(jwt_token)
}
jwt_claims_validated if {
# Validate expiration time (unix timestamp comparison)
jwt_payload.exp > time.now_ns() / 1000000000
# Verify trusted issuer
jwt_payload.iss == "https://auth.internal.net"
}
# 3. Path and HTTP Method check matching client roles to actions
endpoint_permissions_allowed if {
request_method := input.attributes.request.http.method
request_path := split(trim(input.attributes.request.http.path, "/"), "/")
match_path_and_roles(request_method, request_path, jwt_payload.roles)
}
# Define rule permissions based on roles and paths
match_path_and_roles("GET", ["payments", _], roles) if {
"payment-viewer" in roles
}
match_path_and_roles("POST", ["payments"], roles) if {
"payment-creator" in roles
}
# 4. Propagate authorized metadata back to Envoy to inject into upstream request
headers := {
"x-auth-user-id": jwt_payload.sub,
"x-auth-client-spiffe": spiffe_id,
"x-auth-user-roles": concat(",", jwt_payload.roles)
}
apiVersion: apps/v1
kind: Deployment
metadata:
name: payment-service
namespace: core-services
spec:
replicas: 3
selector:
matchLabels:
app: payment-service
template:
metadata:
labels:
app: payment-service
spec:
containers:
# 1. Main Application Container
- name: app
image: internal-registry.net/core/payment-service:v2.4.1
ports:
- containerPort: 8080
env:
- name: PORT
value: "8080"
resources:
limits:
cpu: "1"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
# 2. Envoy Proxy Container (Sidecar)
- name: envoy-proxy
image: envoyproxy/envoy:v1.28.0
args: ["-c", "/etc/envoy/envoy.yaml", "--log-level", "info"]
ports:
- name: ingress-http
containerPort: 443
volumeMounts:
- name: envoy-config
mountPath: /etc/envoy
- name: spiffe-workload-api
mountPath: /run/spire/sockets
readOnly: true
resources:
limits:
cpu: "500m"
memory: "256Mi"
requests:
cpu: "50m"
memory: "64Mi"
# 3. Open Policy Agent (OPA) Container (Sidecar)
- name: opa
image: openpolicyagent/opa:0.61.0-envoy
args:
- "run"
- "--server"
- "--config-file=/etc/opa/opa-config.yaml"
- "/etc/opa/policy.rego"
volumeMounts:
- name: opa-config
mountPath: /etc/opa
ports:
- name: grpc-authz
containerPort: 9001
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
volumes:
- name: envoy-config
configMap:
name: payment-envoy-config
- name: opa-config
configMap:
name: payment-opa-config
- name: spiffe-workload-api
csi:
driver: "spiffe.csi.spiffe.io"
readOnly: true
package main
import (
"context"
"testing"
"github.com/open-policy-agent/opa/rego"
)
func TestRegoPolicy_Allow(t *testing.T) {
ctx := context.Background()
// Initialize the Rego engine with policy files and rules query
r := rego.New(
rego.Query("data.envoy.authz.allow"),
rego.Load([]string{"policy.rego"}, nil),
)
preparedQuery, err := r.PrepareForEval(ctx)
if err != nil {
t.Fatalf("Failed to prepare query: %v", err)
}
// Construct mock Envoy ext_authz payload
mockInput := map[string]interface{}{
"attributes": map[string]interface{}{
"source": map[string]interface{}{
"principal": "spiffe://prod.internal/ns/core-services/sa/billing-service",
},
"request": map[string]interface{}{
"http": map[string]interface{}{
"method": "POST",
"path": "/payments",
"headers": map[string]string{
"authorization": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfOTg3NiIsImV4cCI6NDA5MzUyOTYwMCwiaXNzIjoiaHR0cHM6Ly9hdXRoLmludGVybmFsLm5ldCIsInJvbGVzIjpbInBheW1lbnQtY3JlYXRvciJdfQ.sig",
},
},
},
},
}
results, err := preparedQuery.Eval(ctx, rego.EvalInput(mockInput))
if err != nil {
t.Fatalf("Failed to evaluate policy: %v", err)
}
if len(results) == 0 {
t.Fatal("Expected evaluation results, got none")
}
allowed, ok := results[0].Expressions[0].Value.(bool)
if !ok || !allowed {
t.Errorf("Expected policy to allow request, got allowed=%v", results[0].Expressions[0].Value)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment