-
Notifications
You must be signed in to change notification settings - Fork 930
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
OpenFGA authorization driver #12252
OpenFGA authorization driver #12252
Conversation
29aea6c
to
fdd4e9b
Compare
@markylaing i know this is heavily under development for now, so no need to do this right away, but when it comes to review and merge, I would appreciate it if you could split this into two PRs; 1 for the interface and hook changes across the code base, and 2 introducing the new openfga authorization driver. |
e8c2b94
to
4a486fc
Compare
RBAC tests passing also :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tomponline I've added a few comments to start discussion on a few of the main things I need feedback on. There are still a fair few things to do before this is ready for a proper review.
|
||
var builtinAuthorizationModel client.ClientWriteAuthorizationModelRequest | ||
|
||
err = json.Unmarshal([]byte(authModel), &builtinAuthorizationModel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Migrations
Here authModel
is the json string that is generated via make update-openfga
. If there is an existing model in the store, we ensure that this model is exactly equal to the model we have statically defined. This is where we would have an opportunity to detect different model versions and apply update logic.
Migrations in OpenFGA follow a pretty basic idea. The idea is to create an intermediary model which supports both the new and the old, then write all the tuples required to support the new schema, delete all the tuples that are no longer required, and finally write the updated model (see https://openfga.dev/docs/modeling/migrating/migrating-relations).
In practice, I think we will likely have something like:
- Under an
lxd/auth/openfga
directory:model_v1.openfga
model_v1.go
model_v2_compatible.openfga
model_v2_compatible.go
model_v2.openfga
model_v2.go
migrations.go
synchronise.go
- The
migrations.go
file will contain a map of methods which accept an openfga client and performs the necessary actions to migrate from one schema to the next. These methods will only be valid while the compatible model is in place. - The
synchronise.go
file will contain a map of methods which accept an fga client and a set of LXD resources and ensure they match 1:1 with what is present in the OpenFGA store. Like migrations, this is also model specific. - When we connect to the OpenFGA server:
- Get the current auth model.
- Check if it is the latest version. If it is, sync resources and continue. Otherwise....
- Write the compatible model.
- Call the associated method from
migrations.go
. - Write the latest model.
- Perform a final resource sync from
synchronise.go
.
Hopefully we won't have to do this very often.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can handle this when we come to update the model.
6dff40e
to
0cd077a
Compare
abf91ee
to
3840e42
Compare
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
… server. Signed-off-by: Mark Laing <mark.laing@canonical.com>
This makes it available from other network namespaces when running clustering tests. Signed-off-by: Mark Laing <mark.laing@canonical.com>
I have added reference and explanation documentation. I think this will also need a how-to but I need to figure out how to easily set up an OIDC server in order to do that (keycloak requires a lot of clicking around and openjdk-17). |
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
TLS authorization and RBAC have their own sections in the authorization page now so these are removed. Additionally I have updated the OIDC and Candid sections to notify users that they must configure authorization, else their servers are not secure. Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
Signed-off-by: Mark Laing <mark.laing@canonical.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is great work.
Please can you address/discuss the changes via your existing github card for further minor work.
But I'll merge this now as I can't see any major issues.
Thanks for your thoroughness.
"github.com/canonical/lxd/shared/logger" | ||
) | ||
|
||
func WriteOpenFGAAuthorizationModel(ctx context.Context, apiURL string, apiToken string, storeID string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a docblock to this explaining what it does please.
} | ||
|
||
if readModelResponse.AuthorizationModel.SchemaVersion != builtinAuthorizationModel.SchemaVersion { | ||
return fmt.Errorf("Existing OpenFGA model has schema version %q, but our model has version %q", readModelResponse.AuthorizationModel.SchemaVersion, builtinAuthorizationModel.SchemaVersion) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Des this stop LXD from starting or just log a warning? Does it prevent the authorizer from working?
@@ -1802,6 +1803,246 @@ func (d *Daemon) Stop(ctx context.Context, sig os.Signal) error { | |||
return err | |||
} | |||
|
|||
// Setup OpenFGA. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A docblock comment explaining what this function does would be nice.
if openFGAAuthorizationModelID == "" { | ||
// We should never be missing the model ID at start up if we have other connection details (this means | ||
// something went wrong the last time we tried to set it up). | ||
logger.Warn("OpenFGA authorization driver is misconfigured, skipping...") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this will fallback to TLS only mode or only allow unix socket operation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think either both should be warnings or both should be errors, as they both result in the authorizer not working right?
} else { | ||
err = d.setupOpenFGA(openfgaAPIURL, openfgaAPIToken, openfgaStoreID, openFGAAuthorizationModelID) | ||
if err != nil { | ||
logger.Error("Failed to configure OpenFGA. Reverting to default TLS authorization", logger.Ctx{"error": err}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question as above
@@ -808,6 +813,50 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re | |||
return response.EmptySyncResponse | |||
} | |||
|
|||
func doApi10PreNotifyTriggers(d *Daemon, clusterChanged map[string]string, newClusterConfig *clusterConfig.Config) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing docblock explaining what this is and what it does
@@ -763,6 +763,11 @@ func doApi10Update(d *Daemon, r *http.Request, req api.ServerPut, patch bool) re | |||
} | |||
}) | |||
|
|||
err = doApi10PreNotifyTriggers(d, clusterChanged, newClusterConfig) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to support a revert here if something fails later on?
This PR adds an OpenFGA authentication driver to LXD https://warthogs.atlassian.net/browse/LXD-389?atlOrigin=eyJpIjoiZWExM2NhNjgwMWU2NDZhMGJhODc5MjAzYmZiZGFkNTYiLCJwIjoiaiJ9.
The spec can be found at https://discourse.ubuntu.com/t/openfga-authorization-driver/38979
Work still to be done:
context.Background()
.