Quick start: Steward for a client in 15 minutes¶
This is the main path: one console for one client, with a publicly trusted certificate, reached by the client's power users on their LAN and by your technicians through Teleport or Cloudflare Access. Every step links to the details.
flowchart LR
a["1. Prepare<br/>(AD accounts, DNS name,<br/>Linux VM)"] --> b["2. Guided install<br/>sudo deploy/install.sh"]
b --> c["3. Setup wizard<br/>(browser)"]
c --> d["4. Roles and<br/>delegations"]
d --> e["5. Apply AD rights<br/>(domain admin)"]
e --> f["6. Check and<br/>hand over"]
1. Prepare (with the client's domain administrator)¶
| What | Why | Example |
|---|---|---|
| A Linux VM (2 vCPU, 2 GB RAM, 10 GB disk) with Docker Engine and Docker Compose v2, member of nothing, never a DC | Runs the containers | Ubuntu 24.04, Debian 12 |
| Outbound TCP 636 from the VM to the domain controllers | LDAPS (the only protocol Steward uses to talk to AD) | |
| LDAPS on every DC, with a certificate issued for the DC's FQDN, and the CA certificate (PEM) that issued it | Steward validates the DC certificates strictly; there is no "ignore errors" switch | corp-root-ca.pem |
| A read service account: a plain domain user, no admin rights | Searches and reads | svc-steward-read |
| A write service account (if operators edit attributes, create, move or rename) | Its rights come from the delegation script (step 5) | svc-steward-write |
| A password-reset account (only for the helpdesk) and a LAPS account (only for LAPS) | Held by the separate password service only | svc-steward-reset, svc-steward-laps |
| A DNS name for the console under a public domain the client (or you) controls; it may resolve only internally | It goes into the certificate | steward.client-example.ch |
| A DNS API token of the provider hosting that public zone, limited to the zone | Publicly trusted certificate without opening anything (HTTPS certificate) | Infomaniak, OVH, Cloudflare, ... |
All accounts are ordinary users, one per role (never reuse the reset or LAPS account elsewhere). The delegation script refuses
to grant rights to a privileged account (Domain Admins, adminCount=1, ...), and the console refuses privileged accounts as
operators.
On the VM, if Docker is not installed yet:
curl -fsSL https://get.docker.com | sudo sh # Docker Engine + Compose v2 (or your distribution's packages)
2. Run the guided install¶
git clone https://github.com/Verttigo28/steward.git && cd steward
git checkout v1.0.0 # the release you install (optional: the installer pins it too)
sudo deploy/install.sh
Without options, in a terminal, the installer asks its questions one by one, with a default in brackets (press Enter to accept it). Nothing is changed before the final confirmation, and Ctrl+C aborts at any time.
| Step | Questions |
|---|---|
| 1/6 Instance | Instance name (one per client, e.g. acme), DNS name users will open, Steward version (pin a release) |
| 2/6 Active Directory | Domain and DC names: optional (the setup wizard asks for them anyway). A DC this host cannot resolve can be mapped to its IP |
| 3/6 Helpdesk | Password reset and unlock: off by default. If on: the reset account and its password; optionally the LAPS account |
| 4/6 Exposure | Client LAN only, behind your reverse proxy/WAF, through Teleport, or Cloudflare Tunnel + Access (Exposure and access) |
| 5/6 HTTPS certificate | Public CA through ACME (asks whether port 80 is reachable from the Internet: HTTP-01, else DNS-01 with your DNS provider), your own ACME CA, your own files, or self-signed (labs) |
| 6/6 Summary | Everything chosen, and the equivalent non-interactive command to keep for re-runs |
Passwords and API tokens are typed hidden, never printed, never logged: the installer copies them to
/opt/steward/<name>/secrets/ (mode 0400/0600) and nowhere else.
What a DNS-01 install looks like (example values)
5/6 HTTPS certificate (docs/ops/tls.md)
Where does the certificate come from?
1) A public CA, automatically (ACME: Let's Encrypt), renewed by a sidecar container: recommended
...
Choice [1]:
Is port 80 of steward.client-example.ch reachable from the Internet (from the CA, for your own CA)? [y/N]:
DNS-01: the CA checks a TXT record that the sidecar creates through your DNS provider's API. ...
DNS provider of the public zone
1) Infomaniak
2) OVHcloud
3) Cloudflare
...
Choice [1]: 1
Infomaniak API token (scope: domain) (hidden):
E-mail for the CA's expiry warnings (recommended; Enter: none): ops@msp.example
The installer then pulls the signed image, obtains the certificate before starting Steward, starts the containers, checks
that https://<name>/ verifies like a browser would, and prints the next steps:
Instance 'acme' is running: https://steward.client-example.ch/
TLS: publicly trusted certificate for steward.client-example.ch (letsencrypt), renewed automatically by the 'acme' container
...
Next steps:
1. Setup token (one-time; stored in /data/setup-token inside steward-acme-steward-1):
<token>
Print it again with: docker exec steward-acme-steward-1 cat /data/setup-token
2. Open https://steward.client-example.ch/ and follow the setup wizard ...
Until the setup is completed, a new token is generated at every container start: after a restart, print it again with the command above.
Prefer scripts? Every question has an option, and the options are the reference: see the installer reference. Before installing, you can verify the image signature.
3. Complete the setup wizard (browser)¶
Open the URL, paste the setup token, then give the domain and its DCs with the LDAPS CA, the technical accounts (each one is test-bound), the managed OUs (the outer boundary: nothing outside them can ever be reached), the protected groups, and the first administrator. Step by step: Setup wizard.
4. Create roles and delegations¶
In Delegations, create roles (for example "Helpdesk L1", "Client HR") with their delegations: actions, attributes, OU scope. Add operators by AD login or Teleport username, assign roles, and check with the simulator what a given operator can do on a given user. See Delegation model and AD rights.
5. Apply the AD rights (domain administrator)¶
In Configuration > Diagnostics, click Export AD delegation and give the file and deploy/delegation/ to a domain
administrator, who reviews and applies it:
# The managed OUs and the service accounts as you configured them (they must match the file exactly, or nothing changes).
$ou = 'OU=Staff,DC=corp,DC=example'
$ids = @{ read = 'svc-steward-read@corp.example'; write = 'svc-steward@corp.example'; reset = 'svc-steward-reset@corp.example' }
.\Grant-StewardDelegation.ps1 -ModelPath .\steward-delegation.json -ManagedOu $ou -Identity $ids -WhatIf # review
.\Grant-StewardDelegation.ps1 -ModelPath .\steward-delegation.json -ManagedOu $ou -Identity $ids # apply (confirm the plan)
Add -TierOu <your Tier 0 OU> to refuse any managed OU at, above or below it.
Re-export and re-apply whenever the diagnostics say the delegation is out of date (new role, attribute, OU, helpdesk, LAPS).
6. Check and hand over¶
- [ ] The console opens without any certificate warning, from where operators really are (LAN, Teleport, Cloudflare).
- [ ] Configuration > Diagnostics is all green: certificate, TLS per DC, binds, OUs, groups, write rights, export up to date (and the password service with the helpdesk).
- [ ] A test operator can do exactly what their role allows (simulator + a real sign-in).
- [ ] Notifications go to the MSP channel, including the two certificate events.
- [ ] A backup was taken and restored on a test host (Operations).
- [ ] Audit forwarding to the client's log platform is configured (Operations).
- [ ] Nothing exposes the console raw to the Internet (Exposure and access).
Next: Helpdesk, Onboarding and leavers, Approval requests, Access reviews. Upgrading later is one command: Operations.