Hi I'm new to Envoy and Istio. I'm trying to write an envoy filter to rewrite/redirect HTTP(s) requests. Below is my configuration (yes, a toy example) and it's not working.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: lua-filter
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_OUTBOUND
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"#type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
inlineCode: |
function envoy_on_request(request_handle)
request_handle:headers():add("authorization", "it works!")
end
function envoy_on_response(response_handle)
filter_name = "ENVOY"
response_handle:headers():add("my_Filter", filter_name)
end
after I deploy the app (listening on port 443 for https, behind Cloudflare) and envoy filter, I do curl -v <my_app>. I don't see either the added request header or the response header. I also tried adding xff_num_trusted_hops: 2 suggested by some other answers but to not avail. What did I do incorrect?
To apply the filter to a single pod you have to add workloadSelector for your app.
workloadSelector:
labels:
xxx: xxx
For example, there is an nginx deployment and your envoy filter with appropriate workloadSelector .
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx1
spec:
selector:
matchLabels:
run: nginx1
replicas: 1
template:
metadata:
labels:
run: nginx1
app: frontend
spec:
containers:
- name: nginx1
image: nginx
ports:
- containerPort: 80
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: lua-filter
namespace: default
spec:
workloadSelector:
labels:
run: nginx1
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"#type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
inlineCode: |
function envoy_on_request(request_handle)
request_handle:headers():add("authorization", "it works!")
end
function envoy_on_response(response_handle)
filter_name = "ENVOY"
response_handle:headers():add("my_Filter", filter_name)
end
To apply the filter to all requests going through your istio ingress gateway.
1.Change change context from SIDECAR_INBOUND to GATEWAY .
2.Set a workloadSelector.
workloadSelector:
labels:
istio: ingressgateway
3.Set istio-system namespace.
namespace: istio-system
4.There is your example after few edits.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: lua-filter
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.http_connection_manager"
subFilter:
name: "envoy.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua
typed_config:
"#type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
inlineCode: |
function envoy_on_request(request_handle)
request_handle:headers():add("authorization", "it works!")
end
function envoy_on_response(response_handle)
filter_name = "ENVOY"
response_handle:headers():add("my_Filter", filter_name)
end
5.I checked it with curl
curl -s -I -X HEAD xx.xx.xx.xx/productpage
HTTP/1.1 200 OK
content-type: text/html; charset=utf-8
content-length: 5179
server: istio-envoy
date: Tue, 10 Nov 2020 08:28:30 GMT
x-envoy-upstream-service-time: 60
my_filter: ENVOY <---
AND
I checked it with config_dump in istio ingress-gateway pod.
I exec there with
kubectl exec -ti istio-ingressgateway-86f88b6f6-2tv64 -n istio-system -- /bin/bash
Results from config_dump
curl 0:15000/config_dump | grep my_Filter
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 140k 0 140k 0 0 9.7M 0 --:--:-- --:--:-- --:--:-- 9.7M
"inline_code": "function envoy_on_request(request_handle)\n request_handle:headers():add(\"authorization\", \"it works!\")\nend\nfunction envoy_on_response(response_handle)\n filter_name = \"ENVOY\"\n response_handle:headers():add(\"my_Filter\", filter_name)\nend\n"
Additional resources:
https://discuss.istio.io/t/adding-custom-response-headers-using-istios-1-6-0-envoy-lua-filter/7494/6
https://istio.io/latest/docs/reference/config/networking/envoy-filter/
Related
Why EnVoyFilter does not generate Envoy configurations under the specified namespace. Envoy configurations can be generated under Istio-System.
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: 503-redirect-lua-filter
namespace: idp
spec:
# workloadSelector:
# labels:
# ray-node-name: ray-idp-raycluster-a-executor-head
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"#type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_response(response_handle)
if response_handle:headers():get(":status") == "503" then
response_handle:logInfo("Got status 503, redirect to login...")
response_handle:headers():replace(":status", "302")
response_handle:headers():add("location", "https://xxxx.xxxx.co/studio")
end
end
kubectl -n istio-system exec istio-ingressgateway-787c7bd99b-p97q2 -c istio-proxy -- curl 'localhost:15000/config_dump' > config_dump.jsonv
I wanted to setup and use istio egress gateway.
I followed this link https://preliminary.istio.io/latest/blog/2018/egress-tcp/ and made this manifest:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-oracle
spec:
hosts:
- my.oracle.instance.com
addresses:
- 192.168.100.50/32
ports:
- name: tcp
number: 1521
protocol: tcp
location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: egressgateway
servers:
- hosts:
- my.oracle.instance.com
port:
name: tcp
number: 1521
protocol: TCP
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: egressgateway-destination-rule-for-oracle
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
subsets:
- name: external-oracle
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: direct-external-oracle-through-egress-gateway
spec:
gateways:
- mesh
- istio-egressgateway
hosts:
- my.oracle.instance.com
tcp:
- match:
- destinationSubnets:
- 192.168.100.50/32
gateways:
- mesh
port: 1521
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
port:
number: 1521
subset: external-oracle
- match:
- gateways:
- istio-egressgateway
port: 1521
route:
- destination:
host: my.oracle.instance.com
port:
number: 1521
weight: 100
And then my application not able to start because a JDBC error.
I started to watch the egress-gateway pod's logs but I not see any sign of traffic.
So I googled and found this link: https://istio.io/latest/blog/2018/egress-monitoring-access-control/ to boost my egress-gateway pod logging but this looking a bit deprecated for me.
cat <<EOF | kubectl apply -f -
# Log entry for egress access
apiVersion: "config.istio.io/v1alpha2"
kind: logentry
metadata:
name: egress-access
namespace: istio-system
spec:
severity: '"info"'
timestamp: request.time
variables:
destination: request.host | "unknown"
path: request.path | "unknown"
responseCode: response.code | 0
responseSize: response.size | 0
reporterUID: context.reporter.uid | "unknown"
sourcePrincipal: source.principal | "unknown"
monitored_resource_type: '"UNSPECIFIED"'
---
# Handler for error egress access entries
apiVersion: "config.istio.io/v1alpha2"
kind: stdio
metadata:
name: egress-error-logger
namespace: istio-system
spec:
severity_levels:
info: 2 # output log level as error
outputAsJson: true
---
# Rule to handle access to *.cnn.com/politics
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: handle-politics
namespace: istio-system
spec:
match: request.host.endsWith("cnn.com") && request.path.startsWith("/politics") && context.reporter.uid.startsWith("kubernetes://istio-egressgateway")
actions:
- handler: egress-error-logger.stdio
instances:
- egress-access.logentry
---
# Handler for info egress access entries
apiVersion: "config.istio.io/v1alpha2"
kind: stdio
metadata:
name: egress-access-logger
namespace: istio-system
spec:
severity_levels:
info: 0 # output log level as info
outputAsJson: true
---
# Rule to handle access to *.com
apiVersion: "config.istio.io/v1alpha2"
kind: rule
metadata:
name: handle-cnn-access
namespace: istio-system
spec:
match: request.host.endsWith(".com") && context.reporter.uid.startsWith("kubernetes://istio-egressgateway")
actions:
- handler: egress-access-logger.stdio
instances:
- egress-access.logentry
EOF
But when I want to apply to this I have this error:
no matches for kind "logentry" in version "config.istio.io/v1alpha2"
no matches for kind "stdio" in version "config.istio.io/v1alpha2"
no matches for kind "rule" in version "config.istio.io/v1alpha2"
no matches for kind "stdio" in version "config.istio.io/v1alpha2"
no matches for kind "rule" in version "config.istio.io/v1alpha2"
There is a new api version of there kind's?
istioctl version
client version: 1.12.0
control plane version: 1.12.0
data plane version: 1.12.0 (28 proxies)
There is a way to make a working istio egress-gateway with a logging (as the istio ingress gateway logging works).
Is there any way to mention the prefix of the url for rate limit in istio?
In the below config we are using /actuator/info in which is there any way to mention prefix of the URL?
Say
- key: PATH_PREFIX
value: "/actuator/"
To match all the endpoint under /actuator/* ?
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ratelimit-config
namespace: istio-system
data:
config.yaml: |
domain: test-istio-rate-limit.com
descriptors:
- key: PATH
value: "/actuator/info"
rate_limit:
unit: minute
requests_per_unit: 1
- key: PATH
rate_limit:
unit: minute
requests_per_unit: 100
---
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-ratelimit
namespace: istio-system
spec:
workloadSelector:
# select by label in the same namespace
labels:
istio: ingressgateway
configPatches:
# The Envoy config you want to modify
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
# Adds the Envoy Rate Limit Filter in HTTP filter chain.
value:
name: envoy.filters.http.ratelimit
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
# domain can be anything! Match it to the ratelimter service config
domain: test-istio-rate-limit.com
failure_mode_deny: true
timeout: 10s
rate_limit_service:
grpc_service:
envoy_grpc:
cluster_name: rate_limit_cluster
transport_api_version: V3
- applyTo: CLUSTER
match:
cluster:
service: ratelimit.istio-system.svc.cluster.local
patch:
operation: ADD
# Adds the rate limit service cluster for rate limit service defined in step 1.
value:
name: rate_limit_cluster
type: STRICT_DNS
connect_timeout: 10s
lb_policy: ROUND_ROBIN
http2_protocol_options: {}
load_assignment:
cluster_name: rate_limit_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: ratelimit.istio-system.svc.cluster.local
port_value: 8081
---
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-ratelimit-svc
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: VIRTUAL_HOST
match:
context: GATEWAY
routeConfiguration:
vhost:
name: ""
route:
action: ANY
patch:
operation: MERGE
# Applies the rate limit rules.
value:
rate_limits:
- actions: # any actions in here
- request_headers:
header_name: ":path"
descriptor_key: "PATH"
Use https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/header_to_metadata/v3/header_to_metadata.proto.html
Example : https://dev.to/tresmonauten/setup-an-ingress-rate-limiter-with-envoy-and-istio-1i9g , scroll down to 'Beware of pitfalls'
For some reason, Istio 1.8.1 stopped accepting gzip filter for Envoy.
Warning: Envoy filter: can't unmarshal Any nested proto type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor: unknown field "response_direction_config" in envoy.extensions.filters.http.compressor.v3.Compressor
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: gzip
spec:
workloadSelector:
labels:
app: istio-ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: envoy.http_connection_manager
subFilter:
name: envoy.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.compressor
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
remove_accept_encoding_header: true
response_direction_config:
common_config:
min_content_length: 100
content_type:
- '*/*'
compressor_library:
name: for_response
typed_config:
"#type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
memory_level: 9
window_bits: 15
compression_level: 9
Can you help me please to specify YAML Istio EnvoyFilter to have the request buffer, analog of Nginx request buffer.
I tried
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: connection
namespace: my-test
spec:
workloadSelector:
labels:
role: backend
configPatches:
- applyTo: LISTENER
match:
context: SIDECAR_INBOUND
patch:
operation: MERGE
value:
per_connection_buffer_limit_bytes: 21000000.0 #21MB
This is applied successfully to the cluster but does not work as expected
Thanks
UPD
this works (for istio 1.5)
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: connection
namespace: my-test
spec:
filters:
- filterName: envoy.buffer
filterType: HTTP
filterConfig:
maxRequestBytes: 21000000.0 #21MB
UPD 2
this works (for istio 1.8)
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-buffersize-limit
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.buffer
typed_config:
"#type": type.googleapis.com/envoy.extensions.filters.http.buffer.v3.Buffer
max_request_bytes: 26214400 # 25 MB.