Merge branch 'refact/bash-dockerfile' of ssh://github.com/pratikbin/docker-registry-proxy into HEAD

pull/121/head
git 2022-03-16 01:17:15 +00:00
commit 2a3e6cab5c
4 changed files with 286 additions and 309 deletions

View File

@ -1,16 +1,16 @@
name: test
on:
workflow_dispatch:
pull_request:
branches:
- master
# workflow_dispatch:
# pull_request:
# branches:
# - master
push:
jobs:
sanity-check:
runs-on: ubuntu-latest
steps:
- name: Get machine's first IPv4 address for eth0
id: ip
run: |
@ -25,56 +25,31 @@ jobs:
# We use buildx instead of regular build so we can take advantage of Docker layer cache via Github Actions' cache
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
# Setup the Github Actions cache.
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildxarch-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildxarch-
- name: Build amd64 release image locally to Docker
uses: docker/build-push-action@v2
with:
build-args: |
DEBUG_BUILD=0
BASE_IMAGE_SUFFIX=
builder: ${{ steps.buildx.outputs.name }}
context: .
file: ./Dockerfile
platforms: linux/amd64
tags: sanity-check/docker-registry-proxy:latest
push: false
load: true
cache-from: type=local,src=/tmp/.buildx-cache/release
# this only reads from the cache
cache-from: type=gha
cache-to: type=gha,mode=max # this only reads from the cache
- name: Start proxy instance in docker (ENABLE_MANIFEST_CACHE=false)
run: |
docker run -d --rm --name docker_registry_proxy \
docker run -d --name docker_registry_proxy \
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=false \
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
-v $(pwd)/docker_mirror_certs:/ca \
sanity-check/docker-registry-proxy:latest
- name: Get the initial logs for the container into a file after 10s
run: |
echo "Sleeping 10s..."
sleep 10
docker logs docker_registry_proxy > initial_logs.txt
- name: Upload artifact initial_logs
uses: actions/upload-artifact@v2
with:
name: initial_logs
path: initial_logs.txt
- name: Wait for container to be up
timeout-minutes: 1
timeout-minutes: 2
run: |
declare -i IS_UP=0
while [[ $IS_UP -lt 1 ]]; do
@ -84,14 +59,18 @@ jobs:
done
echo "Container is up..."
- name: Sleep to startup nginx
run: |
echo "Sleeping 10s..."
sleep 20
- name: Grab the CA cert from running container via curl
run: |
curl http://${{ steps.ip.outputs.ETHER }}:3128/ca.crt | sudo tee /usr/share/ca-certificates/docker_registry_proxy.crt
- name: Stop proxy instance in docker
timeout-minutes: 1
run: |
timeout 58 docker stop docker_registry_proxy
docker rm -f docker_registry_proxy
- name: Refresh system-wide CA store
run: |
@ -107,17 +86,14 @@ jobs:
Environment="HTTPS_PROXY=http://${{ steps.ip.outputs.ETHER }}:3128/"
EOD
- name: Reload systemd from disk
- name: Reload systemd from disk & dockerd via systemd
run: |
sudo systemctl daemon-reload
- name: Restart dockerd via systemd
run: |
sudo systemctl restart docker.service
- name: Start proxy instance in docker again (ENABLE_MANIFEST_CACHE=true)
run: |
docker run -d --rm --name docker_registry_proxy \
docker run -d --name docker_registry_proxy \
-p 0.0.0.0:3128:3128 -e ENABLE_MANIFEST_CACHE=true \
-v $(pwd)/docker_mirror_cache:/docker_mirror_cache \
-v $(pwd)/docker_mirror_certs:/ca \
@ -135,49 +111,27 @@ jobs:
echo "Container is up again..."
# This can be quite slow, since Github Actions runner Docker comes preloaded with a lot of images.
- name: Initial prune of all unused images from docker cache (slow)
timeout-minutes: 2
- name: Remove images
run: |
docker image prune --all --force
docker rmi -f alpine:3.6
docker rmi -f k8s.gcr.io/pause:3.3
- name: First round of pulls
timeout-minutes: 2
run: |
docker pull alpine:3.6
docker pull k8s.gcr.io/pause:3.3
- name: Get the cold cache logs for the container into a file
- name: Remove images 2
run: |
docker logs docker_registry_proxy > cold_cache.txt
- name: Upload artifact cold_cache
uses: actions/upload-artifact@v2
with:
name: cold_cache
path: cold_cache.txt
- name: prune all unused images from docker cache again
timeout-minutes: 1
run: |
docker image prune --all --force
docker rmi -f alpine:3.6
docker rmi -f k8s.gcr.io/pause:3.3
- name: sleep 2s to allow cache to stale a bit
run: |
sleep 2
- name: Second round of pulls
timeout-minutes: 2
- name: Get the logs
if: ${{ always() }}
run: |
docker pull alpine:3.6
docker pull k8s.gcr.io/pause:3.3
- name: Get the warm cache docker logs for the container into a file
run: |
docker logs docker_registry_proxy > warm_cache.txt
- name: Upload artifact warm_cache
uses: actions/upload-artifact@v2
with:
name: warm_cache
path: warm_cache.txt
docker logs docker_registry_proxy || true
docker ps -a

View File

@ -47,8 +47,7 @@ ADD nginx.manifest.stale.conf /etc/nginx/nginx.manifest.stale.conf
# Add our very hackish entrypoint and ca-building scripts, make them executable
ADD entrypoint.sh /entrypoint.sh
ADD create_ca_cert.sh /create_ca_cert.sh
RUN chmod +x /create_ca_cert.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Clients should only use 3128, not anything else.
EXPOSE 3128

View File

@ -1,124 +0,0 @@
#! /bin/bash
set -Eeuo pipefail
declare -i DEBUG=0
logInfo() {
echo "INFO: $@"
}
PROJ_NAME=DockerMirrorBox
logInfo "Will create certificate with names $ALLDOMAINS"
CADATE=$(date "+%Y.%m.%d %H:%M")
CAID="$(hostname -f) ${CADATE}"
CN_CA="${PROJ_NAME} CA Root ${CAID}"
CN_IA="${PROJ_NAME} Intermediate IA ${CAID}"
CN_WEB="${PROJ_NAME} Web Cert ${CAID}"
CN_CA=${CN_CA:0:64}
CN_IA=${CN_IA:0:64}
CN_WEB=${CN_WEB:0:64}
mkdir -p /certs /ca
cd /ca
CA_KEY_FILE=${CA_KEY_FILE:-/ca/ca.key}
CA_CRT_FILE=${CA_CRT_FILE:-/ca/ca.crt}
CA_SRL_FILE=${CA_SRL_FILE:-/ca/ca.srl}
if [ -f "$CA_CRT_FILE" ] ; then
logInfo "CA already exists. Good. We'll reuse it."
if [ ! -f "$CA_SRL_FILE" ] ; then
echo 01 > ${CA_SRL_FILE}
fi
else
logInfo "No CA was found. Generating one."
logInfo "*** Please *** make sure to mount /ca as a volume -- if not, everytime this container starts, it will regenerate the CA and nothing will work."
openssl genrsa -des3 -passout pass:foobar -out ${CA_KEY_FILE} 4096
logInfo "generate CA cert with key and self sign it: ${CAID}"
openssl req -new -x509 -days 1300 -sha256 -key ${CA_KEY_FILE} -out ${CA_CRT_FILE} -passin pass:foobar -subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_CA}" -extensions IA -config <(
cat <<-EOF
[req]
distinguished_name = dn
[dn]
[IA]
basicConstraints = critical,CA:TRUE
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
EOF
)
[[ ${DEBUG} -gt 0 ]] && logInfo "show the CA cert details"
[[ ${DEBUG} -gt 0 ]] && openssl x509 -noout -text -in ${CA_CRT_FILE}
echo 01 > ${CA_SRL_FILE}
fi
cd /certs
logInfo "Generate IA key"
openssl genrsa -des3 -passout pass:foobar -out ia.key 4096 &> /dev/null
logInfo "Create a signing request for the IA: ${CAID}"
openssl req -new -key ia.key -out ia.csr -passin pass:foobar -subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_IA}" -reqexts IA -config <(
cat <<-EOF
[req]
distinguished_name = dn
[dn]
[IA]
basicConstraints = critical,CA:TRUE,pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
EOF
)
[[ ${DEBUG} -gt 0 ]] && logInfo "Show the singing request, to make sure extensions are there"
[[ ${DEBUG} -gt 0 ]] && openssl req -in ia.csr -noout -text
logInfo "Sign the IA request with the CA cert and key, producing the IA cert"
openssl x509 -req -days 730 -in ia.csr -CA ${CA_CRT_FILE} -CAkey ${CA_KEY_FILE} -CAserial ${CA_SRL_FILE} -out ia.crt -passin pass:foobar -extensions IA -extfile <(
cat <<-EOF
[req]
distinguished_name = dn
[dn]
[IA]
basicConstraints = critical,CA:TRUE,pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
subjectKeyIdentifier = hash
EOF
) &> /dev/null
[[ ${DEBUG} -gt 0 ]] && logInfo "show the IA cert details"
[[ ${DEBUG} -gt 0 ]] && openssl x509 -noout -text -in ia.crt
logInfo "Initialize the serial number for signed certificates"
echo 01 > ia.srl
logInfo "Create the key (w/o passphrase..)"
openssl genrsa -des3 -passout pass:foobar -out web.orig.key 2048 &> /dev/null
openssl rsa -passin pass:foobar -in web.orig.key -out web.key &> /dev/null
logInfo "Create the signing request, using extensions"
openssl req -new -key web.key -sha256 -out web.csr -passin pass:foobar -subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_WEB}" -reqexts SAN -config <(cat <(printf "[req]\ndistinguished_name = dn\n[dn]\n[SAN]\nsubjectAltName=${ALLDOMAINS}"))
[[ ${DEBUG} -gt 0 ]] && logInfo "Show the singing request, to make sure extensions are there"
[[ ${DEBUG} -gt 0 ]] && openssl req -in web.csr -noout -text
logInfo "Sign the request, using the intermediate cert and key"
openssl x509 -req -days 365 -in web.csr -CA ia.crt -CAkey ia.key -out web.crt -passin pass:foobar -extensions SAN -extfile <(cat <(printf "[req]\ndistinguished_name = dn\n[dn]\n[SAN]\nsubjectAltName=${ALLDOMAINS}")) &> /dev/null
[[ ${DEBUG} -gt 0 ]] && logInfo "Show the final cert details"
[[ ${DEBUG} -gt 0 ]] && openssl x509 -noout -text -in web.crt
logInfo "Concatenating fullchain.pem..."
cat web.crt ia.crt ${CA_CRT_FILE} > fullchain.pem
logInfo "Concatenating fullchain_with_key.pem"
cat fullchain.pem web.key > fullchain_with_key.pem

View File

@ -1,41 +1,188 @@
#! /bin/bash
#!/bin/bash
echo "Entrypoint starting."
set -Eeuo pipefail
trap "echo TRAPed signal" HUP INT QUIT TERM
logInfo() {
echo "INFO: $*"
}
logErr() {
echo "ERR: $*" >&2
}
function creatCa() {
declare -i DEBUG=0
PROJ_NAME=DockerMirrorBox
logInfo "Will create certificate with names ${1}"
CADATE=$(date "+%Y.%m.%d %H:%M")
CAID="$(hostname -f) ${CADATE}"
CN_CA="${PROJ_NAME} CA Root ${CAID}"
CN_IA="${PROJ_NAME} Intermediate IA ${CAID}"
CN_WEB="${PROJ_NAME} Web Cert ${CAID}"
CN_CA=${CN_CA:0:64}
CN_IA=${CN_IA:0:64}
CN_WEB=${CN_WEB:0:64}
mkdir -p /certs /ca
cd /ca
CA_KEY_FILE=${CA_KEY_FILE:-/ca/ca.key}
CA_CRT_FILE=${CA_CRT_FILE:-/ca/ca.crt}
CA_SRL_FILE=${CA_SRL_FILE:-/ca/ca.srl}
if [[ -f "${CA_CRT_FILE}" ]]; then
logInfo "CA already exists. Good. We'll reuse it."
if [[ ! -f "${CA_SRL_FILE}" ]]; then
echo 01 >"${CA_SRL_FILE}"
fi
else
logInfo "No CA was found. Generating one."
logInfo "*** Please *** make sure to mount /ca as a volume -- if not, everytime this container starts, it will regenerate the CA and nothing will work."
openssl genrsa -des3 -passout pass:foobar -out "${CA_KEY_FILE}" 4096
logInfo "generate CA cert with key and self sign it: ${CAID}"
openssl req \
-new \
-x509 \
-days 1300 \
-sha256 \
-key "${CA_KEY_FILE}" \
-out "${CA_CRT_FILE}" \
-passin pass:foobar \
-subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_CA}" \
-extensions IA \
-config <(printf '[req]\ndistinguished_name = dn\n[dn]\n[IA]\nbasicConstraints = critical,CA:TRUE\nkeyUsage = critical, digitalSignature, cRLSign, keyCertSign\nsubjectKeyIdentifier = hash')
if [[ "${DEBUG}" ]]; then
logInfo "show the CA cert details"
openssl x509 -noout -text -in "${CA_CRT_FILE}"
fi
echo 01 >"${CA_SRL_FILE}"
fi
cd /certs
logInfo "Generate IA key"
openssl genrsa -des3 -passout pass:foobar -out ia.key 4096 &>/dev/null
logInfo "Create a signing request for the IA: ${CAID}"
openssl req \
-new \
-key ia.key \
-out ia.csr \
-passin pass:foobar \
-subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_IA}" \
-reqexts IA \
-config <(printf '[req]\ndistinguished_name = dn\n[dn]\n[IA]\nbasicConstraints = critical,CA:TRUE,pathlen:0\nkeyUsage = critical, digitalSignature, cRLSign, keyCertSign\nsubjectKeyIdentifier = hash')
if [[ "${DEBUG}" ]]; then
logInfo "Show the singing request, to make sure extensions are there"
openssl req -in ia.csr -noout -text
fi
logInfo "Sign the IA request with the CA cert and key, producing the IA cert"
openssl x509 \
-req \
-days 730 \
-in ia.csr \
-CA "${CA_CRT_FILE}" \
-CAkey "${CA_KEY_FILE}" \
-CAserial "${CA_SRL_FILE}" \
-out ia.crt \
-passin pass:foobar \
-extensions IA \
-extfile <(printf '[req]\ndistinguished_name = dn\n[dn]\n[IA]\nbasicConstraints = critical,CA:TRUE,pathlen:0\nkeyUsage = critical, digitalSignature, cRLSign, keyCertSign\nsubjectKeyIdentifier = hash') &>/dev/null
if [[ "${DEBUG}" ]]; then
logInfo "show the IA cert details"
openssl x509 -noout -text -in ia.crt
fi
logInfo "Initialize the serial number for signed certificates"
echo 01 >ia.srl
logInfo "Create the key (w/o passphrase..)"
openssl genrsa -des3 -passout pass:foobar -out web.orig.key 2048 &>/dev/null
openssl rsa -passin pass:foobar -in web.orig.key -out web.key &>/dev/null
logInfo "Create the signing request, using extensions"
openssl req \
-new \
-key web.key \
-sha256 \
-out web.csr \
-passin pass:foobar \
-subj "/C=NL/ST=Noord Holland/L=Amsterdam/O=ME/OU=IT/CN=${CN_WEB}" \
-reqexts SAN \
-config <(printf '[req]\ndistinguished_name = dn\n[dn]\n[SAN]\nsubjectAltName=%s' "${1}")
if [[ "${DEBUG}" ]]; then
logInfo "Show the singing request, to make sure extensions are there"
openssl req -in web.csr -noout -text
fi
logInfo "Sign the request, using the intermediate cert and key"
openssl x509 \
-req \
-days 365 \
-in web.csr \
-CA ia.crt \
-CAkey ia.key \
-out web.crt \
-passin pass:foobar \
-extensions SAN \
-extfile <(printf '[req]\ndistinguished_name = dn\n[dn]\n[SAN]\nsubjectAltName=%s' "${1}") &>/dev/null
if [[ "${DEBUG}" ]]; then
logInfo "Show the final cert details"
openssl x509 -noout -text -in web.crt
fi
logInfo "Concatenating fullchain.pem..."
cat web.crt ia.crt "${CA_CRT_FILE}" >fullchain.pem
logInfo "Concatenating fullchain_with_key.pem"
cat fullchain.pem web.key >fullchain_with_key.pem
}
# configure nginx DNS settings to match host, why must we do that nginx?
# this leads to a world of problems. ipv6 format being different, etc.
# below is a collection of hacks contributed over the years.
echo "-- resolv.conf:"
logInfo "-- resolv.conf:"
cat /etc/resolv.conf
echo "-- end resolv"
logInfo "-- end resolv"
# Podman adds a "%3" to the end of the last resolver? I don't get it. Strip it out.
export RESOLVERS=$(cat /etc/resolv.conf | sed -e 's/%3//g' | awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' | sed 's/ *$//g')
if [ "x$RESOLVERS" = "x" ]; then
echo "Warning: unable to determine DNS resolvers for nginx" >&2
RESOLVERS=$(sed -e 's/%3//g' /etc/resolv.conf | awk '$1 == "nameserver" {print ($2 ~ ":")? "["$2"]": $2}' ORS=' ' | sed 's/ *$//g')
if [[ -z "${RESOLVERS}" ]]; then
logErr "Unable to determine DNS resolvers for nginx"
exit 66
fi
echo "DEBUG, determined RESOLVERS from /etc/resolv.conf: '$RESOLVERS'"
logInfo "DEBUG, determined RESOLVERS from /etc/resolv.conf: '${RESOLVERS}'"
conf=""
for ONE_RESOLVER in ${RESOLVERS}; do
echo "Possible resolver: $ONE_RESOLVER"
conf="resolver $ONE_RESOLVER; "
for RESOLVER in ${RESOLVERS}; do
logInfo "Possible resolver: ${RESOLVER}"
conf="resolver ${RESOLVER}; "
done
echo "Final chosen resolver: $conf"
confpath=/etc/nginx/resolvers.conf
if [ ! -e $confpath ]
then
echo "Using auto-determined resolver '$conf' via '$confpath'"
echo "$conf" > $confpath
logInfo "Final chosen resolver: ${conf}"
confpath="/etc/nginx/resolvers.conf"
if [[ ! -f ${confpath} ]]; then
logInfo "Using auto-determined resolver '${conf}' via '${confpath}'"
echo "${conf}" >${confpath}
else
echo "Not using resolver config, keep existing '$confpath' -- mounted by user?"
logInfo "Not using resolver config, keep existing '${confpath}' -- mounted by user?"
fi
# The list of SAN (Subject Alternative Names) for which we will create a TLS certificate.
@ -43,71 +190,74 @@ ALLDOMAINS=""
# Interceptions map, which are the hosts that will be handled by the caching part.
# It should list exactly the same hosts we have created certificates for -- if not, Docker will get TLS errors, of course.
echo -n "" > /etc/nginx/docker.intercept.map
touch /etc/nginx/docker.intercept.map
# Some hosts/registries are always needed, but others can be configured in env var REGISTRIES
for ONEREGISTRYIN in docker.caching.proxy.internal registry-1.docker.io auth.docker.io ${REGISTRIES}; do
ONEREGISTRY=$(echo ${ONEREGISTRYIN} | xargs) # Remove whitespace
echo "Adding certificate for registry: $ONEREGISTRY"
ONEREGISTRY=$(echo "${ONEREGISTRYIN}" | xargs) # Remove whitespace
logInfo "Adding certificate for registry: ${ONEREGISTRY}"
ALLDOMAINS="${ALLDOMAINS},DNS:${ONEREGISTRY}"
echo "${ONEREGISTRY} 127.0.0.1:443;" >> /etc/nginx/docker.intercept.map
echo "${ONEREGISTRY} 127.0.0.1:443;" >>/etc/nginx/docker.intercept.map
done
# Clean the list and generate certificates.
export ALLDOMAINS=${ALLDOMAINS:1} # remove the first comma and export
/create_ca_cert.sh # This uses ALLDOMAINS to generate the certificates.
# export ALLDOMAINS=${ALLDOMAINS:1} # remove the first comma and export
creatCa "${ALLDOMAINS:1}" # This uses ALLDOMAINS to generate the certificates.
# Target host interception. Empty by default. Used to intercept outgoing requests
# from the proxy to the registries.
echo -n "" > /etc/nginx/docker.targetHost.map
touch /etc/nginx/docker.targetHost.map
# Now handle the auth part.
echo -n "" > /etc/nginx/docker.auth.map
touch /etc/nginx/docker.auth.map
# Only configure auth registries if the env var contains values
if [ "$AUTH_REGISTRIES" ]; then
if [[ "${AUTH_REGISTRIES}" ]]; then
# Ref: https://stackoverflow.com/a/47633817/219530
AUTH_REGISTRIES_DELIMITER=${AUTH_REGISTRIES_DELIMITER:-" "}
s=$AUTH_REGISTRIES$AUTH_REGISTRIES_DELIMITER
auth_array=();
while [[ $s ]]; do
auth_array+=( "${s%%"$AUTH_REGISTRIES_DELIMITER"*}" );
s=${s#*"$AUTH_REGISTRIES_DELIMITER"};
s=${AUTH_REGISTRIES}${AUTH_REGISTRIES_DELIMITER}
auth_array=()
while [[ ${s} ]]; do
auth_array+=("${s%%"$AUTH_REGISTRIES_DELIMITER"*}")
s=${s#*"$AUTH_REGISTRIES_DELIMITER"}
done
AUTH_REGISTRY_DELIMITER=${AUTH_REGISTRY_DELIMITER:-":"}
for ONEREGISTRY in "${auth_array[@]}"; do
s=$ONEREGISTRY$AUTH_REGISTRY_DELIMITER
registry_array=();
while [[ $s ]]; do
registry_array+=( "${s%%"$AUTH_REGISTRY_DELIMITER"*}" );
s=${s#*"$AUTH_REGISTRY_DELIMITER"};
s=${ONEREGISTRY}${AUTH_REGISTRY_DELIMITER}
registry_array=()
while [[ ${s} ]]; do
registry_array+=("${s%%"$AUTH_REGISTRY_DELIMITER"*}")
s=${s#*"$AUTH_REGISTRY_DELIMITER"}
done
AUTH_HOST="${registry_array[0]}"
AUTH_USER="${registry_array[1]}"
AUTH_PASS="${registry_array[2]}"
AUTH_BASE64=$(echo -n ${AUTH_USER}:${AUTH_PASS} | base64 -w0 | xargs)
echo "Adding Auth for registry '${AUTH_HOST}' with user '${AUTH_USER}'."
echo "\"${AUTH_HOST}\" \"${AUTH_BASE64}\";" >> /etc/nginx/docker.auth.map
AUTH_BASE64=$(echo -n "${AUTH_USER}:${AUTH_PASS}" | base64 -w0 | xargs)
logInfo "Adding Auth for registry '${AUTH_HOST}' with user '${AUTH_USER}'."
printf '"%s" "%s";' "${AUTH_HOST}" "${AUTH_BASE64}" >>/etc/nginx/docker.auth.map
done
fi
# create default config for the caching layer to listen on 443.
echo " listen 443 ssl default_server;" > /etc/nginx/caching.layer.listen
echo "error_log /var/log/nginx/error.log warn;" > /etc/nginx/error.log.debug.warn
echo " listen 443 ssl default_server;" >/etc/nginx/caching.layer.listen
echo "error_log /var/log/nginx/error.log warn;" >/etc/nginx/error.log.debug.warn
# Set Docker Registry cache size, by default, 32 GB ('32g')
CACHE_MAX_SIZE=${CACHE_MAX_SIZE:-32g}
# The cache directory. This can get huge. Better to use a Docker volume pointing here!
# Set to 32gb which should be enough
echo "proxy_cache_path /docker_mirror_cache levels=1:2 max_size=$CACHE_MAX_SIZE inactive=60d keys_zone=cache:10m use_temp_path=off;" > /etc/nginx/conf.d/cache_max_size.conf
echo "proxy_cache_path /docker_mirror_cache levels=1:2 max_size=${CACHE_MAX_SIZE} inactive=60d keys_zone=cache:10m use_temp_path=off;" >/etc/nginx/conf.d/cache_max_size.conf
# Manifest caching configuration. We generate config based on the environment vars.
echo -n "" >/etc/nginx/nginx.manifest.caching.config.conf
touch /etc/nginx/nginx.manifest.caching.config.conf
[[ "a${ENABLE_MANIFEST_CACHE}" == "atrue" ]] && [[ "a${MANIFEST_CACHE_PRIMARY_REGEX}" != "a" ]] && cat <<EOD >>/etc/nginx/nginx.manifest.caching.config.conf
if [[ "${ENABLE_MANIFEST_CACHE}" == true ]]; then
if [[ -n "${MANIFEST_CACHE_PRIMARY_REGEX}" ]]; then
cat >>/etc/nginx/nginx.manifest.caching.config.conf <<EOD
# First tier caching of manifests; configure via MANIFEST_CACHE_PRIMARY_REGEX and MANIFEST_CACHE_PRIMARY_TIME
location ~ ^/v2/(.*)/manifests/${MANIFEST_CACHE_PRIMARY_REGEX} {
set \$docker_proxy_request_type "manifest-primary";
@ -115,8 +265,9 @@ echo -n "" >/etc/nginx/nginx.manifest.caching.config.conf
include "/etc/nginx/nginx.manifest.stale.conf";
}
EOD
[[ "a${ENABLE_MANIFEST_CACHE}" == "atrue" ]] && [[ "a${MANIFEST_CACHE_SECONDARY_REGEX}" != "a" ]] && cat <<EOD >>/etc/nginx/nginx.manifest.caching.config.conf
fi
if [[ -n "${MANIFEST_CACHE_SECONDARY_REGEX}" ]]; then
cat >>/etc/nginx/nginx.manifest.caching.config.conf <<EOD
# Secondary tier caching of manifests; configure via MANIFEST_CACHE_SECONDARY_REGEX and MANIFEST_CACHE_SECONDARY_TIME
location ~ ^/v2/(.*)/manifests/${MANIFEST_CACHE_SECONDARY_REGEX} {
set \$docker_proxy_request_type "manifest-secondary";
@ -124,8 +275,8 @@ EOD
include "/etc/nginx/nginx.manifest.stale.conf";
}
EOD
[[ "a${ENABLE_MANIFEST_CACHE}" == "atrue" ]] && cat <<EOD >>/etc/nginx/nginx.manifest.caching.config.conf
fi
cat >>/etc/nginx/nginx.manifest.caching.config.conf <<EOD
# Default tier caching for manifests. Caches for ${MANIFEST_CACHE_DEFAULT_TIME} (from MANIFEST_CACHE_DEFAULT_TIME)
location ~ ^/v2/(.*)/manifests/ {
set \$docker_proxy_request_type "manifest-default";
@ -133,8 +284,8 @@ EOD
include "/etc/nginx/nginx.manifest.stale.conf";
}
EOD
[[ "a${ENABLE_MANIFEST_CACHE}" != "atrue" ]] && cat <<EOD >>/etc/nginx/nginx.manifest.caching.config.conf
else
cat >>/etc/nginx/nginx.manifest.caching.config.conf <<EOD
# Manifest caching is disabled. Enable it with ENABLE_MANIFEST_CACHE=true
location ~ ^/v2/(.*)/manifests/ {
set \$docker_proxy_request_type "manifest-default-disabled";
@ -142,13 +293,14 @@ EOD
include "/etc/nginx/nginx.manifest.stale.conf";
}
EOD
fi
echo -e "\nManifest caching config: ---\n"
logInfo "Manifest caching config: ---"
cat /etc/nginx/nginx.manifest.caching.config.conf
echo "---"
logInfo "---"
if [[ "a${ALLOW_PUSH}" == "atrue" ]]; then
cat <<EOF > /etc/nginx/conf.d/allowed.methods.conf
if [[ "${ALLOW_PUSH}" == true ]]; then
cat <<EOF >/etc/nginx/conf.d/allowed.methods.conf
# allow to upload big layers
client_max_body_size 0;
@ -156,7 +308,7 @@ if [[ "a${ALLOW_PUSH}" == "atrue" ]]; then
proxy_cache_methods GET;
EOF
else
cat << 'EOF' > /etc/nginx/conf.d/allowed.methods.conf
cat <<'EOF' >/etc/nginx/conf.d/allowed.methods.conf
# Block POST/PUT/DELETE. Don't use this proxy for pushing.
if ($request_method = POST) {
return 405 "POST method is not allowed";
@ -173,35 +325,35 @@ fi
# normally use non-debug version of nginx
NGINX_BIN="/usr/sbin/nginx"
if [[ "a${DEBUG}" == "atrue" ]]; then
if [[ "${DEBUG}" == true ]]; then
if [[ ! -f /usr/bin/mitmweb ]]; then
echo "To debug, you need the -debug version of this image, eg: :latest-debug"
logErr "To debug, you need the -debug version of this image, eg: :latest-debug"
exit 3
fi
# in debug mode, change caching layer to listen on 444, so that mitmproxy can sit in the middle.
echo " listen 444 ssl default_server;" > /etc/nginx/caching.layer.listen
echo " listen 444 ssl default_server;" >/etc/nginx/caching.layer.listen
echo "Starting in DEBUG MODE (mitmproxy)." >&2
echo "Run mitmproxy with reverse pointing to the same certs..."
logErr "Starting in DEBUG MODE (mitmproxy)."
logInfo "Run mitmproxy with reverse pointing to the same certs..."
mitmweb --no-web-open-browser --set web_host=0.0.0.0 --set confdir=~/.mitmproxy-incoming \
--set termlog_verbosity=error --set stream_large_bodies=128k --web-port 8081 \
--set keep_host_header=true --set ssl_insecure=true \
--mode reverse:https://127.0.0.1:444 --listen-host 0.0.0.0 \
--listen-port 443 --certs /certs/fullchain_with_key.pem &
echo "Access mitmweb via http://127.0.0.1:8081/ "
logInfo "Access mitmweb via http://127.0.0.1:8081/ "
fi
if [[ "a${DEBUG_HUB}" == "atrue" ]]; then
if [[ "${DEBUG_HUB}" == true ]]; then
if [[ ! -f /usr/bin/mitmweb ]]; then
echo "To debug, you need the -debug version of this image, eg: :latest-debug"
logErr "To debug, you need the -debug version of this image, eg: :latest-debug"
exit 3
fi
# in debug hub mode, we remap targetHost to point to mitmproxy below
echo "\"registry-1.docker.io\" \"127.0.0.1:445\";" > /etc/nginx/docker.targetHost.map
echo '"registry-1.docker.io" "127.0.0.1:445";' >/etc/nginx/docker.targetHost.map
echo "Debugging outgoing DockerHub connections via mitmproxy on 8082." >&2
logErr "Debugging outgoing DockerHub connections via mitmproxy on 8082."
# this one has keep_host_header=false so we don't need to modify nginx config
mitmweb --no-web-open-browser --set web_host=0.0.0.0 --set confdir=~/.mitmproxy-outgoing-hub \
--set termlog_verbosity=error --set stream_large_bodies=128k --web-port 8082 \
@ -209,27 +361,23 @@ if [[ "a${DEBUG_HUB}" == "atrue" ]]; then
--mode reverse:https://registry-1.docker.io --listen-host 0.0.0.0 \
--listen-port 445 --certs /certs/fullchain_with_key.pem &
echo "Warning, DockerHub outgoing debugging disables upstream SSL verification for all upstreams." >&2
logErr "Warning, DockerHub outgoing debugging disables upstream SSL verification for all upstreams."
VERIFY_SSL=false
echo "Access mitmweb for outgoing DockerHub requests via http://127.0.0.1:8082/ "
fi
if [[ "a${DEBUG_NGINX}" == "atrue" ]]; then
logInfo "Access mitmweb for outgoing DockerHub requests via http://127.0.0.1:8082/"
if [[ ! -f /usr/sbin/nginx-debug ]]; then
echo "To debug, you need the -debug version of this image, eg: :latest-debug"
logErr "To debug, you need the -debug version of this image, eg: :latest-debug"
exit 4
fi
echo "Starting in DEBUG MODE (nginx)."
echo "error_log /var/log/nginx/error.log debug;" > /etc/nginx/error.log.debug.warn
logInfo "Starting in DEBUG MODE (nginx)."
echo "error_log /var/log/nginx/error.log debug;" >/etc/nginx/error.log.debug.warn
# use debug binary
NGINX_BIN="/usr/sbin/nginx-debug"
fi
# Timeout configurations
echo "" > /etc/nginx/nginx.timeouts.config.conf
touch /etc/nginx/nginx.timeouts.config.conf
cat <<EOD >>/etc/nginx/nginx.timeouts.config.conf
# Timeouts
@ -250,9 +398,9 @@ cat <<EOD >>/etc/nginx/nginx.timeouts.config.conf
proxy_connect_send_timeout ${PROXY_CONNECT_SEND_TIMEOUT};
EOD
echo -e "\nTimeout configs: ---"
logInfo "Timeout configs: ---"
cat /etc/nginx/nginx.timeouts.config.conf
echo -e "---\n"
logInfo "---"
# Request buffering
echo "" > /etc/nginx/proxy.request.buffering.conf
@ -269,9 +417,9 @@ cat /etc/nginx/proxy.request.buffering.conf
echo -e "---\n"
# Upstream SSL verification.
echo "" > /etc/nginx/docker.verify.ssl.conf
if [[ "a${VERIFY_SSL}" == "atrue" ]]; then
cat << EOD > /etc/nginx/docker.verify.ssl.conf
touch /etc/nginx/docker.verify.ssl.conf
if [[ "${VERIFY_SSL}" == true ]]; then
cat <<EOD >/etc/nginx/docker.verify.ssl.conf
# We actually wanna be secure and avoid mitm attacks.
# Fitting, since this whole thing is a mitm...
# We'll accept any cert signed by a CA trusted by Mozilla (ca-certificates-bundle in alpine)
@ -279,13 +427,13 @@ if [[ "a${VERIFY_SSL}" == "atrue" ]]; then
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
proxy_ssl_verify_depth 2;
EOD
echo "Upstream SSL certificate verification enabled."
logInfo "Upstream SSL certificate verification enabled."
else
echo "Upstream SSL certificate verification is DISABLED."
logInfo "Upstream SSL certificate verification is DISABLED."
fi
echo "Testing nginx config..."
logInfo "Testing nginx config..."
${NGINX_BIN} -t
echo "Starting nginx! Have a nice day."
logInfo "Starting nginx! Have a nice day."
${NGINX_BIN} -g "daemon off;"