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

GitOps Support Docs #127

Open
DreamingRaven opened this issue Jan 12, 2023 · 9 comments
Open

GitOps Support Docs #127

DreamingRaven opened this issue Jan 12, 2023 · 9 comments

Comments

@DreamingRaven
Copy link

DreamingRaven commented Jan 12, 2023

Hey Authentik team.

I just wanted to say thank you for all your hard work, I am loving Authentik, and I am keen to see it grow!

In my particular case I want to declaritively define an outpost, application, and provider. The former has a documented example for manual creation in kubernetes. However the latter two do not nor do they have any blueprint examples or breakdowns (if this is possible).

I believe blueprints are the key to this in Authentik and allowing for GitOps for persistent and consistent spin up and spin down of clusters in testing and production. If possible I would also like to create a GitOps documentation page for Kubernetes specifically as it is preferable in k8s (in my opinion) to spin up with all the desired flows configuration theming etc out of the gate without any clicks. Environment variables (they work well) and sealed-secrets (of my own addition) seem to cover half this GitOps use case and I believe blueprints is the final hurdle for me.

@BeryJu
Copy link
Member

BeryJu commented Jan 13, 2023

an example for an LDAP Provider, app and outpost:

entries:
- model: authentik_blueprints.metaapplyblueprint
  attrs:
    identifiers:
      name: Default - Authentication flow
    required: true
- attrs:
    authorization_flow: !Find [authentik_flows.flow, [slug, default-authentication-flow]]
    base_dn: DC=ldap,DC=goauthentik,DC=io
    bind_mode: cached
    gid_start_number: 4000
    search_group: !Find [authentik_core.group, [name, "authentik Admins"]]
    search_mode: cached
    uid_start_number: 2000
  id: provider
  identifiers:
    name: test
  model: authentik_providers_ldap.ldapprovider
- attrs:
    name: ldap
    policy_engine_mode: any
    provider: !KeyOf provider
  id: app
  identifiers:
    slug: ldap
  model: authentik_core.application
- attrs:
    config:
      authentik_host: http://localhost:9000/
    providers:
    - !KeyOf provider
    type: ldap
  id: outpost
  identifiers:
    name: ldap
  model: authentik_outposts.outpost
metadata:
  labels:
    blueprints.goauthentik.io/generated: 'true'
  name: authentik Export - 2022-08-31 21:14:20.484928+00:00
version: 1

There aren't examples for every object, but in general the JSON schema should help (https://goauthentik.io/blueprints/schema.json)

the fields under attrs and identifiers are all fields that are available via API, as that's what the blueprints use internally.

you can also use ak export_blueprint in the server/worker container to export the current config to a blueprint

@DreamingRaven
Copy link
Author

Actually that is quite helpful thanks for that. Also thanks for getting back to me so quickly.

It took me a second to break it down from the schema, but after I converted it into more comfortable (for me atleast) YAML, I could see a good number of the properties that I had been looking for for a good number of maps.

One liner for anyone else who likes YAML:

curl https://goauthentik.io/blueprints/schema.json | yq --yaml-output

I also see what you mean by there are examples for every object. At first I thought you meant blueprint entry examples but you actually mean properties of the schema aren't fully populated in the schema.json (correct me if I am wrong). E.G shema.json does not list sub-properties of attrs map, which you have used in the example LDAP app, provider, and outpost metaapplyblueprint blueprint.

Is there a way I can go any deeper and find even more of these properties somewhere? Maybe in the specific models? As I want to get a more complete picture so that I can generate these blueprints without the use of the GUI since really I want to generate this decoratively in helm / operator (I am building an authentik operator). I can always reverse engineer from clicked together bits and export_blueprint as you mentioned.
Ideally it would be a lot more consistent to have an API I can gather extract this information from if there is such a thing atm, this would also help me in the long run maintain compatibility.

So like kubectl api-resources, kubectl get crd or kubectl explain (or query the specific resources) but for authentik blueprint properties.

@BeryJu
Copy link
Member

BeryJu commented Jan 15, 2023

You can use these settings in vscode to load the schema for yaml files:

    "yaml.schemas": {
        "https://goauthentik.io/blueprints/schema.json": "blueprints/**/*.yaml"
    },

Yes, the schema doesn't list all properties of all possible objects, as much as I want to do that it's not that easy. All the field names in attrs and identifiers are the same as for the API, you can use https://goauthentik.io/developer-docs/api/browser as a reference

I'm actually also thinking about building a (very simple) kubernetes operator into authentik, with a single Blueprint CRD that is automatically recreated/reconcilled in authentik

@DreamingRaven
Copy link
Author

DreamingRaven commented Jan 15, 2023

Yeah funnily enough that is exactly what I am doing among other CRDs.

I am currently making AkBlueprint, AkOutpost, AkProvider, and AkApplication CRDs and the managing operator. I feel it would be extremely convenient to be able to configure authentik in a kube native manner and have it dynamically load configuration in this way which is why I started adding it. In particular my end goal is that you can configure an application in a given namespace and have the controller automatically configure its ingress resource with forward auth and or any providers it needs for integration.

Thanks for the help, I appreciate it. I think I have most of what I need now anyway. If I have any specific issues with blueprints I may drop them in here if that is amiable.

@benedikt-bartscher
Copy link

@DreamingRaven thanks for your input on Gitops and Authentik CRDs, i am highly interested in a Authentik Operator. For blueprints i just tried a sidecar approach which collects configmaps (#146) and supplies those as blueprints to authentik.

However your Operator looks more promising from a GitOps perspective, thank you for your work on this!

@DreamingRaven
Copy link
Author

@benedikt-bartscher No problem, its nowhere near complete, but the basic infrastructure is there (SDK, basic controller, CICD builds, deployment etc), along with the basic authentik management (deploy, destroy, and apply some but not all CRDs). I would not recommend that you use it quite yet (even if a good chunk of the functionality is there) but I should be returning to the operator (https://gitlab.com/GeorgeRaven/authentik-manager) shortly once a few of my other deadlines are met as I have a very strong need for this myself for personal, commercial, and educational reasons. If you have anything you want in particular from the operator I would drop an issue there.

@genofire
Copy link
Contributor

Here are a list of Operator that i find.
goauthentik/authentik#4558

But yes a official Operator with an stabil API whould be nice.
But that need person to maintain, so even https://gitlab.com/GeorgeRaven/authentik-manager switch to blueprint.

so i believe as an first step #146 with declararive blueprints (goauthentik/authentik#5300) could be fast implemented and would solve the most problems

@DreamingRaven
Copy link
Author

DreamingRaven commented May 11, 2023

I have been working on this the last few days, the blueprint functionality should be in place very soon!
I chose to go with internal storage, as it simplifies everything substantially since it wont fight against any gitops orchestration mechanism.

Currently:

  • blueprint CRD is found or changed:
    • attempt to get the CRD
      • if the blueprint has been removed it will remove it from the DB by path (TODO)
    • load the CRD into my api definition / stucts to confirm it conforms to what is expected to be there
    • create a configmap of this CRD or update the existing one (this is so I could mount it in the old version of the operator)
    • create a connection to postgresql
    • query the db in the authentik_blueprints_blueprintinstance table to check if the blueprint is there already
      • if its there is an entry with the given path it will check if it matches and update if not (TODO)
      • if it is not there it will add a new row to the table with the blueprint in the content field with the given path (TODO)

I will drop a message here when its done. Once the last 3 tasks are complete it should be fully functional, after that it will be just keeping everything compatible in case the db structure changes / migrates, and adding new higher level CRDs to automate larger tasks. The ak CRD is already complete and manages the stack of authentik already although I want to add more automation to this going forward like rolling updates etc.

But yeah I get you, an official operator would have been nicer but its a lot to ask, they are such complex beasts and adds a lot more headaches for the authentik guys. The broad steps for mine will look like so, so hopefully that will be sufficient when it is ready:

archer@archbest ~/g/authentik-manager (staging)> kubectl get all -n auth
NAME                                     READY   STATUS    RESTARTS   AGE
pod/authentik-manager-68977fd74f-lltxj   1/1     Running   0          5s

NAME                                         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/controller-manager-metrics-service   ClusterIP   10.96.21.65   <none>        8443/TCP   6s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/authentik-manager   1/1     1            1           6s

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/authentik-manager-68977fd74f   1         1         1       6s
archer@archbest ~/g/authentik-manager (staging)> kubectl apply -f operator/config/samples/akm_v1alpha1_ak.yaml
ak.akm.goauthentik.io/ak-sample created
archer@archbest ~/g/authentik-manager (staging)> kubectl apply -f operator/config/samples/akm_v1alpha1_secret.yaml
secret/auth created
archer@archbest ~/g/authentik-manager (staging)> kubectl get all -n auth
NAME                                     READY   STATUS              RESTARTS      AGE
pod/authentik-manager-68977fd74f-lltxj   1/1     Running             1 (30s ago)   61s
pod/authentik-server-96fff84ff-4mcwh     1/1     Running             0             29s
pod/authentik-server-96fff84ff-p7rqc     1/1     Running             0             29s
pod/authentik-server-96fff84ff-smlgs     1/1     Running             0             29s
pod/authentik-worker-5897cbfbf4-f8kb9    0/1     ContainerCreating   0             29s
pod/authentik-worker-5897cbfbf4-frgxk    1/1     Running             0             29s
pod/authentik-worker-5897cbfbf4-nl5r6    1/1     Running             0             29s
pod/pgadmin-6d8555b6b4-vzsmd             1/1     Running             0             29s
pod/postgres-0                           1/1     Running             0             29s
pod/redis-master-0                       0/1     Running             0             29s
pod/redis-replicas-0                     0/1     Running             0             29s

NAME                                         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                          AGE
service/authentik-server                     ClusterIP   10.109.152.180   <none>        80/TCP,443/TCP,389/TCP,636/TCP,300/TCP,900/TCP   29s
service/authentik-worker                     ClusterIP   10.103.31.217    <none>        80/TCP,443/TCP,389/TCP,636/TCP,300/TCP,900/TCP   29s
service/controller-manager-metrics-service   ClusterIP   10.96.21.65      <none>        8443/TCP                                         62s
service/pgadmin                              ClusterIP   10.103.81.150    <none>        80/TCP                                           29s
service/postgres                             ClusterIP   10.98.213.211    <none>        5432/TCP                                         29s
service/postgres-hl                          ClusterIP   None             <none>        5432/TCP                                         29s
service/redis-headless                       ClusterIP   None             <none>        6379/TCP                                         29s
service/redis-master                         ClusterIP   10.102.51.216    <none>        6379/TCP                                         29s
service/redis-replicas                       ClusterIP   10.100.43.181    <none>        6379/TCP                                         29s

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/authentik-manager   1/1     1            1           62s
deployment.apps/authentik-server    3/3     3            3           29s
deployment.apps/authentik-worker    2/3     3            2           29s
deployment.apps/pgadmin             1/1     1            1           29s

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/authentik-manager-68977fd74f   1         1         1       62s
replicaset.apps/authentik-server-96fff84ff     3         3         3       29s
replicaset.apps/authentik-worker-5897cbfbf4    3         3         2       29s
replicaset.apps/pgadmin-6d8555b6b4             1         1         1       29s

NAME                              READY   AGE
statefulset.apps/postgres         1/1     29s
statefulset.apps/redis-master     0/1     29s
statefulset.apps/redis-replicas   0/3     29s
archer@archbest ~/g/authentik-manager (staging)> kubectl apply -f operator/config/samples/akm_v1alpha1_akblueprint.yaml
akblueprint.akm.goauthentik.io/akblueprint-sample created
archer@archbest ~/g/authentik-manager (staging)> kubectl get akblueprints.akm.goauthentik.io -n auth
NAME                 AGE
akblueprint-sample   81s

Having to play around a bit to reverse what exactly is expected in a few different fields though:
pgauthentik

@DreamingRaven
Copy link
Author

DreamingRaven commented May 18, 2023

Ok I have the base blueprint handling just about sorted which I will release soon. This is a blueprint that was loaded from a cluster CRD using the operator:
blueprint-sample
However one important case that I need to find a good solution for is default blueprint overrides. So say someone wanted to deploy a blueprint that overrides the default behavior for say the login page using:

apiVersion: akm.goauthentik.io/v1alpha1
kind: AkBlueprint
metadata:
  labels:
    app.kubernetes.io/name: akblueprint
    app.kubernetes.io/instance: akblueprint-sample
    app.kubernetes.io/part-of: operator
    app.kubernetes.io/managed-by: kustomize
    app.kubernetes.io/created-by: operator
  name: akblueprint-sample
spec:
  file: /blueprints/default/10-flow-default-authentication-flow.yaml
  blueprint:
    version: 1
    metadata:
      name: Default - Authentication flow
    entries:
    - model: authentik_blueprints.metaapplyblueprint
      attrs:
        identifiers:
          name: Default - Password change flow
        required: false
    - attrs:
        designation: authentication
        # TODO: (USER) adjust the name, title to match your branding
        name: login
        title: Welcome to akm!
        authentication: require_unauthenticated
      identifiers:
        slug: default-authentication-flow
      model: authentik_flows.flow
      id: flow
    - attrs:
        backends:
        - authentik.core.auth.InbuiltBackend
        - authentik.sources.ldap.auth.LDAPBackend
        - authentik.core.auth.TokenBackend
        configure_flow: !Find [authentik_flows.flow, [slug, default-password-change]]
      identifiers:
        name: default-authentication-password
      id: default-authentication-password
      model: authentik_stages_password.passwordstage
    - identifiers:
        name: default-authentication-mfa-validation
      id: default-authentication-mfa-validation
      model: authentik_stages_authenticator_validate.authenticatorvalidatestage
    - attrs:
        user_fields:
        - email
        - username
      identifiers:
        name: default-authentication-identification
      id: default-authentication-identification
      model: authentik_stages_identification.identificationstage
    - identifiers:
        name: default-authentication-login
      id: default-authentication-login
      model: authentik_stages_user_login.userloginstage
    - identifiers:
        order: 10
        stage: !KeyOf default-authentication-identification
        target: !KeyOf flow
      model: authentik_flows.flowstagebinding
    - identifiers:
        order: 20
        stage: !KeyOf default-authentication-password
        target: !KeyOf flow
      model: authentik_flows.flowstagebinding
    - identifiers:
        order: 30
        stage: !KeyOf default-authentication-mfa-validation
        target: !KeyOf flow
      model: authentik_flows.flowstagebinding
    - identifiers:
        order: 100
        stage: !KeyOf default-authentication-login
        target: !KeyOf flow
      model: authentik_flows.flowstagebinding

So that it now says something different (in this case welcome to AKM). Usually you would overwrite the actual file itself with your new version but when you are interacting with the internal storage mechanism or just targeting the db directly I do not see a clear way to do so. If I were to overwrite the db entry that comes from a default file I expect that the file would then overwrite my table changes again whenever authentik re-scans the files and compares their contents. The clearest solution I can think of is to actually remove all the default blueprints and instead package them as default CRDs deployed with authentik. However I would like to avoid this as I am not certain what behavior authentik will have in the few moments it has no blueprints and I do not want to suffer any drift if the default blueprints get updated or changed over time compared to my CRDs.

TLDR: is there any way to tell authentik to ignore a default blueprint file without having to remove or overwrite it?

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

No branches or pull requests

4 participants