-
Notifications
You must be signed in to change notification settings - Fork 2
/
monkeyproof
executable file
·339 lines (293 loc) · 11.2 KB
/
monkeyproof
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#!/bin/bash
# Quick and dirty script to configure monkeysphere and pam-ssh-agent-auth
# It *should* be idempotent...
SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
# shellcheck disable=SC1090
. "$SCRIPT_DIR/poshlib/poshlib.sh" || exit 1
use strict
use utils
APT=''
YUM=''
if [[ -d /etc/apt ]]; then
APT=true
SUDO=sudo
SSH=ssh
elif [[ -d /etc/yum ]]; then
YUM=true
SUDO=wheel
SSH=sshd
else
die 2 "Distribution not supported!"
fi
MS_HOME=/var/lib/monkeysphere
MS_SPHERE_DIR=$MS_HOME/authentication/sphere
MS_CORE_DIR=$MS_HOME/authentication/core
# Support headless installation
export DEBIAN_FRONTEND=noninteractive
export NEEDRESTART_SUSPEND=y
export MONKEYSPHERE_PROMPT=false
# Set some defaults
ID_CERTIFIERS="00CC54C6A0C601691AF4931FFB73E21AF1163937"
PRESEED_USER_ID="Andrew Gallagher <[email protected]>"
PRESEED_USER_ACCOUNT="andrewg"
if [[ -f /etc/monkeyproof ]]; then
# shellcheck disable=SC1091
. /etc/monkeyproof
fi
if [[ -f ~/.monkeyproof ]]; then
# shellcheck disable=SC1090
. ~/.monkeyproof
fi
# Install and configure monkeysphere
if [[ $APT ]]; then
if [ -z "$(find /var/cache/apt/pkgcache.bin -mmin -60)" ]; then
apt-get update
fi
apt-get -y install monkeysphere dirmngr
elif [[ $YUM ]]; then
if rpm -q gnupg2 | grep -q 'gnupg2-2\.2\.'; then
yum -y --setopt=skip_missing_names_on_install=False install monkeysphere
else
# Hacky, hacky method to get monkeysphere to work on a CentOS/RHEL 7
# system with modern settings (Hagrid, etc)
# https://people.kernel.org/monsieuricon/run-gnupg-2-2-17-on-your-el7-system
echo "RHEL/CentOS 7 sticky tape..."
yum install -y yum-plugin-copr
yum copr enable -y icon/lfit
yum install -y gnupg22-static patch
yum -y --setopt=skip_missing_names_on_install=False install monkeysphere
if ! grep -q /opt/gnupg22/bin /usr/share/monkeysphere/defaultenv; then
cat <<'EOF' >> /usr/share/monkeysphere/defaultenv
# Added by monkeyproof script
export PATH=/opt/gnupg22/bin:"$PATH"
EOF
fi
# run monkeysphere-authentication once to create default directories
monkeysphere-authentication list-id-certifiers >/dev/null 2>&1 || true
cat <<EOF > "$MS_SPHERE_DIR/gpg.conf-2.2"
no-greeting
list-options show-uid-validity
keyid-format 0xlong
agent-program /opt/gnupg22/bin/gpg-agent
dirmngr-program /opt/gnupg22/bin/dirmngr
EOF
chown monkeysphere:monkeysphere "$MS_SPHERE_DIR/gpg.conf-2.2"
cat <<EOF > "$MS_CORE_DIR/gpg.conf-2.2"
no-greeting
keyid-format 0xlong
agent-program /opt/gnupg22/bin/gpg-agent
dirmngr-program /opt/gnupg22/bin/dirmngr
EOF
# And now perform a filthy, unforgivable patch against monkeysphere.
# THIS WILL BREAK ON UPGRADES
# ... but then this is CentOS 7 so it won't be getting any.
# For idempotency, check to ensure we don't try to double-patch.
grep -q 'cut -d: -f10 . head -1' /usr/share/monkeysphere/ma/add_certifier || \
patch -f -b -d/ -R -p1 <<'EOF' || die 1 $'\n\nPATCH FAILED, CHECK MANUALLY\n\n'
*** /usr/share/monkeysphere/ma/add_certifier 2020-03-20 16:40:50.976038098 +0000
--- /usr/share/monkeysphere/ma/add_certifier.bak 2016-06-27 02:32:33.000000000 +0000
*************** else
*** 120,126 ****
# get the full fingerprint of new certifier key
log debug "getting fingerprint of certifier key..."
fingerprint=$(gpg_sphere --list-key --with-colons --with-fingerprint "0x${keyID}!" \
! | grep '^fpr:' | cut -d: -f10 | head -1)
# test that there is only a single fingerprint
if (( $(echo "$fingerprint" | wc -l) != 1 )) ; then
--- 120,126 ----
# get the full fingerprint of new certifier key
log debug "getting fingerprint of certifier key..."
fingerprint=$(gpg_sphere --list-key --with-colons --with-fingerprint "0x${keyID}!" \
! | grep '^fpr:' | cut -d: -f10)
# test that there is only a single fingerprint
if (( $(echo "$fingerprint" | wc -l) != 1 )) ; then
EOF
fi
fi
# Monkeysphere in EPEL is broken by default; it sets the user shell to
# /sbin/nologin, so the commands can't drop privileges.
# This has been fixed in fedora for years:
# https://bugzilla.redhat.com/show_bug.cgi?id=732191
# Force a sane login shell no matter what.
chsh -s /bin/bash monkeysphere
cat > /etc/monkeysphere/monkeysphere.conf <<EOF
# Created automatically by monkeyproof script
# Log level. Can be SILENT, ERROR, INFO, VERBOSE, DEBUG, in
# increasing order of verbosity.
#LOG_LEVEL=INFO
# PGP keyserver to search for keys.
KEYSERVER=keys.openpgp.org
# The path to the SSH known_hosts file.
#KNOWN_HOSTS=~/.ssh/known_hosts
# Whether or not to hash the generated known_hosts lines.
# Should be "true" or "false".
#HASH_KNOWN_HOSTS=false
# The path to the SSH authorized_keys file.
#AUTHORIZED_KEYS=~/.ssh/authorized_keys
EOF
cat > /etc/monkeysphere/monkeysphere-authentication.conf <<EOF
# Created automatically by monkeyproof script
# This config prevents privilege escalation when using pam-ssh-agent-auth
# DO NOT allow users to specify their own PGP IDs.
AUTHORIZED_USER_IDS="/etc/monkeysphere/authorized_user_ids/%u"
# DO NOT allow users to supplement monkeysphere's authorized_keys.
# But allow sysadmins to do so for users who don't use PGP
# Use the standard-ish pam_ssh_agent_auth directory for this. #POLS
RAW_AUTHORIZED_KEYS='/etc/security/authorized_keys/%u'
# PGP keyserver to search for keys.
KEYSERVER=keys.openpgp.org
EOF
cat > /etc/monkeysphere/monkeysphere-host.conf <<EOF
# Created automatically by monkeyproof script
# Monkeysphere host configuration file.
# Log level. Can be SILENT, ERROR, INFO, VERBOSE, DEBUG, in
# increasing order of verbosity.
#LOG_LEVEL=INFO
# PGP keyserver to search for keys.
KEYSERVER=keys.openpgp.org
EOF
# Allow for possibility of soft-linked or prepopulated authorized_keys
if [[ ! -L /etc/security/authorized_keys && ! -e /etc/security/authorized_keys ]]; then
mkdir -p /etc/security/authorized_keys
cat > /etc/security/authorized_keys/README <<EOF
# This directory contains authorized keys for use by both ssh and sudo.
# These are NOT used directly, but are polled regularly by monkeysphere.
# To force an update ahead of schedule, run the following command as root:
#
# monkeysphere-authentication update-users
EOF
fi
for id in $ID_CERTIFIERS; do
monkeysphere-authentication add-id-certifier "$id"
done
# Add preseed user
if [[ ! -L /etc/monkeysphere/authorized_user_ids && ! -e /etc/monkeysphere/authorized_user_ids ]]; then
mkdir /etc/monkeysphere/authorized_user_ids
fi
echo "$PRESEED_USER_ID" > "/etc/monkeysphere/authorized_user_ids/$PRESEED_USER_ACCOUNT"
# Create the account if it doesn't exist
if ! grep -q "^$PRESEED_USER_ACCOUNT:" /etc/passwd ; then
if [[ $APT ]]; then
# We can and must do this on one line, else we get prompted
adduser --disabled-password --gecos "${PRESEED_USER_ID%%<*}" "$PRESEED_USER_ACCOUNT"
elif [[ $YUM ]]; then
# We can't do it on one line, but adduser doesn't complain
adduser "$PRESEED_USER_ACCOUNT"
usermod --lock "$PRESEED_USER_ACCOUNT"
usermod --comment "${PRESEED_USER_ID%%<*}" "$PRESEED_USER_ACCOUNT"
fi
usermod -aG "${SUDO}" "$PRESEED_USER_ACCOUNT"
fi
monkeysphere-authentication update-users
# Make sure updates run in regularly
cat > /etc/cron.hourly/monkeysphere <<EOF
#!/bin/bash
# Created automatically by monkeyproof script
TRIES=6
for (( i=0; i<TRIES; i++)); do
monkeysphere-authentication update-users 2> /dev/null && exit 0
sleep 300
done
echo "monkeysphere-authentication gave up after \$TRIES tries"
EOF
chmod +x /etc/cron.hourly/monkeysphere
# Now configure sshd to read the monkeysphere keys
SSHD_CONFIG=/etc/ssh/sshd_config
if grep -q '^Include /etc/ssh/sshd_config\.d/\*\.conf$' "$SSHD_CONFIG"; then
SSHD_MS_CONFIG=/etc/ssh/sshd_config.d/99-monkeysphere.conf
if [[ -f "$SSHD_MS_CONFIG" ]]; then
mv "$SSHD_MS_CONFIG"{,.bak}
fi
else
SSHD_MS_CONFIG=$SSHD_CONFIG
fi
if grep -Eq '^\s*AuthorizedKeysFile\s+%h/.ssh/authorized_keys\s+/var/lib/monkeysphere/authorized_keys/%u\s*$' "$SSHD_CONFIG"; then
# If we find our own handiwork, do nothing; this is for idempotency
echo "SSHD already configured for monkeysphere"
else
if grep -Eq '^\s*AuthorizedKeysFile\s+' "$SSHD_CONFIG"; then
# If there exists a working AuthorizedKeysFile line, comment it out
perl -pi.bak -e 's/^(\s*AuthorizedKeysFile)/#$1/' "$SSHD_CONFIG"
fi
cat >> "$SSHD_MS_CONFIG" <<EOF
# Added automatically by monkeyproof script
# Allow logins with both user-supplied keys and monkeysphere's curated keys
AuthorizedKeysFile %h/.ssh/authorized_keys /var/lib/monkeysphere/authorized_keys/%u
EOF
ssh_restart=true
fi
# Also fix StreamLocalBindUnlink while we're here
if grep -Eq '^\s*StreamLocalBindUnlink\s+yes' "$SSHD_CONFIG"; then
# If we find our own handiwork, do nothing; this is for idempotency
echo "StreamLocalBindUnlink already enabled"
else
if grep -Eq '^\s*StreamLocalBindUnlink\s' "$SSHD_CONFIG"; then
# If there is a working StreamLocalBindUnlink line, comment it out
perl -pi.bak2 -e 's/^(\s*StreamLocalBindUnlink\s.*)$/#$1/' "$SSHD_CONFIG"
fi
cat >> "$SSHD_MS_CONFIG" <<EOF
# Added automatically by monkeyproof script
# Delete forwarded domain sockets once they're no longer required
StreamLocalBindUnlink yes
EOF
ssh_restart=true
fi
# Disable password authentication by default
if grep -Eq '^\s*PasswordAuthentication\s+no' "$SSHD_CONFIG"; then
# If we find our own handiwork, do nothing; this is for idempotency
echo "PasswordAuthentication already disabled"
else
if grep -Eq '^\s*PasswordAuthentication\s' "$SSHD_CONFIG"; then
# If there is a working PasswordAuthentication line, comment it out
perl -pi.bak3 -e 's/^(\s*PasswordAuthentication\s.*)$/#$1/' "$SSHD_CONFIG"
fi
cat >> "$SSHD_MS_CONFIG" <<EOF
# Added automatically by monkeyproof script
PasswordAuthentication no
EOF
ssh_restart=true
fi
if [[ ${ssh_restart:-} ]]; then
service "$SSH" restart
fi
# Populate monkeysphere-host database with SSH's RSA key
serverlist="$(hostname --fqdn -A | sed 's/ /\n/g' | sort -u)"
if [[ $serverlist ]]; then
for server in $serverlist; do
monkeysphere-host import-key /etc/ssh/ssh_host_rsa_key "ssh://${server}" || true
done
else
echo "WARNING: no valid FQDNs found. Not populating monkeysphere-host DB"
fi
# Install and configure libpam-ssh-agent-auth
if [[ $APT ]]; then
apt-get -y install libpam-ssh-agent-auth
cat > /usr/share/pam-configs/pam-ssh-agent-auth <<EOF
Name: SSH agent authentication
Default: yes
Priority: 258
Auth-Type: Primary
Auth:
[success=end default=ignore] pam_ssh_agent_auth.so file=/var/lib/monkeysphere/authorized_keys/%u
Auth-Initial:
[success=end default=ignore] pam_ssh_agent_auth.so file=/var/lib/monkeysphere/authorized_keys/%u
EOF
pam-auth-update --force
elif [[ $YUM ]]; then
yum -y --setopt=skip_missing_names_on_install=False install pam_ssh_agent_auth
if ! grep -q pam_ssh_agent_auth.so /etc/pam.d/system-auth; then
cat <<EOF >/etc/pam.d/system-auth-monkeyproof
auth sufficient pam_ssh_agent_auth.so file=/var/lib/monkeysphere/authorized_keys/%u
auth include system-auth-ac
account include system-auth-ac
password include system-auth-ac
session include system-auth-ac
EOF
ln -sf system-auth-monkeyproof /etc/pam.d/system-auth
fi
fi
cat > /etc/sudoers.d/pam-ssh-agent-auth <<EOF
# Added automatically by monkeyproof script
# Older versions of sudo need this to access user ssh-agent
Defaults env_keep += "SSH_AUTH_SOCK"
EOF