Last active
July 8, 2022 02:09
-
-
Save qguv/850bba7b9b1c4170e28044a0b6f72307 to your computer and use it in GitHub Desktop.
Prepare LXD container which can only access the internet through an http proxy (uses tinyproxy and firewalld). Written for Fedora 31, but will probably work elsewhere too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
create_container="${create_container:-true}" | |
lxd_bridge="${lxd_bridge:-lxdbr0}" | |
container_image="${container_image:-images:debian/8/amd64}" | |
container_name="${container_name:-onpremise-proxy-test}" | |
tinyproxy_conf="${tinyproxy_conf:-/etc/tinyproxy/tinyproxy.conf}" | |
sudo_conf="${sudo_conf:-/etc/sudoers.d/client}" | |
apt_conf="${apt_conf:-/etc/apt/apt.conf.d/proxy.conf}" | |
# don't configure apt for centos containers | |
case "$container_image" in *centos*) apt_conf=;; esac | |
# check that preconditions are met | |
if [ "$UID" -eq 0 ]; then | |
echo 'This must not be run as root!' | |
exit 16 | |
elif ! lxc version >/dev/null; then | |
echo 'LXD must be installed!' | |
exit 17 | |
elif ! sudo firewall-cmd --version >/dev/null; then | |
echo 'firewalld must be installed!' | |
exit 18 | |
elif ! sudo systemctl is-active firewalld >/dev/null; then | |
echo 'firewalld must be running!' | |
exit 19 | |
elif ! sudo tinyproxy -v >/dev/null; then | |
echo 'tinyproxy must be installed!' | |
exit 20 | |
elif [ "$create_container" = true ] && lxc info "$container_name" >/dev/null; then | |
printf '[ERROR] Container "%s" already exists!\n' "$container_name" | |
printf 'Hint: either tell this script to use the existing container:\n\tcreate_container=false %s\n\n' "$0 $@" | |
printf 'or delete the container with:\n\tlxc delete --force "%s"\n\nbefore re-running this script.\n' "$container_name" | |
exit 21 | |
fi | |
printf 'Getting lxd bridge interface subnet... ' | |
lxd_route="$(ip route | grep lxdbr0)" | |
if [ -z "$lxd_route" ]; then | |
printf 'No lxd bridge interface found at %s!\n' "$lxd_bridge" | |
exit 22 | |
fi | |
lxd_subnet="${lxd_route%% *}" | |
printf 'got %s\n' "$lxd_subnet" | |
printf 'Getting tinyproxy port... ' | |
tinyproxy_port="$(sed -n 's/^\s*Port\s\+\([0-9]\+\)\s*$/\1/p' "$tinyproxy_conf")" | |
tinyproxy_port="${tinyproxy_port:-8888}" | |
printf 'got %s\n' "$tinyproxy_port" | |
printf 'Configuring tinyproxy to allow connections from lxd subnet %s... ' "$lxd_subnet" | |
if grep --quiet --line-regexp --fixed-strings "Allow $lxd_subnet" "$tinyproxy_conf"; then | |
echo already ok | |
else | |
sudo tee -a "$tinyproxy_conf" >/dev/null <<-EOF | |
Allow $lxd_subnet | |
EOF | |
echo added ok | |
fi | |
printf 'Restarting tinyproxy... ' | |
sudo systemctl restart tinyproxy | |
echo ok | |
printf 'Disabling lxc network and firewall... ' | |
lxc network set lxdbr0 ipv4.nat false | |
lxc network set lxdbr0 ipv6.nat false | |
lxc network set lxdbr0 ipv6.firewall false | |
lxc network set lxdbr0 ipv4.firewall false | |
echo ok | |
printf '\nConfiguring firewalld to serve as firewall and NAT for lxd containers... \n' | |
( | |
set -v | |
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 -i "$lxd_bridge" -s "$lxd_subnet" -m comment --comment "generated by firewalld for LXD" -j ACCEPT | |
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter OUTPUT 0 -o "$lxd_bridge" -d "$lxd_subnet" -m comment --comment "generated by firewalld for LXD" -j ACCEPT | |
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i "$lxd_bridge" -s "$lxd_subnet" -m comment --comment "generated by firewalld for LXD" -j ACCEPT | |
sudo firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 -s "$lxd_subnet" ! -d "$lxd_subnet" -m comment --comment "generated by firewalld for LXD" -j MASQUERADE | |
sudo firewall-cmd --reload | |
) | |
printf 'Finished configuring firewalld\n\n' | |
if [ "$create_container" = true ]; then | |
printf 'Creating a new container...\n' | |
( | |
set -v | |
lxc init "$container_image" "$container_name" | |
lxc config set "$container_name" security.privileged true | |
lxc start "$container_name" >/dev/null || true | |
) | |
printf 'Finished creating a new container\n\n' | |
fi | |
printf 'Waiting for container IP... ' | |
while | |
container_ip="$(lxc info "$container_name" | grep 'eth0:\sinet\s' | cut -f3)" | |
[ -z "$container_ip" ] | |
do | |
sleep 1 | |
done | |
printf 'got %s\n' "$container_ip" | |
printf 'Getting interface ip... ' | |
interface_ip="$(ip route get "$container_ip" | sed -n 's/.*src \(\S\+\).*/\1/p')" | |
printf 'got %s\n' "$interface_ip" | |
proxy_url="http://$interface_ip:$tinyproxy_port" | |
printf '\nConfiguring http proxy for new container...\n' | |
lxc exec "$container_name" -- tee -a /etc/environment <<-EOF | |
HTTP_PROXY='$proxy_url' | |
HTTPS_PROXY='$proxy_url' | |
FTP_PROXY='$proxy_url' | |
NO_PROXY='localhost,127.0.0.1,$interface_ip' | |
http_proxy='$proxy_url' | |
https_proxy='$proxy_url' | |
ftp_proxy='$proxy_url' | |
no_proxy='localhost,127.0.0.1,$interface_ip' | |
EOF | |
printf 'Finished configuring http proxy for new container\n\n' | |
printf 'Configuring sudo to propagate proxy env variables... ' | |
lxc exec "$container_name" -- sh <<-EOF | |
sudo_dir="\$(dirname "$sudo_conf")" | |
[ -d "\$sudo_dir" ] || mkdir -p "\$sudo_dir" | |
EOF | |
sudo_defaults='Defaults env_keep = "HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY http_proxy https_proxy ftp_proxy no_proxy"' | |
if lxc exec "$container_name" -- cat "$sudo_conf" 2>/dev/null | grep --quiet --line-regexp --fixed-strings "$sudo_defaults"; then | |
echo already ok | |
else | |
printf '%s\n' "$sudo_defaults" | lxc exec "$container_name" -- tee -a "$sudo_conf" >/dev/null | |
echo added ok | |
fi | |
if [ -n "$apt_conf" ]; then | |
printf 'Configuring apt to use http proxy... ' | |
if lxc exec "$container_name" -- cat "$apt_conf" 2>/dev/null | grep --quiet --line-regexp --fixed-strings 'Acquire::http::Proxy "'"$proxy_url"'";'; then | |
echo already ok | |
else | |
lxc exec "$container_name" -- tee -a "$apt_conf" >/dev/null <<-EOF | |
Acquire::http::Proxy "$proxy_url"; | |
Acquire::https::Proxy "$proxy_url"; | |
EOF | |
echo added ok | |
fi | |
fi | |
printf 'Removing direct route to internet for new container... ' | |
if lxc exec "$container_name" -- ip route show default | grep --quiet '^default'; then | |
lxc exec "$container_name" ip route delete default | |
echo ok | |
else | |
echo already ok | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment