An exploration in how to express "allow all except for these" perms when the authorisation backend is the ES Security model, which is unions-only.
This "subtracting-via-adding" could be applied in other similarly-constrained-and-not-uncommon backends, but this repo holds a demo that only interfaces with ES and its Security model.
- If we make the result of each action permission check for an actor and object a vector (magnitude with direction): that is: 0, 1 or -1, we can “subtract by adding”.
- If we only have booleans (1 or 0), assuming that there is a
can_do
function that returns0
if the "current" actor does not have permission to perform action0 on the input object, and1
otherwise, and it can also do so for an "inverse" action, let's say action0-1 if the input actor has been explicitly disallowed from doing action0 on the input object.
There is probably a way to express the above in terms of multiplication, but addition feels more straightforward a mapping..
The isAuthorised
function in poc.sc
demonstrates an implementation of the above building on
- Ammonite: must at least support Scala 3 because we're on that no-parens hotness.
- Docker CLI: Rancher Desktop will do
-
make start-es
to bring up ES, wait until it's up before proceeding.✅ Elasticsearch security features have been automatically configured!
should show up -
make repl
in a separate terminal to load up a REPL with the PoC functions loaded in and tested. -
Test it out
-
Assert that the Support user has blanket permissions to
deployment:edit
a given deploymentval deplIdToTest = generateRandStr() isAuthorised(supportEsUser, deplIdToTest -> "deployment:edit") // res1: Boolean = true
-
Subtract the deployment from the user's allowed set by adding it to the inverse support role
putEsRole( inverse(supportAppPrivName), Seq(deplIdToTest) )()
-
Test the access to that deployment again:
isAuthorised(supportEsUser, deplIdToTest -> "deployment:edit") // res3: Boolean = false
-
Remove it by emptying the inverse support resource list
putEsRole( inverse(supportAppPrivName), Seq.empty )()
-
Test the access to that deployment again:
isAuthorised(supportEsUser, deplIdToTest -> "deployment:edit") // res3: Boolean = true
-
-
Exit the REPL with
ctrl+d
thenctrl+c
-
make stop-es
to stop and cleanup ES