Skip to content

Commit 4733cf8

Browse files
authored
Overhaul container build (#18)
* Use stock Alpine base image * Download nginx using HTTPS * Use a venv * Split complex logic into separate scripts * Fix spnego module build process * General cleanup and optimization
1 parent b77f113 commit 4733cf8

File tree

8 files changed

+193
-117
lines changed

8 files changed

+193
-117
lines changed

Dockerfile

Lines changed: 43 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,60 @@
1-
ARG CONTAINER_VERSION=1.19.2-alpine
1+
FROM quay.io/bedrock/alpine:3.19.1 AS base
22

3-
# builder used to create a dynamic spnego auth module
4-
# https://gist.github.com/hermanbanken/96f0ff298c162a522ddbba44cad31081
5-
FROM nginx:${CONTAINER_VERSION} AS builder
3+
RUN apk add \
4+
nginx \
5+
python3 \
6+
--no-cache
67

7-
ENV SPNEGO_AUTH_COMMIT_ID=72c8ee04c81f929ec84d5a6d126f789b77781a8c
8+
FROM base AS builder
89

9-
RUN set -x && \
10-
NGINX_VERSION="$( nginx -v 2>&1 | awk -F/ '{print $2}' )" && \
11-
NGINX_CONFIG="$( nginx -V 2>&1 | sed -n -e 's/^.*arguments: //p' )" && \
12-
wget "http://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" -O nginx.tar.gz && \
13-
wget https://github.com/stnoonan/spnego-http-auth-nginx-module/archive/${SPNEGO_AUTH_COMMIT_ID}.tar.gz -O spnego-http-auth.tar.gz && \
14-
apk add --no-cache --virtual .build-deps \
10+
RUN apk add \
1511
gcc \
12+
gd-dev \
13+
geoip-dev \
14+
krb5-dev \
1615
libc-dev \
16+
libffi-dev \
17+
libmaxminddb-dev \
18+
libxslt-dev \
19+
linux-headers \
1720
make \
21+
openssl \
22+
openssl-dev \
1823
pcre-dev \
24+
perl-dev \
25+
python3-dev \
1926
zlib-dev \
20-
krb5-dev \
21-
&& \
22-
mkdir /usr/src && \
23-
tar -xzC /usr/src -f nginx.tar.gz && \
24-
tar -xzvf spnego-http-auth.tar.gz && \
25-
SPNEGO_AUTH_DIR="$( pwd )/spnego-http-auth-nginx-module-${SPNEGO_AUTH_COMMIT_ID}" && \
26-
cd "/usr/src/nginx-${NGINX_VERSION}" && \
27-
./configure --with-compat "${NGINX_CONFIG}" --add-dynamic-module="${SPNEGO_AUTH_DIR}" && \
28-
make modules && \
29-
cp objs/ngx_*_module.so /usr/lib
27+
--no-cache
3028

31-
# Create the actual httptester container
32-
FROM nginx:${CONTAINER_VERSION}
29+
COPY extract_nginx_options.py /usr/src/extract_nginx_options.py
30+
COPY build_spnego_module.sh /usr/src/build_spnego_module.sh
3331

34-
ADD constraints.txt /root/constraints.txt
35-
ADD krb5.conf /root/krb5.conf
36-
COPY --from=builder /usr/lib/ngx_*_module.so /usr/lib/nginx/modules/
32+
RUN /usr/src/build_spnego_module.sh
3733

38-
ENV PYTHONDONTWRITEBYTECODE=1
34+
ADD requirements.txt /usr/src/requirements.txt
35+
ADD constraints.txt /usr/src/constraints.txt
3936

40-
# The following packages are required to get httpbin/brotlipy/cffi installed
41-
# openssl-dev python3-dev libffi-dev gcc libstdc++ make musl-dev
42-
# Symlinking /usr/lib/libstdc++.so.6 to /usr/lib/libstdc++.so is specifically required for brotlipy
43-
RUN set -x && \
44-
apk add --no-cache \
45-
ca-certificates \
46-
gcc \
47-
krb5-libs \
48-
krb5-server \
49-
libffi-dev \
50-
libstdc++ \
51-
make \
52-
musl-dev \
53-
openssl \
54-
openssl-dev \
55-
py3-pip \
56-
py3-setuptools \
57-
py3-wheel \
58-
python3-dev \
59-
&& \
60-
update-ca-certificates && \
61-
ln -s /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so && \
62-
mkdir -p /root/ca/certs /root/ca/private /root/ca/newcerts && \
63-
mkdir -p /root/ca2/certs /root/ca2/private /root/ca2/newcerts && \
64-
echo 1000 > /root/ca/serial && \
65-
echo 1000 > /root/ca2/serial && \
66-
touch /root/ca/index.txt && \
67-
touch /root/ca2/index.txt && \
68-
cp /etc/ssl/openssl.cnf /etc/ssl/openssl_ca2.cnf && \
69-
sed -i 's/\.\/demoCA/\/root\/ca/g' /etc/ssl/openssl.cnf && \
70-
sed -i 's/\.\/demoCA/\/root\/ca2/g' /etc/ssl/openssl_ca2.cnf && \
71-
openssl req -new -x509 -days 3650 -nodes -extensions v3_ca -keyout /root/ca/private/cakey.pem -out /root/ca/cacert.pem \
72-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=ansible.http.tests" && \
73-
openssl req -new -x509 -days 3650 -nodes -extensions v3_ca -keyout /root/ca2/private/cakey.pem -out /root/ca2/cacert.pem \
74-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=ca2.ansible.http.tests" && \
75-
openssl req -new -nodes -out /root/ca/ansible.http.tests-req.pem -keyout /root/ca/private/ansible.http.tests-key.pem \
76-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=ansible.http.tests" && \
77-
yes | openssl ca -config /etc/ssl/openssl.cnf -days 3650 -out /root/ca/ansible.http.tests-cert.pem -infiles /root/ca/ansible.http.tests-req.pem && \
78-
openssl req -new -nodes -out /root/ca/sni1.ansible.http.tests-req.pem -keyout /root/ca/private/sni1.ansible.http.tests-key.pem -config /etc/ssl/openssl.cnf \
79-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=sni1.ansible.http.tests" && \
80-
yes | openssl ca -config /etc/ssl/openssl.cnf -days 3650 -out /root/ca/sni1.ansible.http.tests-cert.pem -infiles /root/ca/sni1.ansible.http.tests-req.pem && \
81-
openssl req -new -nodes -out /root/ca/sni2.ansible.http.tests-req.pem -keyout /root/ca/private/sni2.ansible.http.tests-key.pem -config /etc/ssl/openssl.cnf \
82-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=sni2.ansible.http.tests" && \
83-
yes | openssl ca -config /etc/ssl/openssl.cnf -days 3650 -out /root/ca/sni2.ansible.http.tests-cert.pem -infiles /root/ca/sni2.ansible.http.tests-req.pem && \
84-
openssl req -new -nodes -out /root/ca/client.ansible.http.tests-req.pem -keyout /root/ca/private/client.ansible.http.tests-key.pem -config /etc/ssl/openssl.cnf \
85-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=client.ansible.http.tests" && \
86-
yes | openssl ca -config /etc/ssl/openssl.cnf -days 3650 -out /root/ca/client.ansible.http.tests-cert.pem -infiles /root/ca/client.ansible.http.tests-req.pem && \
87-
openssl req -new -nodes -out /root/ca2/self-signed.ansible.http.tests-req.pem -keyout /root/ca2/private/self-signed.ansible.http.tests-key.pem -config /etc/ssl/openssl_ca2.cnf \
88-
-subj "/C=US/ST=North Carolina/L=Durham/O=Ansible/CN=self-signed.ansible.http.tests" && \
89-
yes | openssl ca -config /etc/ssl/openssl_ca2.cnf -days 3650 -out /root/ca2/self-signed.ansible.http.tests-cert.pem -infiles /root/ca2/self-signed.ansible.http.tests-req.pem && \
90-
cp /root/ca/cacert.pem /usr/share/nginx/html/cacert.pem && \
91-
cp /root/ca2/cacert.pem /usr/share/nginx/html/ca2cert.pem && \
92-
cp /root/ca/client.ansible.http.tests-cert.pem /usr/share/nginx/html/client.pem && \
93-
cp /root/ca/private/client.ansible.http.tests-key.pem /usr/share/nginx/html/client.key && \
94-
chmod 644 /usr/share/nginx/html/* && \
95-
pip3 install --no-cache-dir --no-compile -c /root/constraints.txt gunicorn httpbin && \
96-
apk del openssl-dev py3-pip py3-wheel python3-dev libffi-dev gcc libstdc++ make musl-dev && \
97-
rm -rf /root/.cache/pip && \
98-
find /usr/lib/python3.8 -type f -regex ".*\.py[co]" -delete && \
99-
find /usr/lib/python3.8 -type d -name "__pycache__" -delete && \
100-
echo "Microsoft Rulz" > /usr/share/nginx/html/gssapi && \
101-
echo -e "load_module /usr/lib/nginx/modules/ngx_http_auth_spnego_module.so;\n$( cat /etc/nginx/nginx.conf )" > /etc/nginx/nginx.conf && \
102-
cp /root/krb5.conf /etc/krb5.conf && \
103-
PASSWORD="$( < /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c30 )" && \
104-
echo -e "${PASSWORD}\n${PASSWORD}" | /usr/sbin/kdb5_util create -r HTTP.TESTS && \
105-
echo -e "*/[email protected]\t*" > /var/lib/krb5kdc/kadm5.acl && \
106-
kadmin.local -q "addprinc -randkey HTTP/[email protected]" && \
107-
kadmin.local -q "addprinc -randkey HTTP/[email protected]" && \
108-
kadmin.local -q "ktadd -k /etc/nginx.keytab HTTP/[email protected]" && \
109-
kadmin.local -q "ktadd -k /etc/nginx.keytab HTTP/[email protected]" && \
110-
chmod 660 /etc/nginx.keytab && \
111-
chown root:nginx /etc/nginx.keytab
37+
RUN python3 -m venv /usr/share/nginx/venv/
38+
RUN /usr/share/nginx/venv/bin/pip install --no-cache-dir --no-compile -r /usr/src/requirements.txt -c /usr/src/constraints.txt
39+
RUN cd /usr/share/nginx/venv/lib/python*/site-packages/ && rm -rf pip pip-* setuptools setuptools-*
40+
41+
ADD create_certs.sh /usr/src/create_certs.sh
42+
RUN /usr/src/create_certs.sh
43+
44+
FROM base AS output
45+
46+
COPY --from=builder /usr/lib/nginx/modules/ /usr/lib/nginx/modules/
47+
COPY --from=builder /usr/share/nginx/venv/ /usr/share/nginx/venv/
48+
COPY --from=builder /usr/src/nginx.conf /etc/nginx/nginx.conf
49+
COPY --from=builder /root/ca/ /root/ca/
50+
COPY --from=builder /root/ca2/ /root/ca2/
51+
52+
ADD krb5.conf /usr/src/krb5.conf
53+
ADD configure_nginx.sh /usr/src/configure_nginx.sh
54+
RUN /usr/src/configure_nginx.sh
11255

11356
ADD services.sh /services.sh
114-
ADD nginx.sites.conf /etc/nginx/conf.d/default.conf
57+
ADD nginx.sites.conf /etc/nginx/http.d/default.conf
11558

11659
EXPOSE 80 88 443 749
11760

build_spnego_module.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env sh
2+
3+
set -eux
4+
5+
SPNEGO_AUTH_COMMIT_ID="72c8ee04c81f929ec84d5a6d126f789b77781a8c"
6+
NGINX_VERSION="$( nginx -v 2>&1 | awk -F/ '{print $2}' )"
7+
NGINX_CONFIG="$( nginx -V 2>&1 | python3 /usr/src/extract_nginx_options.py )"
8+
NGINX_TAR="nginx.tar.gz"
9+
NGINX_SRC="/usr/src/nginx-${NGINX_VERSION}"
10+
SPNEGO_TAR="spnego-http-auth.tar.gz"
11+
SPNEGO_SRC="/usr/src/spnego-http-auth-nginx-module-${SPNEGO_AUTH_COMMIT_ID}"
12+
MODULE_DIR="/usr/lib/nginx/modules/"
13+
MODULE_NAME="ngx_http_auth_spnego_module.so"
14+
15+
wget "https://nginx.org/download/nginx-${NGINX_VERSION}.tar.gz" -O "${NGINX_TAR}"
16+
wget "https://github.com/stnoonan/spnego-http-auth-nginx-module/archive/${SPNEGO_AUTH_COMMIT_ID}.tar.gz" -O "${SPNEGO_TAR}"
17+
18+
tar -xzC /usr/src -f "${NGINX_TAR}"
19+
tar -xzC /usr/src -f "${SPNEGO_TAR}"
20+
21+
cd "${NGINX_SRC}"
22+
23+
# shellcheck disable=SC2086
24+
./configure ${NGINX_CONFIG} --add-dynamic-module="${SPNEGO_SRC}"
25+
26+
make modules
27+
28+
cp "objs/${MODULE_NAME}" "${MODULE_DIR}"
29+
30+
echo "load_module ${MODULE_DIR}/${MODULE_NAME};" > /usr/src/nginx.conf
31+
32+
cat /etc/nginx/nginx.conf >> /usr/src/nginx.conf

configure_nginx.sh

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env sh
2+
3+
set -eux
4+
5+
apk add \
6+
ca-certificates \
7+
krb5-libs \
8+
krb5-server \
9+
--no-cache
10+
11+
update-ca-certificates
12+
13+
mkdir /usr/share/nginx/html/
14+
15+
cp /usr/src/krb5.conf /etc/krb5.conf
16+
17+
cp /root/ca/cacert.pem /usr/share/nginx/html/cacert.pem
18+
cp /root/ca2/cacert.pem /usr/share/nginx/html/ca2cert.pem
19+
cp /root/ca/client.ansible.http.tests-cert.pem /usr/share/nginx/html/client.pem
20+
cp /root/ca/private/client.ansible.http.tests-key.pem /usr/share/nginx/html/client.key
21+
22+
chmod 644 /usr/share/nginx/html/*
23+
24+
echo "Microsoft Rulz" > /usr/share/nginx/html/gssapi
25+
26+
python3 -c "import secrets; password = secrets.token_hex(30); print(password); print(password);" | /usr/sbin/kdb5_util create -r HTTP.TESTS
27+
python3 -c "print('*/[email protected]\t*')" > /var/lib/krb5kdc/kadm5.acl
28+
29+
kadmin.local -q "addprinc -randkey HTTP/[email protected]"
30+
kadmin.local -q "addprinc -randkey HTTP/[email protected]"
31+
kadmin.local -q "ktadd -k /etc/nginx.keytab HTTP/[email protected]"
32+
kadmin.local -q "ktadd -k /etc/nginx.keytab HTTP/[email protected]"
33+
34+
chmod 660 /etc/nginx.keytab
35+
chown root:nginx /etc/nginx.keytab

constraints.txt

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,24 @@
1-
Flask==1.1.2
2-
Jinja2==2.11.2
3-
MarkupSafe==1.1.1
4-
blinker==1.4
5-
brotlipy==0.7.0
6-
cffi==1.14.3
7-
click==7.1.2
8-
decorator==4.4.2
9-
gunicorn==20.0.4
10-
httpbin==0.7.0
11-
itsdangerous==1.1.0
12-
pycparser==2.20
13-
raven==6.10.0
14-
werkzeug==1.0.1
1+
attrs==23.2.0
2+
blinker==1.8.2
3+
brotlicffi==1.1.0.0
4+
cffi==1.16.0
5+
click==8.1.7
6+
decorator==5.1.1
7+
flasgger==0.9.7.1
8+
Flask==3.0.3
9+
greenlet==2.0.2
10+
gunicorn==22.0.0
11+
httpbin==0.10.2
12+
itsdangerous==2.2.0
13+
Jinja2==3.1.4
14+
jsonschema==4.22.0
15+
jsonschema-specifications==2023.12.1
16+
MarkupSafe==2.1.5
17+
mistune==3.0.2
18+
packaging==24.0
19+
pycparser==2.22
20+
PyYAML==6.0.1
21+
referencing==0.35.1
22+
rpds-py==0.18.1
23+
six==1.16.0
24+
Werkzeug==3.0.3

create_certs.sh

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env sh
2+
3+
set -eux
4+
5+
subj="/C=US/ST=North Carolina/L=Durham/O=Ansible"
6+
days=3650
7+
8+
ca1="/root/ca"
9+
ca2="/root/ca2"
10+
11+
create_ca() {
12+
ca="$1"
13+
name="$2"
14+
15+
mkdir -p "${ca}/certs" "${ca}/private" "${ca}/newcerts"
16+
echo 1000 > "${ca}/serial"
17+
touch "${ca}/index.txt"
18+
sed "s|\./demoCA|${ca}|g" /etc/ssl/openssl.cnf > "${ca}/openssl.cnf"
19+
openssl req -new -x509 -nodes -extensions v3_ca \
20+
-config "${ca}/openssl.cnf" -days "${days}" -subj "${subj}/CN=${name}" -out "${ca}/cacert.pem" -keyout "${ca}/private/cakey.pem"
21+
}
22+
23+
create_cert() {
24+
ca="$1"
25+
name="$2"
26+
27+
openssl req -new -nodes -config "${ca}/openssl.cnf" -subj "${subj}/CN=${name}" -out "${ca}/${name}-req.pem" -keyout "${ca}/private/${name}-key.pem"
28+
yes | openssl ca -config "${ca}/openssl.cnf" -days "${days}" -in "${ca}/${name}-req.pem" -out "${ca}/${name}-cert.pem"
29+
}
30+
31+
create_ca "${ca1}" "ansible.http.tests"
32+
create_ca "${ca2}" "ca2.ansible.http.tests"
33+
34+
create_cert "${ca1}" "ansible.http.tests"
35+
create_cert "${ca1}" "sni1.ansible.http.tests"
36+
create_cert "${ca1}" "sni2.ansible.http.tests"
37+
create_cert "${ca1}" "client.ansible.http.tests"
38+
create_cert "${ca2}" "self-signed.ansible.http.tests"

extract_nginx_options.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import sys
2+
3+
prefix = 'configure arguments: '
4+
5+
for line in sys.stdin:
6+
if line.startswith(prefix):
7+
line = line.removeprefix(prefix)
8+
options = line.split()
9+
options = [option for option in options if not option.startswith('--add-dynamic-module=')]
10+
line = ' '.join(options)
11+
print(line)
12+
break
13+
else:
14+
raise Exception()

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
gunicorn
2+
httpbin

services.sh

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
#!/bin/sh
1+
#!/usr/bin/env sh
22

3-
if [ -z ${KRB5_PASSWORD} ]; then
3+
if [ -z "${KRB5_PASSWORD}" ]; then
44
echo "No KRB5_PASSWORD provided for the admin account."
55
exit 1
66
fi
77

88
kadmin.local -q "addprinc -pw ${KRB5_PASSWORD} admin"
9+
910
/usr/sbin/krb5kdc
10-
gunicorn -D httpbin:app
11+
/usr/share/nginx/venv/bin/gunicorn -D httpbin:app
12+
1113
nginx -g "daemon off;"

0 commit comments

Comments
 (0)