Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Open Policy Agent

Bo-Yi Wu
October 12, 2021

Introduction to Open Policy Agent

1. Why do we need a Policy Engine?
2. Why do we choose Open Policy Agent?
3. Workflow with Open Policy Agent?
4. What is Policy Language (Rego)?
5. RBAC and IAM Role Design
6. Three ways to deploy an Open Policy Agent.

Bo-Yi Wu

October 12, 2021
Tweet

More Decks by Bo-Yi Wu

Other Decks in Programming

Transcript

  1. Introduction to


    Open Policy Agent
    Bo-Yi Wu


    2021/10/23


    View full-size slide

  2. About me
    • Software Engineer in Mediatek


    • Member of Drone CI/CD Platform


    • Member of Gitea Platform


    • Member of Gin Golang Framework


    • Maintain Some GitHub Actions Plugins.

    View full-size slide

  3. Outline
    • Why we need Policy Engine?


    • Why we choose Open Policy Agent?


    • Work
    fl
    ow with Open Policy Agent?


    • What is Policy Language (Rego)?


    • RBAC and IAM Role Design


    • Three ways to deploy Open Policy Agent.

    View full-size slide

  4. Why we need


    Policy Engine?

    View full-size slide

  5. 1. RBAC is Hard

    View full-size slide

  6. 4JNQMF(SPVQ
    1FSNJTTJPO

    View full-size slide

  7. {


    "group_roles": {


    "project_leader": ["kpi_editor_design", "viewer_limit_ds"],


    "software_leader": ["kpi_editor_design", "kpi_editor_system"]


    },


    "role_permissions": {


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "kpi_editor_system": [


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"}


    ]


    }


    }


    View full-size slide

  8. 2. Cross


    Multi-Service

    View full-size slide

  9. 1FSNJTTJPOGPSNVMUJQMFTFSWJDF

    View full-size slide

  10. 3. Applying to


    Multi-System

    View full-size slide

  11. 1FSNJTTJPOGPSNVMUJQMFTZTUFN

    View full-size slide

  12. Why we choose


    Open Policy Agent?

    View full-size slide

  13. Open Policy Engine
    • Written in Golang


    • Easy to write policy testing


    • Easy to integrate with Go Application


    • Embed in GO


    • RESTful API

    View full-size slide

  14. Request Work
    fl
    ow with


    Open Policy Agent

    View full-size slide


  15. Client Send Request

    View full-size slide



  16. Client Send Request
    Ask Permission

    View full-size slide



  17. Client Send Request
    Ask Permission
    Response Result

    View full-size slide




  18. Client Send Request
    Ask Permission
    Response Result
    Response to Client

    View full-size slide

  19. Query Input and Result


    with policy engine

    View full-size slide


  20. Upload Data
    Upload Policy Rule

    View full-size slide



  21. Upload Data
    Upload Policy Rule
    Send Query Input
    *OQVUDBOCF
    "/:+40/WBMVF

    View full-size slide



  22. Upload Data
    Upload Policy Rule
    Send Query Input
    Get Query Result
    *OQVUDBOCF
    "/:+40/WBMVF
    0VUQVUDBOCF
    "/:+40/WBMVF

    View full-size slide

  23. Policy Decision
    • Data (JSON)


    • Policy (Rego)


    • Query Input (JSON)

    View full-size slide

  24. RBAC Example


    (Role-base Access Control)

    View full-size slide

  25. {


    "group_roles": {


    "project_leader": ["kpi_editor_design", "viewer_limit_ds"],


    "software_leader": ["kpi_editor_design", "kpi_editor_system"]


    },


    "role_permissions": {


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "kpi_editor_system": [


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"}


    ]


    }


    }


    %BUB

    View full-size slide

  26. {


    "group_roles": {


    "project_leader": ["kpi_editor_design", "viewer_limit_ds"],


    "software_leader": ["kpi_editor_design", "kpi_editor_system"]


    },


    "role_permissions": {


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "kpi_editor_system": [


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"}


    ]


    }


    }


    3PMF

    View full-size slide

  27. {


    "group_roles": {


    "project_leader": ["kpi_editor_design", "viewer_limit_ds"],


    "software_leader": ["kpi_editor_design", "kpi_editor_system"]


    },


    "role_permissions": {


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "kpi_editor_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"}


    ],


    "kpi_editor_system": [


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"}


    ]


    }


    }


    (SPVQ

    View full-size slide

  28. {


    "input": {


    "user": ["project_leader", "software_leader"],


    "action": "edit",


    "object": "design"


    }


    }
    *OQVU

    View full-size slide

  29. {


    "input": {


    "user": ["project_leader", "software_leader"],


    "action": "edit",


    "object": "design"


    }


    }
    6TFSHSPVQT

    View full-size slide

  30. package rbac.authz


    import data.rbac.authz.acl


    import input


    # logic that implements RBAC.


    default allow = false


    allow {


    # lookup the list of roles for the user


    roles
    : =
    acl.group_roles[input.user[_]]


    # for each role in that list


    r
    : =
    roles[_]


    # lookup the permissions list for role r


    permissions
    : =
    acl.role_permissions[r]


    # for each permission


    p
    : =
    permissions[_]


    # check if the permission granted to r matches the user's request


    p
    = =
    {"action": input.action, "object": input.object}


    }


    1PMJDZ

    View full-size slide

  31. Policy Language


    (Rego)

    View full-size slide

  32. Rego Playground

    https://play.openpolicyagent.org/

    View full-size slide

  33. rule01 {


    input.x < input.y


    }


    rule02 = "foobar" {


    input.x < input.y


    }


    rule03 = x {


    x
    : =
    input.x


    x < input.y


    }


    %F
    fi
    OF3VMF
    IUUQTQMBZPQFOQPMJDZBHFOUPSHQ7"IJ/[YN

    View full-size slide

  34. rule01 {


    input.x < input.y


    }


    rule02 = "foobar" {


    input.x < input.y


    }


    rule03 = x {


    x
    : =
    input.x


    x < input.y


    }


    %F
    fi
    OF3VMF
    SFUVSOCPPMFBO

    View full-size slide

  35. rule01 {


    input.x < input.y


    }


    rule02 = "foobar" {


    input.x < input.y


    }


    rule03 = x {


    x
    : =
    input.x


    x < input.y


    }


    %F
    fi
    OF3VMF
    SFUVSOCPPMFBO
    SFUVSOTUSJOH

    View full-size slide

  36. rule01 {


    input.x < input.y


    }


    rule02 = "foobar" {


    input.x < input.y


    }


    rule03 = x {


    x
    : =
    input.x


    x < input.y


    }


    %F
    fi
    OF3VMF
    SFUVSOCPPMFBO
    SFUVSOTUSJOH
    SFUVSOWBSJBCMF

    View full-size slide

  37. rule01 {


    input.x < input.y


    input.y < input.z


    }


    rule02 {


    input.x < input.y


    }


    rule02 {


    input.y < input.z


    }


    "OE0SDPOEJUJPO
    BOEDPOEJUJPO
    PSDPOEJUJPO
    IUUQTQMBZPQFOQPMJDZBHFOUPSHQ-Q1STV

    View full-size slide

  38. default rule01 = false


    default rule02 = false


    rule01 {


    input.x < input.y


    input.y < input.z


    }


    rule02 {


    input.x < input.y


    }


    rule02 {


    input.y < input.z


    }


    EFGBVMUWBMVF

    View full-size slide

  39. func allow() bool {


    if input.group
    = =
    "admin" {


    return true


    }


    if input.user
    = =
    data.admin {


    return true


    }


    return false


    }


    default allow = false


    allow {


    input.group
    = =
    "admin"


    }


    allow {


    input.user
    = =
    data.admin


    }
    (PMBOH
    3FHP

    View full-size slide

  40. numbers = [1, 2, 3, 4, 5]


    rule[x] {


    x
    : =
    numbers[_]


    x % 2
    = =
    0


    }


    containers = {


    "app": {


    "image": "app:18.04"


    },


    "db": {


    "image": "db:latest"


    }


    }


    rule01[key] = image {


    image
    : =
    containers[key].image


    endswith(image, ":latest")


    }
    'JOEFWFOOVNCFS
    'JOEMBUFTUJNBHF

    View full-size slide

  41. numbers = [1, 2, 3, 4, 5]


    rule01 {


    x
    : =
    numbers[_]


    x < 0


    }


    rule02 {


    not rule01


    }


    positives {


    negative
    : =

    [x | x
    : =
    numbers[_]; x < 0]


    count(negative)
    = =
    0


    }


    numbers = [1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    "OZOVNCFS
    HSFBUFSUIBO;FSP
    numbers = [-1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    "MMOVNCFS
    HSFBUFSUIBO;FSP

    View full-size slide

  42. numbers = [1, 2, 3, 4, 5]


    rule01 {


    x
    : =
    numbers[_]


    x < 0


    }


    rule02 {


    not rule01


    }


    positives {


    negative
    : =

    [x | x
    : =
    numbers[_]; x < 0]


    count(negative)
    = =
    0


    }


    numbers = [1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    numbers = [-1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    "OZOVNCFS
    HSFBUFSUIBO;FSP
    "MMOVNCFS
    HSFBUFSUIBO;FSP

    View full-size slide

  43. numbers = [1, 2, 3, 4, 5]


    rule01 {


    x
    : =
    numbers[_]


    x < 0


    }


    rule02 {


    not rule01


    }


    positives {


    negative
    : =

    [x | x
    : =
    numbers[_]; x < 0]


    count(negative)
    = =
    0


    }


    numbers = [1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    numbers = [-1, 2, 3, 4, 5]


    rule {


    x
    : =
    numbers[_]


    x > 0


    }
    "OZOVNCFS
    HSFBUFSUIBO;FSP
    "MMOVNCFS
    HSFBUFSUIBO;FSP

    View full-size slide

  44. func rule() []string {


    results
    : =
    []string{}


    for _, img
    : =
    range images {


    for _, repo
    : =
    range repos {


    if strings.HasPref
    i
    x(img, repo) {


    results = append(results, img)


    }


    }


    }


    return results


    }


    images = [


    "docker.io/nginx",


    "quay.io/ubuntu",


    "localhost/nginx"


    ]


    repos = [


    "docker.io",


    "quay.io"


    ]


    rule[image] {


    image = images[_]


    startswith(image, repos[_])


    }


    3FHP (P-BOHVBHF

    View full-size slide

  45. rule07verify(answer) {


    rule07.db
    = =
    answer


    }


    test_rule07 {


    rule07verify("db:latest") with input as {"containers": {


    "app": {"image": "app:18.04"},


    "db": {"image": "db:latest"},


    }}


    not rule07verify("db:latest") with input as {"containers": {


    "app": {"image": "app:18.04"},


    "db": {"image": "postgres:latest"},


    }}


    }


    View full-size slide

  46. rule12verify(answer) {


    count(rule12)
    = =
    answer


    }


    test_rule12 {


    rule12verify(2) with input as {


    "images": [


    "docker.io/nginx",


    "quay.io/ubuntu",


    "localhost/nginx",


    ],


    "repos": [


    "docker.io",


    "quay.io",


    ],


    }


    }


    rule12[image] {


    image = input.images[_]


    startswith(image, input.repos[_])


    }


    3VMF
    5FTUJOH

    View full-size slide

  47. $ opa test
    -
    v .


    data.example.test_rule01
    :
    PASS (5.9055ms)


    data.example.test_rule02
    :
    PASS (157.292µs)


    data.example.test_rule03
    :
    PASS (839.958µs)


    data.example.test_rule04
    :
    PASS (150.125µs)


    data.example.test_rule05
    :
    PASS (3.447417ms)


    data.example.test_rule06
    :
    PASS (224.833µs)


    data.example.test_rule07
    :
    PASS (721.959µs)


    data.example.test_rule08
    :
    PASS (354.917µs)


    data.example.test_rule09
    :
    PASS (207.583µs)


    data.example.test_rule11
    :
    PASS (169.708µs)


    data.example.test_rule12
    :
    PASS (198.042µs)


    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    PASS
    :
    11/11 IUUQTHJUIVCDPNHPUSBJOJOHPQBEFNP

    View full-size slide

  48. Upload Data and Policy

    View full-size slide

  49. {


    "group_roles": {


    "admin": ["admin"],


    "project_leader": ["viewer_limit_ds"]


    },


    "role_permissions": {


    "admin": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"},


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "viewer_limit_m": [{"action": "view_l3_project"}]


    }


    }
    %BUB

    View full-size slide

  50. {


    "group_roles": {


    "admin": ["admin"],


    "project_leader": ["viewer_limit_ds"]


    },


    "role_permissions": {


    "admin": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"},


    ],


    "viewer_limit_ds": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"}


    ],


    "viewer_limit_m": [{"action": "view_l3_project"}]


    }


    }
    package rbac.authz


    import data.rbac.authz.acl


    import input


    default allow = false


    allow {


    roles := acl.group_roles[input.user[_]]


    r := roles[_]


    permissions := acl.role_permissions[r]


    p := permissions[_]


    p == {"action": input.action, "object": input.object}


    }
    %BUB
    1PMJDZ

    View full-size slide

  51. Query Result

    View full-size slide

  52. {


    "input": {


    "user": ["admin", "system_group_kpi_editor"],


    "action": "edit",


    "object": "design"


    }


    }
    *OQVU

    View full-size slide

  53. {


    "input": {


    "user": ["admin", "system_group_kpi_editor"],


    "action": "edit",


    "object": "design"


    }


    }
    {


    "result": true


    }
    *OQVU
    3FTVMU

    View full-size slide

  54. / /
    GetUserGroupNames get user groups


    func GetUserGroupNames(username string) ([]string, error) {


    if !helper.IsUsername(username) {


    return []string{}, errors.EBadRequest(errors.ErrUserNotExist, nil)


    }


    result
    : =
    &getUserGroups{}


    response, err
    : =
    resty.New().R().


    SetHeader("Content-Type", "application/json").


    SetHeader("Accept", "application/json").


    SetQueryParam("username", username).


    SetBasicAuth(conf
    i
    g.Crowd.BasicUsername, conf
    i
    g.Crowd.BasicPassword).


    SetResult(result).


    Get(conf
    i
    g.Crowd.Address + "/user/group/nested")


    if err
    ! =
    nil {


    return []string{}, err


    }


    if response.StatusCode()
    ! =
    http.StatusOK {


    log.Error().Msg("failed to get user groups from crowd:" + response.String())


    }


    groups
    : =
    []string{}


    for _, v
    : =
    range result.Groups {


    if strings.HasPref
    i
    x(v.Name, "prime_") {


    groups = append(groups, v.Name)


    }


    }


    return groups, err


    }


    View full-size slide

  55. 3PMF1FSNJTTJPO

    View full-size slide

  56. 3PMF1FSNJTTJPO

    View full-size slide

  57. # role
    -
    permissions assignments


    role_permissions
    : =
    {


    "admin": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"},


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"},


    {"action": "view_all", "object": "manufacture"},


    {"action": "edit", "object": "manufacture"},


    ],


    "quality_head_design": [


    {"action": "view_all", "object": "design"},


    {"action": "edit", "object": "design"},


    {"action": "view_all", "object": "system"},


    {"action": "view_all", "object": "manufacture"},


    ],


    "quality_head_system": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"},


    {"action": "edit", "object": "system"},


    {"action": "view_all", "object": "manufacture"},


    ],


    "quality_head_manufacture": [


    {"action": "view_all", "object": "design"},


    {"action": "view_all", "object": "system"},


    {"action": "view_all", "object": "manufacture"},


    {"action": "edit", "object": "manufacture"},


    ],


    }


    View full-size slide

  58. 3PMF1FSNJTTJPO

    View full-size slide

  59. # user
    -
    role assignments


    group_roles
    : =
    {


    "prime_cqc_admin": ["admin"],


    "prime_cqc_design_quality_head": ["quality_head_design"],


    "prime_cqc_system_quality_head": ["quality_head_system"],


    "prime_cqc_manufacturing_quality_head": ["quality_head_manufacture"],


    "prime_cqc_design_kpi_editor": ["kpi_editor_design"],


    "prime_cqc_system_kpi_editor": ["kpi_editor_system"],


    "prime_cqc_manufacturing_kpi_editor": ["kpi_editor_manufacture"],


    "prime_cqc_viewer": ["viewer"],


    "prime_cqc_limitedviewer_design_system": ["viewer_limit_ds"],


    "prime_cqc_limitedviewer_manufacturing": ["viewer_limit_m"],


    }


    View full-size slide

  60. 3PMF1FSNJTTJPO

    View full-size slide

  61. # user
    -
    role assignments


    group_roles
    : =
    {


    # for testing


    "design_group_kpi_editor": ["kpi_editor_design", "viewer_limit_ds"],


    "system_group_kpi_editor": ["kpi_editor_system", "viewer_limit_ds"],


    "manufacture_group_kpi_editor": ["kpi_editor_manufacture", "viewer"],


    "project_leader": ["viewer_limit_ds", "viewer_limit_m"],


    }


    View full-size slide

  62. test_design_group_kpi_editor {


    allow with input as {"user": ["design_group_kpi_editor"], "action": "view_all", "object": "design"}


    allow with input as {"user": ["design_group_kpi_editor"], "action": "edit", "object": "design"}


    allow with input as {"user": ["design_group_kpi_editor"], "action": "view_all", "object": "system"}


    not allow with input as {"user": ["design_group_kpi_editor"], "action": "edit", "object": "system"}


    not allow with input as {"user": ["design_group_kpi_editor"], "action": "view_all", "object": "manufacture"}


    not allow with input as {"user": ["design_group_kpi_editor"], "action": "edit", "object": "manufacture"}


    }


    View full-size slide

  63. $ opa test
    -
    v ./module/opa/policy
    / *
    .rego


    data.rbac.authz.test_design_group_kpi_editor: PASS (13.0495ms)


    data.rbac.authz.test_system_group_kpi_editor: PASS (2.158583ms)


    data.rbac.authz.test_manufacture_group_kpi_editor: PASS (2.235167ms)


    data.rbac.authz.test_project_leader: PASS (1.90625ms)


    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    PASS
    :
    4/4

    View full-size slide

  64. How about


    Dynamic Actions and


    Dynamic Resources?

    View full-size slide

  65. "NB[POF8FC4FSWJDF*".

    View full-size slide

  66. {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "FirstStatement",
    "Effect": "Allow",
    "Action": ["iam:ChangePassword"],
    "Resource": "*"
    },
    {
    "Sid": "SecondStatement",
    "Effect": "Allow",
    "Action": "s3:ListAllMyBuckets",
    "Resource": "*"
    },
    {
    "Sid": "ThirdStatement",
    "Effect": "Allow",
    "Action": [
    "s3:List*",
    "s3:Get*"
    ],
    "Resource": [
    "arn:aws:s3:::confidential-data",
    "arn:aws:s3:::confidential-data/*"
    ]
    }
    ]
    }
    "NB[POF8FC
    4FSWJDF*".

    View full-size slide

  67. package aws


    default allow = false


    allow {


    actions_match


    resources_match


    }


    actions_match {


    # iterate over the actions in the list


    actions
    : =
    ["s3
    :
    List.*","s3
    :
    Get.*"]


    action
    : =
    actions[_]


    # check if input.action matches an action


    regex.globs_match(input.action, action)


    }


    resources_match {


    # iterate over the resources in the list


    resources
    : =
    ["arn:aws:s3
    : : :
    conf
    i
    dential
    -
    data","arn:aws:s3
    : : :
    conf
    i
    dential
    -
    data/.*"]


    resource
    : =
    resources[_]


    # check if input.resource matches a resource


    regex.globs_match(input.resource, resource)


    }
    IUUQTXXXPQFOQPMJDZBHFOUPSHEPDTMBUFTUDPNQBSJTPOUPPUIFSTZTUFNTBNB[POXFCTFSWJDFTJBN
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "FirstStatement",
    "Effect": "Allow",
    "Action": ["iam:ChangePassword"],
    "Resource": "*"
    },
    {
    "Sid": "SecondStatement",
    "Effect": "Allow",
    "Action": "s3:ListAllMyBuckets",
    "Resource": "*"
    },
    {
    "Sid": "ThirdStatement",
    "Effect": "Allow",
    "Action": [
    "s3:List*",
    "s3:Get*"
    ],
    "Resource": [
    "arn:aws:s3:::confidential-data",
    "arn:aws:s3:::confidential-data/*"
    ]
    }
    ]
    }
    1PMJDZ
    %BUB

    View full-size slide

  68. package aws


    default allow = false


    allow {


    actions_match


    resources_match


    }


    actions_match {


    # iterate over the actions in the list


    actions
    : =
    ["s3
    :
    List.*","s3
    :
    Get.*"]


    action
    : =
    actions[_]


    # check if input.action matches an action


    regex.globs_match(input.action, action)


    }


    resources_match {


    # iterate over the resources in the list


    resources
    : =
    ["arn:aws:s3
    : : :
    conf
    i
    dential
    -
    data","arn:aws:s3
    : : :
    conf
    i
    dential
    -
    data/.*"]


    resource
    : =
    resources[_]


    # check if input.resource matches a resource


    regex.globs_match(input.resource, resource)


    }
    IUUQTXXXPQFOQPMJDZBHFOUPSHEPDTMBUFTUDPNQBSJTPOUPPUIFSTZTUFNTBNB[POXFCTFSWJDFTJBN
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "FirstStatement",
    "Effect": "Allow",
    "Action": ["iam:ChangePassword"],
    "Resource": "*"
    },
    {
    "Sid": "SecondStatement",
    "Effect": "Allow",
    "Action": "s3:ListAllMyBuckets",
    "Resource": "*"
    },
    {
    "Sid": "ThirdStatement",
    "Effect": "Allow",
    "Action": [
    "s3:List*",
    "s3:Get*"
    ],
    "Resource": [
    "arn:aws:s3:::confidential-data",
    "arn:aws:s3:::confidential-data/*"
    ]
    }
    ]
    }
    1PMJDZ
    %BUB

    View full-size slide

  69. How to resolve


    Multiple Statement and


    Multiple Effect?

    View full-size slide

  70. {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "FirstStatement",
    "Effect": "Allow",
    "Action": ["iam:ChangePassword"],
    "Resource": "*"
    },
    {
    "Sid": "SecondStatement",
    "Effect": "Deny",
    "Action": "s3:GetFile",
    "Resource": "*"
    },
    {
    "Sid": "ThirdStatement",
    "Effect": "Allow",
    "Action": [
    "s3:List*",
    "s3:Get*"
    ],
    "Resource": [
    "arn:aws:s3:::bucket",
    "arn:aws:s3:::bucket/*"
    ]
    }
    ]
    }
    1FSNJTTJPO%BUB
    {
    "action": "s3:GetFile",
    "Resource": "arn:aws:s3:::bucket"
    }
    *OQVU%BUB

    View full-size slide

  71. {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Sid": "FirstStatement",
    "Effect": "Allow",
    "Action": ["iam:ChangePassword"],
    "Resource": "*"
    },
    {
    "Sid": "SecondStatement",
    "Effect": "Deny",
    "Action": "s3:GetFile",
    "Resource": "*"
    },
    {
    "Sid": "ThirdStatement",
    "Effect": "Allow",
    "Action": [
    "s3:List*",
    "s3:Get*"
    ],
    "Resource": [
    "arn:aws:s3:::bucket",
    "arn:aws:s3:::bucket/*"
    ]
    }
    ]
    }
    1FSNJTTJPO%BUB
    {
    "action": "s3:GetFile",
    "Resource": "arn:aws:s3:::bucket"
    }
    *OQVU%BUB

    View full-size slide

  72. package iam.authz


    default authorized = false


    has_resource[statement_id] {


    statement_resource
    : =
    data.statements[statement_id].resources[_]


    regex.globs_match(input.resource, statement_resource)


    }


    has_action[statement_id] {


    statement_resource
    : =
    data.statements[statement_id].actions[_]


    regex.globs_match(input.action, statement_resource)


    }


    match[[effect, statement_id]] {


    effect
    : =
    data.statements[statement_id].effect


    has_resource[statement_id]


    has_action[statement_id]


    }


    allow {


    match[["allow", _]]


    }


    deny {


    match[["deny", _]]


    }


    authorized {


    allow


    not deny


    }

    View full-size slide

  73. Three Ways to Deploy


    Open Policy Agent

    View full-size slide

  74. Architectural Flexibility
    • Embed in Go Application


    • Deploy in Single Project (REST API)


    • Deploy one OPA service (REST API)

    View full-size slide

  75. Embed in Go Application

    View full-size slide

  76. Deploy in Single Project

    View full-size slide

  77. Deploy one OPA service

    View full-size slide

  78. AWS Lambda
    Function With OPA

    View full-size slide