Repository navigation
Expand file tree
/
Copy pathentrypoint.sh
More file actions
executable file
·83 lines (77 loc) · 3.88 KB
/
Copy pathentrypoint.sh
File metadata and controls
executable file
·83 lines (77 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#!/bin/sh
# Stages the credentials somewhere their mode is real, drops privileges, and becomes the daemon.
#
# **`serve` is added here, not in the image's CMD.** It is the one word that turns the argument
# list every compose file already writes into the subcommand `big` now needs, and putting it in
# one place means a compose file that predates the rename still starts.
#
# **Why this starts as root.** Two things are true at once: `big serve` refuses a users file or a
# private key that anyone but its owner can read, and a bind-mounted file arrives with whatever ownership and
# mode the *host* gave it - root-owned `600` on one machine, `0755` on Docker Desktop, uid 1000
# somewhere else. Nothing the image can do makes those two agree. Reading the file as root and
# writing a private copy makes them agree, and costs the container root for the length of one
# `install`.
#
# **The daemon never runs as root.** The last line drops to `big` and stays there. If this is
# already running unprivileged - `user:` in a compose file, a hardened runtime - the staging is
# done with whatever access it has and the drop is skipped, so the strict deployment still
# works as long as the host files are readable by that user.
#
# What is mounted is the *directory*, never the files. A single-file bind mount breaks the
# first time anything replaces the file rather than writing through it - which is what every
# editor and most secret managers do - and the container goes on holding the inode that used to
# be there.
set -eu
me=$(id -u)
stage() {
[ -r "$1" ] || return 0
if [ "$me" = 0 ]; then
# Owner and mode set as it copies, so there is no moment where the file exists and is
# readable by anyone else.
install -o big -g big -m 600 "$1" "$2"
else
install -m 600 "$1" "$2"
fi
}
stage /etc/big/secrets/users /run/big/users
# The CA is not a secret - it is what everybody checks against - but it is staged the same way so
# that one rule covers the directory. The per-node key is a secret, and gets the same mode 600.
stage /etc/big/secrets/peer-ca.pem /run/big/peer-ca.pem
# The revocation list, when the CA has one. Optional so that a `secrets/` written by an older
# `certs.sh` still starts - but `certs.sh` writes an empty one at bootstrap, because a cluster
# that has never had a CRL cannot begin checking without restarting every node, and the moment
# somebody needs to revoke a key is the worst moment to find that out.
[ -f /etc/big/secrets/peer-ca.crl ] && stage /etc/big/secrets/peer-ca.crl /run/big/peer-ca.crl
# Which node this is, read out of the arguments rather than out of a second environment variable.
# The name is already in the command line as `--node`, and a deployment that had to write it
# twice is a deployment where the two can disagree - which would present as a node holding a
# certificate for somebody else and being refused by every peer.
#
# **Both spellings.** The parser accepts `--node=a` as well as `--node a`, and a scanner that
# knew only the second would silently stage somebody else's certificate rather than fail - the
# one outcome this whole block exists to prevent.
node=""
want=""
for arg do
if [ -n "$want" ]; then
node=$arg
want=""
else
case "$arg" in
--node) want=1 ;;
--node=*) node=${arg#--node=} ;;
esac
fi
done
if [ -n "$node" ]; then
stage "/etc/big/secrets/$node.pem" /run/big/peer.pem
stage "/etc/big/secrets/$node.key" /run/big/peer.key
fi
if [ "$me" = 0 ]; then
# `setpriv` rather than `su`: no shell in between, no session, no signal indirection - the
# daemon becomes PID 1's child directly and sees a stop signal as itself.
# The `big` in `--reuid=big` is the user; the `big` after `--init-groups` is the binary.
# They are spelled the same and are not the same thing.
exec setpriv --reuid=big --regid=big --init-groups big serve "$@"
fi
exec big serve "$@"