Using istio with requestauth and a jwt issuer, but currently need to exclude certain paths traffic to the sidecar from actually validating any incoming jwt headers, is that possible? else istio tries to validate the jwt header ( even if not in issuerurl ) it receives.
added authpolicy to ignore those paths but the sidecar still decodes incoming authorization headers and validates them with my issuer.
Yes, this is possible with an AuthorizationPolicy that looks like this:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: my-auth-policy
spec:
rules:
- from:
- source:
requestPrincipals: ["*"]
- to:
- operation:
paths: ["/insecure"]
This authz policy defines two rules. The first is for all authenticated request principals to access everything. The second rule is for any source to access the /insecure path.
With this authz policy, an unauthenticated request can successfully reach the /insecure route, and only that one.
Related
We have some spring-boot containers which use oauth2 for authorisation
Unfortunately they were not compiled with jwks
Is it possible to use jwt in istio without configuring jwksUri or jwks?
According to istio documentation about JWT Rule the jwksUri and jwks are not required fields for jwtRule. However the issuer field is required.
Example configuration:
apiVersion: "security.istio.io/v1beta1"
kind: "RequestAuthentication"
metadata:
name: "jwt-example"
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
jwtRules:
- issuer: "testing#secure.istio.io"
This configuration should only check if the issuer of JWT matches.
Also from envoy documentation it is mentioned that JWT without verification is possible:
This message specifies a Jwt requirement. An empty message means JWT verification is not required.
Hope this helps.
As of Istio 1.5 this is not possible. Envoy will not add a Listener without a valid jwks
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.
We've designed our API to use Istio JWT authentication which is mandatory and at the same time we've used the CORS. The problem is our JS code will do ajax call and HTTP Option pre-flight request will be called without JWT Authorization header. Unfornately the pre-flight request will be blocked by Istio. How to solve it?
Not sure if I understood your question correctly, but I think Service Entry will solve this.
ServiceEntry enables adding additional entries into Istio’s internal service registry, so that auto-discovered services in the mesh can access/route to these manually specified services. A service entry describes the properties of a service (DNS name, VIPs, ports, protocols, endpoints). These services could be external to the mesh (e.g., web APIs) or mesh-internal services that are not part of the platform’s service registry (e.g., a set of VMs talking to services in Kubernetes).
Service Entry for your example might look like the following:
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: external-svc-https
spec:
hosts:
- api.foobar.com
location: MESH_EXTERNAL
ports:
- number: 80
name: http
resolution: DNS
We have a microservice architecture based on Kubernetes in Amazon EKS with Ambassador as API Gateway.
We have 2 Ambassadors: 1 public and 1 private. So we have services that are only accessible by services in the cluster or VPN, and we have some services that are public.
We have the need for making private some URL paths in the public services. For example, we have a public API that is accessible in api.company.com, and we want to leave all paths public like api.company.com/createuser, api.company.com/login, etc... but for other paths we want to make them private, for example: api.company.com/swagger.html.
We know that we could enable authentication for those paths in the API, but we are looking for a solution without auth.
An example of how we configure K8s service with Ambassador for public services:
apiVersion: v1
kind: Service
metadata:
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: backends_mapping
prefix: /
ambassador_id: ambassador-public
service: backends.svc:8080
host: api.mycompany.com
labels:
app: backends
name: backends
namespace: svc
spec:
ports:
- name: http-backends
port: 8080
protocol: TCP
targetPort: http-api
selector:
app: backends
type: ClusterIP
Not sure what do you mean by without auth. You will need some sort of check to serve internal content.
One approach to achieve this can be(Note this is a high level overview).
You can make the service private, do not expose this service directly.
Prefix all your internal routes with say /internal/ or /private/ prefix.
So api.company.com/swagger.html becomes api.company.com/internal/swagger.html
You can create a load balancer that points to this middleware.
Middleware(public service) will intercept all the requests. I think Nginx can be used here. If the request has /internal/ path check if it satisfies the condition(origin, internal network etc).
If the check passes, redirect to private service.
If the check fails return 403 forbidden or whatever response code that fits.
Cilium can do just what you want:http://docs.cilium.io/en/stable/policy/language/#http
Basically you can specify L7 network policies which will only allow access to some of you API paths from certain pods.
Cilium project page: https://cilium.io/
Layer 7 policies example: http://docs.cilium.io/en/stable/policy/language/#http
EKS install guide: http://docs.cilium.io/en/v1.4/gettingstarted/k8s-install-eks/?highlight=eks
Disclaimer: I am part of the team that develops Cilium.
I'am on a journey of testing Istio and at the moment I'am about to test the "canary" capabilities of routing traffic.
For my test, I created a small servicemesh composed of 5 microservices (serviceA, serviceB, serviceC, serviceD, serviceE). Each one is able to call the others. I just pass a path like A,E,C,B,B,D and the request follows this path.
In order to call my servicemesh from outside the cluster I have an Nginx Ingress Controller with an Ingress rule that point on serviceA pod
This is working fine.
The problem I'am facing concerns the traffic switching using a custom header matching like this :
kind: VirtualService
metadata:
name: ServiceA
namespace: demo
labels:
app: demo
spec:
hosts:
- service-a
http:
- route:
- destination:
host: service-a
subset: v1
- match:
- headers:
x-internal-request:
exact: true
route:
- destination:
host: service-a
subset: v2
So here, I want to try to route the traffic to the v2 version of ServiceA when I have the custom header x-internal-request set to true.
Questions :
In order to use this feature, do my services have to be aware of the x-internal-header and do they have to pass it to the next service in the request? Or they do not need to deal with it because Istio do the job for them ?
In order to use this feature, do I need to use the Istio Ingress Controller (with an Istio Gateway) instead of the Nginx Ingress Controller ?
Today, I am using Nginx Ingress Controller to expose some of my services. We choose Nginx because it has some feature likes "external authorization" that saves us a lot of work and if we need to use Istio Ingress controller instead, I'am not sure it offers the same features than Nginx.
Perhaps there is a middle path I do not see
Thank you for your help
Istio is designed to use Envoy deployed on each Pod as sidecars to intercept and proxy network traffic between microservices in service mesh.
You can manipulate with HTTP headers for requests and responses via Envoy as well. According to the official Documentation, custom headers can be added to the request/response in the following order: weighted cluster level headers, route level headers, virtual host level headers and finally global level headers. Because your Envoy proxies are deployed on each relevant service Pod as sidecar, custom HTTP header should pass to each request or response.
I would recommend using Istio Ingress Controller with its core component Istio Gateway which is commonly used for enabling monitoring and routing rules features in Istio mesh services.
There was an issue opened on GitHub about the implementation of Nginx Ingress controller in mesh services and the problem with routing requests.