Skip to content

Instantly share code, notes, and snippets.

@donaldguy
Created August 8, 2018 21:45
Show Gist options
  • Save donaldguy/415f94ea7a553f2c4e7db58327566450 to your computer and use it in GitHub Desktop.
Save donaldguy/415f94ea7a553f2c4e7db58327566450 to your computer and use it in GitHub Desktop.
Ensure an Ubuntu AKS worker pool is patched against CVE-2018-5390 aka SegmentSmack/FragmentSmack
#!/bin/bash
# This script is intended to ensure an AKS worker pool is patched against CVE-2018-5390 aka SegmentSmack/FragmentSmack
# by ensuring kernel is patched to version 4.15.0-1019
set -eu
case ${1:-} in
-h|--help|help|/?)
echo "Usages:"
echo " To determine unpatched machines and upgrade all (after prompt):"
echo " $0 - will prompt for args"
echo " $0 [subscription_id] [aks_cluster_name]"
echo " $0 [subscription_id] [resource_group]/[aks_cluster_name] (if name ambiguous)"
echo " Attempt to upgrade a single machine (even if detection would think it done):"
echo " $0 [subscription_id] [aks_cluster_name] [worker node name]"
;;
*)
;;
esac
subscription=${1:-}
aks_cluster=${2:-}
if echo $aks_cluster | grep -q '/'; then
aks_cluster_resource_group=$(echo $aks_cluster | cut -d'/' -f 1)
aks_cluster=$(echo $aks_cluster | cut -d'/' -f 2)
fi
node_name=${3:-}
printf "Verifying az installed: "
if ! which az; then
echo "not found!"
exec >&2
echo "Could not find azure-cli! Please install it per https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"
exit 1
fi
printf "Verifying az acs/aks module version is 2.X: "
if ! az --version | grep acs | grep '(2.'; then
echo "pre-2.x"
exec >&2
echo "Please upgrade your azure-cli, https://docs.microsoft.com/en-us/cli/azure/install-azure-cli"
fi
if [[ -z "$subscription" ]]; then
subscriptions=()
while IFS="\n" read -r sub; do
subscriptions+=( "$sub" )
done < <(az account list -o tsv | awk -F '\t' '{print $4}')
PS3="Which subscription do you want to use? "
select sub_name in "${subscriptions[@]}"; do
az account set -s "$sub_name"
subscription=$(az account show --query id | sed 's/"//g')
echo "Using subscription: $subscription"
echo
break
done
fi
if [[ ! -z "${aks_cluster_resource_group:-}" ]]; then
constrained_resource_group_args="--resource-group $aks_cluster_resource_group"
else
constrained_resource_group_args=""
fi
if [[ -z "$aks_cluster" ]]; then
while IFS="\n" read -r cluster; do
clusters+=( "$cluster" )
done < <(az aks list $constrained_resource_group_args --query "[:].name | join('|', @)" | sed 's/"//g' | tr '|' "\n")
PS3="Which cluster do you want to use? "
select cluster in "${clusters[@]}"; do
aks_cluster=$cluster
echo
break
done
fi
echo "Determining resource groups: "
if [[ -z "${aks_cluster_resource_group:-}" ]]; then
aks_cluster_resource_group=$(az aks list --query "[?name == '$aks_cluster'].resourceGroup | @[0] " | sed 's/"//g')
fi
echo " managedCluster in: $aks_cluster_resource_group"
aks_cluster_node_resource_group=$(az aks show --resource-group $aks_cluster_resource_group --name $aks_cluster --query nodeResourceGroup | sed 's/"//g')
echo " worker pool in: $aks_cluster_node_resource_group"
kubeconfig_path="$(mktemp $TMPDIR/aks_kubeconfig_XXXXX)"
printf "Fetching kubeconfig: "
az aks get-credentials --resource-group $aks_cluster_resource_group --name $aks_cluster --file $kubeconfig_path
export KUBECONFIG="$kubeconfig_path"
printf "Checking for kubectl: "
if ! which kubectl; then
echo "Not found."
printf "Determining k8s version: "
k8s_version=$(az aks show --resource-group $aks_cluster_resource_group --name $aks_cluster --query kubernetesVersion | sed 's/"//g')
echo "$k8s_version"
echo "Installing kubectl: "
az aks install-cli --client-version $k8s_version
fi
function kubectl_get_kernel_versions() {
kubectl get node -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kernelVersion}{"\n"}{end}'
}
declare -a nodes_to_patch=()
if [ -z "$node_name" ]; then
echo
printf "Examining kernel versions (target is >= 4.15.0-1019): "
node_kernels="$(kubectl_get_kernel_versions)"
echo
(
printf "NAME\tKERNEL\n"
echo "$node_kernels"
) | column -t -s $'\t'
echo
echo "Determining nodes to update:"
while IFS="\n" read -r line; do
node=$(echo $line | awk '{print $1}')
version=$(echo $line | awk '{print $2}')
major=$(echo $version | awk -F '.' '{print $1}' )
minor=$(echo $version | awk -F '.' '{print $2}' )
patch_str=$(echo $version | awk -F '.' '{print $3}' )
patch=$(echo $patch_str | awk -F '-' '{print $1}' )
iteration=$(echo $patch_str | awk -F '-' '{print $2}' )
if [[ $major < 5 && $minor < 16 && $patch < 1 && $iteration < 1019 ]]; then
nodes_to_patch+=( "$node" )
fi
done < <(echo "$node_kernels")
if [[ ${#nodes_to_patch[@]} == 0 ]]; then
echo "Everything is up to date!"
exit
fi
for node in ${nodes_to_patch[@]}; do
echo " - $node"
done
read -p "Do you want to patch these nodes now? " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo
else
echo
echo "Okay! exiting. You can patch each node individually by running: "
for node in ${nodes_to_patch[@]}; do
echo " $0 $subscription $aks_cluster_resource_group/$aks_cluster $node"
done
exit 0
fi
else
nodes_to_patch=( "$node_name" )
fi
function do_remote_command() {
RESOURCE_GROUP=$1
VM_NAME=$2
SCRIPT="$3"
az vm run-command invoke --command-id RunShellScript \
--resource-group $RESOURCE_GROUP \
--name $VM_NAME \
--scripts "$SCRIPT" > /dev/null
}
for node in ${nodes_to_patch[@]}; do
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
echo "!!! Going to patch and restart $node"
echo "= Draining:"
kubectl drain --ignore-daemonsets $node
echo "= Patching:"
commands=(
"apt-get update"
"apt-get install -y linux-azure"
)
for cmd in "${commands[@]}"; do
echo "- $cmd:"
do_remote_command $aks_cluster_node_resource_group $node "$cmd"
echo "done"
done
echo "= Restarting: "
az vm restart --resource-group $aks_cluster_node_resource_group --name $node
printf "= Waiting for node to go NotReady: "
while ! kubectl get node $node --no-headers | awk '{print $2}' | grep -q "^NotReady"; do
printf "."
sleep 2
done
echo "NotReady"
printf "= Waiting for node to go Ready: "
while ! kubectl get node $node --no-headers | awk '{print $2}' | grep -q "^Ready"; do
printf "."
sleep 2
done
echo "Ready"
printf "= Removing cordon: "
kubectl uncordon $node
done
printf '%*s\n' "${COLUMNS:-$(tput cols)}" '' | tr ' ' -
echo "Final State"
(
printf "NAME\tKERNEL\n"
kubectl_get_kernel_versions
) | column -t -s $'\t'
@1600
Copy link

1600 commented Aug 9, 2018

which linux distro are you checking against?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment