Skip to content

Instantly share code, notes, and snippets.

@pyhedgehog
Last active July 3, 2026 09:51
Show Gist options
  • Select an option

  • Save pyhedgehog/feb63215603273a11c92d0915238f8a5 to your computer and use it in GitHub Desktop.

Select an option

Save pyhedgehog/feb63215603273a11c92d0915238f8a5 to your computer and use it in GitHub Desktop.
acp2kubeconfig - Script to patch (not to setup) user auth to Alauda ACP from Firefox cookies to kubectl config.

acp2kubeconfig

Script to patch (not to setup) user auth to Alauda ACP from Firefox cookies to kubectl config.

Usage

On Windows command will be acp2kubeconfig (aka acp2kubeconfig.cmd), on other systems - acp2kubeconfig.sh (will not work as firefox have other profile locations).

Usage: acp2kubeconfig.cmd [-qvD] [--quiet] [--verbose] [--debug] [-s|--site <host>] [-c|--cookies <cookies-sqlite-path] [[-t|--token] <token>]
Options:
  -q, --quiet		Be quiet
  -v, --verbose		Be verbose
  -d, --debug		Be very verbose
  -s, --site <host>	Host of alauda console (default: acp.ecpk.sibintek.ru)
  -c, --cookies <file>	Path of cookies.sqlite file in Firefox profile (autodetected profile ...)
  -t, --token <token>	Override token (use instead of --cookies)

Requirements

  • busybox64 (choco install busybox)
  • sqlite3 (choco install SQLite)
  • jq (choco install jq)
  • python (choco install python312 or later)
  • yq (python wrapper around jq: python -m pip install pipx&&pipx install yq)
  • (optional) Firefox as a source of login token (choco install FirefoxESR)
  • (sane) kubectl to use result (choco install kubernetes-cli)

Limitations

  • Token can be parsed from firefox cookies (or passed manualy which is nonpractical)
  • A lot of non windows-standard utilities used (starting from busybox-w32).
  • No code to setup kubectl config from ground up.
  • Output if fragile on console code page. Some issues fixed by PYTHONUTF8=1, but you never know...

As a result this almost only can be used by author. Sorry.

@echo off
busybox64 env ACP2KUBECONFIG=%~nx0 %~dpn0.sh %*
#!/usr/bin/env sh
set -e -o pipefail
trap 'echo "On $action failed with $?"' ERR
action=setup
quiet=false
verbose=false
debug=false
site="${ACP_SITE:-}"
ffbase=~/AppData/Roaming/Mozilla/Firefox
acptoken=
cookies=
ffprofile=
if [ -f "$ffbase/profiles.ini" ] ; then
ffprofile="$(sed -nre 's/^Default=Profiles\/(.*)\r?$/\1/p' "$ffbase/profiles.ini"|head -1)"
if [ -f "$ffbase/Profiles/$ffprofile/cookies.sqlite" ] ; then
cookies="$ffbase/Profiles/$ffprofile/cookies.sqlite"
else
ffprofile=
fi
fi
progname="${ACP2KUBECONFIG:-${0##*/}}"
usage="Usage: ${progname} [-qvD] [--quiet] [--verbose] [--debug] [-s|--site <host>] [-c|--cookies <cookies-sqlite-path] [[-t|--token] <token>]"
if ! O=`getopt -l quiet,verbose,debug,site:,cookies:,token:,help -n "${0##*/}" -- qvDs:c:t:h "$@"` ; then
echo "$usage"
exit 1
fi
eval set -- "$O"
while true; do
case "$1" in
-v|--verbose)
verbose=true;quiet=false;shift;;
-q|--quiet)
quiet=true;verbose=false;shift;;
-D|--debug)
debug=true;shift;;
-s|--site)
site="$2";shift 2;;
-c|--cookies)
cookies="$2";shift 2;;
-t|--token)
acptoken="$2";shift 2;;
-h|--help)
echo "$usage"
echo "Options:"
echo " -q, --quiet Be quiet$($quiet && echo " (default)")"
echo " -v, --verbose Be verbose$($verbose && echo " (default)")"
echo " -d, --debug Be very verbose"
echo " -s, --site <host> Host of alauda console$(test -n "$site" && echo " (default: $site)" || echo " (required)")"
echo " -c, --cookies <file> Path of cookies.sqlite file in Firefox profile$(test -n "$cookies" && echo " (autodetected profile $ffprofile)")"
echo " -t, --token <token> Override token (use instead of --cookies)"
exit 1;;
--)
shift; break;;
*)
echo getopt error;echo "$usage";exit 1;;
esac
done
if [ "$#" == "1" ] && [ -z "$acptoken" ] ; then
acptoken="$1"
shift
fi
if [ "$#" != "0" ] ; then
echo "getopt error: Leftover arguments: $*"
echo "$usage"
exit 1
fi
if [ -z "$site" ] ; then
echo "Either pass --site with host of Alauda ACP or set ACP_SITE globally."
echo "$usage"
exit 1
fi
if [ -z "$cookies" ] && [ -z "$acptoken" ] ; then
echo "$(test -z "$ffprofile" && echo "Unable to autodetect ff profile. ")Either pass --cookies with path to cookies.sqlite or --token."
echo "$usage"
exit 1
fi
#echo -e "quiet=$quiet\nverbose=$verbose\ndebug=$debug\nsite=$site\nffprofile=$ffprofile\ncookies=$cookies\nacptoken=$acptoken"
#exit
if [ -z "$acptoken" ] ; then
#if ! [ -f "$cookies" ] ; then
# echo "FATAL: Unable to find file $cookies"
# exit 1
#fi
acptoken="$(sqlite3 -ifexists -readonly -batch "$cookies" "select value from moz_cookies where host='$site' and name='cpaas_id_token'" \
| jq -n '[inputs][0]? // ""|split(" ")[1]? // ("FATAL: Unable to detect acptoken.\n"|halt_error)' -r)"
fi
#kubeuser=c-common
kubeuser="$(yq -r --arg site "$site" '"FATAL: Incorrect ~/.kube/config file.\n" as $e|(.clusters|map(select(.cluster.server|startswith("https://\($site)")))[0]? // ($e|halt_error)|.name) as $cluster|(.contexts[]|select(.context.cluster==$cluster)|.context+{context:.name}) as {$context,$user}|.users[]|select(.name==$user)|if .user.token then $user else $e|halt_error end' ~/.kube/config)"
kubetoken="$(yq -r --arg kubeuser "$kubeuser" '.users|map(select(.name==$kubeuser).user.token)[0]? // ("FATAL: Incorrect ~/.kube/config file.\n"|halt_error)' ~/.kube/config)"
#echo -e "acptoken=$acptoken\nkubeuser=$kubeuser\nkubetoken=$kubetoken"
#exit
action=check
if [ "$acptoken" == "$kubetoken" ] ; then
action=skip
$verbose && echo "Already up to date."
else
action='prepare patch'
$verbose && echo "Will patch..."
sed -e "s/${kubetoken//./\\.}/$acptoken/" ~/.kube/config > ~/.kube/config.new
action='verify patch'
yq -s --arg kubeuser "$kubeuser" --arg kubetoken "$kubetoken" --arg acptoken "$acptoken" '
if type=="array" and length==2 then (
. as [$old,$new]|
if $new|(type!="object" or (has("users")|not) or (.users|type)!="array") then "FATAL: New config has invalid format.\n"|halt_error
elif $old|(type!="object" or (has("users")|not) or (.users|type)!="array") then "FATAL: Old config has invalid format.\n"|halt_error
else . end|
($old.users|to_entries|map(select(.value.name==$kubeuser))[0].key) as $i|
if $new.users[$i]?.name?!=$kubeuser then "FATAL: New config has invalid $i user ref.\n"|halt_error
elif $new.users[$i].user.token!=$acptoken then "FATAL: New config has invalid $i user token.\n"|halt_error
elif $old.users[$i].user.token!=$kubetoken then "FATAL: Old config has invalid $i user token.\n"|halt_error
else empty end
) else "FATAL: Input error\n"|halt_error end' ~/.kube/config ~/.kube/config.new
$debug && diff -su ~/.kube/config ~/.kube/config.new || true
action='diff patch'
commentchanges="$(diff -awNU0 ~/.kube/config ~/.kube/config.new|grep -cEe '^-\s*#')"||true
changes="$(diff -awNU0 ~/.kube/config ~/.kube/config.new|grep -vEe '^-\s*#'|grep -cEe '^[+-]\s')"||true
action='check patch'
warn=false
fail=false
skip=false
if [ $commentchanges -gt 0 ] ; then echo "WARN: Will remove $commentchanges comment lines" ; warn=true ; fi
if [ $changes -ge 10 ] ; then echo "WARN: Too much changes$($debug && echo ": $changes")" ; fail=true
elif [ $changes -gt 2 ] ; then echo "WARN: More changes than expecpected$($debug && echo ": $changes")" ; fail=true
elif [ $changes -lt 1 ] ; then echo "WARN: Seems there are no changes" ; skip=true
elif [ $changes -lt 2 ] ; then echo "WARN: Incorrect number of changes$($debug && echo ": $changes != 2")" ; fail=true
elif $debug ; then echo "Correct: $changes == 2"
fi
if $skip ; then
action='skip patch'
true
elif $fail ; then
action='fail patch'
echo If sure:
echo mv -f ~/.kube/config.new ~/.kube/config
elif $warn ; then
action='warn patch'
mv -i ~/.kube/config.new ~/.kube/config
$debug && echo mv-res=$?
else
action='apply patch'
mv -f ~/.kube/config.new ~/.kube/config
$debug && echo mv-res=$?
fi
fi
action=inspect
if $quiet ; then
true
elif $verbose ; then
yq '.users[].user.token? // empty|gsub("_";"/")|gsub("-";"+")|split(".")[1]|@base64d|fromjson
|(.exp,.iat)|=(. as $in|try todate catch $in)|if .roles then .roles|=join(",") end
|del(.sub,.c_hash,.at_hash,.nonce,.aud)|if .email_verified?==true then del(.email_verified) end
|if .ext?.is_admin?==false and (.ext? // {}|keys)==["conn_id","is_admin"] then del(.ext) end' ~/.kube/config
else
#saveCP=`chcp.com 2>&1|sed -nre 's/^.*: (\S+)\r?$/\1/p'`
#chcp.com 65001 &> /dev/null
#yq -r -b '.users[].user.token? // empty|gsub("_";"/")|gsub("-";"+")|split(".")[1]|@base64d|fromjson
# |(.exp,.iat)|=todate|"Token for \(.name) (\(.email)) as \(.iss),\nsince \(.iat) till \(.exp)"' ~/.kube/config
#test -z "$saveCP" || chcp.com "$saveCP" &> /dev/null
PYTHONUTF8=1 yq -y '.users[].user.token? // empty|gsub("_";"/")|gsub("-";"+")|split(".")[1]|@base64d|fromjson
|(.exp,.iat)|=todate|{user:"\u0022\(.name)\u0022 <\(.email)>",target:.iss,since:.iat,till:.exp}' ~/.kube/config
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment