opa icon indicating copy to clipboard operation
opa copied to clipboard

Add built-in function to execute LDAP queries

Open tsandall opened this issue 5 years ago • 17 comments

In some cases, the typical approaches for getting LDAP data into OPA do not work (e.g., replication may not scale and authenticating proxies may not have enough knowledge to gather the right context.) For example. if the data required from LDAP is only known at request-time then it has to be fetched on the fly (either by the app and provided as input) or by the policy. Putting this logic into the app increases coupling between the app the policy which is undesirable.

In situations like this it would be useful to have the ability to execute LDAP queries from inside the policy that can fetch the relevant context on the fly. This capability would be similar to the existing http.send built-in function, except that it would work with LDAP instead of HTTP.

We can introduce a new built-in function, e.g., ldap.query(args, output) which takes as input a set of arguments and returns as output the JSON representation of the LDAP query result.

There are a few details that need to be fleshed out before we commit to adding this.

  1. How should the query arguments be represented in JSON?

  2. How should the query results be represented in JSON?

  3. Which Golang LDAP library should we use to execute the queries? When it comes to selecting the client library, we should be careful to find one that is well supported, robust, and introduces minimal additional dependencies. gopkg.in/ldap.v2 is a good candidate.

tsandall avatar Sep 07 '18 15:09 tsandall

ℹ️ There's so many search variants in LDAP -- but luckily, cURL supports querying LDAP server, and maybe its mapping rules could be taken as an example: see for example here. As pointed out there, it's based on RFC 4516

srenatus avatar Sep 10 '18 14:09 srenatus

Just a side note, testing this could be difficult, but we might snatched a line or two from the ldap tests in dex: https://github.com/dexidp/dex/blob/master/connector/ldap/ldap_test.go

srenatus avatar Sep 12 '18 07:09 srenatus

Here's a rough sketch for the query function:

ldap.query(connection_params, query_params, output)

Where:

  • connection_params is an object containing the required connection params, e.g., url, username, password, or whatever is most idiomatic from the perspective of LDAP clients.
  • query_params is an object containing the required query params, e.g., base DN, scope, filters, etc.
  • output is a JSON object containing the attributes resulting from the query. We may want to add a level of nesting to the output, e.g., {"attributes": ....} so that if we need to include additional information in the future, we're not boxed in.

As far as error handling goes, I'd expect that non-connection errors will result in an evaluation/runtime error that gets returned to the caller. Connection retries and timeouts could be controlled via the connection_params.

When we want to add additional built-ins, e.g., membership tests, we could follow a similar pattern:

ldap.is_member(connection_params, user, group)

tsandall avatar Oct 31 '18 01:10 tsandall

In the last community meeting @repenno indicated he was interested in looking into this and working on it. I'm going to assign to him for now.

tsandall avatar Feb 05 '19 16:02 tsandall

Hi all,

Is some of the OPA documentation aspirational? I node the reference to data.ldap on https://github.com/open-policy-agent/opa/blob/master/README.md and on the best practice page it really makes it sound like this is at lease experimentally available already: https://www.openpolicyagent.org/docs/best-practice-identity.html (#4)

Is there any current solution to this, or am I left having to implement something that bridges AD to http for this right now?

Thanks!

Jody

mudlark avatar Feb 22 '19 18:02 mudlark

Hi Jody,

Apologies if the docs came off as "aspirational". We could make it clearer that there's NOT an LDAP integration available out of the box today. The JWT and Push sections I think are pretty good, but the Bundle section requires you to know the semantics of OPA's bundle API. Opened a PR that should help: https://github.com/open-policy-agent/opa/pull/1230

No there's no bridge to AD/LDAP right now. Contributions are welcome!

Tim

On Fri, Feb 22, 2019 at 10:39 AM Jody Pearson [email protected] wrote:

Hi all,

Is some of the OPA documentation aspirational? I node the reference to data.ldap on https://github.com/open-policy-agent/opa/blob/master/README.md and on the best practice page it really makes it sound like this is at lease experimentally available already: https://www.openpolicyagent.org/docs/best-practice-identity.html (#4 https://github.com/open-policy-agent/opa/pull/4)

Is there any current solution to this, or am I left having to implement something that bridges AD to http for this right now?

Thanks!

Jody

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/open-policy-agent/opa/issues/938#issuecomment-466501359, or mute the thread https://github.com/notifications/unsubscribe-auth/AJlYK1v7RrliatL1ilWX35LLyWrJKq7Dks5vQDlWgaJpZM4WfFGC .

timothyhinrichs avatar Feb 23 '19 00:02 timothyhinrichs

To Tim,

That makes sense. I do.appreciate the fact that this is solved when using jwt /oidc etc. I've been wanting to learn go for a while, so this looks like my itch to scratch ;) I wanted to make sure this was not already in hand before assuming.

I'm a huge fan of OPA - you have a very nice tool here - thanks for providing it!

Jody

mudlark avatar Feb 23 '19 01:02 mudlark

We should figure out how we're going to deal with other protocols before we implement this. We need to avoid to be careful about pulling in too many 3rdparty dependencies.

tsandall avatar Jul 16 '19 13:07 tsandall

Agreed. We can go back to our discussion about allowing OPA to flourish vs. dependencies vs. stifling development. There will always be another protocol so we should have some generic built-in that calls an executable with some parameters. The executable would not be part off OPA distribution of course, just the generic built-in. This seems better: https://golang.org/pkg/plugin/

BenderScript avatar Jul 16 '19 14:07 BenderScript

Is there any PR raised for this yet?

ahmedtalhakhan avatar Dec 09 '19 22:12 ahmedtalhakhan

@ahmedtalhakhan I don't think so. 😃

srenatus avatar Dec 10 '19 13:12 srenatus

@srenatus @tsandall @repenno I understand from the above commentary that this effort is not complete yet. But I would like to take this opportunity to ask the following.

What is the simplest way to write a new custom built-in function of the form ldap.query(params) or mongo.query(params). Is there a brief write-up/tutorial on what code change need to be done and what files/data structures need to be updated in order to achieve this.

Assume that the nitty gritty about the internals(what driver to use inside, how to represent data etc)of the new function have been resolved.

ahmedtalhakhan avatar Dec 10 '19 22:12 ahmedtalhakhan

https://www.openpolicyagent.org/docs/latest/extensions/#custom-built-in-functions-in-go Shows how to add a custom built-in function through the Rego public golang API's. This is the easiest way if you want to customize OPA.

The process is pretty easy to add one to OPA as a default part of the language too, here is a simple example of a PR that adds one: https://github.com/open-policy-agent/opa/commit/7537f7ad06c3fa1a8038b861d9234bedf2a06c0c#diff-a6bb3036dbf3fa3bfaed6650acfa9879

At a high level you define the signature, implement the function, and connect the two by registering it at init time (or whenever, as long as it is before you start calling other OPA API's).

In both cases the implementation of the builtin function that is registered is pretty much the same.

patrick-east avatar Dec 10 '19 23:12 patrick-east

@patrick-east thanks for the swift reply. Will the approach explained at https://www.openpolicyagent.org/docs/latest/extensions/#custom-built-in-functions-in-go work if I want to use that built-in inside policy files?

ahmedtalhakhan avatar Dec 10 '19 23:12 ahmedtalhakhan

Depends on how you intend to run OPA, if you are doing everything through the Golang API then yes, you can register one like that and call the API's to load files and evaluate them.

If you want to run OPA CLI's and have the built-in function then use the second example on that page to build a customized opa https://www.openpolicyagent.org/docs/latest/extensions/#custom-plugins-for-opa-daemon

Instead of implementing the custom decision logger in that example you would instead define the function and register it similar to how that PR I linked to does it (just with the code in your files rather than in OPA). The only difference is instead of adding the signature into ast/builtins.go you call the ast.RegisterBuiltin function in addition to the topdown.RegisterXXXXX call.

patrick-east avatar Dec 10 '19 23:12 patrick-east

Thanks @patrick-east

ahmedtalhakhan avatar Dec 11 '19 00:12 ahmedtalhakhan

Working with NIST Zero Trust and UK NCSC Zero Trust principles for secure environments the importance of knowing your devices and users is crucial to the securing those systems. Devices tend to end up being published via DNS and Users tend to be shared within an environment using LDAP/Kerberos/JWT Tokens.

These principles have been continued into recommendations such as Azure Naming Best Practices, GCP Naming Conventions

The ability as part of policy to validate the existence of these names, particularly those residence in services such as LDAP and DNS are key to meeting the Zero Trust recommendations presented by governmental organisations.

The ability to take attributes such as groupOwner and validating that the groupOwner exists within the authorised users of an organisation is key to confirming policy compliance. This can be extended to further requirements such as the need for the group description match say to the DNS CNAME or A record for the service which is in operational. If the group is MailEnabled that this group is capable of being matched to a DNS MX record and the DNS resolve. Similar requirements exist for DNS SRV records used to locate services such as LDAP, SQL Servers and load balanced service pools.

For example, the ability to confirm that a DNS Server is using DNSSec, and that it is providing an SRV record to the LDAP server which in turn can be authenticated to and confirm that a hostmaster group exists and it is MailEnabled and to discover that it has a valid owner within the organisation or a group is part of validating the conformance to regulatory and best practice standards.

The ability to processes ideally with Regular Expressions so that they strings can be matched between DNS and LDAP resources within OPA would allow this to be embedded within the provisioning of Zero Trust Environments for governmental and highly regulated environments

thoughtful-solutions avatar Aug 10 '22 09:08 thoughtful-solutions