Skip to content
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

Allow associating an ID with a biscuit's root key #151

Merged
merged 2 commits into from
Nov 13, 2024

Conversation

seh
Copy link
Contributor

@seh seh commented Oct 31, 2024

In order to accommodate biscuit issuers with multiple key pairs in use, whether concurrently or in an ongoing rotation cycle, biscuits can record and expose an identifier for the root private key used to sign its authority block. Allow issuers to associate such an identifier with the private key when creating a new biscuit.

Introduce the option function WithRootKeyID to supply such an identifier at composition time, and the (*Biscuit).RootKeyID method to query this identifier later.

Contributes to #150.

In order to accommodate biscuit issuers with multiple key pairs in
use, whether concurrently or in an ongoing rotation cycle, biscuits
can record and expose an identifier for the root private key used to
sign its authority block. Allow issuers to associate such an
identifier with the private key when creating a new biscuit.

Introduce the option function "WithRootKeyID" to supply such an
identifier at composition time, and the "(*Biscuit).RootKeyID" method
to query this identifier later.
Copy link
Contributor

@divarvel divarvel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, given the current state of the library.

An interesting thing to note, however is that we have moved away from this design in other libs, especially biscuit rust.

In biscuit rust, we now have two kinds of builders:

With this setup, there is no need for separate add_fact / add_authority_fact distinctions, everything uses the same code for adding facts, rules and checks.

This also makes the root key id part of the builder, so that there is no need to modify the build() function, the builder can be extended without affecting the rest of the codebase.

This is clearly a big change and this PR improves the situation, but at some point i’d like to have this structure in the go lib as well.

return *v, true
}
return 0, false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would returning a pointer instead of a tuple also work to signal optionality?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I vacillated over this decision for a while before implementing this new method. I'm glad you asked about it.

Yes, it would work to return a pointer, though it's fairly typical in Go to use this style, especially when the primary return value's type has a sensible zero value.

This paired value style comes from and is adapted somewhat unjustly from a few of Go's statements and expressions that benefit from it:

  • Channel receive statements that can include an optional second untyped boolean value to check whether the channel is closed.
  • Map index expressions that can use an optional second untyped boolean value to check whether the given key is present in the map.
  • Type assertions can use an optional second untyped boolean value to check whether the interface value's dynamic type matches the asserted type.

In each of these cases, callers are free to omit the assignment of this second value, and I don't mean just not assigning it to a named variable. Callers can omit mention of the second value entirely if they don't care about it. By contrast, if a map index expression returned by pointer to indicate whether or not the key was bound to a value in the map, all callers would have to confront the possibility of absence.

My use of that idiom here doesn't benefit from that same treatment, though. A caller of my (*Biscuit).RootKeyID cannot ignore the presence of that second return value. They are free to ignore its value, though, and use the first value unconditionally, since the zero value for uint32 is, well, zero, which is a valid key ID.

Given that, I'm now coming back around to thinking that returning by pointer would be a safer choice here. Please allow me to make that change, and then you can decide if you like that by-pointer approach better.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i also think returning a pointer would be a bit safer. The rust implementation distinguishes between no id and 0. Since biscuit uses protobuf 2, I think the serialization also makes that distinction.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see commit 9b7f488 for this change. I'll squash the commits before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good, thanks! in can also squash-merge the PR if that’s simpler for you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's fine with if you squash the commits. I recommend preserving the message from the first one.

After we merge this, I'll carry on with addressing the rest of #150—selecting a public key in calls to the (b *Biscuit).Authorizer method, or a new sibling method, per #150 (comment).

@divarvel divarvel merged commit 6cde69d into biscuit-auth:main Nov 13, 2024
3 checks passed
@seh seh deleted the allow-specifying-root-key-id branch November 13, 2024 14:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants