goauthentik / authentik

The authentication glue you need.
https://goauthentik.io
Other
7.84k stars 601 forks source link

Overwrite default blueprints deterministically #4945

Open MrMuster opened 1 year ago

MrMuster commented 1 year ago

Writing custom blueprints that change parts of the default blueprints Often I want to change only some small parts of the default configuration. I.e. change the title of a default flow, add or remove a stage... One way to do this is to copy the complete default blueprint and apply the small changes. The Problem is that this causes a lot of configuration redundancy and I will miss all upstream configuration updates/changes. Therefore I prefer to overwrite only the necessary default objects. With authentik_blueprints.metaapplyblueprint I can create all the dependencies that need to be applied before my custom blueprints overwrite their objects.

Problem: nondeterministic blueprint execution Even if I define the needed dependencies, this doesn't prevent the default blueprints to be applied afterwards again, so my changes might be overwritten by the default values again.

Possible solution Define the blueprint execution order by the authentik_blueprints.metaapplyblueprint dependencies. This requires to read all blueprints to create a dependency graph. This must also handle circular dependencies, i.e. throw an error. Always when a blueprint is applied all the blueprints that depend on that should be applied in the correct order as well.

Alternative Solutions

MrMuster commented 1 year ago

My current workaround hack is a script that enables some specific default blueprints using the API, than it executes my custom blueprints (ak apply_blueprint custom_blueprint.yaml) in the correct order, and than it disables the default blueprints again.

For disabling blueprints via API:

import requests
session = requests.Session()
my_token='$TOKEN'
blueprint_path='$BLUEPRINT_PATH'
resp = session.get(f'https://$DOMAIN/api/v3/managed/blueprints/?path={blueprint_path}', headers={'Authorization':f'Bearer {my_token}'})
auth_flow_uuid = resp.json()['results'][0]['pk']
blueprint_name = resp.json()['results'][0]['name']
params = {'name': blueprint_name,'path': blueprint_path,'context':{},'enabled': False}
resp = session.put(f'https://$DOMAIN/api/v3/managed/blueprints/{auth_flow_uuid}/', json=params, headers={'Authorization':f'Bearer {my_token}'})
if resp.ok:
    print(f'{blueprint_name} disabled')
else:
    print(resp)

Unfortunately disabled blueprints can not be applied using authentik_blueprints.metaapplyblueprint. There should be a way to only prevent automatic execution of blueprints, but explicit application using authentik_blueprints.metaapplyblueprint should be still possible.