-
Notifications
You must be signed in to change notification settings - Fork 0
Security
The installer's security choices and its known limits, stated honestly.
- The
admindefault is discouraged. Interactively it requires an explicit confirmation; non-interactively withadminthe installer stops (set a different password). - The password is treated as a secret: it never appears in the logs, the summary or the output. It
ends up only in the final config file (
/opt/odoo/odoo<N>.conf, permissions0640 odoo:odoo) — and that file is written through a private temporary (0600), so the password is never readable by other users at any instant.
The installer verifies the SHA-256 of the wkhtmltopdf package before installing it. But the official release publishes neither checksums nor signatures for the packages (only the git tag is GPG-signed). Hence manual TOFU pinning (trust-on-first-use): pins generated once from a trusted source (official HTTPS), after which every download is verified against that pin.
The pins are preloaded for the three amd64
.debfiles of release0.12.6.1-3(jammy,bullseye,bookworm), generated by downloading them over HTTPS from the official release. If a download does not match its pin — or if a variant has no pin — the fail-closed check refuses the installation. That behaviour is never bypassed.
To regenerate them (only needed when changing the pinned version):
for cn in jammy bullseye bookworm; do
url="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.${cn}_amd64.deb"
echo -n "$cn = "; curl -fsSL "$url" | sha256sum | cut -d' ' -f1
donePut the values into default_checksums() (src/steps/install_wkhtmltopdf.rs). They are TOFU pins,
not upstream checksums: update them when you change version. Detail:
1.5 InstallWkhtmltopdf.
- The
odoosystem user is created withuseradd --system --user-group --shell /bin/false: no interactive shell, a system account with no password. - The systemd service runs as
odoo(not root), with hardening (NoNewPrivileges,PrivateTmp,ProtectSystem=full,ProtectHome, …). See 1.14 SetupSystemd. - The
odoohelper command is installed for the installing user only (~/.local/bin), not in/usr/local/bin: less exposure to other users and automations.
The .env file is parsed declaratively, never sourced: it is not a code-execution vector, unlike
the old Bash version. See .env file reference.
By default the rollback leaves the common utilities installed and does not purge PostgreSQL (too
destructive to do automatically). With --aggressive-rollback those are purged as well — but the
PostgreSQL purge is still declined if the cluster hosts other databases, so as not to destroy
another application's data. Do not use it on machines with a shared cluster unless you are certain.
Wherever root writes a file that another user will read, the file is not born in a shared
directory. /tmp is world-writable, and a name written in the source is known to anyone: between
root's write and the odoo user's read there is a window in which that file can be replaced. For pip's
requirements that would mean having arbitrary packages installed into the venv — that is, code
execution as the owner of the filestore and the database. The issue is not the symlink (which
fs.protected_symlinks mitigates) but the replacement of the contents, and there the kernel does
not help.
| File | Where it is born | Why |
|---|---|---|
| pip requirements | <install_dir>/sandbox |
it belongs to odoo and is not writable by third parties: the attack's premise disappears. And it sits inside the reversible perimeter |
| source tarball | system temp, random name, created fail-closed | there is no expected checksum to hold against replaced contents |
| wkhtmltopdf package | system temp, random name (extension preserved) | the contents are already protected by the TOFU pin; here we close the point where the file is born |
“Fail-closed” means O_CREAT | O_EXCL | O_NOFOLLOW: if something is already at that path — file,
directory or symlink — the operation fails instead of writing over it.
/var/lib/invok/state.json drives rm -rf, dropdb and userdel. Before consuming it for a real
rollback we check that it belongs to root, is not writable by group or others, and does not live in
a directory writable by third parties — where it could be replaced without even being modified. And
that it declares the expected perimeter (/opt/odoo, a constant that cannot be overridden): a manifest
declaring a different one does not describe an installation made by this program.
Security vulnerabilities: see SECURITY.md in the repository.
Start here
Key concepts
References
For developers
Technical detail — how it works inside
Steps:
- 1.1 PrepareOptRoot
- 1.2 CreateOdooUser
- 1.3 SetupLogDir
- 1.3b SetupCacheDir
- 1.4 AptPackages (delta)
- 1.5 InstallWkhtmltopdf
- 1.6 SetupPostgres
- 1.7 CreateDbRole
- 1.8 CreateDatabase
- 1.9 CloneOdooRepo
- 1.10 CreateVirtualenv
- 1.11 InstallPythonRequirements
- 1.12 GenerateConfig
- 1.12b SetupDataDir
- 1.13 InitializeOdooDatabase
- 1.14 SetupSystemd
- 1.15 Nginx (6 sub-steps)
- 1.16 WriteControlScript + PatchBashrc
Cross-cutting: