Skip to content

Commit

Permalink
Merge pull request #12 from qpoint-io/marc-barry/refactor
Browse files Browse the repository at this point in the history
Rename to kubernetes-qpoint-init, add docs and support IPv4 and IPv6.
  • Loading branch information
marc-barry authored Jun 21, 2024
2 parents 2341a3e + 424d7eb commit bc410cf
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init
images: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qpoint-init
tags: |
type=sha
type=raw,value=branch-${{ env.REF_NAME }},enable=${{ env.REF_NAME != 'main' }}
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM alpine:3.18
FROM alpine:3.20

RUN apk add --no-cache bash bind-tools iptables && rm -rf /var/cache/apk/*

Expand Down
39 changes: 35 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
# kubernetes-qtap-init
# kubernetes-qpoint-init

A Kubernetes init container for transparently routing traffic.

## Overview

The container makes use of `iptables` and puts in place rules which selectively route traffic egressing the pod to a destination which is configurable.

The container makes use of the following concepts:

- `ACCEPT_UIDS` and `ACCEPT_GIDS`
- Any user IDs or group IDs in these lists jump directly to the `ACCEPT` target.
- `TO_IPV4_ADDR`
- Optional to IPv4 address which jumps to the `DNAT` target. If not provided a `REDIRECT` target is assumed.
- `TO_IPV6_ADDR`
- Optional to IPv6 address which jumps to the `DNAT` target. If not provided a `REDIRECT` target is assumed.
- `TO_DOMAIN`
- Optional domain which is used to perform address resolution for both IPv4 and IPv6 addresses.
- `PORT_MAPPING`
- Optional port mapping of the form `<to_port>:<destination_port>`. The `to_port` is the port for which a jump to `DNAT` or `REDIRECT` is performed (i.e. use in `--to-destination` or `-to-port` arguments.) The `destination_port` is the port for which the `--dport` argument is set. If just `<to_port>` is provided all ports will be impacted.
- `IPV4_ACCEPT_BLOCKS`
- Optional list of IPv4 address blocks for which a jump to `ACCEPT` should be added. This would generally include addresses such as `"127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Loopback and RFC 1918 address blocks`.
- `IPV6_ACCEPT_BLOCKS`
- Optional list of IPv6 address blocks for which a jump to `ACCEPT` should be added. This would generally include addresses such as `"::1/128,fc00::/7" # Loopback and Unique Local Addresses (ULA)`.

A set of defaults are defined which are:

```sh
# Default values for ACCEPT_UIDS and ACCEPT_GIDS
DEFAULT_ACCEPT_UIDS="1010" # Default UID of Qpoint
DEFAULT_ACCEPT_GIDS="1010" # Default GID of Qpoint
DEFAULT_PORT_MAPPING="10080:80,10443:443"
DEFAULT_IPV4_ACCEPT_BLOCKS="127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Loopback and RFC 1918 address blocks
DEFAULT_IPV6_ACCEPT_BLOCKS="::1/128,fc00::/7" # Loopback and Unique Local Addresses (ULA)
```

## Usage

The rules being set can be tested in a local Docker container by running the following:

```sh
docker run \
--cap-add NET_ADMIN \
-e DESTINATION_PORTS="443,80,8080" \
-e TO_PORT="10000" \
-e PORT_MAPPING="10080:80,10443:443" \
-e ACCEPT_UIDS="0,1000" \
-e ACCEPT_GIDS="0,1000" \
us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init:<TAG>
us-docker.pkg.dev/qpoint-edge/public/kubernetes-qpoint-init:<TAG>
```

The above will redirect destination ports within the container (or Kubernetes pod) to a local destination port. A list of UIDs and GIDs can be provided to excluded from the redirection.
Expand Down
78 changes: 56 additions & 22 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,73 @@

set -e

# Function to resolve domain to IP
resolve_domain_to_ip() {
# Function to resolve domain to IPv4
resolve_domain_to_ipv4() {
local domain=$1
local ip

ip=$(dig +short "$domain" | head -n 1)
if [[ -z "$ip" ]]; then
echo "Error: Failed to resolve domain $domain"
exit 1
# If there are multiple addresses returned, the first address is selected
ip=$(dig +short A "$domain" | head -n 1)
if [[ -n "$ip" ]]; then
echo "$ip"
fi

echo "$ip"
echo ""
}

# If provided resolve TO_DOMAIN to IP and set it to TO_ADDR
# Function to resolve domain to IPv6
resolve_domain_to_ipv6() {
local domain=$1
local ip

# If there are multiple addresses returned, the first address is selected
ip=$(dig +short AAAA "$domain" | head -n 1)
if [[ -n "$ip" ]]; then
echo "[$ip]"
fi

echo ""
}

TO_IPV4_ADDR=""
TO_IPV6_ADDR=""

# If provided, resolve TO_DOMAIN to IP and set it to TO_IPV4_ADDR and TO_IPV6_ADDR
if [[ -n "$TO_DOMAIN" ]]; then
TO_ADDR=$(resolve_domain_to_ip "$TO_DOMAIN")
echo "Resolving $TO_DOMAIN"
TO_IPV4_ADDR=$(resolve_domain_to_ipv4 "$TO_DOMAIN")
echo "IPv4: $TO_IPV4_ADDR"
TO_IPV6_ADDR=$(resolve_domain_to_ipv6 "$TO_DOMAIN")
echo "IPv6: $TO_IPV6_ADDR"
fi

# Default values for ACCEPT_UIDS and ACCEPT_GIDS
DEFAULT_ACCEPT_UIDS="1010" # Default UID of Qtap
DEFAULT_ACCEPT_GIDS="1010" # Default GID of Qtap
DEFAULT_PORT_MAPPING="10080:80,10443:443,10000:"
DEFAULT_ACCEPT_BLOCKS="127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # loopback and RFC 1918 address blocks
DEFAULT_ACCEPT_UIDS="1010" # Default UID of Qpoint
DEFAULT_ACCEPT_GIDS="1010" # Default GID of Qpoint
DEFAULT_PORT_MAPPING="10080:80,10443:443"
DEFAULT_IPV4_ACCEPT_BLOCKS="127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16" # Loopback and RFC 1918 address blocks
DEFAULT_IPV6_ACCEPT_BLOCKS="::1/128,fc00::/7" # Loopback and Unique Local Addresses (ULA)

# Set default values if they are not provided
ACCEPT_UIDS="${ACCEPT_UIDS:-$DEFAULT_ACCEPT_UIDS}"
ACCEPT_GIDS="${ACCEPT_GIDS:-$DEFAULT_ACCEPT_GIDS}"
PORT_MAPPING="${PORT_MAPPING:-$DEFAULT_PORT_MAPPING}"
ACCEPT_BLOCKS="${ACCEPT_BLOCKS:-$DEFAULT_ACCEPT_BLOCKS}"
IPV4_ACCEPT_BLOCKS="${ACCEPT_BLOCKS:-$DEFAULT_IPV4_ACCEPT_BLOCKS}"
IPV6_ACCEPT_BLOCKS="${ACCEPT_BLOCKS:-$DEFAULT_IPV6_ACCEPT_BLOCKS}"

echo "----->"
echo "ACCEPT_UIDS: $ACCEPT_UIDS"
echo "ACCEPT_GIDS: $ACCEPT_GIDS"
echo "PORT_MAPPING: $PORT_MAPPING"
echo "ACCEPT_BLOCKS: $ACCEPT_BLOCKS"
echo "IPV4_ACCEPT_BLOCKS: $IPV4_ACCEPT_BLOCKS"
echo "IPV6_ACCEPT_BLOCKS: $IPV6_ACCEPT_BLOCKS"
echo "<-----"

apply_rules() {
local TO_PORT="$1"
local DEST_PORT="$2"
local iptables_cmd="$3"
local TO_ADDR="$4"

local PORT_SPECIFIER=""
if [[ -n "$DEST_PORT" ]]; then
Expand All @@ -52,37 +78,45 @@ apply_rules() {
# Apply rules for UIDs
IFS=',' read -ra UIDS <<< "$ACCEPT_UIDS"
for USER_ID in "${UIDS[@]}"; do
iptables -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -m owner --uid-owner "$USER_ID" -j ACCEPT
$iptables_cmd -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -m owner --uid-owner "$USER_ID" -j ACCEPT
done

# Apply rules for GIDs
IFS=',' read -ra GIDS <<< "$ACCEPT_GIDS"
for GROUP_ID in "${GIDS[@]}"; do
iptables -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -m owner --gid-owner "$GROUP_ID" -j ACCEPT
$iptables_cmd -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -m owner --gid-owner "$GROUP_ID" -j ACCEPT
done

# Apply redirect or DNAT rule
if [[ -n "$TO_ADDR" ]]; then
iptables -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -j DNAT --to-destination "$TO_ADDR:$TO_PORT"
$iptables_cmd -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -j DNAT --to-destination "$TO_ADDR:$TO_PORT"
else
iptables -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -j REDIRECT --to-port "$TO_PORT"
$iptables_cmd -t nat -A OUTPUT -p tcp $PORT_SPECIFIER -j REDIRECT --to-port "$TO_PORT"
fi
}

# Apply rules for each block
IFS=',' read -ra BLOCKS <<< "$ACCEPT_BLOCKS"
# Apply IPv4 rules for each block
IFS=',' read -ra BLOCKS <<< "$IPV4_ACCEPT_BLOCKS"
for BLOCK in "${BLOCKS[@]}"; do
iptables -t nat -A OUTPUT -p tcp -d "$BLOCK" -j ACCEPT
done

# Apply IPv6 rules for each block
IFS=',' read -ra BLOCKS <<< "$IPV6_ACCEPT_BLOCKS"
for BLOCK in "${BLOCKS[@]}"; do
ip6tables -t nat -A OUTPUT -p tcp -d "$BLOCK" -j ACCEPT
done

IFS=',' read -ra MAPPINGS <<< "$PORT_MAPPING"
for MAPPING in "${MAPPINGS[@]}"; do
IFS=':' read -ra PORTS <<< "$MAPPING"
TO_PORT="${PORTS[0]}"
DEST_PORT="${PORTS[1]}"

apply_rules "$TO_PORT" "$DEST_PORT"
apply_rules "$TO_PORT" "$DEST_PORT" "iptables" "$TO_IPV4_ADDR"
apply_rules "$TO_PORT" "$DEST_PORT" "ip6tables" "$TO_IPV6_ADDR"
done

# Ensure the rules are set
iptables -t nat -L -n -v
ip6tables -t nat -L -n -v
14 changes: 6 additions & 8 deletions example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,17 @@ metadata:
name: relayed-pod
spec:
initContainers:
- name: qtap-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init:sha-b2640d3
- name: qpoint-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qpoint-init:<SHA>
env:
- name: DESTINATION_PORTS
value: "443"
- name: TO_ADDR
value: "192.168.194.219"
- name: TO_PORT
value: "10000"
- name: PORT_MAPPING
value: "10080:80,10443:443"
- name: ACCEPT_UIDS
value: "0"
- name: ACCEPT_GIDS
value: "0"
- name: TO_DOMAIN
value: "api.qpoint.io"
securityContext:
capabilities:
add:
Expand Down
16 changes: 9 additions & 7 deletions example1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@ metadata:
name: relayed-pod
spec:
initContainers:
- name: qtap-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init:<SHA>
- name: qpoint-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qpoint-init:<SHA>
env:
- name: DESTINATION_PORTS
value: "443"
- name: TO_ADDR
value: "192.168.194.219"
- name: TO_PORT
value: "10000"
value: "192.168.1.1"
- name: PORT_MAPPING
value: "10080:80,10443:443"
- name: ACCEPT_UIDS
value: "0"
- name: ACCEPT_GIDS
value: "0"
securityContext:
capabilities:
add:
Expand Down
13 changes: 7 additions & 6 deletions example2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ metadata:
name: relayed-pod
spec:
initContainers:
- name: qtap-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qtap-init:<SHA>
- name: qpoint-init
image: us-docker.pkg.dev/qpoint-edge/public/kubernetes-qpoint-init:<SHA>
securityContext:
capabilities:
add:
Expand All @@ -27,11 +27,12 @@ spec:
- name: proxy
image: us-docker.pkg.dev/qpoint-edge/public/qtap:<SHA>
ports:
- containerPort: 10000
- containerPort: 10080
- containerPort: 10443
command: ["qtap"]
args: ["gateway", "--no-hot-restart"]
- containerPort: 18080
- containerPort: 18443
command: ["qpoint"]
args: ["proxy", "--envoy-log-level=error", "--log-level=info", "--dns-lookup-family=V4_ONLY"]
env:
- name: TOKEN
- name: REGISTRATION_TOKEN
value: "<TOKEN>"

0 comments on commit bc410cf

Please sign in to comment.