unable use "Split large virtual services and destination rules into multiple resources" - istio

istio document dercribe "Split large virtual services and destination rules into multiple resources"
https://istio.io/docs/ops/best-practices/traffic-management/
this is my virtualService yaml ,
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: project-b
namespace: test1
spec:
hosts:
- project-b.test1.svc.cluster.local
http:
- match:
- headers:
route-namespace:
exact: "test1"
route:
- destination:
host: project-b.test1.svc.cluster.local
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: project-b-test2
namespace: test1
spec:
hosts:
- project-b.test1.svc.cluster.local
http:
- match:
- headers:
route-namespace:
exact: "test2"
route:
- destination:
host: project-b.test2.svc.cluster.local
enter image description here
just one virtural service is availabe,

Yes, this is expected behavior.
According to istio documentation:
In situations where it is inconvenient to define the complete set of route rules or policies for a particular host in a single VirtualService or DestinationRule resource, it may be preferable to incrementally specify the configuration for the host in multiple resources. Pilot will merge such destination rules and merge such virtual services if they are bound to a gateway.
When a second and subsequent VirtualService for an existing host is applied, istio-pilot will merge the additional route rules into the existing configuration of the host. There are, however, several caveats with this feature that must be considered carefully when using it.
Although the order of evaluation for rules in any given source VirtualService will be retained, the cross-resource order is UNDEFINED. In other words, there is no guaranteed order of evaluation for rules across the fragment configurations, so it will only have predictable behavior if there are no conflicting rules or order dependency between rules across fragments.
There should only be one “catch-all” rule (i.e., a rule that matches any request path or header) in the fragments. All such “catch-all” rules will be moved to the end of the list in the merged configuration, but since they catch all requests, whichever is applied first will essentially override and disable any others.
A VirtualService can only be fragmented this way if it is bound to a gateway. Host merging is not supported in sidecars.

Related

Istio AuthorizationPolicy only for external requests

Right now I'm having 3 services. A, B and C. They all are running in the same namespace. I'm making use of the EnvoyFilter to transcode the http requests to grpc calls.
Now I want to add security for those calls but I want each service to allow internal communication as well.
So I only want to check external requests for authentication.
Right now I have the following RequestAuthentication:
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-authentication
spec:
selector:
matchLabels:
sup.security: jwt-authentication
jwtRules:
- issuer: "http://keycloak-http/auth/realms/supporters"
jwksUri: "http://keycloak-http/auth/realms/supporters/protocol/openid-connect/certs"
Then I added the following AuthorizationPolicy:
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "auth-policy-deny-default"
spec:
selector:
matchLabels:
sup.security: jwt-authentication
action: DENY
rules: []
How do I configure istio in a way that it allows intercommunication without checking for authentication?
The recommended approach in Istio is not to think from the perspective of what you want to deny, but of what you want to allow, and then deny everything else.
To deny everything else create a catch-all deny rule as shown below:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: YOUR_NAMESPACE
spec:
{}
Now what you need to do is decide what are the cases when you want to allow requests. In your case, it would be:
All authenticated requests from within the cluster achieved with principals: ["*"].
All authenticated requests with a valid jwt token achieved with requestPrincipals: ["*"]
Putting those together give the policy below:
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "allow-all-in-cluster-and-authenticated"
namespace: YOUR_NAMESPACE
spec:
rules:
- from:
- source:
principals: ["*"]
- source:
requestPrincipals: ["*"]
The field principals has a value only if a workload can identify itself via a certificate (it must have the istio proxy) during PeerAuthentication. And the field requestPrincipals is extracted from the jwt token during RequestAuthentication.
Please let me know if it doesn't work or there are tweaks needed :)

Configure mutual TLS origination for egress traffic for more then 200 target destination with different cert requirements

I've got a use case of an application that needs to authenticate with mTLS to hundreds of different destination servers outside of the mesh with a different client certificate. I thought offloading this procedure form the app to Istio is that even possible?
Yes it is possible.
You can follow this guide to configure mutual TLS orgination for egress traffic.
Then for each destination modify the DestinationRule to use different certificate like in this example:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: db-mtls
spec:
host: mydbserver.prod.svc.cluster.local
trafficPolicy:
tls:
mode: MUTUAL
clientCertificate: /etc/certs/myclientcert.pem
privateKey: /etc/certs/client_private_key.pem
caCertificates: /etc/certs/rootcacerts.pem
Hope it helps.

What is the purpose of a VirtualService when defining an wildcard ServiceEntry in Istio?

The Istio documentation gives an example of configuring egress using a wildcard ServiceEntry here.
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: wikipedia
spec:
hosts:
- "*.wikipedia.org"
ports:
- number: 443
name: tls
protocol: TLS
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: wikipedia
spec:
hosts:
- "*.wikipedia.org"
tls:
- match:
- port: 443
sniHosts:
- "*.wikipedia.org"
route:
- destination:
host: "*.wikipedia.org"
port:
number: 443
What benefit/difference does the VirtualService give? If I remove the VirtualService nothing seems to be affected. I am using Istio 1.6.0
The VirtualService is not really doing anything, but if you take a look at this or this istio docs.
creating a VirtualService with a default route for every service, right from the start, is generally considered a best practice in Istio.
Virtual services play a key role in making Istio’s traffic management flexible and powerful. They do this by strongly decoupling where clients send their requests from the destination workloads that actually implement them. Virtual services also provide a rich way of specifying different traffic routing rules for sending traffic to those workloads.
Service Entry adds those wikipedia sites as an entry to istio internal service registry, so auto-discovered services in the mesh can route to these manually specified services.
Usually that's used to allow monitoring and other Istio features of external services from the start, when the Virtual Service would allow the proper routing of request.
Take a look at this istio documentation.
Service Entry makes sure your mesh knows about the service and can monitor it.
Using Istio ServiceEntry configurations, you can access any publicly accessible service from within your Istio cluster.
Virtual Service manage traffic to external services and controls traffic which go to the service, which in this case is all of it.
I would say the benefit is that, you can use istio routing rules, which can also be set for external services that are accessed using Service Entry configurations. In this example, you set a timeout rule on calls to the httpbin.org service.

Configure Istio Ingress Gateway to require header token using Authorization Policy

I configured Istio Ingress Gateway to accept my URLs (using https) like microservices.myexample.com, grafana.myexample.com and so on.
Everything is working but all the urls are public.
Beacause of that I was asked to configure ingress gateway to protect urls inside microservices.myexample.com (Grafana has a login page). The idea is allow acess only if the request contains a token inside the header.
But when I applied this yml file all the URLs are blocked and they require the header including grafana.myexample.com:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ingress
namespace: istio-system
spec:
selector:
matchLabels:
app: istio-ingressgateway
rules:
- from: []
to:
- operation:
#paths: ["/customers*"] # I also tried with paths. Every microservice has a path after microservices.myexample.com
hosts: ["microservices.myexample.com"]
when:
- key: request.headers[token]
values: ["test123"]
We did it.
Just in case if someone is stuck at the same problem. The following code will be applied to all services in mynamespace. All the urls will require the token except the ones ending with /actuator/health
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: token-authorization
namespace: mynamespace
spec:
rules:
- to:
- operation:
paths: ["*/actuator/health"]
- to:
- operation:
paths: ["/*"]
when:
- key: request.headers[token]
values: ["test123"]
This will not work.
This is because in Your AuthorizationPolicy the hosts under operation: does not support HTTPS protocol.
According to Istio documentation:
Optional. A list of hosts, which matches to the “request.host” attribute.
If not set, any host is allowed. Must be used only with HTTP.
This is because the host header in HTTPS traffic is encrypted. More info about this is here.
The same goes for request header token.

What's the purpose of the `VirtualService` in this example?

I am looking at this example of Istio, and they are craeting a ServiceEntry and a VirtualService to access the external service, but I don't understand why are they creating a VirtualService as well.
So, this is the ServiceEntry:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: edition-cnn-com
spec:
hosts:
- edition.cnn.com
ports:
- number: 80
name: http-port
protocol: HTTP
- number: 443
name: https-port
protocol: HTTPS
resolution: DNS
With just this object, if I try to curl edition.cnn.com, I get 200:
/ # curl edition.cnn.com -IL 2>/dev/null | grep HTTP
HTTP/1.1 301 Moved Permanently
HTTP/1.1 200 OK
While I can't access other services:
/ # curl google.com -IL
HTTP/1.1 502 Bad Gateway
location: http://google.com/
date: Fri, 10 Jan 2020 10:12:45 GMT
server: envoy
transfer-encoding: chunked
But in the example they create this VirtualService as well.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: edition-cnn-com
spec:
hosts:
- edition.cnn.com
tls:
- match:
- port: 443
sni_hosts:
- edition.cnn.com
route:
- destination:
host: edition.cnn.com
port:
number: 443
weight: 100
What's the purpose of the VirtualService in this scenario?.
The VirtualService object is basically an abstract pilot resource that modifies envoy filter.
So creating VirtualService is a way of modification of envoy and its main purpose is like answering the question: "for a name, how do I route to backends?"
VirtualService can also be bound to Gateway.
In Your case lack of VirtualService results in lack of modification of the envoy from the default/global configuration. That means that the default configuration was enough for this case to work correctly.
So the Gateway which was used was most likely default. With same protocol and port that you requested with curl which all matched Your ServiceEntry requirements for connectivity.
This is also mentioned in istio documentation:
Virtual
services,
along with destination
rules,
are the key building blocks of Istio’s traffic routing functionality.
A virtual service lets you configure how requests are routed to a
service within an Istio service mesh, building on the basic
connectivity and discovery provided by Istio and your platform. Each
virtual service consists of a set of routing rules that are evaluated
in order, letting Istio match each given request to the virtual
service to a specific real destination within the mesh. Your mesh can
require multiple virtual services or none depending on your use case.
You can use VirtualService to add thing like timeout to the connection like in this example.
You can check the routes for Your service with the following command from istio documentation istioctl proxy-config routes <pod-name[.namespace]>
For bookinfo productpage demo app it is:
istioctl pc routes $(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}') --name 9080 -o json
This way You can check how routes look without VirtualService object.
Hope this helps You in understanding istio.
The VirtualService is not really doing anything, but as the docs say:
creating a VirtualService with a default route for every service, right from the start, is generally considered a best practice in Istio
The ServiceEntry adds the CNN site as an entry to Istio’s internal service registry, so auto-discovered services in the mesh can route to these manually specified services.
Usually that's used to allow monitoring and other Istio features of external services from the start, whereas the VirtualService would allow the proper routing of request (basically traffic management).
This page in the docs gives a bit more background info on using ServiceEntries and VirtualServices, but basically the ServiceEntry makes sure your mesh knows about the service and can monitor it, and the VirtualService controls what traffic is going to the service, which in this case is all of it.