Skip to content

Instantly share code, notes, and snippets.

@fernandoacorreia
Last active April 15, 2024 23:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fernandoacorreia/253e73d7f5f75043efa9ced8ac43d238 to your computer and use it in GitHub Desktop.
Save fernandoacorreia/253e73d7f5f75043efa9ced8ac43d238 to your computer and use it in GitHub Desktop.
Add mitmproxy sidecar
#!/bin/bash
#
# Adds a sidecar container running mitmproxy to a deployment resource.
# See https://mitmproxy.org
#
# The goal is to make it easier to inspect service-to-service HTTP requests in a dev, staging or QA environment.
#
# Not recommended for production usage since it can reveal secrets and it is an actual man-in-the-middle
# (https://owasp.org/www-community/attacks/Manipulator-in-the-middle_attack).
#
# This script assumes some deployment conventions regarding names and labels.
#
# This is what it does:
# - It adds a sidecar container running mitmproxy to a deployment resource's spec template.
# This sidecar is running a reverse proxy and a web UI for inspecting traffic.
# - Sets the deployment's replica count to 1 so that all traffic to that service goes through a
# single reverse proxy instance.
# - Modifies the service resource so that traffic is routed to the reverse proxy.
# The reverse proxy in turn will redirect traffic to the original port (provided via a command line argument).
# - Creates a network policy to allow traffic to the reverse proxy port.
# - Creates a script to port-forward the mitmproxy web ui so that traffic can be inspected in the browser.
set -o nounset -o errexit -o pipefail
die() {
echo $1
exit 1
}
usage() {
echo "Usage: $0 NAMESPACE APP_NAME PORT"
die "Missing argument: $1"
}
# Check if the NAMESPACE argument is provided
if [ -z "${1:-}" ]; then
usage "NAMESPACE"
fi
NAMESPACE=$1
# Check if the APP_NAME argument is provided
if [ -z "${2:-}" ]; then
usage "APP_NAME"
fi
APP_NAME=$2
# Check if the PORT argument is provided
if [ -z "${3:-}" ]; then
usage "PORT"
fi
PORT=$3
# Validate the NAMESPACE and APP_NAME arguments
kubectl get deployment "$APP_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || die "Error: Deployment $APP_NAME does not exist in namespace $NAMESPACE." >&2
kubectl get service "$APP_NAME" -n "$NAMESPACE" >/dev/null 2>&1 || die "Error: Service $APP_NAME does not exist in namespace $NAMESPACE." >&2
# Validate the PORT argument
PORT_INDEX=$(kubectl get svc $APP_NAME -n $NAMESPACE -o json | jq ".spec.ports | map(.port == $PORT) | index(true)")
if [ "$PORT_INDEX" = "null" ]; then
die "No port with value $PORT found in service $APP_NAME."
fi
# Arbitrary port numbers that can be changed if necessary to avoid a conflict
MITM_WEB_PORT=9090
MITM_PROXY_PORT=9099
# Add mitmproxy to deployment resource
echo ""
echo "Adding mitmproxy container to deployment $APP_NAME in namespace $NAMESPACE reverse proxying to port $PORT"
cat > "/tmp/$APP_NAME-patch.json" <<EOF
[
{
"op": "add",
"path": "/spec/template/spec/containers/-",
"value": {
"args": [
"--mode", "reverse:http://localhost:$PORT",
"--web-port", "$MITM_WEB_PORT",
"--listen-port", "$MITM_PROXY_PORT",
"--listen-host", "0.0.0.0",
"--set", "confdir=/tmp",
"--set", "termlog_verbosity=debug",
"--set", "proxy_debug=true",
"--set", "web_debug=true",
"--set", "console_eventlog_verbosity=debug",
"--set", "flow_detail=4",
"--save-stream-file", "/tmp/output.mitm"
],
"command": ["mitmweb"],
"image": "mitmproxy/mitmproxy",
"imagePullPolicy": "Always",
"name": "mitmproxy",
"ports": [
{
"containerPort": $MITM_WEB_PORT,
"name": "mitmweb",
"protocol": "TCP"
},
{
"containerPort": $MITM_PROXY_PORT,
"name": "mitmproxy",
"protocol": "TCP"
}
],
"resources": {},
"securityContext": {
"runAsUser": 1000
},
"terminationMessagePath": "/dev/termination-log",
"terminationMessagePolicy": "File"
}
}
]
EOF
kubectl patch deployment $APP_NAME --namespace=$NAMESPACE --type='json' --patch-file="/tmp/$APP_NAME-patch.json"
# Set replica count to 1 so that all requests go through a single reverse proxy
echo ""
echo "Scaling deployment $APP_NAME to a single pod"
kubectl scale deployment "$APP_NAME" --replicas=1 -n "$NAMESPACE"
# Route traffic to mitmproxy container
echo ""
echo "Updating service $APP_NAME to route external port $PORT to internal port $MITM_PROXY_PORT"
kubectl patch service $APP_NAME -n $NAMESPACE --type='json' -p="[{'op': 'replace', 'path': '/spec/ports/$PORT_INDEX/targetPort', 'value': $MITM_PROXY_PORT}]"
# Create network policy to allow traffic from anywhere to the app's mitmproxy port
NETPOL_NAME=$APP_NAME-mitmproxy
echo ""
echo "Creating network policy $NETPOL_NAME"
cat > "/tmp/$APP_NAME-netpol.json" <<EOF
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: $NETPOL_NAME
spec:
ingress:
- ports:
- port: $MITM_PROXY_PORT
protocol: TCP
podSelector:
matchLabels:
app.kubernetes.io/name: $APP_NAME
policyTypes:
- Ingress
EOF
kubectl apply --namespace=$NAMESPACE -f "/tmp/$APP_NAME-netpol.json"
# Create a script to port-forward the web UI
PORT_FORWARD_SCRIPT="/tmp/$APP_NAME-port-forward.sh"
cat > $PORT_FORWARD_SCRIPT <<EOF
#!/bin/bash
# Port forward port $MITM_WEB_PORT of a single pod in Ready state from the $APP_NAME deployment.
# Retrieve the name of the pod
POD_NAME=\$(kubectl get pods -n $NAMESPACE -l app.kubernetes.io/name=$APP_NAME -o jsonpath="{.items[0].metadata.name}")
# Check if the pod exists
if [ -z "\$POD_NAME" ]; then
echo "No pod found for app $APP_NAME in namespace $NAMESPACE"
exit 1
fi
# Check if the pod is Ready
IS_READY=\$(kubectl get pod -n $NAMESPACE \$POD_NAME -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [ "\$IS_READY" != "True" ]; then
echo "Pod \$POD_NAME is not ready."
exit 1
fi
# Port-forward the MITM_WEB_PORT
echo "Setting up port-forwarding to Ready pod \$POD_NAME on port $MITM_WEB_PORT..."
echo "To view open in your browser: http://localhost:$MITM_WEB_PORT"
kubectl port-forward -n $NAMESPACE \$POD_NAME $MITM_WEB_PORT:$MITM_WEB_PORT
EOF
chmod +x $PORT_FORWARD_SCRIPT
echo ""
echo "Run this command to port-forward mitmproxy's web ui:"
echo "$PORT_FORWARD_SCRIPT"
echo ""
echo "Remember to disable automatic upgrades of this cluster so that the changes don't get reverted."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment