Envoy filter in istio unable to apply rate limit based on regex - istio

I am working on rate limit using the istio. I want to apply different rate limit based on the regex. The url which has /api/iam/.* should have rate limit of 2 req/minute and default rate limit on other paths should be 100 req/s. I am trying to use
rate_limits:
- actions:
- header_value_match:
descriptor_value: two_legged_path
headers:
- name: ":path"
string_match:
safe_regex:
google_re2: {}
regex: "api/iam/.*"
we used string_match with safe_regex but it is not working. It always applies the default behaviour which is 100 req/s. Could you please help I have followed numerious examples and nothing seemed to work.
The full configuration
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-local-ratelimit-svc
namespace: istio-system
spec:
workloadSelector:
labels:
app: iam-authn-service
env: az-dev
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"#type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
- applyTo: HTTP_ROUTE
match:
context: SIDECAR_INBOUND
routeConfiguration:
vhost:
name: "inbound|http|8080"
route:
action: ANY
patch:
operation: MERGE
value:
route:
rate_limits:
- actions:
- header_value_match:
descriptor_value: two_legged_path
headers:
- name: ":path"
string_match:
safe_regex:
google_re2: {}
regex: "api/iam/.*"
typed_per_filter_config:
envoy.filters.http.local_ratelimit:
"#type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
descriptors:
- entries:
- key: header_match
value: two_legged_path
token_bucket:
max_tokens: 2
tokens_per_fill: 2
fill_interval: 60s
token_bucket:
max_tokens: 100
tokens_per_fill: 100
fill_interval: 1s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value:
numerator: 100
denominator: HUNDRED
response_headers_to_add:
- append: false
header:
key: x-local-rate-limit
value: 'true'

The istio doesn't use the latest envoy, the valid doc: https://www.envoyproxy.io/docs/envoy/v1.17.1/api-v3/type/matcher/v3/regex.proto#envoy-v3-api-msg-type-matcher-v3-regexmatcher-googlere2
use safe_regex_match instead of string_match

Related

Istio: Multiple query parameters with the same key

I'd like to re-direct queries with Istio based on the query parameter ?key=value. That works with the following VirtualService (with re-directing replaced by returning a different string):
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- queryParams:
key:
exact: "value"
directResponse:
status: 301
body:
string: "redirected"
- directResponse:
status: 200
body:
string: "standard"
The issue is that sometimes I get the query ?key=foo&key=value for which I would also like to match and re-direct, but that doesn't work, the first "key" matches, the value param "foo" doesn't, so the whole match fails. Is there a way to match one of multiple keys with different values? "value" is fixed, "foo" can also be something else, except it is not "value".

Istio Installation Failed - Apple Silicon M1

istio-1.12.2
istioctl install --set profile=demo -y
Not sure why the pod is still pending and didn't match Pod's node affinity.
SecretName: istio-ingressgateway-ca-certs
Optional: true
kube-api-access-sfpw2:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 55s (x4 over 4m31s) default-scheduler 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector.
From the pod here is the affinity
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
weight: 2
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- ppc64le
weight: 2
- preference:
matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- s390x
weight: 2
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- ppc64le
- s390x
When I check node ( Single node )
NAME STATUS ROLES AGE VERSION LABELS
minikube Ready control-plane,master 11m v1.23.3 beta.kubernetes.io/arch=arm64,beta.kubernetes.io/os=linux,kubernetes.io/arch=arm64,kubernetes.io/hostname=minikube,kubernetes.io/os=linux,minikube.k8s.io/commit=362d5fdc0a3dbee389b3d3f1034e8023e72bd3a7,minikube.k8s.io/name=minikube,minikube.k8s.io/primary=true,minikube.k8s.io/updated_at=2022_05_01T10_16_33_0700,minikube.k8s.io/version=v1.25.2,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
As of June 2022, there is no support for istio on MacOS m1 chip. Istio init containers fail initialization because of iptables.
Command error output: xtables parameter problem: iptables-restore: unable to initialize table 'nat'.
The temporary fix for this is to use istio operator with hub pointing to RESF's repo.
After you have installed/downloaded the istioctl command line.
Run following commands -
Set hub for istio operator.
istioctl operator init --hub=ghcr.io/resf/istio
Create namespace for istio insatallation.
kubectl create ns istio-system
Install istio
kubectl apply -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: istio-system
name: example-istiocontrolplane
spec:
hub: ghcr.io/resf/istio
profile: demo
EOF
This temporary fix is by RESF until official fix and all credit goes to them.
I found this workaround Apple Silicon/M1 builds for Istioctl #29596

How to match a particular string using regex?

Hi i have string like below,
apiVersion: v1
clusters:
- cluster: <------------------------ this is one cluster
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ
server: https://api.someaddress
name: https://api.anotheraddress
- second_cluster: <------------------------ this is second cluster
certificate-authority-data: LS0tLS1
server: https://api.someaddress
name: https://api.
contexts:
- context: <------------------------ this is one context
cluster: https://api.another1address
namespace: name1
user: user1
name: somename
- another_context: <------------------------ this is second context
cluster: https://api.anotheraddress
namespace: esm2
user: admin
name: somename1
current-context: some-context
kind: somekind
preferences: {}
users:
- name: user-admin
user:
token: eyJhb
how can i check if the there is more than one cluster under clusters and more than one context under contexts using regex.
i have tried something like below
var matchServer = new RegExp(/- cluster:\n[A-Za-z0-9\- :]*\n[ ]+server: ([A-Za-z:.//]*)/, "gi").exec(s);
const namespace = s.match(/contexts:\n- context:\n[A-Za-z0-9\- :.//]*\n[ ]+namespace: ([A-Za-z0-9]*)/i);
but this gives server and namespace also only one occurrence is returned.
i want to get the number of matched string "cluster" under clusters and context under contexts.
could someone help me with this. i am new to programming. thanks.
what i have tried?
i have tried regex to match "context" "another_context" under contexts. but it matches only "context"
contexts:\n-.*context:+
could someone help me understand why it doesnt match the another_context string
updated question:
with the regex
const matchServer = result.match(/- [a-z_]cluster:[A-Za-z0-9- :\n][ ]+server: ([A-Za-z0-9:.//]*)/gi);
this returns null for below string although there is server under cluster.
apiVersion: v1
clusters:
- cluster:
certificate-authority-data:
LS0tLS1CRUd
server: https://api.sandbox1.lab.fi.eu.ericsson.se
name: https://api.sandbox1.lab.fi.eu.ericsson.se
contexts:
- context:
cluster: https://api.sandbox1.lab.fi.eu.ericsson.se
namespace: esm1
user: esm-esm1-ci-namespace-admin
name: esm-context
current-context: esm-context
kind: Config
preferences: {}
users:
- name: esm-esm1-ci-namespace-admin
user:
token:
eyJhbGc
why doesnt the above regex work for this string. could someone help me with this. thanks.
<html>
<head>
<script>
var s = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ
server: https://api.someaddress1
name: https://api.anotheraddress
- second_cluster:
certificate-authority-data: LS0tLS1
server: https://api.someaddress2
name: https://api.
contexts:
- context:
cluster: https://api.another1address
namespace: name1
user: user1
name: somename
- another_context:
cluster: https://api.anotheraddress
namespace: esm2
user: admin
name: somename1
current-context: some-context
kind: somekind
preferences: {}
users:
- name: user-admin
user:
token: eyJhb`;
var matchServer = s.match(/- [a-z_]*cluster:/gi)
var matchNamespace = s.match(/- [a-z_]*context:/gi)
document.write(matchServer.length + ' servers <br/>')
for(i=0;i<matchServer.length;i++)
document.write(matchServer[i] + '<br/>')
document.write(matchNamespace.length + ' namespaces <br/>')
for(i=0;i<matchNamespace.length;i++)
document.write(matchNamespace[i] + '<br/>')
</script>
</head>
<body>
</body>
</html>
js fiddle
For completeness, here's a solution with a YAML parser - provided that it actually is YAML, because the last part (users) isn't valid YAML. Also some indentation wasn't right. I assume it has been modified to not leak sensitive information.
Update: Oh, I see this is a kubernetes config file. So it really is YAML then.
https://jsfiddle.net/1Lpsk740/ (with document.write instead of console.log)
<!DOCTYPE html>
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.js"></script>
<script>
var input = `apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ
server: https://api.someaddress1
name: https://api.anotheraddress
- second_cluster:
certificate-authority-data: LS0tLS1
server: https://api.someaddress2
name: https://api.
contexts:
- context:
cluster: https://api.another1address
namespace: name1
user: user1
name: somename
- another_context:
cluster: https://api.anotheraddress
namespace: esm2
user: admin
name: somename1`;
const doc = jsyaml.load(input);
console.log('servers: ' + doc.clusters.length);
doc.clusters.forEach(e => console.log('- ' + Object.keys(e)[0]));
console.log('namespaces: ' + doc.contexts.length);
doc.contexts.forEach(e => console.log('- ' + Object.keys(e)[0]));
</script>
</html>
Output:
servers: 2
- cluster
- second_cluster
namespaces: 2
- context
- another_context

Istio: Health check / sidecar fails when I enable the JWT RequestAuthentication

OBSOLETE:
I keep this post for further reference, but you can check better diagnose (not solved yet, but workarounded) in
Istio: RequestAuthentication jwksUri does not resolve internal services names
UPDATE:
In Istio log we see the next error. uaa is a kubernetes pod serving OAUTH authentication/authorization. It is accessed with the name uaa from the normal services. I do not know why the istiod cannot find uaa host name. Have I to use an specific name? (remember, standard services find uaa host perfectly)
2021-03-03T18:39:36.750311Z error model Failed to fetch public key from "http://uaa:8090/uaa/token_keys": Get "http://uaa:8090/uaa/token_keys": dial tcp: lookup uaa on 10.96.0.10:53: no such host
2021-03-03T18:39:36.750364Z error Failed to fetch jwt public key from "http://uaa:8090/uaa/token_keys": Get "http://uaa:8090/uaa/token_keys": dial tcp: lookup uaa on 10.96.0.10:53: no such host
2021-03-03T18:39:36.753394Z info ads LDS: PUSH for node:product-composite-5cbf8498c7-jd4n5.chp18 resources:29 size:134.3kB
2021-03-03T18:39:36.754623Z info ads RDS: PUSH for node:product-composite-5cbf8498c7-jd4n5.chp18 resources:14 size:14.2kB
2021-03-03T18:39:36.790916Z warn ads ADS:LDS: ACK ERROR sidecar~10.1.1.56~product-composite-5cbf8498c7-jd4n5.chp18~chp18.svc.cluster.local-10 Internal:Error adding/updating listener(s) virtualInbound: Provider 'origins-0' in jwt_authn config has invalid local jwks: Jwks RSA [n] or [e] field is missing or has a parse error
2021-03-03T18:39:55.618106Z info ads ADS: "10.1.1.55:41162" sidecar~10.1.1.55~review-65b6886c89-bcv5f.chp18~chp18.svc.cluster.local-6 terminated rpc error: code = Canceled desc = context canceled
Original question
I have a service that is working fine, after injecting istio sidecar to a standard kubernetes pod.
I'm trying to add jwt Authentication, and for this, I'm following the official guide Authorization with JWT
My problem is
If I create the JWT resources (RequestAuthorization and AuthorizationPolicy) AFTER injecting the istio dependencies, everything (seems) to work fine
But if I create the JWT resources (RequestAuthorization and AuthorizationPolicy) and then inject the Istio the pod doesn't start. After checking the logs, seems that the sidecar is not able to work (maybe checking the health?)
My code:
JWT Resources
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
name: "ra-product-composite"
spec:
selector:
matchLabels:
app: "product-composite"
jwtRules:
- issuer: "http://uaa:8090/uaa/oauth/token"
jwksUri: "http://uaa:8090/uaa/token_keys"
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: "ap-product-composite"
spec:
selector:
matchLabels:
app: "product-composite"
action: ALLOW
# rules:
# - from:
# - source:
# requestPrincipals: ["http://uaa:8090/uaa/oauth/token/faf5e647-74ab-42cc-acdb-13cc9c573d5d"]
# b99ccf71-50ed-4714-a7fc-e85ebae4a8bb
2- I use destination rules as follows
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: dr-product-composite
spec:
host: product-composite
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
3- My service deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: product-composite
spec:
replicas: 1
selector:
matchLabels:
app: product-composite
template:
metadata:
labels:
app: product-composite
version: latest
spec:
containers:
- name: comp
image: bthinking/product-composite-service
imagePullPolicy: Never
env:
- name: SPRING_PROFILES_ACTIVE
value: "docker"
- name: SPRING_CONFIG_LOCATION
value: file:/config-repo/application.yml,file:/config-repo/product-composite.yml
envFrom:
- secretRef:
name: rabbitmq-client-secrets
ports:
- containerPort: 80
resources:
limits:
memory: 350Mi
livenessProbe:
httpGet:
scheme: HTTP
path: /actuator/info
port: 4004
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 20
successThreshold: 1
readinessProbe:
httpGet:
scheme: HTTP
path: /actuator/health
port: 4004
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1
volumeMounts:
- name: config-repo-volume
mountPath: /config-repo
volumes:
- name: config-repo-volume
configMap:
name: config-repo-product-composite
---
apiVersion: v1
kind: Service
metadata:
name: product-composite
spec:
selector:
app: "product-composite"
ports:
- port: 80
name: http
targetPort: 80
- port: 4004
name: http-mgm
targetPort: 4004
4- Error log in the pod (combined service and sidecar)
2021-03-02 19:34:41.315 DEBUG 1 --- [undedElastic-12] o.s.s.w.s.a.AuthorizationWebFilter : Authorization successful
2021-03-02 19:34:41.315 DEBUG 1 --- [undedElastic-12] .b.a.e.w.r.WebFluxEndpointHandlerMapping : [0e009bf1-133] Mapped to org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ReadOperationHandler#e13aa23
2021-03-02 19:34:41.316 DEBUG 1 --- [undedElastic-12] ebSessionServerSecurityContextRepository : No SecurityContext found in WebSession: 'org.springframework.web.server.session.InMemoryWebSessionStore$InMemoryWebSession#48e89a58'
2021-03-02 19:34:41.319 DEBUG 1 --- [undedElastic-15] .s.w.r.r.m.a.ResponseEntityResultHandler : [0e009bf1-133] Using 'application/vnd.spring-boot.actuator.v3+json' given [*/*] and supported [application/vnd.spring-boot.actuator.v3+json, application/vnd.spring-boot.actuator.v2+json, application/json]
2021-03-02 19:34:41.320 DEBUG 1 --- [undedElastic-15] .s.w.r.r.m.a.ResponseEntityResultHandler : [0e009bf1-133] 0..1 [java.util.Collections$UnmodifiableMap<?, ?>]
2021-03-02 19:34:41.321 DEBUG 1 --- [undedElastic-15] o.s.http.codec.json.Jackson2JsonEncoder : [0e009bf1-133] Encoding [{}]
2021-03-02 19:34:41.326 DEBUG 1 --- [or-http-epoll-3] r.n.http.server.HttpServerOperations : [id: 0x0e009bf1, L:/127.0.0.1:4004 - R:/127.0.0.1:57138] Detected non persistent http connection, preparing to close
2021-03-02 19:34:41.327 DEBUG 1 --- [or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [0e009bf1-133] Completed 200 OK
2021-03-02 19:34:41.327 DEBUG 1 --- [or-http-epoll-3] r.n.http.server.HttpServerOperations : [id: 0x0e009bf1, L:/127.0.0.1:4004 - R:/127.0.0.1:57138] Last HTTP response frame
2021-03-02 19:34:41.328 DEBUG 1 --- [or-http-epoll-3] r.n.http.server.HttpServerOperations : [id: 0x0e009bf1, L:/127.0.0.1:4004 - R:/127.0.0.1:57138] Last HTTP packet was sent, terminating the channel
2021-03-02T19:34:41.871551Z warn Envoy proxy is NOT ready: config not received from Pilot (is Pilot running?): cds updates: 1 successful, 0 rejected; lds updates: 0 successful, 1 rejected
5- Istio injection
kubectl get deployment product-composite -o yaml | istioctl kube-inject -f - | kubectl apply -f -
NOTICE: I have checked a lot of post in SO, and it seems that health checking create a lot of problems with sidecars and other configurations. I have checked the guide Health Checking of Istio Services with no success. Specifically, I tried to disable the sidecar.istio.io/rewriteAppHTTPProbers: "false", but it is worse (in this case, doesn't start neither the sidecar neither the service.

Is it possible to combine AND and OR matches in a Virtual Service definition?

I'm trying to define a Virtual Service in Istio (1.3.3) which has multiple matches but within the matches, there should be OR functionality.
For example : (pseudo code)
match
header-key = value1
OR header-key = value2
OR header-key = value3
OR ....
OR header-key = value100
AND
match
uri-prefix = prefix1
OR uri-prefix = prefix2
OR uri-prefix = prefix3
OR uri-prefix = ...
OR uri-prefix = prefix100
So for every AND block there should be at least one matching OR condition.
I 've tried with a match but then if 1 of all the conditions are met, then it is valid, but what I want is to match one of the API keys and match one of the URI prefixes.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: test
namespace: demo
spec:
hosts:
- test1
gateways:
- test-gateway
http:
- match:
- headers:
apikey:
exact: 111
- headers:
apikey:
exact: 222
- headers:
apikey:
exact: 333
- uri:
prefix: /path1/
- uri:
prefix: /path2/
rewrite:
uri: /newpath/v1/
authority: test2
route:
- destination:
host: test2
- fault:
abort:
httpStatus: 444
percent: 100
route:
- destination:
host: test2