diff --git a/docs/README.md b/docs/README.md index 1715c4b..e88965d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -6,6 +6,7 @@ engine does with it. | | | |---|---| +| [Getting started](getting-started.md) | Bringing your people in: from an empty Kanidm to everyone at their own desk, from what the content says. | | [Architecture](architecture.md) | What the engine is made of and where each piece lives in the source. | | [Content reference](content-reference.md) | Every key a content repo may write, and what it does. | | [State machines](state-machines.md) | `aggregates.yaml`: stages, who moves a case, mail, deadlines, memberships. | diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..08de04e --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,145 @@ +# Getting started: bringing your people in + +A site is run by a handful of people: whoever answers for each question +it asks, and whoever works each desk. This is how they get in - from +an empty Kanidm to everyone signed in at their own desk - without +anyone handing out passwords or running an admin tool per person. + +The idea in one line: **the content says who is involved, and portal +makes their accounts.** A page names who is responsible for it; a +directory is gated on a group; a desk may invite into groups. Portal +reads that and does the rest at start. + +## What you need + +- A content repo, and a portal instance running it + ([Operations](operations.md) has adding a site). +- A Kanidm of the site's own. Group names below are exactly the ones + the content uses, with no prefix; that is only safe when the Kanidm + serves this site alone. +- Mail: `mail: { from }` in `site.yaml`, and gdo on the host. Without + it accounts are still made, but nobody hears about them. + +## 1. Say who is involved, in the content + +Three things in the content decide who needs an account: + +| content | who | what they get | +|---|---|---| +| `responsible: { name, contact }` on a page | the person answering for that question | an account, and a mail saying they are listed as responsible for asking it | +| `qualifies: styret` on a page or `_section.yaml` | members of that group | the pages and desks under it | +| `invite: { group: kasserer }` on a desk page | the desk's own group | the right to bring people into `kasserer` | + +The desk whose group may invite into the most groups is the site's most +privileged one; on a vel that is the board. Portal works that out from +the content (see step 4). + +## 2. Set up Kanidm for portal + +Portal needs four things from Kanidm. The +[tomtervel/infrastructure](https://prosjekt.klingenbergbygg.no/tomtervel/infrastructure) +repo's `kanidm-setup.sh` does all of them and is a good starting point; +by hand, as `idm_admin`: + +```sh +K="kanidm -D idm_admin -H https://id.example.no" + +# An onboarding account: may create people and issue a first password +# link, nothing more. pii_read lets an invite find someone who already +# has an account by their email instead of making a second one. +$K service-account create portal-onboarding "Portal onboarding" idm_admin +$K group add-members idm_people_on_boarding portal-onboarding +$K group add-members idm_people_pii_read portal-onboarding + +# One group per `qualifies:` in the content, managed by that account: +# adding a member to a group takes the right to manage it. +for g in styret kasserer trafikk; do + $K group create "$g" portal-onboarding +done + +# The sign-in client. Everyone in this Kanidm may sign in; what they +# see comes from their groups, in the `groups` claim. +$K system oauth2 create portal "My site" https://site.example.no +$K system oauth2 add-redirect-url portal https://site.example.no/auth/callback +$K system oauth2 update-scope-map portal idm_all_persons openid profile email +for g in styret kasserer trafikk; do + $K system oauth2 update-claim-map portal groups "$g" "$g" +done +$K system oauth2 update-claim-map-join portal groups array + +# The onboarding token, read-write, shown once: into portal's env. +$K service-account api-token generate portal-onboarding portal --readwrite +``` + +Then portal's environment: + +| variable | value | +|---|---| +| `KANIDM_URL` | `https://id.example.no` | +| `OAUTH2_CLIENT_ID`, `OAUTH2_CLIENT_SECRET` | the client above (`show-basic-secret`) | +| `KANIDM_API_TOKEN` | the onboarding token | + +## 3. Name the first person + +Someone has to be first: every later person is invited from a desk, +and on an empty Kanidm there is no desk anyone can open yet. + +| variable | value | +|---|---| +| `SEED_ADMIN_EMAIL` | the first person's address | +| `SEED_ADMIN_NAME` | their name, as it should appear (optional) | +| `SEED_GROUP` | a group to put them in, if not the most privileged one (optional) | +| `RESPONSIBLE_GROUP` | a group every responsible person joins, e.g. `redaktor` (optional) | + +## 4. Start portal + +At start, portal: + +1. **Invites the first person** into `SEED_GROUP`, or the most + privileged group, and mails them the one-time link. Once: it is + remembered in the `portal_seed` bucket, so restarts and upgrades + never send a second link. +2. **Makes an account for everyone named responsible** who has none, + and mails them that they are listed as responsible for asking those + questions, with their link. With `RESPONSIBLE_GROUP` they all join + it; someone who already had an account is added without a mail. + +Kanidm may still be starting beside portal, so a failed attempt is +tried again, a minute apart. The log says what happened, per person. + +## 5. The rest come in from the desks + +From here nobody touches Kanidm: + +- **At a desk**, whoever may invite fills in a name and an address. + Portal makes the account, adds them to the group, and mails the link. + The invites sent are listed on that desk. +- **A decision can be the invitation.** A state with `grants: group` + in `aggregates.yaml` puts the person a case is about into that group + when the case arrives there - an approved committee application that + *is* the membership. +- **A new page with a new responsible person** gets them an account at + the next start. + +## 6. What the people who ask the questions can do + +Signed in, a person a page names as responsible sees a card at the +foot of their own pages to suggest a change. The server checks it is +really them; the suggestion is kept (`portal_edit_suggestions`), +announced (`portal.edits.suggested`), and mailed to the site's inbox +with them as reply-to, so answering it answers them. + +Their group can also be the way into other tools. The vel's +`redaktor` group signs in to the project Gitea with the same account: +a second OAuth2 client scoped to that group alone. + +## When it does not work + +| what you see | why | +|---|---| +| an invite fails with `403` setting `mail` | a portal before 0.5.4 set the address in a second call; the onboarding account may create but not modify | +| an invite fails with `404` adding to a group | the group is not managed by `portal-onboarding`: `group set-entry-manager portal-onboarding` | +| `Item not found` setting the login page's name or logo | those are system settings only `admin` may change, not `idm_admin` - or the CLI and server versions differ | +| accounts are made but nobody is mailed | `site.yaml` has no `mail.from`, or gdo is not running on the host | +| someone responsible never got a mail | they already had an account (they are only added to `RESPONSIBLE_GROUP`), or their `contact` is not an email address | +| the first person was invited twice | it cannot be, per address and group; changing `SEED_ADMIN_EMAIL` or `SEED_GROUP` invites the new pair |