How to remove or modify header from istio ingress gateway - istio

Chrome browser redirects all my domain and subdomain requests to HTTPS, this is unwanted behavior in my case.
according to https://www.chromium.org/hsts, this is HSTS policy that been added to chrome browser to the domain and all subdomains.
I am using Istio version 1.7.4 and noticed that the Istio ingress gateway add the header strict-transport-security that causes this issue.
strict-transport-security: max-age=15552000; includeSubDomains
how can I remove this header from the ingress gateway?

You can use VirtualService to add or remove certain headers.
The example from the official Istio documentation shows the way how you can remove it:
Headers
Message headers can be manipulated when Envoy forwards requests to, or responses from, a destination service. Header manipulation rules can be specified for a specific route destination or for all destinations. The following VirtualService adds a test header with the value true to requests that are routed to any reviews service destination. It also removes the foo response header, but only from responses coming from the v1 subset (version) of the reviews service.
v1alpha3
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- headers:
request:
set:
test: true
route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
weight: 25
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
headers:
response:
remove:
- foo # <-- HERE!
weight: 75
Istio.io: Latest: Docs: Reference: Config: Networking: Virtual service: Headers
Additional resources:
Istio.io: Latest: Docs

Related

nginx ingress redirect to https based on header

I have a EKS setup where traffic is sent in the following way.
Users -> Cloudfront -> ALB -> EKS. EKS has an NginX ingress controller.
Currently "force-ssl-redirect" is enabled and hence, NginX ingress controller redirects all HTTP traffic to HTTPS.
I want Cloudfront to connect with ALB using HTTP. Hence, I am looking to have a conditional HTTPS redirect in NginX controller.
Hence,
I will set a custom header to requests in from Cloudfront
If this new header is found, I want NginX controller to return the correct response in HTTP. If not, I want to redirect to HTTPS.
How can this be done?
I assume that you would like to add a custom header on Cloudfront, and then do a redirect on the Nginx side.
You can add custom headers to the request via Cloudfront Functions - https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html
Then I think you need to use the nginx.ingress.kubernetes.io/configuration-snippet annotation in the Ingress Kubernetes resource to add custom configuration to the Nginx location. Maybe something like this can work:
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: redirect
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_x_custom_header) {
return 301 http://$host$request_uri;
}
return 301 https://$host$request_uri;
spec:
rules:
- host: ...
You can use the NginX configuration map for conditional HTTPS redirection.
You need to create Nginx Configuration with a custom snippet for checking the custom header set by CloudFront.
apiVersion: v1
Kind: ConfigMap
Metadata:
Name: nginx-config
Data:
Ssl-redirect-snippet: |
If ($http_cf_custom_header) {
Return 301 http://$server_name$request_uri;
}
Return 301 https://$server_name$request_uri;
If header is present, NginX returns a 301 redirect with HTTP; if it is not present it will redirect to same URL using HTTPS
Now you need to add configuration map to your NginX ingress controller
apiVersion: networking.k8s.io/v1
Kind: Ingress
Metadata:
Name: my-ingress
Annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
Include /etc/nginx/ssl-redirect-snippet;
Spec:
Rules:
-host: my.domain.com
Http:
Paths:
-Path: /
pathType: Prefix
Backend:
Service:
Name: my-service
Port:
Name: http
You need to set CLoudFront to include ‘http_cf_custom_header’ when you are forwarding to ALB. Check this official page and for further information check AWS official documentation.

istio How to configure services that use the root directory to convert to secondary paths

enter image description here
How does my nginx configuration work in the isio? I need to be able to access pgadmin through the secondary path rather than through the root directory. The root directory will be used by other important servers
You would need to create istio gateway and istio virtual service objects. Please refer istio documentation for traffic management. Below is the sample of uri base routing and similarly you can add different routes based on the requirement.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: app-route
spec:
hosts:
- app.prod.svc.cluster.local
http:
- match:
- uri:
prefix: /pgadmin
- route:
- destination:
host: <db service name>

Enbale HSTS when using Istio in AWS EKS

I have installed istio-gateway using helm charts in AWS EKS. I am able to reach application using AWS alb and gateway. Configured virtualservice for traffic route.
For security purpose I tried enabling HSTS but its not enabling it and I could see HSTS headers in browser too.
Below is the virtualservice config I have used
http:
- match:
- uri:
prefix: /
route:
- destination:
host: serviceA
port:
number: 80
headers:
response:
set:
Strict-Transport-Security: max-age=31536000; includeSubDomains

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.