· about 40 minutes · runs on ubuntu-26.04-automation · unrated
An unrated lab. It runs on your machine with no account and no network, and everything about it — the faults, the checks, the hints and the reference solution — is in the repository. An attempt on it is recorded on your profile and never moves a rating: only rated labs do. Rated and unrated labs.
chat-gateway is the internal front door to the model API: colleagues post a prompt to
http://127.0.0.1:8090/ask through nginx, and the gateway calls the upstream model service with
the company's API key.
The security review came back with four findings:
systemctl show.Client tokens are in /etc/chat-gateway/clients.token (one token, the first line). The gateway
reads its settings from /etc/chat-gateway/gateway.env; it understands UPSTREAM_KEY_FILE,
REQUIRE_TOKEN and LOG_HEADERS, and it also accepts the key as a systemd credential named
upstream_key.
What is expected, and graded:
Environment=, not on the
ExecStart line.You have root through sudo. Everything must still hold after a reboot.
The machine is checked, rebooted, and checked again. A check passes only if it passes both times.
| Check | Objective |
|---|---|
| 01_key_not_in_the_unit | Keep an upstream API key out of unit files and out of other accounts' reach |
| 02_key_file_private | Keep an upstream API key out of unit files and out of other accounts' reach |
| 03_gateway_requires_a_token | Require authentication on an internal AI gateway |
| 04_bursts_are_rate_limited | Rate-limit an expensive endpoint at the proxy |
| 05_logs_have_no_secrets | Keep secrets out of the logs |
Where the lab's hints send you, level by level, as you ask for them (h, then l opens a journal section in the TUI).
4 questions on the same topic, in the lab's Theory tab. They never affect the lab's grade. Three of them, to answer here:
An API key is in a unit's Environment= line. Which command lets any unprivileged user on the machine read it?
systemctl show -p Environment <unit>
systemctl show and systemctl cat work without privilege, and unit files are normally 0644. The journal shows the key only if the service logs it; /proc/1/environ is root-only. A drop-in that blanks the variable does not help, because systemctl cat still prints the original file.
man 1 systemctl · man 5 systemd.exec (Environment=)
What does LoadCredential= give a service that EnvironmentFile= does not?
A private copy of the secret for that unit, read by systemd as root, with nothing in the process environment
systemd reads the source file (which can stay 0600 root:root) and exposes it in $CREDENTIALS_DIRECTORY for this unit only. EnvironmentFile puts the value into the environment, inherited by every child process. Encryption at rest is a separate feature (systemd-creds encrypt); nothing rotates secrets for you.
man 5 systemd.exec (Credentials)
nginx rate limiting is set with `limit_req zone=chat burst=5 nodelay`. What status do rejected requests get unless `limit_req_status` says otherwise?
503
The default limit_req_status is 503, which clients read as an outage. Setting `limit_req_status 429` tells well-behaved clients to slow down and retry later.
https://nginx.org/en/docs/http/ngx_http_limit_req_module.html#limit_req_status