Policy Authoring
Policy authoring with Istio specifies which HTTP APIs are allowed in and out of a service running next to the Istio proxy. Istio enforces those policies, and the service never sees a rejected API request. Additionally, you can write a policy the service calls into explicitly to provide additional information that Istio does not have; it is your service's responsibility to enforce that decision appropriately.
Pre-installed Policies
When you add the Istio System, several policies are automatically installed. In the Styra DAS UI, click app, egress, or ingress folders from your Istio to see the policies.
-
app: A custom policy that you can use if your application needs additional policy decisions from OPA.
-
egress: Policy that either allows or denies outgoing traffic.
-
ingress: Policy that either allows or denies incoming traffic.
Write Ingress and Egress Policies
Use Open Policy Agent's policy language called Rego to author policies.
The following resources provide an introduction to Rego:
-
OPA Documentation Introduction to OPA or Rego Documentation.
-
Free Video Training: Styra Academy.
When writing Rego policies, you need to know the JSON format provided to each of your policies as input. The following shows a sample input provided by Istio for Ingress and Egress policies. This sample includes source, destination, request, and additional metadata.
{
"attributes":{
"destination":{
"address":{
"socketAddress":{
"address":"10.244.0.17",
"portValue":5000
}
},
"principal":"spiffe://cluster.local/ns/default/sa/default"
},
"metadataContext":{
"filterMetadata":{
"envoy.filters.http.header_to_metadata":{
"policy_type":"ingress"
}
}
},
"request":{
"http":{
"headers":{
":authority":"example-app-service",
":method":"GET",
":path":"/hr/dashboard",
"accept":"*/*",
"authorization":"Basic ZGF2aWQ6cGFzc3dvcmQ=",
"content-length":"0",
"user-agent":"curl/7.74.0-DEV",
"x-b3-sampled":"1",
"x-b3-spanid":"377316f76c868da6",
"x-b3-traceid":"39a2e4a341b0691c377316f76c868da6",
"x-envoy-attempt-count":"1",
"x-ext-auth-allow":"yes",
"x-forwarded-client-cert":"By=spiffe://cluster.local/ns/default/sa/default;Hash=a1cc8ec55ad9eedfe4952c8ea58a79566b539d7e7e153130407bcaa440ceef32;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default",
"x-forwarded-proto":"http",
"x-request-id":"b8a81629-2c76-9176-b5eb-71531e78bed6"
},
"host":"example-app-service",
"id":"13759678405448271543",
"method":"GET",
"path":"/hr/dashboard",
"protocol":"HTTP/1.1"
},
"time":"2021-08-25T07:55:18.474536Z"
},
"source":{
"address":{
"socketAddress":{
"address":"10.244.0.16",
"portValue":52078
}
},
"principal":"spiffe://cluster.local/ns/default/sa/default"
}
},
"parsed_body":null,
"parsed_path":[
"hr",
"dashboard"
],
"parsed_query":{},
"truncated_body":false,
"version":{
"encoding":"protojson",
"ext_authz":"v3"
}
}
When writing policies, the allow
or deny
rules are written to describe the conditions under which a request is allowed or denied. By default, requests are all allowed, so you must write a policy to deny them.
For example, if you want to allow all GET
requests and deny all POST
requests to the root path, then write the following allow
and deny
rule.
# allow GET requests to the root path
allow {
input.attributes.request.http.method == "GET"
input.attributes.request.http.path == "/"
}
# deny POST requests to the root path
deny {
input.attributes.request.http.method == "POST"
input.attributes.request.http.path == "/"
}
Response Options
Styra DAS automatically creates response options for the following:
Allow Decisions
As covered in writing egress/ingress policies, Styra DAS returns allow
decisions based on the allow/deny rules written.
Headers Decisions
You can write rules that return additional, custom headers that Istio will add to the request before forwarding it to the microservice. To implement a headers decision, write rules that define headers
to be a JSON object that maps the header's name to its value.
For example, if you want to add the headers X-Via-Proxy: Istio
and X-Via-OPA: true
then write the following headers
rules.
headers["X-Via-Proxy"] = "Istio"
headers["X-Via-OPA"] = true
The example above has empty rule bodies so the headers
are included on every request. If required, you could add conditions to the rule bodies.
status_code
Decisions
You can write rules that control the HTTP status code. By default, the status_code
will be 200 if allow
is true and 403 if deny
is true. To override the defaults, you can define the status_code
variable to any desired value.
For example, if you want to return 200 when allow
is true and 400 when deny
is true, then write following status_code
rules.
status_code = 200 { allow }
status_code = 400 { deny }
Write app rules for OPA-aware Applications
Istio systems support application policies. The structure of these policies are customizable according to the application requirements. By default, the module policy.app
contains allow
and deny
- rules similar to ingress and egress policies, but you can remove those and write any Rego that you want.
An application can directly query the OPA embedded in data plane sidecar, by default listening at localhost:8181
, for application-specific authorization decisions. The default data document for application policies is data.application.main
. This exercises the allow
or deny
rule created in policy.app
module.
The application-specific main
rule can be queried using the following example:
curl -XPOST localhost:8181/v1/data/application/main \
-d '{
"input": {
"method": "GET",
"path": [
"finance",
"salary",
"bob"
],
"user": "david"
}
}'
{
"decision_id":"19d32bcc-ec43-4f9a-b042-927b07d04104",
"result":{
"allowed":true,
"code":200,
"http_status":200,
"outcome":{
"allowed":true,
"code":200,
"http_status":200,
"policy_type":"app",
"system_type":"template.istio:1.0"
}
}
}
The decision mappings for Istio systems rely on the presence of well-known fields to correctly parse the results. The decision mapper expects an outcome structure in the result with two required fields:
allowed
policy_type
{
"outcome": {
"allowed": false, // boolean value to determine if decision was Allowed or Denied
// an absence of this value will mark the decision as Unknown
"policy_type": "app" // classifies the decision as an app decision
// useful for filtering decisions by type in the Decisions UI
}
}
The allow
rule for policy.app
can also be queried directly through http://localhost:8181/v1/data/policy/app/allow
, but since the returned result will not contain the outcome
object, the decisions will mark it as Unknown
in the Styra DAS UI. Querying the rule through the main
rule at policy.application.main
ensures that the returned decision document is well-formed and conforms to the requirements of the decision mapper.