Skip to content

Commit

Permalink
initial script to install root cert into proxied-app container
Browse files Browse the repository at this point in the history
  • Loading branch information
JJ-Author committed Oct 27, 2024
1 parent 28ea2e4 commit b8f1c28
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 29 deletions.
22 changes: 1 addition & 21 deletions tests/transparent-setup/3proxy-Dockerfile-full
Original file line number Diff line number Diff line change
@@ -1,24 +1,4 @@
# 3proxy.full is fully functional 3proxy build based on busibox:glibc
#
#to build:
# docker build -f Dockerfile.full -t 3proxy.full .
#to run:
# by default 3proxy uses safe chroot environment with chroot to /usr/local/3proxy with uid/gid 65535/65535 and expects
# configuration file to be placed in /usr/local/etc/3proxy.
# Paths in configuration file must be relative to /usr/local/3proxy, that is use /logs instead of
# /usr/local/3proxy/logs. nserver in chroot is required for DNS resolution. An example:
#
# echo nserver 8.8.8.8 >/path/to/local/config/directory/3proxy.cfg
# echo proxy -p3129 >>/path/to/local/config/directory/3proxy.cfg
# docker run -p 3129:3129 -v /path/to/local/config/directory:/usr/local/3proxy/conf -name 3proxy.full 3proxy.full
#
# /path/to/local/config/directory in this example must conrain 3proxy.cfg
# if you need 3proxy to be executed without chroot with root permissions, replace /etc/3proxy/3proxy.cfg by e.g. mounting config
# dir to /etc/3proxy ot by providing config file /etc/3proxy/3proxy.cfg
# docker run -p 3129:3129 -v /path/to/local/config/directory:/etc/3proxy -name 3proxy.full 3proxy.full
#
# use "log" without pathname in config to log to stdout.
# plugins are located in /usr/local/3proxy/libexec (/libexec for chroot config).
# modified version of dockerfile from github.com/3proxy/3proxy that works with ubuntu 20.04 docker hosts and installs iptables and ipset

# switched to ubuntu:20.04 to not have problems with apt install on docker hosts with ubuntu 20.04
FROM ubuntu:20.04 AS buildenv
Expand Down
166 changes: 166 additions & 0 deletions tests/transparent-setup/add-cert-pre-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#!/bin/sh
set -e

# Path to the custom root certificate (assumed to be mounted into the container)
CUSTOM_CERT_PATH="/certs/custom_root.crt"

# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}

# Install certificate utilities if not present
install_cert_utilities() {
echo "Checking for certificate utilities and package manager..."

if command_exists apk; then
PM="apk"
INSTALL_CMD="apk add --no-cache"
CERT_PACKAGE="ca-certificates ca-certificates-bundle openssl"

echo "Using apk package manager."
# Install ca-certificates package if not already installed
$INSTALL_CMD $CERT_PACKAGE

elif command_exists apt-get; then
PM="apt-get"
CERT_PACKAGE="ca-certificates openssl"

echo "Using apt-get package manager."
# Update package lists
apt-get update
# Install ca-certificates
apt-get install -y $CERT_PACKAGE

elif command_exists yum; then
PM="yum"
INSTALL_CMD="yum install -y"
CERT_PACKAGE="ca-certificates openssl"

echo "Using yum package manager."
# Install ca-certificates
$INSTALL_CMD $CERT_PACKAGE

elif command_exists dnf; then
PM="dnf"
INSTALL_CMD="dnf install -y"
CERT_PACKAGE="ca-certificates openssl"

echo "Using dnf package manager."
$INSTALL_CMD $CERT_PACKAGE

elif command_exists zypper; then
PM="zypper"
INSTALL_CMD="zypper install -y"
CERT_PACKAGE="ca-certificates openssl"

echo "Using zypper package manager."
$INSTALL_CMD $CERT_PACKAGE

else
echo "No supported package manager found. Cannot install certificate utilities."
exit 1
fi
}

# Install certificate utilities if not already installed
if ! command_exists update-ca-certificates && ! command_exists update-ca-trust; then
install_cert_utilities
else
echo "Certificate utilities already installed."
fi

# Copy the custom certificate into the appropriate directory and update trust store
update_trust_store() {
echo "Updating trust store with custom certificate..."

if [ -f /etc/alpine-release ]; then
# Alpine Linux
echo "Detected Alpine Linux."
cp "$CUSTOM_CERT_PATH" /usr/local/share/ca-certificates/custom_root.crt
update-ca-certificates

elif [ -f /etc/debian_version ]; then
# Debian/Ubuntu
echo "Detected Debian/Ubuntu."
cp "$CUSTOM_CERT_PATH" /usr/local/share/ca-certificates/custom_root.crt
update-ca-certificates

elif [ -f /etc/redhat-release ] || [ -f /etc/centos-release ]; then
# RedHat/CentOS/Fedora
echo "Detected RedHat/CentOS/Fedora."
cp "$CUSTOM_CERT_PATH" /etc/pki/ca-trust/source/anchors/custom_root.crt
update-ca-trust extract

elif [ -f /etc/os-release ]; then
OS_ID=$(grep '^ID=' /etc/os-release | cut -d'=' -f2 | tr -d '"')
case "$OS_ID" in
sles|opensuse*)
echo "Detected SUSE Linux."
cp "$CUSTOM_CERT_PATH" /etc/pki/trust/anchors/custom_root.crt
update-ca-certificates
;;
*)
echo "Unsupported OS detected."
exit 1
;;
esac
else
echo "Cannot detect OS type. Exiting."
exit 1
fi
}

# Update the trust store
update_trust_store

# Check for common runtimes and configure them if needed

configure_java() {
if command_exists java; then
echo "Java runtime detected. Importing custom certificate into Java truststore."

JAVA_HOME=$(dirname $(dirname $(readlink -f $(which java))))
JAVA_CACERTS_PATH="$JAVA_HOME/lib/security/cacerts"
if [ ! -f "$JAVA_CACERTS_PATH" ]; then
echo "Java cacerts file not found at $JAVA_CACERTS_PATH. Skipping Java truststore update."
return
fi

echo "Importing custom certificate into Java cacerts at $JAVA_CACERTS_PATH."
yes | keytool -importcert -trustcacerts -alias custom_root -file "$CUSTOM_CERT_PATH" -keystore "$JAVA_CACERTS_PATH" -storepass changeit || true
fi
}

configure_nodejs() {
if command_exists node; then
echo "Node.js runtime detected. Setting NODE_EXTRA_CA_CERTS environment variable."
export NODE_EXTRA_CA_CERTS="$CUSTOM_CERT_PATH"
fi
}

configure_python() {
if command_exists python || command_exists python3; then
echo "Python runtime detected. Setting SSL_CERT_FILE and REQUESTS_CA_BUNDLE environment variables."
export SSL_CERT_FILE="$CUSTOM_CERT_PATH"
export REQUESTS_CA_BUNDLE="$CUSTOM_CERT_PATH"
fi
}

# Configure runtimes
configure_java
configure_nodejs
configure_python

# Ensure all environment variables are exported
export NODE_EXTRA_CA_CERTS
export SSL_CERT_FILE
export REQUESTS_CA_BUNDLE

# Log environment variables for debugging (optional)
echo "Environment variables set:"
#env | grep -E 'NODE_EXTRA_CA_CERTS|SSL_CERT_FILE|REQUESTS_CA_BUNDLE'

# Execute the original command
echo "Executing original command: $@"
exec "$@"
20 changes: 12 additions & 8 deletions tests/transparent-setup/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: '2.4' #starting from version 3.4, docker-compose supports healthcheck startperiod but only 2.x supports condition: service_healthy
version: '2.4' # only 2.x supports condition: service_health #starting from version 3.4, docker-compose supports healthcheck startperiod
services:

# Example/demo service for which http (port 80) and https (port 443) traffic will be routed transparently through the proxy
Expand All @@ -8,7 +8,12 @@ services:
transparent-proxy:
condition: service_healthy # Ensures transparent-proxy is started and transparent setup via time-machine is working - RECOMMENDED
network_mode: "service:transparent-proxy" # Uses the same network (namespace) of the transparent proxy container to route traffic through it - REQUIRED
entrypoint: ["sh", "-c", "
# template to try to automatically add time-machine CA root certificate to the app container for well-known base images with package managers
volumes:
- ../../ca-cert.pem:/certs/custom_root.crt:ro
- ./add-cert-pre-entrypoint.sh:/usr/local/bin/entrypoint.sh:ro
entrypoint: ["/bin/sh", "/usr/local/bin/entrypoint.sh"]
command: ["sh", "-c", "echo 'Running main application command...' && \
apt-get update && \
apt-get install -y curl raptor2-utils openssl socat && \
curl -I http://example.org && \
Expand Down Expand Up @@ -44,14 +49,17 @@ services:
- my_network
healthcheck:
# test: ["CMD", "sh", "-c", "sleep 3 && curl -If http://1.1.1.1 && curl -Ikf https://1.1.1.1 && sleep 30"] # && curl -x localhost:8011 -If http://1.1.1.1
# test: ["CMD", "sh", "-c", "sleep 5 && curl -If http://1.1.1.1 && curl -Ikf https://1.1.1.1 && ( [ -f /tmp/healthcheck_flag ] && sleep 60 || touch /tmp/healthcheck_flag )"]
test: ["CMD", "sh", "-c", "sleep 5 && curl -If http://1.1.1.1 && curl -Ikf https://1.1.1.1 && ( [ -f /dev/shm/healthcheck_flag ] && sleep 60 || touch /dev/shm/healthcheck_flag )"]
test: ["CMD", "sh", "-c", "sleep 5 && curl -If http://1.1.1.1 && curl -Ikf https://1.1.1.1 && curl -x localhost:8011 -If http://1.1.1.1 && ( [ -f /dev/shm/healthcheck_flag ] && sleep 60 || touch /dev/shm/healthcheck_flag )"]
interval: 1s # in compose 2.4 the first health check waits for the interval time -> make that short and add long sleep to the test command at the end that is only executed after the first health check
timeout: 80s #
retries: 3
# start_period: 5s # Only available in docker-compose version 3.4 and above -> add sleep in front to test cmd instead
entrypoint: ["sh", "-c", "
set -x && \
echo starting 3proxy instance for HTTP_to_HTTP-proxied && \
(/usr/bin/3proxy /etc/3proxy/3proxy-HTTP.cfg &) && \
echo starting 3proxy instance for TLS_to_HTTP-CONNECT-tunnelled && \
(/usr/bin/3proxy /etc/3proxy/3proxy-TLS.cfg &) && \
echo applying iptable transparent redirection rules && \
`# Create an ipset named 'private_ips' for private IP ranges` \
ipset create private_ips hash:net && \
Expand All @@ -64,10 +72,6 @@ services:
`# Redirect HTTPS traffic (port 443) to port 8012, but exclude private IP ranges using ipset` \
iptables -t nat -A OUTPUT -p tcp --dport 443 -m set ! --match-set private_ips dst -j REDIRECT --to-port 8012 && \
iptables -t nat -L -v -n && \
echo starting 3proxy instance for HTTP_to_HTTP-proxied && \
(/usr/bin/3proxy /etc/3proxy/3proxy-HTTP.cfg &) && \
echo starting 3proxy instance for TLS_to_HTTP-CONNECT-tunnelled && \
(/usr/bin/3proxy /etc/3proxy/3proxy-TLS.cfg &) && \
sleep inf"]

networks:
Expand Down

0 comments on commit b8f1c28

Please sign in to comment.