应用开放策略代理 (OPA) 策略

使用中间件对传入的请求应用开放策略代理(OPA)策略。

开放策略代理(OPA)HTTP 中间件OPA 策略应用到传入的 Dapr HTTP 请求中。 这可以用来将可重用的授权策略应用到应用终结点。

配置

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Component
  3. metadata:
  4. name: my-policy
  5. namespace: default
  6. spec:
  7. type: middleware.http.opa
  8. version: v1
  9. metadata:
  10. # `includedHeaders` is a comma-separated set of case-insensitive headers to include in the request input.
  11. # Request headers are not passed to the policy by default. Include to receive incoming request headers in
  12. # the input
  13. - name: includedHeaders
  14. value: "x-my-custom-header, x-jwt-header"
  15. # `defaultStatus` is the status code to return for denied responses
  16. - name: defaultStatus
  17. value: 403
  18. # `rego` is the open policy agent policy to evaluate. apiVersion: dapr.io/v1alpha1
  19. kind: Component
  20. metadata:
  21. name: my-policy
  22. namespace: default
  23. spec:
  24. type: middleware.http.opa
  25. version: v1
  26. metadata:
  27. # `includedHeaders` is a comma-separated set of case-insensitive headers to include in the request input.
  28. # Request headers are not passed to the policy by default. Include to receive incoming request headers in
  29. # the input
  30. - name: includedHeaders
  31. value: "x-my-custom-header, x-jwt-header"
  32. # `defaultStatus` is the status code to return for denied responses
  33. - name: defaultStatus
  34. value: 403
  35. # `rego` is the open policy agent policy to evaluate. required
  36. # The policy package must be http and the policy must set data.http.allow
  37. - name: rego
  38. value: |
  39. package http
  40. default allow = true
  41. # Allow may also be an object and include other properties
  42. # For example, if you wanted to redirect on a policy failure, you could set the status code to 301 and set the location header on the response:
  43. allow = {
  44. "status_code": 301,
  45. "additional_headers": {
  46. "location": "https://my.site/authorize"
  47. }
  48. } {
  49. not jwt.payload["my-claim"]
  50. }
  51. # You can also allow the request and add additional headers to it:
  52. allow = {
  53. "allow": true,
  54. "additional_headers": {
  55. "x-my-claim": my_claim
  56. }
  57. } {
  58. my_claim := jwt.payload["my-claim"]
  59. }
  60. jwt = { "payload": payload } {
  61. auth_header := input.request.headers["authorization"]
  62. [_, jwt] := split(auth_header, " ")
  63. [_, payload, _] := io.jwt.decode(jwt)
  64. }
  65. # Request headers are not passed to the policy by default. Include to receive incoming request headers in
  66. # the input
  67. - name: includedHeaders
  68. value: "x-my-custom-header, x-jwt-header"
  69. # `defaultStatus` is the status code to return for denied responses
  70. - name: defaultStatus
  71. value: 403
  72. # `rego` is the open policy agent policy to evaluate. required
  73. # The policy package must be http and the policy must set data.http.allow
  74. - name: rego
  75. value: |
  76. package http
  77. default allow = true
  78. # Allow may also be an object and include other properties
  79. # For example, if you wanted to redirect on a policy failure, you could set the status code to 301 and set the location header on the response:
  80. allow = {
  81. "status_code": 301,
  82. "additional_headers": {
  83. "location": "https://my.site/authorize"
  84. }
  85. } {
  86. not jwt.payload["my-claim"]
  87. }
  88. # You can also allow the request and add additional headers to it:
  89. allow = {
  90. "allow": true,
  91. "additional_headers": {
  92. "x-my-claim": my_claim
  93. }
  94. } {
  95. my_claim := jwt.payload["my-claim"]
  96. }
  97. jwt = { "payload": payload } {
  98. auth_header := input.request.headers["authorization"]
  99. [_, jwt] := split(auth_header, " ")
  100. [_, payload, _] := io.jwt.decode(jwt)
  101. }

您可以使用 官方 opa playground对策略进行原型设计和实验。 例如,您可以在这里找到上面的示例策略

元数据字段规范

字段详情示例
regoRego策略语言见上文
defaultStatus状态码返回拒绝的响应https://accounts.google.com, https://login.salesforce.com
includedHeaders一组以逗号分隔的不区分大小写的头信息,包含在请求输入中。 默认情况下,请求头不会传递给策略。 在输入中包含接收传入的请求头。“x-my-custom-header, x-jwt-header”

Dapr配置

要应用中间件,必须在配置中进行引用。 请参阅中间件管道

  1. apiVersion: dapr.io/v1alpha1
  2. kind: Configuration
  3. metadata:
  4. name: appconfig
  5. spec:
  6. httpPipeline:
  7. handlers:
  8. - name: my-policy
  9. type: middleware.http.opa

输入

这个中间件提供了一个 HTTPRequest 作为输入。

HTTP请求

HTTPRequest 输入包含所有关于传入HTTP请求的透彻信息,但它的正文除外。

  1. type Input struct {
  2. request HTTPRequest
  3. }
  4. type HTTPRequest struct {
  5. // The request method (e.g. GET,POST,etc...)
  6. method string
  7. // The raw request path (e.g. "/v2/my-path/")
  8. path string
  9. // The path broken down into parts for easy consumption (e.g. ["v2", "my-path"])
  10. path_parts string[]
  11. // The raw query string (e.g. "?a=1&b=2")
  12. raw_query string
  13. // The query broken down into keys and their values
  14. query map[string][]string
  15. // The request headers
  16. // NOTE: By default, no headers are included. You must specify what headers
  17. // you want to receive via `spec.metadata.includedHeaders` (see above)
  18. headers map[string]string
  19. // The request scheme (e.g. http, https)
  20. scheme string
  21. }
  22. method string
  23. // The raw request path (e.g. "/v2/my-path/")
  24. path string
  25. // The path broken down into parts for easy consumption (e.g. ["v2", "my-path"])
  26. path_parts string[]
  27. // The raw query string (e.g. "?a=1&b=2")
  28. raw_query string
  29. // The query broken down into keys and their values
  30. query map[string][]string
  31. // The request headers
  32. // NOTE: By default, no headers are included. You must specify what headers
  33. // you want to receive via `spec.metadata.includedHeaders` (see above)
  34. headers map[string]string
  35. // The request scheme (e.g. http, https)
  36. scheme string
  37. }

结果

策略必须设置 data.http.allow 带有 boolean 值或者一个 object 值与一个 allow 布尔属性。 true allow 将允许请求 当一个 false 值将以 defaultStatus 指定的状态拒绝请求。 下面的策略,在默认情况下,演示了对所有请求的 403 - Forbidden:

  1. package http
  2. default allow = false

等价于:

  1. package http
  2. default allow = {
  3. "allow": false
  4. }

更改拒绝的响应状态代码

拒绝请求时,您可以覆盖返回的状态代码。 例如,如果您想退回 401 而不是 403,你可以这样做:

  1. package http
  2. default allow = {
  3. "allow": false,
  4. "status_code": 401
  5. }

添加响应头

若要重定向,添加消息头并将 status_code 设置为返回的结果:

  1. package http
  2. default allow = {
  3. "allow": false,
  4. "status_code": 301,
  5. "additional_headers": {
  6. "Location": "https://my.redirect.site"
  7. }
  8. }

添加请求头

你也可以在允许的请求上设置额外的头信息:

  1. package http
  2. default allow = false
  3. allow = { "allow": true, "additional_headers": { "X-JWT-Payload": payload } } {
  4. not input.path[0] == "forbidden"
  5. // Where `jwt` is the result of another rule
  6. payload := base64.encode(json.marshal(jwt.payload))
  7. }

结果结构

  1. type Result bool
  2. // or
  3. type Result struct {
  4. // Whether to allow or deny the incoming request
  5. allow bool
  6. // Overrides denied response status code; Optional
  7. status_code int
  8. // Sets headers on allowed request or denied response; Optional
  9. additional_headers map[string]string
  10. }

相关链接