09 3 security
Authorization is answering the access control portion of the question. Is an authenticated principal allowed to perform an action on an object? Can User A send a
GET request to path
/hello to Service A? Remember that certain actions may still be prohibited even if we authenticate a principal.
Your company ID card might be valid and authentic. However, you won’t be able to use it to enter the offices of a different company. If we continue with the customs officer metaphor from before, authorization is similar to a visa stamp in your passport.
It is essential to have both authentication and authorization. Without one or the other, it will not be beneficial. For proper access control, we need both.
For example: If we only authenticate the principals and don’t authorize them, they can do anything and perform any actions on any objects. Conversely, suppose we authorize a request but don’t authenticate it. In that case, we can pretend to be someone else and perform any actions on objects again.
Armed with an authenticated principal, we can now decide to restrict access based on that. To do that, we use an
AuthorizationPolicy resource is where we can use the principle from the
PeerAuthentication policies and the
RequestAuthentication policy. Suppose we attempt to write policies based on peer or service identities. In that case, we can use the principals’ field, and if we are making decisions based on the users, we will use request principals.
This example applies the
AuthorizationPolicy to all workloads matching the
app=prod label. The second part of the resource is where we define the rules and say that we allow calls from a source with any
requestPrincipal set. We aren’t checking for any specific principal here, just that the principal is set. With this
AuthorizationPolicy and the
RequestAuthentication policy, we guarantee that only authenticated requests will reach the prod workloads.
apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: require-jwt namespace: default spec: selector: matchLabels: app: prod rules: - from: - source: requestPrincipals: ["*"]
The previous example was simple, but we can write rules in the authorization policies in multiple ways. We have seen the
from field in the last example. With
from, you can define a list of source identities, namespaces, and principals allowed to call the services to which we’ve applied the policy.
This example will allow calls from services that use the workload service account, are coming from the prod namespace, and have the requesting principal set to
rules: - from: - source: principals: ["cluster.local/ns/default/sa/workload"] - source: namespaces: ["prod"] - source: requestPrincipals: ["tetrate.io/nauticalmike"]
All these sources, principals, request principals, namespaces, and IP blocks also have negative matches, so we could write
notNamespaces to include a list of negative matches.
For example: If we want to apply the rules to all the namespaces except the
prod namespace, we could write
The second field is the
to field. This field is where we can specify what paths, methods, ports, or hosts we use when making the calls to the service. This example shows that we can call
DELETE on the
/logs path, call
GET on the
/data path, and allow ports
5000 for requests from
rules: - from: - ... to: - operation: methods: ["DELETE"] paths: ["/logs*"] - operation: methods: ["GET"] paths: ["/data"] - operation: hosts: ["request.host"] ports: ["3000", "5000"]
Like with the
from field, we can also write negative matches.
when field permits us to specify various conditions depending on the attributes of the request, such as headers, source IP, remote IP, namespaces, principals, destination ports, and connection SNI.
This example shows that we can only make the calls
to when the request has a valid JWT token that was issued by
accounts.google.com when the
some-value and the request is coming from the
rules: - from: to: when: - key: request.auth.claims[iss] values: ["https://accounts.google.com"] - key: request.headers[my-header] values: ["some-value"] - key: source.namespace value: ["foo"] ...
Once we’ve written the rules, we can configure the action. We can either
DENY the requests matching those rules. Additional supported actions are
CUSTOM action specifies our custom extension to handle the request. You must configure the custom extension in the
MeshConfig. An example of this would be if you wanted to integrate a custom external authorization system to delegate the auth decisions. The
CUSTOM action is experimental, which might break or change in future Istio versions.
AUDIT action audits a request that matches the rules. If the request matches the rules, the
AUDIT action will trigger logging that request. This action does not affect where the request is allowed or denied. Only
CUSTOM actions can do that. A sample scenario for when you could use the
AUDIT action is when you are migrating your workloads from
STRICT mTLS mode.
spec: action: DENY rules: - from: to: when: ...
In summary, services get their identity through x.509 certificates from service accounts in Kubernetes. To manage the communication between services, use the
PeerAuthentication resource. You can choose between
STRICT mutual TLS mode settings here.
The system saves specific metadata about the authenticated service, such as the principal name. It can later use to impose access control. Utilize the
RequestAuthentication resource to verify the identity of users using JWT tokens. Once users have verified their identity, the system uses the data in the JWT token to control their access.
After obtaining the authenticated principal, which can be a service or a user, we can utilize an
AuthorizationPolicy to determine which services have permission to access the workloads and establish restrictions for methods and paths.
Next, we will focus on the security lab.