Save 37% off PRO during our Black Friday Sale! »

Introduction to Open Policy Agent

406ea2cac59924cedae4629c3c6c84fb?s=47 Kengo Suzuki
September 11, 2018

Introduction to Open Policy Agent

皆様の組織には何かしらのポリシーがあると思います。単なる組織内ルールにとどまらない、法的要件や技術的制約化の守りごとを定義したポリシーがあるかと思います。これらを手順書レベルやサービス内定義するのではなく、OPAをサイドカーなりでは知らせることで、柔軟で詳細なアクセス制御を、サービスのりコンパイルなしで実施できるようになります。今回はこのOPAについてお話したいと思います。

406ea2cac59924cedae4629c3c6c84fb?s=128

Kengo Suzuki

September 11, 2018
Tweet

Transcript

  1. Open Policy Agent is Կ? 2018/09/06 @ken5scal

  2. None
  3. What I will talk 1. Why Policy Engine 2. What’s

    Policy Engine 3. Use-Case of Policy Engine
  4. What I will talk 1. Why Policy Engine 2. What’s

    Policy Engine 3. Use-Case of Policy Engine
  5. Policy: Rule to govern system behavior

  6. What I will talk 1. Why Policy Engine 2. What’s

    Policy Engine 3. Use-Case of Policy Engine
  7. RBAC is HARD

  8. None
  9. None
  10. None
  11. None
  12. - Applying rules (operations) - Increasing Operation patterns - Sharing

    knowledge of Operation Main Concerns
  13. Applying in High Level .BTUFS /PEF /PEF /PEF admin

  14. kind: role version: v3 metadata: name: backend spec: allow: logins:

    - backend node_labels: '*': '*' rules: - resources: - session verbs: - list - read deny: node_labels: sre-only: true kind: role version: v3 metadata: name: frontend spec: allow: logins: - frontend node_labels: application: - “^front-web(\d+)$” service: - web rules: - resources: - session verbs: - list - read deny: {} kind: role version: v3 metadata: name: sre spec: allow: logins: - sre - admin node_labels: '*': '*' rules: - resources: - '*' verbs: - '*' kind: role version: v3 metadata: name: outsource spec: allow: logins: - outsource node_labels: env: - stg - dev deny: {} "MMPX"MM
  15. kind: role version: v3 metadata: name: backend spec: allow: logins:

    - backend node_labels: '*': '*' rules: - resources: - session verbs: - list - read deny: node_labels: sre-only: true kind: role version: v3 metadata: name: frontend spec: allow: logins: - frontend node_labels: application: - “^front-web(\d+)$” service: - web rules: - resources: - session verbs: - list - read deny: {} kind: role version: v3 metadata: name: sre spec: allow: logins: - sre - admin node_labels: '*': '*' rules: - resources: - '*' verbs: - '*' kind: role version: v3 metadata: name: outsource spec: allow: logins: - outsource node_labels: env: - stg - dev deny: {} %FOZTPNFOPEFT
  16. kind: role version: v3 metadata: name: backend spec: allow: logins:

    - backend node_labels: '*': '*' rules: - resources: - session verbs: - list - read deny: node_labels: sre-only: true kind: role version: v3 metadata: name: frontend spec: allow: logins: - frontend node_labels: application: - “^front-web(\d+)$” service: - web rules: - resources: - session verbs: - list - read deny: {} kind: role version: v3 metadata: name: sre spec: allow: logins: - sre - admin node_labels: '*': '*' rules: - resources: - '*' verbs: - '*' kind: role version: v3 metadata: name: outsource spec: allow: logins: - outsource node_labels: env: - stg - dev deny: {} "MMPXTPNFOPEF
  17. kind: role version: v3 metadata: name: backend spec: allow: logins:

    - backend node_labels: '*': '*' rules: - resources: - session verbs: - list - read deny: node_labels: sre-only: true kind: role version: v3 metadata: name: frontend spec: allow: logins: - frontend node_labels: application: - “^front-web(\d+)$” service: - web rules: - resources: - session verbs: - list - read deny: {} kind: role version: v3 metadata: name: sre spec: allow: logins: - sre - admin node_labels: '*': '*' rules: - resources: - '*' verbs: - '*' kind: role version: v3 metadata: name: outsource spec: allow: logins: - outsource node_labels: env: - outsource env: - stg - dev deny: {} "MMPXTPNFFOW
  18. Applying Configs to Multi-Env admin sytem B sytem C

  19. Applying Configs to multi-systems admin

  20. Applying to team (education)

  21. ʊਓਓਓਓʊ ʼɹDeathɹʻ ʉY^Y^Y^Y^ʉ

  22. What I will talk 1. Why Policy Engine 2. What’s

    Policy Engine 3. Use-Case of Policy Engine
  23. None
  24. Policy Engine - “It compares the request coming from the

    enforcement component against policy in order to determine whether the request is authorized or not” - “decouples the policy implementation from the business logic so that administrators can define policy without changing the application while still keeping up with the size, complexity, and dynamic nature of modern applications”
  25. Policy Engine 4FSWJDF %FDJTJPO &OGPSDFNFOU-BZFS %FDPVQMF JO QSPDMFWFM 4FSWJDF &OGPSDFNFOU-BZFS

    1PMJDZ&OHJOF %FDJTJPO-BZFS %PD 1PMJDZ query decision
  26. 1PMJDZ&OHJOF %FDJTJPO-BZFS %BUB %PDVNFOU 1PMJDZ 3VMF  How OPA works

  27. Data - Base Document 1PMJDZ&OHJOF %FDJTJPO-BZFS %BUB %PDVNFOU 1PMJDZ 3VMF

     - In memory - can store in Disk - Represented in JSON - Restful HTTP API - Data API
  28. curl -X PUT --data-binary @data.json localhost:8181/v1/data/servers { "servers": [ {"id":

    "s1", "name": "app", "protocols": ["https", "ssh"], "ports": ["p1", "p3"]}, {"id": "s2", "name": "db", "protocols": ["mysql"], "ports": [“p1”, "p2"]}, {"id": "s3", "name": "cache", "protocols": ["memcache"], "ports": [“p1”, “p2"]}, {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["p1", "p3"]} ], "networks": [ {"id": "n1", "public": false}, {"id": "n2", "public": false}, {"id": "n3", "public": true} ], "ports": [ {"id": "ssh", "networks": ["n1"]}, {"id": “db", "networks": ["n2"]}, {"id": "web", "networks": ["n3"]} ] }
  29. PUT https://example.com/v1/data/servers HTTP/1.1 Content-Type: application/json-patch+json { "servers": [ {"id": "s1",

    "name": "app", "protocols": ["https", "ssh"], "ports": ["mgt", “web"]}, {"id": "s2", "name": "db", "protocols": ["mysql"], "ports": [“mgt”, "db"]}, {"id": "s3", "name": "cache", "protocols": ["memcache"], "ports": [“mgt”, “db"]}, {"id": "s4", "name": "dev", "protocols": ["http"], "ports": ["mgt", "web"]} ], "networks": [ {"id": "n1", "public": false}, {"id": "n2", "public": false}, {"id": "n3", "public": true} ], "ports": [ {"id": "mgt", "networks": ["n1"]}, {"id": “db", "networks": ["n2"]}, {"id": "web", "networks": ["n3"]} ] }
  30. Policy (Rule) 1PMJDZ&OHJOF %FDJTJPO-BZFS %BUB %PDVNFOU 1PMJDZ 3VMF  -

    Written in Rego - purpose-built - declarative - Represented in JSON - Restful HTTP API - Policy API
  31. curl -X PUT --data-binary @server-rule.rego localhost:8181/v1/policies/servers package opa.example import data.servers

    import data.networks import data.ports public_servers[s] { s = servers[_] s.ports[_] = ports[i].id ports[i].networks[_] = networks[j].id networks[j].public = true } violations[server] { server = servers[_] server.protocols[_] = "http" public_servers[server] = true }
  32. package opa.example import data.servers import data.networks import data.ports public_servers[s] {

    s = servers[_] s.ports[_] = ports[i].id ports[i].networks[_] = networks[j].id networks[j].public = true } violations[server] { server = servers[_] server.protocols[_] = "http" public_servers[server] = true }
  33. package opa.example import data.servers import data.networks import data.ports public_servers[s] {

    s = servers[_] s.ports[_] = ports[i].id ports[i].networks[_] = networks[j].id networks[j].public = true } violations[s] { s = servers[_] s.protocols[_] = "http" public_servers[s] }
  34. curl -X GET localhost:8181/v1/data/opa/example/violations [ { "id": "s4", "name": "dev",

    "ports": [ "p1", "p2" ], "protocols": [ "http" ] } ]
  35. How OPA is deployed 4FSWJDF import ( “github.com/open-policy-agent/* ) EBFNPOTFSWJDF

    EBFNPO DPOUBJOFSTFSWJDF DPOUBJOFS
  36. - Unified - Declarative - Context-Aware Feature

  37. - Unified - Declarative - Context-Aware Feature

  38. - Unified - Declarative - Context-Aware Feature

  39. - Unified - Declarative - Context-Aware Feature

  40. None
  41. What I will talk 1. Why Policy Engine 2. What’s

    Policy Engine 3. Use-Case of Policy Engine
  42. - Docker - Web-server - Terraform Use-cases

  43. [ { "labels": { "app": "my-example-app", "id": "1780d507-aea2-45cc-ae50-fa153c8e4a5a" }, "decision_id":

    "4ca636c1-55e4-417a-b1d8-4aceb67960d1", "revision": "W3sibCI6InN5cy9jYXRhbG9nIiwicyI6NDA3MX1d", "path": "http/example/authz/allow", "input": { "method": "GET", "path": "/salary/bob" }, "result": "true", "requested_by": "[::1]:59943", "timestamp": "2018-01-01T00:00:00.000000Z" } ]
  44. { "labels": { "app": "my-example-app", "id": "1780d507-aea2-45cc-ae50-fa153c8e4a5a" }, "bundle": {

    "name": "http/example/authz", "active_revision": "TODO", "last_successful_download": "2018-01-01T00:00:00.000Z", "last_successful_activation": "2018-01-01T00:00:00.000Z" } }
  45. - Payment Service - Everyone can see their own payment

    - Manager can see her/his member’s payment - HR Dep can see all employee’s payment Use-Case: Web-Service
  46. version: '2' services: api_server: image: openpolicyagent/demo-restful-api:0.2 ports: - 5000:5000 environment:

    - OPA_ADDR=http://opa:8181 - POLICY_PATH=/v1/data/httpapi/authz opa: image: openpolicyagent/opa:0.9.0 ports: - 8181:8181 command: - "run" - "--server" - "--log-level=debug" IUUQTXXXPQFOQPMJDZBHFOUPSHEPDTIUUQBQJBVUIPSJ[BUJPOIUNM
  47. # Grab basic information. We assume user is passed on

    a form. http_api_user = request.form['user'] orig_path_list = request.path.split("/") # Remove empty entries from list that are a result of the split # Example: "<some_prefix>/finance/salary/" will become ["", "finance", "salary", ""] http_api_path_list = [x for x request.path.split("/") if x] input_dict = { # create input to hand to OPA "input": { "user": request.form['user'], "path": [x for x request.path.split("/") if x], "method": request.method } } # ask OPA for a policy decision # (in reality OPA URL would be constructed from environment) rsp = requests.post("http://127.0.0.1:8181/v1/data/httpapi/authz", data=json.dumps(input_dict)) if rsp.json()["allow"]: # HTTP API allowed else:
  48. version: '2' services: api_server: image: openpolicyagent/demo-restful-api:0.2 ports: - 5000:5000 environment:

    - OPA_ADDR=http://opa:8181 - POLICY_PATH=/v1/data/httpapi/authz opa: image: openpolicyagent/opa:0.9.0 ports: - 8181:8181 command: - "run" - "--server" - "--log-level=debug" IUUQTXXXPQFOQPMJDZBHFOUPSHEPDTIUUQBQJBVUIPSJ[BUJPOIUNM
  49. package httpapi.authz # HTTP API request import input as http_api

    default allow = false # Allow users to get their own salaries. allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] username = http_api.user } # Allow managers to get their member' salaries. # bob is alice's manager, and betty is charlie's. members = {"alice": [], "charlie": [], "bob": ["alice"], "betty": [“charlie"]} allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] members[http_api.user][_] = username } # Allow HR members to get anyone's salary. hr = [ “david" ] allow { http_api.method = "GET" http_api.path = ["finance", "salary", _] hr[_] = http_api.user } DVSMVTFSBMJDFQBTTXPSEMPDBMIPTUpOBODFTBMBSZBMJDF 4VDDFTTVTFSBMJDFJTBVUIPSJ[FE
  50. package httpapi.authz # HTTP API request import input as http_api

    default allow = false # Allow users to get their own salaries. allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] username = http_api.user } # Allow managers to get their member' salaries. # bob is alice's manager, and betty is charlie's. members = {"alice": [], "charlie": [], "bob": ["alice"], "betty": [“charlie"]} allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] members[http_api.user][_] = username } # Allow HR members to get anyone's salary. hr = [ “david" ] allow { http_api.method = "GET" http_api.path = ["finance", "salary", _] hr[_] = http_api.user } DVSMVTFSCPCQBTTXPSEMPDBMIPTUpOBODFTBMBSZBMJDF 4VDDFTTVTFSCPCJTBVUIPSJ[FE
  51. package httpapi.authz # HTTP API request import input as http_api

    default allow = false # Allow users to get their own salaries. allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] username = http_api.user } # Allow managers to get their member' salaries. # bob is alice's manager, and betty is charlie's. members = {"alice": [], "charlie": [], "bob": ["alice"], "betty": [“charlie"]} allow { http_api.method = "GET" http_api.path = ["finance", "salary", username] members[http_api.user][_] = username } # Allow HR members to get anyone's salary. hr = [ “david" ] allow { http_api.method = "GET" http_api.path = ["finance", "salary", _] hr[_] = http_api.user } DVSMVTFSEBWJEQBTTXPSEMPDBMIPTUpOBODFTBMBSZBMJDF 4VDDFTTVTFSEBWJEJTBVUIPSJ[FE DVSMVTFSEBWJEQBTTXPSEMPDBMIPTUpOBODFTBMBSZCPC 4VDDFTTVTFSEBWJEJTBVUIPSJ[FE
  52. None
  53. - Unauthorize user from executing docker commands - Docker for

    MacͩͱόάΔ Use-Case: Docker Authz
  54. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/ docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  55. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  56. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  57. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  58. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  59. # OPA-docker-auth plugin % docker run -d --restart=always -v $PWD/policies:/policies

    -v /run/docker/plugins:/run/docker/plugins openpolicyagent/opa-docker-authz:0.2 -policy-file /policies/example.reg # Inside the rule (Deny any request % cat policies/example.rego package docker.authz default allow = false # Run Docker Daemon w/ opa-docker-auth plugin as Access Authorization plugin % /usr/bin/dockerd -H fd:// —authorization-plugin=opa-docker-authz # Watch % docker ps Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
  60. % cat policies/example.rego package docker.authz default allow = false #

    allow if the user is granted read/write access. allow { user_id = input.Headers["Authz-User"] user = users[user_id] not user.readOnly } # users defines permissions for the user. In this case, we define a single # attribute 'readOnly' that controls the kinds of commands the user can run. users = { "alice": {"readOnly": false}, }
  61. % cat ~/.docker/config.json { "HttpHeaders": { "Authz-User": "alice" } }

  62. % docker ps % docker logs 2018/08/12 13:08:39 Querying OPA

    policy data.docker.authz.allow. Input: { "AuthMethod": "", "Body": null, "Headers": { "User-Agent": "Go-http-client/1.1" }, "Method": "GET", "Path": "/containers/ 8690a3302bb73d29c7cd182b91058e7549e0fbb10f0f025c604d8f793f63bb aa/json", "User": “alice" } 2018/08/12 13:08:39 Returning OPA policy decision: true
  63. - SSH - Terraform Other Use Cases

  64. - Plugins - https://github.com/open-policy-agent/opa-istio- plugin - https://github.com/open-policy-agent/opa-kube- scheduler Other Use

    Cases
  65. Conclusion

  66. - Why Policy Engine - RBACΛ࢝Ίͱͨ͠ϧʔϧద༻ͷਏΈ - What’s Policy Engine

    - Policy Engineొ৔ - Unified, Declartive & Context-AwareͳOPAొ৔ - Use Case of Policy Engine - HTTP API, Docker - ୺຤ϕʔεͷೝՄʹܨ͛ΒΕΔͱ͍Ζ͍ΖḿΓͦ͏ ·ͱΊ
  67. None