Authorization policy overview
Unlike a monolithic application that might be running in one place, globally-distributed microservices apps make calls across network boundaries. This means more points of entry into your applications, and more opportunities for malicious attacks. And because Kubernetes pods have transient IPs, conventional IP-based firewall rules aren't adequate to secure access between workloads. In a microservices architecture, a new approach to security is needed. Building on security features such as Kubernetes service accounts and Istio security policies, Cloud Service Mesh provides even more capabilities to help you secure your applications.
This page gives application operators an overview of the AuthorizationPolicy
custom resource (CR). Authorization policies let you enable access control on
workloads at the application (L7) and transport (L3/4) layers. You configure
authorization policies to specify permissions—what is this service or user
allowed to do?
Authorization policies
Requests between services in your mesh (and between end-users and services) are
allowed by default. You use the AuthorizationPolicy CR to define granular
policies for your workloads. After you apply the authorization policies,
Cloud Service Mesh distributes them to the sidecar proxies. As requests come into a
workload, the sidecar proxy checks the authorization policies to determine if
the request should be allowed or denied.
See Supported features for details of which
fields of the AuthorizationPolicy CR are supported by platform.
Policy scope
You can apply a policy to the entire service mesh, to a namespace, or to an individual workload.
To apply a mesh-wide policy, specify the root namespace,
istio-system, in themetadata:namespacefield:apiVersion: "security.istio.io/v1beta1" kind: "AuthorizationPolicy" metadata: name: "mesh-wide" namespace: istio-system spec: ...To apply a policy to a namespace, specify the namespace in the
metadata:namespacefield:apiVersion: "security.istio.io/v1beta1" kind: "AuthorizationPolicy" metadata: name: "currencyservice" namespace: currencyservice spec: ...To restrict a policy to a specific workload, include a
selectorfield.apiVersion: "security.istio.io/v1beta1" kind: "AuthorizationPolicy" metadata: name: "frontend" namespace: demo spec: selector: matchLabels: app: frontend ...
Basic structure
An authorization policy includes the policy scope, an action, and a list of
rules:
As described in the previous section, the policy scope can be the entire mesh, a namespace, or a specific workload. If you include it, the
selectorfield specifies the target of the policy.The
actionfield specifies whether toALLOWorDENYthe request. If you don't specify an action, by default, the action is set toALLOW. For clarity, we recommend that you always specify the action. (Authorization policies also supportAUDITandCUSTOMactions. TheAUDITaction is only supported on some platforms. See Supported features for details.)The
rulesspecify when to trigger the action.The
fromfield in therulesspecifies the sources of the request.The
tofield in therulesspecifies the operations of the request.The
whenfield specifies additional conditions needed to apply the rule.
In the following example:
The policy is applied to requests to the
frontendservice in thedemonamespace.Requests are allowed when "hello:world" is in the request header; otherwise, requests are denied.
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "hello-world"
namespace: demo
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
- when:
- key: request.headers[hello]
values: ["world"]
Access control on request operation
You can control access to specific request
operations
such as HTTP methods or TCP ports by adding a to section under rules.
In the following example, only the GET and POST HTTP methods are allowed
to the currencyservice in the demo namespace.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: currencyservice
namespace: demo
spec:
selector:
matchLabels:
app: currencyservice
action: ALLOW
rules:
- to:
- operation:
methods: ["GET", "POST"]
Access control on authenticated identity
In the previous examples, the policies allow requests from unauthenticated
workloads. If you have
STRICT mutual TLS (mTLS) enabled,
you can restrict access based on the identity of the workload or namespace that
the request is from in the
source
section.
Use the
principalsornotPrincipalfield to control access at the workload level.Use the
namespacesornotNamespacesfield to control access at the namespace level.
All of the preceding fields require that you have STRICT mTLS enabled. If you are
unable to set STRICT mTLS, see
Reject plaintext requests for an alternative
solution.
Identified workload
In the following example, requests to the currencyservice are allowed only
from the frontend service. Requests to the currencyservice from other
workloads are denied.
apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
name: "currencyservice"
namespace: demo
spec:
selector:
matchLabels:
app: currencyservice
action: ALLOW
rules:
- from:
- source:
principals: ["example-project-1234.svc.id.goog/ns/demo/sa/frontend-sa"]
To specify a service account, the principals must be in the following format:
principals: ["PROJECT_ID.svc.id.goog/ns/NAMESPACE/sa/SERVICE_ACCOUNT_NAME"]
If you are using in-cluster Cloud Service Mesh with Citadel CA, then
cluster.local is the trust domain. In all other cases,
PROJECT_ID.svc.id.googis the trust domain for the mesh.
A trust domain
corresponds to the root of trust of a system and is part of a workload identity.
Cloud Service Mesh uses a trust domain to create all identities within a mesh. For
example, in the SPIFFE ID
spiffe://mytrustdomain.com/ns/default/sa/myname, the substring
mytrustdomain.com specifies that the workload is from a trust domain called
mytrustdomain.com.
When using the Cloud Service Mesh certificate authority, the trust domain is automatically generated by Cloud Service Mesh. It is based on the cluster's workload pool.
You can have one or more trust domains in a multi-cluster mesh, as long as the clusters share the same root of trust.
Identified namespace
The following example shows a policy that denies requests if the source is not
the foo namespace:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: httpbin-deny
namespace: foo
spec:
selector:
matchLabels:
app: httpbin
version: v1
action: DENY
rules:
- from:
- source:
notNamespaces: ["foo"]
Value matching
Most fields in authorization policies support all the following matching schemas:
- Exact match: exact string match.
- Wildcard match using the
"*"wildcard character:- Prefix match: a string with an ending
"*". For example,"test.example.*"matches"test.example.com"or"test.example.com.cn". - Suffix match: a string with a starting
"*". For example,"*.example.com"matches"eng.example.com"or"test.eng.example.com".
- Prefix match: a string with an ending
- Presence match: To specify that a field must be present and not empty, use
the
fieldname: ["*"]format. This is different from leaving a field unspecified, which means match anything, including empty.
There are a few exceptions. For example, the following fields only support exact match:
- The
keyfield under thewhensection - The
ipBlocksunder thesourcesection - The
portsfield under thetosection
The following example policy allows access at paths with the /test/* prefix
or the */info suffix:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: tester
namespace: default
spec:
selector:
matchLabels:
app: products
action: ALLOW
rules:
- to:
- operation:
paths: ["/test/*", "*/info"]
Exclusion matching
To match negative conditions like notValues in the when field,
notIpBlocks in the source field, notPorts in the to field, Cloud Service Mesh
supports exclusion matching. The following example requires a valid request
principals, which is derived from JWT authentication, if the request path is
not /healthz. Thus, the policy excludes requests to the /healthz path from
the JWT authentication:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: disable-jwt-for-healthz
namespace: default
spec:
selector:
matchLabels:
app: products
action: ALLOW
rules:
- to:
- operation:
notPaths: ["/healthz"]
from:
- source:
requestPrincipals: ["*"]
Reject plaintext requests
In Cloud Service Mesh, auto mTLS is enabled by default. With auto mTLS, a client sidecar proxy automatically detects if the server has a sidecar. The client sidecar sends mTLS to workloads with sidecars and sends plaintext to workloads without sidecars. For the best security, we recommend that you enable STRICT mTLS.
If you are unable to enable mTLS with STRICT mode for a workload or
namespace, you can:
- create an authorization policy to explicitly allow traffic with non-empty
namespacesor non-emptyprincipals, or - reject traffic with empty
namespacesorprincipals.
Because the namespaces and principals can only be extracted with a mTLS
request, these policies effectively reject any plaintext traffic.
The following policy denies the request if the principal in the request is
empty (which is the case for plaintext requests). The policy allows
requests if the principal is non-empty. The ["*"] means a non-empty match, and
using with notPrincipals means matching on empty principal.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-mtls
namespace: NAMESPACE
spec:
action: DENY
rules:
- from:
- source:
notPrincipals: ["*"]
Authorization policy precedence
You can configure separate ALLOW and DENY authorization policies, but you
need to understand the policy precedence and default behavior to make sure that
the policies do what you want. The following diagram describes the policy
precedence.
The example policies in the following sections illustrate some of the default behavior and the situations where you might find them useful.
Allow nothing
The following example shows an ALLOW policy that doesn't match anything. By
default, if there are no other ALLOW policies, requests are always denied.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-nothing
spec:
action: ALLOW
It is a good security practice to start with the allow-nothing policy and
incrementally add more ALLOW policies to open more access to a workload.
Deny all access
The following example shows a DENY policy that matches everything. Because
DENY policies are evaluated before ALLOW policies, all requests are denied
even if there is an ALLOW policy that matches the request.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
spec:
action: DENY
rules:
- {}
A deny-all policy is useful if you want to temporarily disable all access to a workload.
Allow all access
The following example shows an ALLOW policy that matches everything, and
allows full access to a workload. The allow-all policy makes other ALLOW
policies useless because it always allows the request.
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-all
spec:
action: ALLOW
rules:
- {}
An allow-all policy is useful if you want to temporarily expose full access to
a workload. If there are any DENY policies, requests could still be denied
since DENY policies are evaluated before ALLOW policies.
Best practices
Create a Kubernetes service account for each service, and specify the service account in the Deployment. For example:
apiVersion: v1 kind: ServiceAccount metadata: name: frontend-sa namespace: demo --- apiVersion: apps/v1 kind: Deployment metadata: name: frontend namespace:demo spec: selector: matchLabels: app: frontend template: metadata: labels: app: frontend spec: serviceAccountName: frontend-sa ...Start with an allow-nothing policy and incrementally add more
ALLOWpolicies to open more access to workloads.If you are using JWTs for your service:
Create a
DENYpolicy to block unauthenticated requests, for example:apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: requireJWT namespace: admin spec: action: DENY rules: - from: - source: notRequestPrincipals: ["*"]Apply an allow-nothing policy.
Define
ALLOWpolicies for each workload. For examples, see JWT Token.
What's next
Learn more about Cloud Service Mesh security features:
- Configuring Cloud Service Mesh user authentication
- Configuring audit policies for your services
- Configuring transport security
- Integrating Identity-Aware Proxy with Cloud Service Mesh
- Best Practices for using Cloud Service Mesh egress gateways on GKE clusters
Learn more about authorization policies from the Istio documentation: