Параметры в правилах Rego [Open Policy Agent]

Как использовать параметры в правилах Rego? У меня было бы что-то вроде этого:

deny[reason] {
  input.request.kind.kind == "Route"
  not valid_route_request[label]
  reason := sprintf("missing or wrong router selector label: %v", [label])
}

valid_route_request[label] {
  requester := input.request.userInfo.username
  some i # iterate on all users
  requester == data.kubernetes.users[i].metadata.name
  label := input.request.object.metadata.labels["router-selector"]
  label == data.kubernetes.users[i].metadata.annotations[router_selector_key]
}

где labelиспользуется для создания сообщения об ошибке. Я получаю сообщение об ошибке от OPA: метка var небезопасна...

Вообще мне до сих пор непонятно, как передавать параметры в Rego.

1 ответ

Решение

Ваш пример почти верен - проблема, с которой вы столкнулись, заключается в том, чтоlabel "небезопасно".

TL; DR; назначатьlabel внутри deny правило:

deny[reason] {
    input.request.kind.kind == "Route"
    label := input.request.object.metadata.labels["router-selector"]
    not valid_route_request[label]
    reason := sprintf("wrong 'router-selector' label: %v", [label])
}

deny[reason] {
    input.request.kind.kind == "Route"
    not input.request.object.metadata.labels["router-selector"]
    reason := "missing 'router-selector' label"
}

Обратите внимание, я создал ДВА правила запрета. Один для случая, когда путьinput.request.object.metadata.labels["route-selector'] не определено, а другое - недопустимое значение.

Почему OPA генерирует ошибку безопасности в исходном примере? Безопасность - это свойство Rego, которое гарантирует, что всем переменным может быть присвоено конечное число значений. Чтобы считаться "безопасной", переменная должна появляться как результат хотя бы одного неотрицательного выражения.

Вот несколько безопасных примеров:

# 'a' is assigned to the value referenced by input.foo
a := input.foo

# 'x' is assigned to the keys of the collection referenced by input.foo
input.foo[x]

# 'label' is is assigned to the keys of the collection referenced by valid_route_request
valid_route_request[label]

# 'x' is safe because it is assigned outside the negated expression
x := 7; not illegal_numbers[x]

Вот примеры небезопасных выражений:

# 'x' is unsafe because it does not appear as an output of a non-negated expression
not p[x]; not q[x]


# 'y' is unsafe because it only appears as a built-in function input
count(y)

Ошибки безопасности также могут возникать с переменными, которые появляются в заголовке правила:

# 'msg' is unsafe because it is not assigned inside the body of the rule.
deny[msg] {
  input.request.kind.kind == "BadKind"
}

Безопасность важна, поскольку она гарантирует, что OPA может перечислить все значения, которые могут быть присвоены переменной. Если переменная небезопасна, это означает, что может быть бесконечное количество назначений переменных. В вашем примере утверждениеvalid_route_requestгенерирует набор значений (меток?). Вnot valid_route_request[label] заявление в deny правило небезопасно, потому что label больше нигде в deny правило (и label (предположительно, не появляется в глобальной области видимости). На самом деле это станет немного яснее, если вы включите 'some' в правило запрета:

deny[reason] {
  some label
  input.request.kind.kind == "Route"
  not valid_route_request[label]
  reason := ...
}

Это правило гласит (на английском языке):

reason is in deny if for some label, input.request.kind.kind equals Route and label is not in valid_route_request, and ...

Технически было бы бесконечное количество назначений на label которые удовлетворяют этому правилу (например, строка "12345" НЕ будет содержаться в valid_route_request и так будет "123456" и так будет...)

Другие вопросы по тегам