AWS Service Task Access
This section covers how to connect to Parallel's service tasks through AWS bastion hosts using port forwarding.
Parallel Config
bash
# Configuration
typeset -A _PARALLEL_CONFIG
_PARALLEL_CONFIG=(
# Bastion instances
[bastion_prod]="i-0430e03b4e1c1bbdd"
[bastion_staging]="i-0f052721e4ba2c318"
# RDS cluster identifiers
[rds_suffix_prod]="clwscu6m8xeq.eu-west-3.rds.amazonaws.com"
[rds_suffix_staging]="c5wmseg8am3n.eu-west-3.rds.amazonaws.com"
# Environment prefixes
[prefix_prod]="parallel-euw3-prod"
[prefix_staging]="parallel-euw3-staging"
# Default local port ranges (prod: 554xx, staging: 654xx)
[port_base_prod]="55432"
[port_base_staging]="65432"
)Connect to a task
bash
# ============================================
# Connect to Generic Task Service
# ============================================
_connect-service() {
local ENV="$1"
local SERVICE="$2"
local LOCAL_PORT="$3"
local REMOTE_PORT="$4"
aws-sso-util login --profile "parallel_${ENV}"
export AWS_PROFILE="parallel_${ENV}"
local BASTION="${_PARALLEL_CONFIG[bastion_${ENV}]}"
local PREFIX="${_PARALLEL_CONFIG[prefix_${ENV}]}"
local CLUSTER="${PREFIX}-ecs-cluster"
local ECS_SERVICE="${PREFIX}-ecs-${SERVICE}"
echo "🔍 Finding task for ${SERVICE}..."
# 1. Get Task ARN
local TASK_ARN
TASK_ARN=$(aws ecs list-tasks \
--cluster "$CLUSTER" \
--service-name "$ECS_SERVICE" \
--query 'taskArns[0]' \
--output text)
if [[ "$TASK_ARN" == "None" ]] || [[ -z "$TASK_ARN" ]]; then
echo "❌ No running task found for service: $SERVICE"
return 1
fi
local HOST_IP=""
# 2. Get Task Details (Raw JSON) to find ENI
# We grep for the specific pattern "eni-..." inside the task description
local TASK_JSON
TASK_JSON=$(aws ecs describe-tasks --cluster "$CLUSTER" --tasks "$TASK_ARN" --output json)
# Extract ENI ID using grep (looks for "value": "eni-...")
local ENI_ID
ENI_ID=$(echo "$TASK_JSON" | grep -o '"value": "eni-[^"]*"' | cut -d'"' -f4 | head -n 1)
if [[ -n "$ENI_ID" ]]; then
HOST_IP=$(aws ec2 describe-network-interfaces \
--network-interface-ids "$ENI_ID" \
--query 'NetworkInterfaces[0].PrivateIpAddress' \
--output text)
fi
# 3. Fallback: Check for EC2 Instance ID (if grep failed or it's not Fargate)
if [[ -z "$HOST_IP" || "$HOST_IP" == "None" ]]; then
# Extract Instance ID using grep
local INSTANCE_ID
INSTANCE_ID=$(echo "$TASK_JSON" | grep -o '"ec2InstanceId": "i-[^"]*"' | cut -d'"' -f4 | head -n 1)
if [[ -n "$INSTANCE_ID" ]]; then
HOST_IP=$(aws ec2 describe-instances \
--instance-ids "$INSTANCE_ID" \
--query 'Reservations[0].Instances[0].PrivateIpAddress' \
--output text)
fi
fi
if [[ -z "$HOST_IP" || "$HOST_IP" == "None" ]]; then
echo "❌ Could not resolve Host IP. The task might be pending or the network mode is unsupported."
return 1
fi
echo ""
echo "🥑 Connecting to ${SERVICE} service (${ENV})..."
echo " Task: $TASK_ARN"
echo " Host: $HOST_IP"
echo " Port: ${REMOTE_PORT} → localhost:${LOCAL_PORT}"
echo ""
aws ssm start-session \
--target "$BASTION" \
--document-name "AWS-StartPortForwardingSessionToRemoteHost" \
--parameters "{\"host\":[\"${HOST_IP}\"],\"portNumber\":[\"${REMOTE_PORT}\"],\"localPortNumber\":[\"${LOCAL_PORT}\"]}"
}
# ================== PROD ==================
# Prod usually starts at 9080.
connect-guacamole-prod() { _connect-service "prod" "guacamole" "8080" "9080"; }
# ================ STAGING =================
# Staging usually starts at 8080.
connect-guacamole-staging() { _connect-service "staging" "guacamole" "8080" "8080"; }