Published on 00/00/0000
Last updated on 00/00/0000
Published on 00/00/0000
Last updated on 00/00/0000
Share
Share
INSIGHTS
10 min read
Share
AuthorizationPolicies
.
AuthorizationPolicy
, but more on the YAML details later. First, let's see how are these rules enforced in Istio.
If you're reading this article, you should already be familiar with Istio's high level architecture, but here's a (very) brief recap. Istio has a data plane, and a control plane. The data plane consists of sidecar proxies running alongside the application containers in the same pod, and they are responsible for forwarding all incoming, and outgoing traffic to the application. The control plane on the other hand is accepting user configuration through CRDs, and - among a few other things - transforms these CRDs to Envoy configuration and delivers it to the proxies. The sidecars are Envoy proxies, and the control plane is now basically a single service, called istiod
.
Similarly to telemetry and traffic management, the real deal happens in the data plane. All checks are performed runtime by the Envoy proxy's authorization engine. A request is evaluated against the authorization policies when it arrives to the proxy. Then Envoy returns the result, either ALLOW
or DENY
.
ClusterRbacConfig
, ServiceRole
, ServiceRoleBinding
. Those resources were part of the v1alpha1
API, that is now completely replaced by the v1beta1
API. The new API was introduced in Istio 1.4, and from Istio 1.6, the old API is not supported anymore. If you're looking for a migration path, I'd recommend to read the official blog post.
The new model simplifies configuration (one CRD instead of three), supports ingress and egress gateways, and better aligns with the Istio configuration model, as it is applied to workloads instead of services.
AuthorizationPolicies
, we have to mention Kubernetes NetworkPolicies
, because they are quite similar in terms of what problem they are trying to solve. The Kubernetes docs define network policies as follows:
A network policy is a specification of how groups of pods are allowed to communicate with each other and other network endpoints. For more details about network policies check out our blog post, Exploring Network Policies in Kubernetes.There's no easy answer to which one is better?, because they are good at different things. Istio policy enforcement works at the application layer (L7), - that's where the Envoy proxies operate - while Kubernetes network policies work at the network (L3) and transport layers (L4). Kubernetes network policies are implemented by different networking solutions, like Calico. These solutions are running a controller that's watching
NetworkPolicies
, and configures the underlying networking layer accordingly.
Operating at the application layer has its advantages. Because Envoy understands different protocols (most commonly HTTP), it allows for a rich set of attributes to base policy decisions on. A few examples are policies based on HTTP methods, URIs, or HTTP headers. A NetworkPolicy
cannot do these, because these concepts are unknown at the network and transport layers. But operating at the network layer has the advantage of being universal, since all network applications use IP. So you can apply policies regardless of the layer 7 protocol, and these will be enforced in the kernel space. It's extremely fast, but not as flexible as Envoy policies.
Another difference worth mentioning is that NetworkPolicies
work in an additive, whitelist model. When a NetworkPolicy
selects a specific pod, that pod will reject any connections, except those that are explicitly allowed. These policies are additive, they do not conflict, and order of evaluation is irrelevant. AuthorizationPolicies
on the other hand have DENY
and ALLOW
rules as well, that complicates things a bit, but again, allows for more flexible rules.
So should you use Istio AuthorizationPolicies
over plain Kubernetes NetworkPolicies
? Well, it always depends on your use case. If you want to have a finer grained authorization model, you should go with Istio, but if your only requirement is that "pod A should only be able to communicate with pod B", then NetworkPolicies
are just as good. Or you can even use the two concepts side-by-side.
AuthorizationPolicies
select a workload, all requests are allowed. To enforce access control, you have to apply at least one AuthorizationPolicy
resource.
To start experimenting with Istio and
AuthorizationPolicies
, we suggest to try Backyards (now Cisco Service Mesh Manager) and get up and running with an example application in minutes. Backyards (now Cisco Service Mesh Manager) provides an Istio control panel where you can track, visualize or even manage your Istio YAML configuration.Register for an evaluation version](https://eti.cisco.com/appnet/smm) and run the following command to install the CLI tool (
KUBECONFIG
must be set for your cluster):Want to know more? Get in touch with us, or delve into the details of the latest release.Or just take a look at some of the Istio features that Backyards automates and simplifies for you, and which we've already blogged about.
AuthorizationPolicies
can be mesh-, namespace-, and workload-wide depending on the namespace
and the spec/selector
field. The namespace
of the resource determines the namespace where the rules will be enforced. When the spec/selector
field is omitted, the rules are namespace-wide. The selector, that is a standard Kubernetes label selector, can be used to restrict the policy to specific workload(s) in the namespace, making the policy workload-wide. Just like with the PeerAuthentication
resource, putting it in the root Istio namespace (usually istio-system
), without a selector has a special effect: these rules will be enforced mesh-wide, in all namespaces.
The following is a workload-wide policy, that applies to pods in the backyards-demo
namespace that have the app=catalog
label.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: get-only
namespace: backyards-demo
spec:
selector:
matchLabels:
app: catalog
action: ALLOW
rules:
- to:
- operation:
methods: ["GET"]
NetworkPolicies
, AuthorizationPolicies
support both ALLOW
and DENY
actions. If any ALLOW
policies are applied to a workload, traffic is denied to that workload by default, and only those requests that are explicitly configured are allowed. It could be a bit confusing at first, especially that the default action is ALLOW
, so a policy like this will deny all traffic in a namespace:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: backyards-demo
spec: {}
While this one allows all traffic:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-any
namespace: backyards-demo
spec:
rules:
- {}
The deny policies take precedence over allow policies, so for example if there are conflicting rules, where a policy allows GET requests, and another denies them, the deny policy will be applied. When multiple policies are applied to the same workload, Istio applies them additively.
from
field, and answer the who? question. Operations are listed in the to
field, and answer the what? question. Then at last, conditions are described in the when
field and answer the when? question.
Let's see a concrete example:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: catalog
namespace: backyards-demo
spec:
selector:
matchLabels:
app: catalog
rules:
- from:
- source:
principals:
[
"cluster.local/ns/backyards-demo/sa/frontpage",
]
to:
- operation:
methods: ["GET"]
This AuthorizationPolicy
is applied to the catalog
workload in the backyards-demo
namespace, and while not explicitly specified, it's an ALLOW
rule, so it will deny all traffic that doesn't match the rules described here. The rules contain a source
, that means that traffic is allowed only from a workload with the cluster.local/ns/backyards-demo/sa/frontpage
identity (service account). It also contains an operation
, that only matches GET
requests. It doesn't contain a condition
, which means match any conditions. So to recap, the above policy allows GET requests from workloads with the cluster.local/ns/backyards-demo/sa/frontpage
identity to backyard-demo/catalog
, and denies everything else.
In the example, the source is a principal, but it can be requestPrincipals
, namespaces
or ipBlocks
as well. Istio also support exclusion matching, by providing the same fields with a not
prefix. So for example notNamespaces: default
would match sources from all namespaces, except from default
.
Let's take a look at the operation
field as well: along methods
, valid matchers are hosts
, ports
, paths
and their exclusion pairs, like notHosts
.
In most cases the when
field can be omitted, it's usually only used in complex scenarios, but it can be used to further customize request matching with a list of supported Istio attributes. For example the below example matches request header values:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: header-matching
namespace: backyards-demo
spec:
selector:
matchLabels:
app: catalog
action: ALLOW
rules:
- from:
- source:
principals:
[
"cluster.local/ns/backyards-demo/sa/frontpage",
]
to:
- operation:
methods: ["GET"]
when:
- key: request.headers[version]
values: ["v1", "v2"]
Finally, take a look at a more complex rule to see how it matches requests when most fields contain multiple entries:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: example-policy
namespace: backyards-demo
spec:
selector:
matchLabels:
app: movies
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/backyards-demo/sa/catalog"]
- source:
namespaces: ["backyards-test"]
to:
- operation:
methods: ["GET"]
paths: ["/api/v1*"]
- operation:
methods: ["POST"]
paths: ["/api/v1*"]
- from:
- source:
principals: ["cluster.local/ns/backyards-demo/sa/bookings"]
to:
- operation:
methods: ["GET"]
paths: ["/api/v1/movies*"]
when:
- key: request.auth.claims[iss]
values: ["https://accounts.banzaicloud.io"]
This final example contains two separate rules in one policy with an ALLOW
action.
app=movies
in the backyards-demo
namespaceGET
requests to /api/v1*
OR POST
requests to /api/v1*
from workloads in the backyards-test
namespace, OR from workloads with the cluster.local/ns/backyards-demo/sa/catalog
service accountGET
requests to /api/v1/movies*
from workloads with the cluster.local/ns/backyards-demo/sa/bookings
service account, when the request has a valid JWT token, issued by "https://accounts.banzaicloud.io"AuthorizationPolicy
entries for the two different rulessource.principals
, source.namespaces
, or the connection.sni
conditionhosts
, methods
and paths
operations have no effect, as well as the request_principals
field in the source section and some of the custom conditions*
, presence matching is *
and it's used to specify anything but emptysource.principals: ["*"]
, that means all authenticated requestsAuthorizationPolicy
custom resource. This kind of access control is enforced at the application layer by the Envoy sidecar proxies. It gives the user a very powerful and flexible, yet performant way of authorization between Kubernetes workloads.Get emerging insights on emerging technology straight to your inbox.
The Shift is Outshift’s exclusive newsletter.
Get the latest news and updates on cloud native modern applications, application security, generative AI, quantum computing, and other groundbreaking innovations shaping the future of technology.
Discover why security teams rely on Panoptica's graph-based technology to navigate and prioritize risks across multi-cloud landscapes, enhancing accuracy and resilience in safeguarding diverse ecosystems.