-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcapp-installer-template
212 lines (211 loc) · 7.58 KB
/
capp-installer-template
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
#!/bin/bash
set -e
CAPP_VER=to_replace
COMPOSE_SYSTEMD_VER=v1.6.1
def_min_dca_ver=2
def_cont_mem='10G'
def_cont_proc=1000
me=$(readlink -f "$0")
offset=$(($(sed -rn '/#{10}/=' "$me") + 1))
usage() {
echo "$0 default_hostname default_email [min_dca_ver=$def_min_dca_ver] [container_max_memory_size=$def_cont_mem] [container_max_process=$def_cont_proc] [nohttps]" >&2
echo " container_max_memory_size should be expressed with M or G units" >&2
echo "-v|--version show the version" >&2
echo "-h|--help show this help message" >&2
echo "-e|--extract extract the inner archive to src.tar.xz"
# shellcheck disable=SC2086
exit ${1:-1}
}
if [ "$1" = "-v" ] || [ "$1" = "--version" ]; then
echo "$CAPP_VER"
exit 0
fi
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
usage 0
fi
if [ "$1" = "-e" ] || [ "$1" = "--extract" ]; then
tail -n+$offset "$me" | base64 -d > src.tar.xz
exit 0
fi
# shellcheck disable=SC2046
if [ $(id -u) -ne 0 ]; then
echo "Root required" >&2
exit 1
fi
for bin in useradd usermod base64 curl docker sudo tar unxz; do
if ! which $bin >/dev/null 2>&1; then
echo "$bin required" >&2
exit 1
fi
done
docker="$(which docker)"
if "$docker" compose version | grep -q 'Docker Compose'; then
dc="$docker compose"
elif which docker-compose >/dev/null 2>&1; then # legacy
dc="$(which docker-compose)"
else
echo "docker with compose required" >&2
exit 1
fi
dh="$1"
# shellcheck disable=SC2015
[ -n "$dh" ] && shift || usage
de="$1"
# shellcheck disable=SC2015
[ -n "$dh" ] && shift || usage
min_dca_ver=
cont_mem=
cont_proc=
nohttps=0
while [ -n "$1" ]; do
p="$1"
shift
if [ -z "$min_dca_ver" ]; then
echo "$p" | grep -E -q '^[0-9](\.[0-9]+)?$' || usage
min_dca_ver="$p"
elif [ -z "$cont_mem" ]; then
echo "$p" | grep -E -q '^[0-9]+[MG]$' || usage
cont_mem="$p"
elif [ -z "$cont_proc" ]; then
echo "$p" | grep -E -q '^[0-9]+$' || usage
cont_proc="$p"
elif [ "$p" = "nohttps" ]; then
nohttps=1
else
usage
fi
done
[ -n "$min_dca_ver" ] || min_dca_ver=$def_min_dca_ver
[ -n "$cont_mem" ] || cont_mem=$def_cont_mem
[ -n "$cont_proc" ] || cont_proc=$def_cont_proc
cat > /etc/capp.conf <<EOF
min_dca_version=${min_dca_ver}
max_mem_size=${cont_mem}
max_proc=${cont_proc}
default_hostname=${dh}
EOF
mkdir -p /etc/capp/users /etc/capp/pubkeys /etc/capp/rights /etc/capp/hooks.d/{pre_deploy,post_deploy,pre_undeploy,post_undeploy}
tmpdir=$(mktemp -d)
cd "$tmpdir"
curl -Ls https://github.com/jrd/compose-systemd/archive/${COMPOSE_SYSTEMD_VER}.tar.gz | tar xzf -
tail -n+$offset "$me" | base64 -d | tar xJf -
cp compose-systemd-*/compose-dirs.conf /etc/
cp compose-systemd-*/compose-dirs /usr/local/bin/
cat > /usr/local/bin/dc <<EOF
#!/bin/sh
exec $dc "\$@"
EOF
chmod +x /usr/local/bin/dc
mkdir -p /var/docker-volumes/nginx-proxy/{vhost.d,certs} /etc/compose /home/deploy/dca
id -u compose >/dev/null 2>&1 || useradd --home-dir /etc/compose --no-create-home --user-group --shell /usr/sbin/nologin -c "Compose" -l compose
chown :compose /var/docker-volumes/nginx-proxy/vhost.d /etc/capp/users /etc/capp/pubkeys /etc/capp/rights
chmod g+w,o=rX /var/docker-volumes/nginx-proxy/vhost.d /etc/capp/users /etc/capp/pubkeys /etc/capp/rights
cp -r proxy dca /etc/compose/
if [ "$nohttps" -eq 1 ]; then
# comment the letsencrypt service
sed -ri '/le:/,/certs:rw/s/^/#/' /etc/compose/proxy/docker-compose.yml
# do not bind the 443 port on the host
sed -ri '/:443/d' /etc/compose/proxy/docker-compose.yml
# do not redirect http access to https
sed -ri '/Env\.HTTPS_METHOD/s/redirect/nohttps/' /etc/compose/proxy/gen/nginx.tmpl
fi
sed -ri "s/dca:1000:1000/dca:$(id -u compose):$(id -g compose)/" /etc/compose/dca/docker-compose.yml
mkdir -p /usr/local/bin
cp capp verify_dca.py get_deploy_keys /usr/local/bin/
chown :compose /usr/local/bin/capp
DOCKER_GEN_VERSION=$(/etc/compose/proxy/gen/docker-gen --version)
cat > /etc/compose/proxy/.env <<EOF
DEFAULT_HOST=$dh
DEFAULT_EMAIL=$de
DOCKER_GEN_VERSION=${DOCKER_GEN_VERSION}
EOF
if [ -f /etc/compose/compose.deps ]; then
for svc in proxy dca; do
grep -q "^$svc:" /etc/compose/compose.deps || echo "$svc:" >> /etc/compose/compose.deps
done
else
cat > /etc/compose/compose.deps <<EOF
proxy:
dca:
EOF
fi
chown -R compose: ~compose
id -u deploy >/dev/null 2>&1 || useradd --no-create-home --user-group --password '*' -c "Deploy" deploy
cat > ~deploy/capp <<'EOF'
#!/usr/bin/env python3
from os import environ, execvpe
from shlex import split
from sys import exit
args = ['sudo', '-u', 'compose', '/usr/local/bin/capp'] + split(environ.pop('SSH_ORIGINAL_COMMAND', ''))
if 'SHELL' not in environ:
try:
environ['SHELL'] = [l.strip() for l in open('/etc/passwd').readlines() if l.startswith(environ['USER'] + ':')][0].split(':')[6]
except Exception:
pass
execvpe('sudo', args, environ)
exit(1)
EOF
chmod u=rx,g=rx,o= ~deploy/capp
chmod g+w ~deploy/dca
chown -R deploy: ~deploy
chown -R :compose ~deploy/dca
grep -q '^PermitUserEnvironment yes' /etc/ssh/sshd_config || sed -ri '/^#PermitUserEnvironment /a PermitUserEnvironment yes' /etc/ssh/sshd_config
grep -q '^Match User deploy' /etc/ssh/sshd_config && ! grep -q '^ *AuthorizedKeysCommand' /etc/ssh/sshd_config && sed -ri '/^Match User deploy/,/^.*AuthorizedKeys.*/d' /etc/ssh/sshd_config
grep -q '^Match User deploy' /etc/ssh/sshd_config || cat >> /etc/ssh/sshd_config <<EOF
Match User deploy
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
DisableForwarding yes
PasswordAuthentication no
ForceCommand /home/deploy/capp
AuthorizedKeysFile /dev/null
AuthorizedKeysCommand /usr/local/bin/get_deploy_keys
AuthorizedKeysCommandUser compose
EOF
[ -e /etc/compose/dca/users-keys ] && rm /etc/compose/dca/users-keys
[ -e /etc/deploy-authorized-keys ] && rm /etc/deploy-authorized-keys
[ -e /etc/dca-authorized-keys ] && rm /etc/dca-authorized-keys
touch /var/log/capp.log
chown compose: /var/log/capp.log
chmod g+w /var/log/capp.log
groups compose | grep -q '\<docker\>' || usermod -a -G docker compose
groups compose | grep -q '\<systemd-journal\>' || usermod -a -G systemd-journal compose
groups compose | grep -q '\<deploy\>' || usermod -a -G deploy compose
systemctl_path=$(which systemctl)
cat > /etc/sudoers.d/compose <<EOF
# Allow members of compose group to execute compose-dirs command
Cmnd_Alias COMPOSE_DIRS = /usr/local/bin/compose-dirs
Cmnd_Alias COMPOSE_SVC = $systemctl_path start compose@*,\
$systemctl_path stop compose@*,\
$systemctl_path reload compose@*,\
$systemctl_path reload-or-restart compose@*,\
$systemctl_path restart compose@*,\
$systemctl_path status compose@*
Cmnd_Alias CAPP_HOOKS = /etc/capp/hooks.d/pre_deploy/*,\
/etc/capp/hooks.d/post_deploy/*,\
/etc/capp/hooks.d/pre_undeploy/*,\
/etc/capp/hooks.d/post_undeploy/*
%compose ALL= NOPASSWD: COMPOSE_DIRS, COMPOSE_SVC, CAPP_HOOKS
EOF
cat > /etc/sudoers.d/deploy <<EOF
# Allow members of deploy group to execute capp command
Defaults env_keep="SSH_USER"
Cmnd_Alias CAPP_CMD = /usr/local/bin/capp
%deploy ALL=(compose) NOPASSWD: CAPP_CMD
EOF
chmod u=r,g=r,o= /etc/sudoers.d/{compose,deploy}
set +e
(
cd /etc/compose/dca
$dc build --pull --no-cache
cd ../proxy
$dc build --pull --no-cache
)
/usr/local/bin/compose-dirs install
/usr/local/bin/compose-dirs update
/usr/local/bin/compose-dirs start
rm -rf "$tmpdir"
exit 0
##########