Skip to content

Commit b0b4ab5

Browse files
committed
Add --overrides-file and --allow-system-uid options.
These options make it possible to actually use this tool on single-user systems like OpenWRT, where individual users don't make much sense but we still want to be able to use the github-provided SSH key fingerprint checking. The design is to allow explicit whitelisting of system UIDs, then to provide an overrides file that maps UIDs to (potentially multiple) GitHub usernames.
1 parent c8d768a commit b0b4ab5

File tree

8 files changed

+257
-93
lines changed

8 files changed

+257
-93
lines changed

Diff for: Cargo.lock

-29
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ edition = "2018"
66

77
[dependencies]
88
clap = "2.33.0"
9-
fstrings = "0.2.2"
109
sshkeys = "0.3.2"
1110
users = "0.9.1"
1211
tempfile = "3.1.0"

Diff for: Dockerfile

+3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ ARG GID=1000
99
RUN useradd -u ${UID} staticfloat
1010
RUN echo "staticfloat ALL = NOPASSWD: ALL" >> /etc/sudoers
1111

12+
# Create `keno` user that will not work by default, because he's a system user
13+
RUN useradd -u 900 keno
14+
1215
# Copy in our build artifacts
1316
COPY runtests.sh /var/runtests.sh
1417
COPY target/release/authorized-keys-github /usr/local/bin/authorized-keys-github

Diff for: Makefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ TARGET_TRIPLETS := aarch64-unknown-linux-gnu \
7070
$(foreach triplet,$(TARGET_TRIPLETS),$(eval multibuild: target/$(triplet)/release/authorized-keys-github))
7171

7272
check:
73-
$(call docker_exec,rust,cargo fmt --color=always --all -- --check)
73+
$(call docker_exec,rust,cargo fmt --all -- --check)
7474

7575
format:
76-
$(call docker_exec,rust,cargo fmt --color=always --all)
76+
$(call docker_exec,rust,cargo fmt --all)
7777

7878
.PHONY: test build
7979
test: $(NATIVE_EXE)

Diff for: README.md

+12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ For this tool to work, users must use the same username as their GitHub username
1313

1414
The tool will attempt to build a cache of SSH key fingerprints at `/var/keys` by default; to change this, use the `--keys-dir` option.
1515

16+
## Overriding local usernames and usage for system accounts
17+
18+
In the event that you want to use this tool with local usernames that you do not control (such as the `root` user on a single-user system like OpenWRT) you can use the `--overrides-file` argument to explicitly map UIDs to GitHub usernames.
19+
A simple example is given here:
20+
```
21+
# Allow users `keno` and `staticfloat` to login as `root`
22+
0: keno staticfloat
23+
```
24+
A more complete example overrides file with comments is [given in `example.overrides`](./example.overrides).
25+
Note that overrides files must be owned by the user that the command is being run by (usually `root`) and cannot be writable by any other user or group.
26+
In order to actually login as `root` (or any system user account with a UID <1000) you must explicitly whitelist the account by passing `--allow-system-uid=xxx` to the command.
27+
1628
## Usage Warning
1729

1830
Although we have taken some pains to test this in exceptional circumstances (such as disk space exhaustion, read-only filesystems, etc...) it is possible there remain serious bugs that can lock you out of your server.

Diff for: example.overrides

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# This is an "overrides" file, it allows the administrator to provide
2+
# overrides on which UIDs should be mapped to which GitHub usernames.
3+
# The syntax is a series of lines of the form:
4+
#
5+
# <uid>: username1 username2 ...
6+
#
7+
# Multiple usernames are permissable, to allow multiple github users
8+
# to log in to a shared account (e.g. `root` on single-user systems).
9+
# Note that you must pass `--allow-system-uid=xxx` for each UID under
10+
# 1000 for these to be accepted.
11+
#
12+
# If a UID is listed here, the typical user database in `/etc/passwd`
13+
# is not consulted at all; this provides a secure mechanism by which
14+
# to map local usernames which are constrained in some way to github
15+
# usernames that you do have full control over.
16+
#
17+
# Needless to say, lines starting with '#' are ignored.
18+
# What follows here is a series of examples:
19+
20+
# A single UID can be mapped to multiple GitHub usernames
21+
0: keno staticfloat
22+
23+
# A GitHub username can be assigned to multiple UIDs
24+
1000: staticfloat

Diff for: runtests.sh

+65-1
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ export RUST_BACKTRACE=full
1515

1616
header() {
1717
tput bold
18-
tput setaf 1
18+
tput setaf 4
1919
echo "$*"
2020
tput sgr0
2121
}
2222

2323
die() {
24+
tput bold
25+
tput setaf 1
2426
echo "ERROR: $*" >&2
27+
tput sgr0
2528
exit 1
2629
}
2730

@@ -83,6 +86,67 @@ FINGERPRINT="SHA256:0000000000000000000000000000000000000000000"
8386
OUTPUT="$(authorized-keys-github --keys-dir="${KEYS_DIR}" --fp=${FINGERPRINT} $(id -u) 2>&1 | tee >(cat 1>&2))"
8487
test_output "${OUTPUT}" "REFRESH_EXPECTED" ""
8588

89+
# System users are not allowed without `--allow-system-user`:
90+
# In our `Dockerfile`, we setup a user with a valid GitHub username (keno) with UID 900:
91+
if [[ $(getent passwd 900 2>/dev/null) == "keno:"* ]]; then
92+
header "System user, errors"
93+
if authorized-keys-github --keys-dir="${KEYS_DIR}" 900 ; then
94+
die "System user should not be allowed!"
95+
fi
96+
97+
header "System user, positive"
98+
OUTPUT="$(authorized-keys-github --keys-dir="${KEYS_DIR}" --allow-system-uid=900 900 2>&1 | tee >(cat 1>&2))"
99+
test_output "${OUTPUT}" "REFRESH_EXPECTED" "KEYS_EXPECTED"
100+
fi
101+
102+
# Generate overrides file for a system user:
103+
OVERRIDES_FILE="${KEYS_DIR}/overrides"
104+
cat >"${OVERRIDES_FILE}" <<EOF
105+
901: staticfloat keno
106+
32000: staticfloat
107+
EOF
108+
109+
header "Overrides, single"
110+
OUTPUT="$(authorized-keys-github --keys-dir="${KEYS_DIR}" --overrides-file="${OVERRIDES_FILE}" 32000 2>&1 | tee >(cat 1>&2))"
111+
test_output "${OUTPUT}" "REFRESH_EXPECTED" "KEYS_EXPECTED"
112+
num_staticfloat_keys=$(grep "ssh-rsa" <<<"${OUTPUT}" | wc -l)
113+
114+
header "Overrides, multiple and system user"
115+
OUTPUT="$(authorized-keys-github --keys-dir="${KEYS_DIR}" --overrides-file="${OVERRIDES_FILE}" --allow-system-uid=901 901 2>&1 | tee >(cat 1>&2))"
116+
test_output "${OUTPUT}" "REFRESH_EXPECTED" "KEYS_EXPECTED"
117+
num_combined_keys=$(grep "ssh-rsa" <<<"${OUTPUT}" | wc -l)
118+
119+
if [[ "${num_combined_keys}" -le "${num_staticfloat_keys}" ]]; then
120+
die "Expected more keys than ${num_combined_keys}!"
121+
fi
122+
123+
# Generate a completely invalid overrides file
124+
header "Invalid overrides, errors"
125+
cat >"${OVERRIDES_FILE}" <<EOF
126+
901: staticfloat keno
127+
science: you monster
128+
EOF
129+
if authorized-keys-github --keys-dir="${KEYS_DIR}" --overrides-file="${OVERRIDES_FILE}" $(id -u) ; then
130+
die "Invalid override file should fail!"
131+
fi
132+
133+
# Generate an overrides file that contains a duplicate mapping
134+
header "Overlapping overrides, errors"
135+
cat >"${OVERRIDES_FILE}" <<EOF
136+
901: staticfloat keno
137+
902: staticfloat
138+
901: keno
139+
EOF
140+
if authorized-keys-github --keys-dir="${KEYS_DIR}" --overrides-file="${OVERRIDES_FILE}" $(id -u) ; then
141+
die "Overlapping override file should fail!"
142+
fi
143+
144+
# Generate an overrides file that is writable by other users
145+
header "Other-writable overrides, errors"
146+
chmod g+w "${OVERRIDES_FILE}"
147+
if authorized-keys-github --keys-dir="${KEYS_DIR}" --overrides-file="${OVERRIDES_FILE}" $(id -u) ; then
148+
die "Other-writable override file should fail!"
149+
fi
86150

87151
# Fill up tmpfs to generate out-of-space errors:
88152
fill_up_disk_space "${KEYS_DIR}"

0 commit comments

Comments
 (0)