harden production debug wrapper
This commit is contained in:
parent
0768f6d783
commit
d8dcb84edb
3 changed files with 24 additions and 5 deletions
|
|
@ -45,6 +45,10 @@ on the diagnostics client at:
|
|||
- Preserve the `restrict` and forced-command options in `authorized_keys`.
|
||||
- Verify arbitrary commands and malformed arguments are denied.
|
||||
- Do not print container environment variables or application secrets.
|
||||
- Ensure `status` passes its token to curl through stdin, not an argv `-H`
|
||||
argument visible through `/proc`.
|
||||
- Resolve the container into a variable before Docker calls so selector failure
|
||||
propagates with the documented return code.
|
||||
|
||||
The account may run only:
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,11 @@ Security invariants:
|
|||
fail closed.
|
||||
- Verify denials as well as successful commands. Audit records are available via
|
||||
`journalctl -t chart-debug`.
|
||||
- Keep secrets off process command lines. The status command supplies
|
||||
`CHART_AUTH_TOKEN` to curl through stdin (`curl --config -`), never `-H`.
|
||||
- Assign `resolve_container` before invoking Docker. Calling it inline through
|
||||
command substitution can trap its exit in a subshell and obscure the intended
|
||||
fail-closed return code.
|
||||
|
||||
## Observability
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,8 @@ case "${args[0]}" in
|
|||
[[ "${args[2]}" =~ ^[1-9][0-9]*(s|m|h|d)$ ]] || {
|
||||
echo "invalid duration" >&2; exit 2;
|
||||
}
|
||||
docker logs --timestamps --tail "$MAX_LOG_LINES" --since "${args[2]}" "$(resolve_container)" 2>&1 | redact
|
||||
container=$(resolve_container)
|
||||
docker logs --timestamps --tail "$MAX_LOG_LINES" --since "${args[2]}" "$container" 2>&1 | redact
|
||||
;;
|
||||
status)
|
||||
[[ ${#args[@]} -eq 1 ]] || { echo "usage: status" >&2; exit 2; }
|
||||
|
|
@ -63,7 +64,13 @@ case "${args[0]}" in
|
|||
[[ "$entry" == CHART_AUTH_TOKEN=* ]] && token=${entry#CHART_AUTH_TOKEN=}
|
||||
done < <(docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' "$container")
|
||||
if [[ -n "$token" ]]; then
|
||||
curl -fsS -H "X-Chart-Token: $token" "$CHART_PUBLIC_URL/api/status" | redact
|
||||
[[ "$token" != *$'\n'* && "$token" != *$'\r'* ]] || {
|
||||
echo "invalid CHART_AUTH_TOKEN" >&2; exit 4;
|
||||
}
|
||||
escaped_token=${token//\\/\\\\}
|
||||
escaped_token=${escaped_token//\"/\\\"}
|
||||
printf 'url = "%s/api/status"\nheader = "X-Chart-Token: %s"\nfail\nsilent\nshow-error\n' \
|
||||
"$CHART_PUBLIC_URL" "$escaped_token" | curl --config - | redact
|
||||
else
|
||||
echo "CHART_AUTH_TOKEN is unavailable" >&2
|
||||
exit 4
|
||||
|
|
@ -71,21 +78,24 @@ case "${args[0]}" in
|
|||
;;
|
||||
container-state)
|
||||
[[ ${#args[@]} -eq 1 ]] || { echo "usage: container-state" >&2; exit 2; }
|
||||
container=$(resolve_container)
|
||||
docker inspect --format \
|
||||
'name={{.Name}} image={{.Config.Image}} status={{.State.Status}} started={{.State.StartedAt}} restarts={{.RestartCount}} oom={{.State.OOMKilled}} exit={{.State.ExitCode}}' \
|
||||
"$(resolve_container)"
|
||||
"$container"
|
||||
;;
|
||||
recent-deploy)
|
||||
[[ ${#args[@]} -eq 1 ]] || { echo "usage: recent-deploy" >&2; exit 2; }
|
||||
curl -fsS "$CHART_PUBLIC_URL/api/version"
|
||||
printf '\n'
|
||||
docker inspect --format 'container_started={{.State.StartedAt}} image={{.Config.Image}}' "$(resolve_container)"
|
||||
container=$(resolve_container)
|
||||
docker inspect --format 'container_started={{.State.StartedAt}} image={{.Config.Image}}' "$container"
|
||||
;;
|
||||
capture-read)
|
||||
[[ ${#args[@]} -eq 2 ]] && valid_capture_id "${args[1]}" || {
|
||||
echo "usage: capture-read c-XXXXXXXXXXXX" >&2; exit 2;
|
||||
}
|
||||
docker exec "$(resolve_container)" base64 "/tmp/chart-captures/${args[1]}.png"
|
||||
container=$(resolve_container)
|
||||
docker exec "$container" base64 "/tmp/chart-captures/${args[1]}.png"
|
||||
;;
|
||||
capture-delete)
|
||||
[[ ${#args[@]} -eq 2 ]] && valid_capture_id "${args[1]}" || {
|
||||
|
|
|
|||
Loading…
Reference in a new issue