-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CEL functions/macros errors with tls.client placeholders #5491
Comments
In the next version, it will be possible to use variadic args. See #5249. The syntax is approximately the same as Go's slice syntax with an upper and lower bound index into the args. You can build from source to try this out if you like. You can do Regarding your CEL compile error, essentially that's a type error. It's saying that the type of the placeholder (which is turned into a function call with regexp replacement ahead of compiling) has the return type But with variadic args you can probably ensure it's always a list by doing like |
Thanks! I didn't know variadic args were coming and now I'm looking forward to that. I'll try out the master branch and I think I can work around for what I want to accomplish. Regarding the errors, I realize they are spread out and buried in my post so I'll summarize the three types:
|
Re "receiver", that's talking about https://github.com/google/cel-spec/blob/master/doc/langdef.md#receiver-call-style. That's interesting though, func (celPkixName) ConvertToType(typeVal ref.Type) ref.Val {
panic("not implemented")
} I think this should support a cast to func (pn celPkixName) ConvertToType(typeVal ref.Type) ref.Val {
if typeVal.TypeName() == "string" {
return types.String(pn.Name.String())
}
panic("not implemented")
} I can open a PR with this change if you want to try it out. (Edit: see #5492) For |
For For string conversion, you might also have to hack it a bit since it's not easy to change the declaration set for the builtin types (not yet anyway): For your custom function, you'd want the following which would be more CEL idiomatic: func (pn celPkixName) ConvertToType(typeVal ref.Type) ref.Val {
if typeVal.TypeName() == "string" {
return types.String(pn.Name.String())
}
if typeVal.TypeName() == "type" {
return pn.Type()
}
return types.ValOrErr(typeVal, "no such overload")
} To get the type-checker to pass, you might need to use the |
Hmm, that code doesn't seem right @TristonianJones, both those parts give errors:
|
I tried out the variadic args from #5249 but so far no luck. If I should make a separate issue to discuss this feature let me know.
Error on starting Caddy:
Similar results for all the passing test cases from that pull request:
I'm able to get (I also made a comment here regarding the proposed |
Hmm, I'm confused. I'm not sure why the args didn't get replaced. Can you run Edit: Oh, right. Variadic placeholders only get expanded if they're a token on their own (i.e. starts with One dumb workaround is to put spaces around it so like |
Ah, ok. I see the warning now that I run
FWIW, here's the relevant portion it generates. "match": [
{
"expression": "[{args[:]}].exists(email, email in {http.request.tls.client.san.emails})"
}
] With spaces it does the expansion but, as you said, there are no quotes or commas to make it valid list syntax. Thanks for the explanation! |
Oh I guess this could work:
You just need to make sure to specify the import arg as a valid CEL array as a single-token-string. So with the above solution and #5492, are all your concerns satisfied? I'm not sure where we're at now. Anything left? |
Nice! That works. Just to make sure I understand it, the backticks in the import statement are to allow spaces within a single "token" right? Without them, Caddy will separate tokens on whitespace? I ask because that's my understanding and both of these seem to work. I removed the space in the second line to make it all one token without the backticks needed.
I'm guessing using backticks is preferred though to avoid unintentionally creating multiple tokens. Out of curiosity, is there a difference between single quote I'm satisfied with the solutions here. Here's my summary for anyone finding this in the future. This is written with the
ExamplesDo This: (requires #5249, otherwise use (enforce_mtls) {
# The value in {args[0]} will be inserted in the CEL expression and interpreted as a list by the CEL parser
@user expression {args[0]}.exists(email, email in {http.request.tls.client.san.emails})
# This also works
#@user expression dyn({http.request.tls.client.san.emails}).exists(email, email in {args[0})
}
user.acme.corp {
# Pass a list as a single token to the enforce_mtls snippet
import enforce_mtls `['[email protected]', '[email protected]']`
respond @user "Authorized. Welcome, {http.request.tls.client.subject}."
} Not This: (enforce_mtls) {
@user expression {args[:]}.exists(email, email in {http.request.tls.client.san.emails})
@user expression [{args[:]}].exists(email, email in {http.request.tls.client.san.emails})
@user expression [ {args[:]} ].exists(email, email in {http.request.tls.client.san.emails})
@user expression {http.request.tls.client.san.emails}.exists(email, email in {args[:]})
}
user.acme.corp {
# Attempt at using variadic args
import enforce_mtls [email protected] [email protected]
respond @user "Authorized. Welcome, {http.request.tls.client.subject}."
} Do This: (requires #5492) @subjectMatches expression string({http.request.tls.client.subject}).matches("@acme\\.corp$")
@subjectEndsWith expression string({http.request.tls.client.subject}).endsWith("@acme.corp") Not This: @subjectMatches expression {http.request.tls.client.subject}.matches("@acme\\.corp$")
@subjectEndsWith expression {http.request.tls.client.subject}.endsWith("@acme.corp") Thank you for all the help! |
Correct, the Caddyfile considers spaces the end of a token, unless quoted. Either
CEL supports both interchangeably. I tend to use
Btw you can still use |
I'm attempting to implement some simple authorization checks using CEL and client certificate fields
subject
,emails
, anddns_names
.What I'd really like is a reusable snippet that lets me pass in a list of names that I can then validate against the current certificate.
Something like this is what I imagine as ideal:
I haven't found that it's possible to use
{args}
as a list, however, so I'm trying cousins of what I want as a workaround.I'm getting several different types of errors that I believe are bugs, but may be user error. Most of my attempts involve
{http.request.tls.client.*}
, but I'm including an example using{http.request.method}
mainly to prove to myself that something similar works.I don't believe the examples I'm including are exhaustive. I've tried some other variations and functions and gotten similar errors.
Repro steps
I'm running Caddy using docker (in case that's relevant), but my steps are for reproducing with just the Caddy binary.
/etc/host
entry./etc/caddy/certs/root_ca.crt
(or change Caddyfile path to match).curl
command arguments to match)./etc/caddy/Caddyfile
(or changecaddy
command argument to match).Start Caddy.
Use curl to access sites and submit client certificates.
The commented blocks in the Caddyfile all produce errors when I start the server and Caddy parses the config. They all basically say the same thing. I admit I could be doing something wrong, but if I try replacing the placeholder with a literal list then it works.
Supporting Files
certs.zip (I just realized these expire in 24 hours. Ask if you'd like new ones.)
Caddyfile
References
caddy/modules/caddyhttp/app.go
Lines 39 to 102 in 10b265d
caddy/modules/caddyhttp/replacer.go
Lines 344 to 437 in 223cbe3
The text was updated successfully, but these errors were encountered: