Restrict access from one service to another

Good day!

We are thinking about deploying istio servie mesh in our cluster. One of the tasks is convinient way of restriction access from one service to another. In plain Kubernetes we can to it with Network Policies.
With what kind of object we can achieve it in istio?

Thank you!

Hi @reistlin,

In Istio you have a few options.

If you’re using Calico for Network Policy, you can use Calico’s integration with Istio to extend your existing Network Policy to the application layer.

Or, you can use Istio’s built-in authorization framework, which involves creating ServiceRole and ServiceRoleBinding objects.

Finally, you can use one of several Mixer adapters that allow you to enforce access control.

Hope that helps,
Spike

As @spikecurtis mentioned, one of the options is to use Istio authorization. You can try this task to see how it works https://istio.io/docs/tasks/security/authz-http/. Istio authorization is usually used with authentication. If you decide to use mTLS for your service to service communication (which you don’t need to change any code in your applications), you’ll also get encrypted communication out of the box.

Thank you!

Say I need one service has abilities to GET from another service.

I am creating simple ServiceRole which allows GET to my httpbin service:

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: httpbin
  namespace: default
spec:
  rules:
  - services: ["httpbin.default.svc.cluster.local"]
    methods: ["GET", "HEAD"]

And I am trying to bind this role to another service:

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: httpbind
  namespace: default
spec:
  subjects:
  - properties:
      source.namespace: "default" // What property to use ???
  roleRef:
    kind: ServiceRole
    name: "httpbin"

How could I achieve that? I see the closest one is source.principal property, but that means I will need to create a service account for all services?

Thank you!

K8s already created a default service account for each namespace you created (and you may guess, the name is indead default). Unless you specify otherwise, the pod running under that namespace will use the default service account.

You can create K8s accounts and annotate your deployment to use that service account. However, it is recommended to use separate namespaces if you want your policy is also protected via K8s RBAC.

To add to what Diem said, I think you should create a service account for each service. If you use the default service account for the namespace, every application in the same namespace will have the same identity. This is no difference than just restricting the access to namespace-level (source.namespace: <namespace), rather than service-level.

So if you have httpbin in namespace default like above, and sleep in namespace default or any other namespace, you can create a service account for sleep and use source.principal under properties or user, and use (most likely) cluster.local/ns/<sleep deployment namespace>/sa/<sleep service account> to allow only sleep to have GET access to httpbin.

Another choice you can try Sidecar to restrict a Service from accessing other services, this can work without authz. It works on networking layer.

You mean Kubernetes Network Policies?

Istio Sidecar https://istio.io/docs/reference/config/networking/v1alpha3/sidecar/ which introduced in 1.1

Thank you!

I am trying to use sidecar, but it seems does not work. Where is mistake?

apiVersion: networking.istio.io/v1alpha3
kind: Sidecar
metadata:
  name: iam
  namespace: ns1
spec:
  workloadSelector:
    labels:
      app: iam
  egress:
    - hosts:
        - "ns1/postgres.ns1.svc.cluster.local"

After applying this config IAM service still has access to all services

Hi @reistlin, I was able to make blocking work as expected. Seems that default outbound traffic ppolicy is ALLOW_ANY . Here are github issue and istio doc steps to change policy
Not sure if it still relevant but I spent few hours investigation such behavior. Hopefully it will help someone…

Regards,
Stepan

I have a similar situation where I want to restrict access to one of my workload by any other workload exists in the same namespace, except those which are authorized to access it.

I have tried these approaches but no joy so far:

  1. VirtualService with Matching rules with some custom headers: Result= Did not work at all. I think the example given in here works only for routing a request based on the match condition, but it does not block the request if match rule fails.

  2. SideCar: Sidecars may work for outgoing traffic or Egress, where you can restrict a workload to access any unwanted endpoint or service within the cluster. This is not my use case as I want to restrict the Ingress traffic and want to apply the policy only in my target workload which I want to protect.

  3. Istio Security with mTLS enabled and Authorization : I realized that the Authentication & Authorization framework in Istio requires a JWT token to be used for Source Authentication, but my target Workload is already protected with a JWT which we used to protect the APIs exposed from the workload and we do not want to mix this JWT with the Istio recommended JWT.

So all of the above approach is not working for me as of now.

Can someone please suggest any other way to achieve my goal where I want to restrict one of Workload from any unauthorized Ingress requests.

My case is a bit more complex: Restrict pod access to specific internal endpoints (VPC), services (K8s), and the entire internet.

But the idea is similar, block access from one service to another. I could do something similar with NetworkPolicy, but with istio it’s not clear how it can be accomplished without using jwt token, just service labels, hosts (Only used in gateways).